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);