好记性不如铅笔头

kernel, linux, 操作系统

mmap.c中的find_vma

简单的笔记下mmap.c中的部分函数:

find_vma:

/* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
/*
在mm中查找addr对应的线性地址块wma
*/
struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
{
	struct vm_area_struct *vma = NULL;

      /* mm不能为空,没什么好说的 */
	if (mm) {
		/* Check the cache first. */
        /* (Cache hit rate is typically around 35%.) */
/*
mmap_cache保存的是上次访问该函数时返回的wma,一般来说,查找addr对应的wma时,
addr一般都是累加的,因此有很大可能进行查找时,上次查找的就符合条件。
*/
		vma = mm->mmap_cache;
/*
如果上次查找的wma不为空,而且addr恰好也在该wma之内,直接返回就OK了
*/
		if (!(vma && vma->vm_end > addr && vma->vm_start <= addr)) {
/*
如果上次查找的wma不符合条件,那就只能从mm中查找了。这里wma的存储是使用
红黑树来实现的,因此这里使用红黑树查找。
*/
			struct rb_node * rb_node;

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

			while (rb_node) {
				struct vm_area_struct * vma_tmp;

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

				if (vma_tmp->vm_end > addr) {
					vma = vma_tmp;
					if (vma_tmp->vm_start <= addr)
						break;
					rb_node = rb_node->rb_left;
				} else
					rb_node = rb_node->rb_right;
			}
            /* 如果找到了,就存下来,加速后面的查找 */
			if (vma)
				mm->mmap_cache = vma;
		}
	}
	return vma;
}

EXPORT_SYMBOL(find_vma);

/* Same as find_vma, but also return a pointer to the previous VMA in *pprev. */

/*
在mm中查找addr对应的线性地址块wma,,不过同样也会返回该wma前面的那个wma
*/
struct vm_area_struct *
find_vma_prev(struct mm_struct *mm, unsigned long addr,
			struct vm_area_struct **pprev)
{
	struct vm_area_struct *vma = NULL, *prev = NULL;
	struct rb_node * rb_node;
	if (!mm)
		goto out;

	/* Guard against addr being lower than the first VMA */
	vma = mm->mmap;

	/* Go through the RB tree quickly. */
	rb_node = mm->mm_rb.rb_node;

	while (rb_node) {
		struct vm_area_struct *vma_tmp;
		vma_tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);

		if (addr < vma_tmp->vm_end) {
			rb_node = rb_node->rb_left;
		} else {
			prev = vma_tmp;
			if (!prev->vm_next || (addr < prev->vm_next->vm_end))
				break;
			rb_node = rb_node->rb_right;
		}
	}

out:
	*pprev = prev;
	return prev ? prev->vm_next : vma;
}

 

发表评论

6 + 7 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据