8.1 查找VMA

通过虚拟地址addr来查找VMA是内核中常用的操作,内核提供一个API函数来实现这个查找操作。find_vma()函数根据给定地址addr查找满足如下条件之一的VMA,如下图:

  • addr在VMA空间范围内,即vma->vm_start <= addr < vma->vm_end。[vma->vm_start, vma->vm_end)

  • 距离addr最近并且VMA的结束地址大于addr的一个VMA。

    find_vma函数的实现如下:

 mm/mmap.c

/* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
{
    struct rb_node *rb_node;
    struct vm_area_struct *vma;

    /* Check the cache first. */
    /*首先查找vma cache中的VMA是否满足要求。
    vmacache_find()是内核中最近出现的一个查找VMA的优化方法。
    在task_struct结构中,有一个存放最近访问过的VMA的数组
    vmacache[VMACACHE_SIZE],其中可以存放4个最近使用的VMA,
    充分利用了局部性原理。如果在vmacache中没有找到VMA,那么
    遍历这个用户进程的mm_rb红黑树,这个红黑树存放该用户进程所有
    的VMA。
    */
    vma = vmacache_find(mm, addr);
    if (likely(vma))
        return vma;

    rb_node = mm->mm_rb.rb_node;
    vma = NULL;

    /*while循环要找一块满足上述要求的VMA*/
    while (rb_node) {
        struct vm_area_struct *tmp;

        tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);

        if (tmp->vm_end > addr) {
            vma = tmp;
            if (tmp->vm_start <= addr)
                break;
            rb_node = rb_node->rb_left;
        } else
            rb_node = rb_node->rb_right;
    }

    if (vma)
        vmacache_update(addr, vma);
    return vma;
}

find_vma_intersection()函数是另外一个API接口,用于查找start_addr、end_addr和现存的VMA有重叠的一个VMA,它基于find_vma()来实现

include/linux/mm.h


/* Look up the first VMA which intersects the interval start_addr..end_addr-1,
   NULL if none.  Assume start_addr < end_addr. */
static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
{
    struct vm_area_struct * vma = find_vma(mm,start_addr);

    if (vma && end_addr <= vma->vm_start)
        vma = NULL;
    return vma;
}

find_vma_prev()函数的逻辑和find_vma()一样,但是返回VMA的前继成员vma->vm_prev。

mm/mmap.c

/*
 * Same as find_vma, but also return a pointer to the previous VMA in *pprev.
 */
struct vm_area_struct *
find_vma_prev(struct mm_struct *mm, unsigned long addr,
            struct vm_area_struct **pprev)
{
    struct vm_area_struct *vma;

    vma = find_vma(mm, addr);
    if (vma) {
        *pprev = vma->vm_prev;
    } else {
        struct rb_node *rb_node = mm->mm_rb.rb_node;
        *pprev = NULL;
        while (rb_node) {
            *pprev = rb_entry(rb_node, struct vm_area_struct, vm_rb);
            rb_node = rb_node->rb_right;
        }
    }
    return vma;
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

byd yes

你的鼓励是我最大的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值