8.3 合并VMA(具体实现还需继续理解)

  在新的VMA被加入到进程的地址空间时,内核会检查它是否可以与一个或多个现存的VMA进行合并。vma_merge()函数实现将一个新的VMA和附近的VMA合并功能。如下图:

 

就一个函数:

vma_merge()函数参数多达9个,其中mm是相关进程的struct mm_struct数据结构;prev是紧接着新VMA前继节点的VMA,一般通过find_vma_links()函数来获取;add和end是最新的VMA的起始地址和结束地址;vm_flags是最新VMA的标志位。如果新VMA属于一个文件映射,则参数file指向该文件struct file数据结构。参数proff指定文件映射偏移量;参数anon_vma是匿名映射的struct anon_vma数据结构。

/*
 * Given a mapping request (addr,end,vm_flags,file,pgoff), figure out
 * whether that can be merged with its predecessor or its successor.
 * Or both (it neatly fills a hole).给定一个映射请求(addr,end,vm_flags,file,pgoff),
弄清楚是否可以将其与其前任或后继合并。 或两者兼有(整齐地填充了一个洞)。
 *
 * In most cases - when called for mmap, brk or mremap - [addr,end) is
 * certain not to be mapped by the time vma_merge is called; but when
 * called for mprotect, it is certain to be already mapped (either at
 * an offset within prev, or at the start of next), and the flags of
 * this area are about to be changed to vm_flags - and the no-change
 * case has already been eliminated.
在大多数情况下-当调用mmap,brk或mremap时-确定在调用vma_merge时不会将[addr,end)
映射。 但是当调用mprotect时,肯定已经被映射(在prev内的偏移量处,或者在next的开始处),
并且该区域的标志将被更改为vm_flags,并且无变化的情况是 已经被淘汰。
 *
 * The following mprotect cases have to be considered, where AAAA is
 * the area passed down from mprotect_fixup, never extending beyond one
 * vma, PPPPPP is the prev vma specified, and NNNNNN the next vma after:
必须考虑以下mprotect情况,其中AAAA是从mprotect_fixup向下传递的区域,从不延伸超过
一个vma,PPPPPP是指定的上一个vma,而NNNNNN是后面的下一个vma:
 *
 *     AAAA             AAAA                AAAA          AAAA
 *    PPPPPPNNNNNN    PPPPPPNNNNNN    PPPPPPNNNNNN    PPPPNNNNXXXX
 *    cannot merge    might become    might become    might become
 *                    PPNNNNNNNNNN    PPPPPPPPPPNN    PPPPPPPPPPPP 6 or
 *    mmap, brk or    case 4 below    case 5 below    PPPPPPPPXXXX 7 or
 *    mremap move:                                    PPPPNNNNNNNN 8
 *        AAAA
 *    PPPP    NNNN    PPPPPPPPPPPP    PPPPPPPPNNNN    PPPPNNNNNNNN
 *    might become    case 1 below    case 2 below    case 3 below
 *
 * Odd one out? Case 8, because it extends NNNN but needs flags of XXXX:
 * mprotect_fixup updates vm_flags & vm_page_prot on successful return.
 */
struct vm_area_struct *vma_merge(struct mm_struct *mm,
            struct vm_area_struct *prev, unsigned long addr,
            unsigned long end, unsigned long vm_flags,
            struct anon_vma *anon_vma, struct file *file,
            pgoff_t pgoff, struct mempolicy *policy)
{
    pgoff_t pglen = (end - addr) >> PAGE_SHIFT;
    struct vm_area_struct *area, *next;
    int err;

    /*
     * We later require that vma->vm_flags == vm_flags,
     * so this tests vma->vm_flags & VM_SPECIAL, too.
     */
    if (vm_flags & VM_SPECIAL)
        return NULL;

    /*如果新插入的节点有前继节点,那么next指向prev->vm_next,否则指向mm->mmap的第一个节点*/
    if (prev)
        next = prev->vm_next;
    else
        next = mm->mmap;
    area = next;
    if (next && next->vm_end == end)        /* cases 6, 7, 8 */
        next = next->vm_next;

    /*
     * Can it merge with the predecessor?
     */
    if (prev && prev->vm_end == addr &&
            mpol_equal(vma_policy(prev), policy) &&
            can_vma_merge_after(prev, vm_flags,
                        anon_vma, file, pgoff)) {
        /*
         * OK, it can.  Can we now merge in the successor as well?
         */
        /*判断是否可以和前继节点合并。当要插入节点的起始地址和prev节点的结束地址相等,就满足第一个条件了,
        can_vma_merge_after()函数判断prev节点是否可以被合并。理想情况下新插入节点的结束地址等于next节点的起始地址,
        那么前后节点prev和next可以合并在一起。最终合并是在vma_adjust()函数中实现的,它会适当地修改所涉及的数据结构,
        例如VMA等,最后会释放不需要的VMA数据结构。*/
        if (next && end == next->vm_start &&
                mpol_equal(policy, vma_policy(next)) &&
                can_vma_merge_before(next, vm_flags,
                    anon_vma, file, pgoff+pglen) &&
                is_mergeable_anon_vma(prev->anon_vma,
                              next->anon_vma, NULL)) {
                            /* cases 1, 6 */
            err = vma_adjust(prev, prev->vm_start,
                next->vm_end, prev->vm_pgoff, NULL);
        } else                  /* cases 2, 5, 7 */
            err = vma_adjust(prev, prev->vm_start,
                end, prev->vm_pgoff, NULL);
        if (err)
            return NULL;
        khugepaged_enter_vma_merge(prev, vm_flags);
        return prev;
    }

    /*
     * Can this new request be merged in front of next?
     */
    /*判断是否可以和后继节点合并*/
    if (next && end == next->vm_start &&
            mpol_equal(policy, vma_policy(next)) &&
            can_vma_merge_before(next, vm_flags,
                    anon_vma, file, pgoff+pglen)) {
        if (prev && addr < prev->vm_end)    /* case 4 */
            err = vma_adjust(prev, prev->vm_start,
                addr, prev->vm_pgoff, NULL);
        else                    /* cases 3, 8 */
            err = vma_adjust(area, addr, next->vm_end,
                next->vm_pgoff - pglen, NULL);
        if (err)
            return NULL;
        khugepaged_enter_vma_merge(area, vm_flags);
        return area;
    }

    return NULL;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

byd yes

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值