linux进程地址空间--api

转载:https://blog.csdn.net/tiantao2012/article/details/79060784

struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
用于根据属于某个进程的虚拟地址,找到其所属的进程虚拟区间,并返回相应的vm_area_struct 指针
其使用的例程如下:
static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
{
    struct mm_struct *mm = vma->vm_mm;
    unsigned long old_start = vma->vm_start;
    unsigned long old_end = vma->vm_end;
    unsigned long length = old_end - old_start;
    unsigned long new_start = old_start - shift;
    unsigned long new_end = old_end - shift;
    struct mmu_gather tlb;
 
    BUG_ON(new_start > new_end);
 
    /*
     * ensure there are no vmas between where we want to go
     * and where we are
     */
    if (vma != find_vma(mm, new_start))
        return -EFAULT;
 
}
其源码分析如下:
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. */
    #首先查找addr释放在vma的cache中是否有缓存
    vma = vmacache_find(mm, addr);
    #这里用likely修饰,看来有很大的几率可以找到
    if (likely(vma))
        return vma;
    #进程的虚拟空间是按红黑树组织的。如果在cache中没有找到的话,这里会遍历红黑树查找
    rb_node = mm->mm_rb.rb_node;
 
    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;
            #查找到的标准是   tmp->vm_start < addr < tmp->vm_end.
            if (tmp->vm_start <= addr)
                break;
            rb_node = rb_node->rb_left;
        } else
            rb_node = rb_node->rb_right;
    }
    #如果找到vma的话,则将这个vma更新到缓存中
    if (vma)
        vmacache_update(addr, vma);
    return vma;
}

 

find_vma_intersection

static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
这个函数用于查找在start_addr~end_addr ,之间的第一个vma
其使用的例程如下:
int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
             unsigned int gup_flags, struct frame_vector *vec)
{
    struct mm_struct *mm = current->mm;
    struct vm_area_struct *vma;
    int ret = 0;
    int err;
    int locked;
 
    if (nr_frames == 0)
        return 0;
 
    if (WARN_ON_ONCE(nr_frames > vec->nr_allocated))
        nr_frames = vec->nr_allocated;
 
    down_read(&mm->mmap_sem);
    locked = 1;
    vma = find_vma_intersection(mm, start, start + 1);
    if (!vma) {
        ret = -EFAULT;
        goto out;
    }
 
}
其源码分析如下:
static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
{
    #调用find_vma找到包含start_addr 的vma
    struct vm_area_struct * vma = find_vma(mm,start_addr);
    #如果找到vma,但是vma 不在start_addr和end_addr 之前的话,就等于没有找到
    #start_addr~end_addr之间的vma。就返回null

    if (vma && end_addr <= vma->vm_start)
        vma = NULL;
    #找到start_addr~end_addr之间的第一个vma
    return vma;
}

你可能感兴趣的:(Linux内存)