do_brk()源码剖析

unsigned long do_brk(unsigned long addr, unsigned long len){...}
do_brk函数目的是为了将addr位置向后继续申请len字节长度,用作于扩展堆内存的长度
  1. 首先会对于len这个长度进行页面对齐,并且去判断页面对齐之后是否超出了边界

       len = PAGE_ALIGN(len);
       if (!len)
           return addr;
       if ((addr + len) > TASK_SIZE || (addr + len) < addr)
           return -EINVAL;
  2. 判断一下当前的物理内存是否处于锁定状态(防止被交换出去),保持和原来状态的一致性

       if (mm->def_flags & VM_LOCKED) {
           unsigned long locked, lock_limit;
           locked = mm->locked_vm << PAGE_SHIFT;
           lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
           locked += len;
           if (locked > lock_limit && !capable(CAP_IPC_LOCK))
               return -EAGAIN;
       }
  3. 寻找当前addr位置对应的vma,看看是不是已经存在的vma将addr已经覆盖了,需要调用munmap将覆盖部分清除,保证addr到addr+len这一段内存是空白的没有被任何的vma所覆盖。

       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;
       }
  4. 对于当前上一个的vma进行扩展,扩展至addr加上len的位置,如果成功那么OK,进行mm_struct的维护然后返回。

       if (vma_merge(mm, prev, addr, addr + len, flags,
                   NULL, NULL, pgoff, NULL))
       goto out;
  5. 否则需要来创建一个新的vma来对当前的内存进行映射,将变量设置后放入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->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_link(mm, vma, prev, rb_link, rb_parent);
       

且行且歌_C
62 声望8 粉丝

逝者如斯夫,不舍昼夜


引用和评论

0 条评论