int do_munmap(struct mm_struct *mm, unsigned long start, size_t len,struct list_head *uf)
用于释放通过do_mmap 映射的内存
其源码分析如下:
int do_munmap(struct mm_struct *mm, unsigned long start, size_t len,
struct list_head *uf)
{
unsigned long end;
struct vm_area_struct *vma, *prev, *last;
if ((offset_in_page(start)) || start > TASK_SIZE || len > TASK_SIZE-start)
return -EINVAL;
#要ummap的长度也是page size对齐的
len = PAGE_ALIGN(len);
if (len == 0)
return -EINVAL;
/* Find the first overlapping VMA */
#找到起始地址是落在哪个vm_area_struct *vma内
vma = find_vma(mm, start);
#没有找到这个vma的话,直接返回
if (!vma)
return 0;
prev = vma->vm_prev;
/* we have start < vma->vm_end */
/* if it doesn't overlap, we have nothing.. */
#得到要释放空间的结束地址
end = start + len;
#如果要释放空间的结束地址都小于vma的起始地址,说明这两者就没有重叠,直接退出
if (vma->vm_start >= end)
return 0;
/*
* If we need to split any vma, do it now to save pain later.
*
* Note: mremap's move_vma VM_ACCOUNT handling assumes a partially
* unmapped vm_area_struct will remain in use: so lower split_vma
* places tmp vma above, and higher split_vma places tmp vma below.
*/
if (start > vma->vm_start) {
int error;
/*
* Make sure that map_count on return from munmap() will
* not exceed its limit; but let map_count go just above
* its limit temporarily, to help free resources as expected.
*/
#
if (end < vma->vm_end && mm->map_count >= sysctl_max_map_count)
return -ENOMEM;
#由于start > vma->vm_start ,所以要释放的空间和vm_start 之间有一段gap。这里就是分离这段gap
error = __split_vma(mm, vma, start, 0);
if (error)
return error;
prev = vma;
}
/* Does it split the last one? */
#找到要释放空间结束地址的vm_area_struct
last = find_vma(mm, end);
#如果下面这个if 条件成立,则说明要释放的空间和last的vm_end 之间有gap
if (last && end > last->vm_start) {
int error = __split_vma(mm, last, end, 1);
if (error)
return error;
}
vma = prev ? prev->vm_next : mm->mmap;
if (unlikely(uf)) {
/*
* If userfaultfd_unmap_prep returns an error the vmas
* will remain splitted, but userland will get a
* highly unexpected error anyway. This is no
* different than the case where the first of the two
* __split_vma fails, but we don't undo the first
* split, despite we could. This is unlikely enough
* failure that it's not worth optimizing it for.
*/
int error = userfaultfd_unmap_prep(vma, start, end, uf);
if (error)
return error;
}
/*
* unlock any mlock()ed ranges before detaching vmas
*/
#如果这段要释放的空间是lock的,则要ublock掉
if (mm->locked_vm) {
struct vm_area_struct *tmp = vma;
while (tmp && tmp->vm_start < end) {
if (tmp->vm_flags & VM_LOCKED) {
mm->locked_vm -= vma_pages(tmp);
munlock_vma_pages_all(tmp);
}
tmp = tmp->vm_next;
}
}
/*
* Remove the vma's, and unmap the actual pages
*/
#unmap 实际的占用的pages
detach_vmas_to_be_unmapped(mm, vma, prev, end);
unmap_region(mm, vma, prev, start, end);
arch_unmap(mm, vma, start, end);
/* Fix up all other VM information */
#删除进程mm中的vma
remove_vma_list(mm, vma);
return 0;
}
内存管理API之do_munmap
最新推荐文章于 2023-03-02 00:07:11 发布