unsigned long do_brk(unsigned long addr, unsigned long len){...}
do_brk函数目的是为了将addr位置向后继续申请len字节长度,用做于扩展堆内存的长度
首先会对于len这个长度进行页面对齐,而且去判断页面对齐以后是否超出了边界函数
len = PAGE_ALIGN(len); if (!len) return addr; if ((addr + len) > TASK_SIZE || (addr + len) < addr) return -EINVAL;
判断一下当前的物理内存是否处于锁定状态(防止被交换出去),保持和原来状态的一致性code
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; }
寻找当前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; }
对于当前上一个的vma进行扩展,扩展至addr加上len的位置,若是成功那么OK,进行mm_struct的维护而后返回。源码
if (vma_merge(mm, prev, addr, addr + len, flags, NULL, NULL, pgoff, NULL)) goto out;
不然须要来建立一个新的vma来对当前的内存进行映射,将变量设置后放入vma的红黑树链表中。it
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);