看上面可以看出:clear_page_tables中,要操作的线性地址即为prev,prev->next之间的空洞线性地址。理解了这点之后,上面的代码就变得很简单了^_^

三:用户空间的伸展

先回顾一下sys_brk的代码:

asmlinkage unsigned long sys_brk(unsigned long brk)

{

……

……

//前一部份是用户空间的收缩

/* Check against rlimit.. */

//不能超过数据段上限

rlim = current->rlim[RLIMIT_DATA].rlim_cur;

if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim)

goto out;

/* Check against existing mmap mappings. */

//伸展空间已经有映射了

if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))

goto out;

/* Ok, looks good - let it rip. */

//执行具体的伸展过程

if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)

goto out;

set_brk:

//设置新边界

mm->brk = brk;

out:

retval = mm->brk;

up_write(&mm->mmap_sem);

return retval;

}

在这有一个值得注意的地方:

find_vma_intersection()的实现如下:

//判断进程的地址空间是否与给定的地址区间相交叉

static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)

{

//找到第一个结束地址大于addr的vma

struct vm_area_struct * vma = find_vma(mm,start_addr);

//判断vma是否是给定地址区间有交叉

if (vma && end_addr <= vma->vm_start)

vma = NULL;

return vma;

}

那为什么sys_brk中

find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)调用中,newbrk为什么要加上PAGE_SIZE呢?

这是因为newbrk与oldbrk已经是经过页框对齐后的地址:如下

newbrk = PAGE_ALIGN(brk);

oldbrk = PAGE_ALIGN(mm->brk);

而且,每个vma的起始地址跟长度都是与页框对齐的(参考ULK3).注意到find_vma_intersection()判断是否交替的时候带有一个’=’.也就是判断newbrk的下一个页框是否在进程的线性区中

接着往下看,经过判断之后,就会进入到do_brk():

unsigned long do_brk(unsigned long addr, unsigned long len)

{

struct mm_struct * mm = current->mm;

struct vm_area_struct * vma, * prev;

unsigned long flags;

struct rb_node ** rb_link, * rb_parent;

pgoff_t pgoff = addr >> PAGE_SHIFT;

//长度按页框对齐,不过在我们这个流程来说,这个步骤是没必要的

//因为start与end都与页框对齐,end – start肯定也是与页框对齐的

len = PAGE_ALIGN(len);

if (!len)

return addr;

//有效性判断

if ((addr + len) > TASK_SIZE || (addr + len) < addr)

return -EINVAL;

//VM_LOCKED:页被锁住不能被交换出去

if (mm->def_flags & VM_LOCKED) {

unsigned long locked, lock_limit;

locked = mm->locked_vm << PAGE_SHIFT;

lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;

locked += len;

if (locked > lock_limit && !capable(CAP_IPC_LOCK))

return -EAGAIN;

}

/*

* Clear old maps.this also does some error checking for us

*/

munmap_back:

//sys_brk的流程会进入到这个if吗???

vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);

if (vma && vma->vm_start < addr + len) {

if (do_munmap(mm, addr, len))

return -ENOMEM;

goto munmap_back;

}

//判断是否超过了限制

if ((mm->total_vm << PAGE_SHIFT) + len

> current->rlim[RLIMIT_AS].rlim_cur)

return -ENOMEM;

if (mm->map_count > sysctl_max_map_count)

return -ENOMEM;

//判断系统是否有足够的内存

if (security_vm_enough_memory(len >> PAGE_SHIFT))

return -ENOMEM;

flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;

//判断是否可以合并

//如果可以合并,就将基合并为一个VMA区

if (vma_merge(mm, prev, addr, addr + len, flags,

NULL, NULL, pgoff, NULL))

goto out;

//不可以合并,新建一个VMA

vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);

if (!vma) {

vm_unacct_memory(len >> PAGE_SHIFT);

return -ENOMEM;

}

memset(vma, 0, sizeof(*vma));

//设值VMA的值

vma->vm_mm = mm;

vma->vm_start = addr;

vma->vm_end = addr + len;

vma->vm_pgoff = pgoff;

vma->vm_flags = flags;

vma->vm_page_prot = protection_map[flags & 0x0f];

//将新分配的VMA插入到进程的VMA链表

vma_link(mm, vma, prev, rb_link, rb_parent);

out:

mm->total_vm += len >> PAGE_SHIFT;

if (flags & VM_LOCKED) {

mm->locked_vm += len >> PAGE_SHIFT;

//如果定义了LOCKED。就为其分配内存

make_pages_present(addr, addr + len);

}

return addr;

}

make_pages_present()其实就是为每一个线性区模拟了一个缺页异常,然后再由缺页异常程序为之分配内存。

若vm flag没有带VM_LOCKED的时候,它只是为进程分配了一个可以使用的线性地址,以后要访问这个地址的时候,就会产生缺页异常,具体关于缺页异常的处理,我们在下一节接着分析

四:总结

我们在前面分析过了vfree()的实现。还记得vfree()只是释放了内存页表项所映射的物理内存,而在进程管理的时候,sys_brk收缩线性区的时候,它不仅释放了内表所映射的物理内存还把空间页表项。PMD所占的内存释放掉了。内核这样处理是为了效率考虑的。

另外,sys_brk在扩展线性区的时候,仅分配了一个允许进程使用的合法的线性地址,等到真正要使用的时候再给其映射具体的内存,这在操作系统设计里也叫请求调页。等到下节分析缺页异常的时候,再来详细讨论

sys_brk分析 linux1.2.0版本,linux内存管理之sys_brk实现分析(续)相关推荐

  1. sys_brk分析 linux1.2.0版本,linux内存管理之sys_brk实现分析

    分析完linux内存管理的基本概念与实现之后,就可以接着分析用户空间与内核空间的交互操作了.Brk系统调用属于那种常用但是"可见度"不高的操作,常用于用户空间堆的管理(请参阅本站的 ...

  2. Linux内核分析(三)----初识linux内存管理子系统

    原文:Linux内核分析(三)----初识linux内存管理子系统 Linux内核分析(三) 昨天我们对内核模块进行了简单的分析,今天为了让我们今后的分析没有太多障碍,我们今天先简单的分析一下linu ...

  3. linux brk函数,linux内存管理之sys_brk实现分析(续)

    unmap_region是整个收缩过程中的核心,它主要完成相应项表项的修改,具体映射页框的释放 代码如下: static void unmap_region(struct mm_struct *mm, ...

  4. Linux内存管理(四):paging_init分析

    上文介绍了启动页表的创建,通过fix map建立DTB物理地址的映射,以及memblock管理物理内存.现在我们能够通过memblock进行物理内存的分配,但分配的内存还不能够进行访问,我们需要对me ...

  5. Linux内存page,【原创】(十四)Linux内存管理之page fault处理

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  6. Linux内存管理 brk(),mmap()系统调用源码分析2:brk()的内存释放流程

    Linux brk(),mmap()系统调用源码分析 brk()的内存释放流程 荣涛 2021年4月30日 内核版本:linux-5.10.13 注释版代码:https://github.com/Rt ...

  7. Linux内存管理 brk(),mmap()系统调用源码分析1:基础部分

    Linux内存管理 brk(),mmap(),munmap()系统调用源码分析 基础部分 荣涛 2021年4月30日 内核版本:linux-5.10.13 注释版代码:https://github.c ...

  8. 深入理解Linux内存管理(0.3)

    学习方法论 写作原则 标题括号中的数字代表完成度与完善度 0.0-1.0 代表完成度,1.1-1.5 代表完善度 0.0 :还没开始写 0.1 :写了一个简介 0.3 :写了一小部分内容 0.5 :写 ...

  9. Linux内存管理和分析vmalloc使用的地址范围

    From: http://www.cnblogs.com/dubingsky/archive/2010/04/20/1716158.html Vmalloc可以获得的地址在VMALLOC_START到 ...

最新文章

  1. scratch跳一跳游戏脚本_跳一跳游戏:经典跳一跳2微信小游戏,点开既玩
  2. c# ftp类[转]
  3. Python学习笔记——os模块【文件、目录方法】
  4. 深入理解了MySQL,你才能说熟悉数据库
  5. [转载] $CF290F$ 题解
  6. Android应用程序窗口(Activity)与WindowManagerService服务的连接过程分析
  7. react动态改变选中不选中_reactjs – 如何避免使用重新选择来计算派生状态时React重新渲染...
  8. linux eclipse c++ 如何生成arm可执行文件_干货 | protobuf-c之嵌入式平台使用
  9. 《构建之法》1、2、3章读后感
  10. 跳转前暂停几秒js如何实现
  11. Windows2008+MyEclipse10+Android开发环境搭配
  12. Mysql中Drop,Truncate,Delete的区别
  13. 精通git中文版 (连载四)
  14. java batik_java – 如何在Batik SVG库中使用自定义字体?
  15. 服务器lsass状态代码c0000005,提示lsass.exe失败状态代码c0000005
  16. MongoDB下载、安装和配置教程
  17. INCONEL 625合金介绍
  18. css固定图片大小 vue_img设置图片大小 vue_如何改变图片大小
  19. 题目 1341. 十三号星期五
  20. echarts画工作流(流程图)

热门文章

  1. web安全检查_如何利用现代Web检查器的功能
  2. python seaborn heatmap可视化相关性矩阵
  3. 增删改查通用测试用例-禅道模板
  4. Python中多线程和多处理的初学者指南
  5. shell编程之进阶篇三常见命令详解
  6. ASP.NET状态管理之十三(总结)
  7. 多站点IIS的架设:端口法
  8. 漫步最优化三十——非精确线搜索
  9. Python:数据类型
  10. 【论文学习】Fast End-to-End Trainable Guided Filter