我们通常所说的page mapped是指page建立了对应的页表项,但是其实还有一种mapped是指page被映射到用户态线性地址,及我们通常所说的建立vma,这两种mapped很容易混淆,咱这来一次性把这个给理清楚。
-
/*
-
* Might pages of this file be mapped into userspace?
-
*/
-
static inline int mapping_mapped(struct address_space *mapping)
-
{
-
return !RB_EMPTY_ROOT(&mapping->i_mmap);
-
}
-
/*
-
* Return true if this page is mapped into pagetables.
-
*/
-
static inline int page_mapped(struct page *page)
-
{
-
return atomic_read(&(page)->_mapcount) >= 0;
-
}
偶然碰到个社区有人发用page_mapped替代mapping_mapped来检测page是否真正被*mapped*的patch,于是扒了下kernel的代码和changelog,发现Lei Ming以前发的提升arm flush dcache的patch:
commit 81f28946a8b066d484ca8935ff545d94ce730aa3
Author: Ming Lei
Date: Wed Jun 5 02:44:00 2013 +0100
ARM: 7746/1: mm: lazy cache flushing on non-mapped pages
Currently flush_dcache_page() thinks pages as non-mapped if
mapping_mapped(mapping) return false. This approach is very
coase:
- mmap on part of file may cause all pages backed on
the file being thought as mmaped
- file-backed pages aren't mapped into user space actually
if the memory mmaped on the file isn't accessed
This patch uses page_mapped() to decide if the page has been
mapped.
comment里面写得很详细了,检测page是否被mapped最好是从page本身出发,而不应该通过上层的address_space,我们知道一个文件只会用一个address_space来管理所有属于它的page,这就可能出现comment说的这种情况,file先被mmap了一段,后续被load进来的page的mapping还是指向这个address_space,页表已经建好,但是如果没有被用户态线程访问,那就不会分配对应的vma (rb-tree节点),好,那现在如果把前面的mmap解除,address_space的rb-tree会被清空,这个时候如果再通过mapping_mapped检测后面load进来的page是否mapped,则会返回false,但是实际上不是,这样在truncate或者invalidate page的时候出现遗漏。
再来看page_mapped,它是直接检测_mapcount,这个参数初始化是-1,在buddy里面的时候也是负值,一旦建立页表(mapped)的就没被设置为非负值,所有通过它来检测一个page是否建立页表才是最严谨的,或者说唯一正确的方式。
阅读(2601) | 评论(0) | 转发(0) |