1 哪些页需要swap
(本文基于linux2.6.21.5)
总之内核将没有文件backed的用户空间的数据swap到交换空间。
这些页一般是应用程序的堆栈空间的数据,而进程的代码段的内容、以及其使用的文件产生的page cahe等都不会被swap到交换空间。
2交换空间
交换空间对应磁盘上的分区或文件,其本身和普通磁盘文件一样,用一个struct address_space 来抽象。
struct address_space swapper_space = {
.page_tree = RADIX_TREE_INIT(GFP_ATOMIC|__GFP_NOWARN),//用来挂这个空间上的page cache
.tree_lock = __RW_LOCK_UNLOCKED(swapper_space.tree_lock),
.a_ops = &swap_aops,//这个空间上的page cache的操作函数
.i_mmap_nonlinear = LIST_HEAD_INIT(swapper_space.i_mmap_nonlinear),
.backing_dev_info = &swap_backing_dev_info,//对应该交换空间的块设备
};
3换出
这是在static unsigned long shrink_page_list(struct list_head *page_list,struct scan_control *sc)里进行的.该函数主要在收缩内存page cache时被调用,它检查当前inactive里的待选页。针对匿名页被换出的情景如下:
A 如果发现其是匿名页:PageAnon(page),且没有被加入到交换空间:!PageSwapCache(page),则调用add_to_swap(page, GFP_ATOMIC);将该页加入到交换空间,即上述swapper_space的page_tree里。
B 找到这个页的对应的struct address_space,对于被加入到swap的匿名页,显然返回swapper_space
static inline struct address_space *page_mapping(struct page *page)
{
struct address_space *mapping = page->mapping;
if (unlikely(PageSwapCache(page)))//加入到swap的匿名页,会被置位PG_swapcache
mapping = &swapper_space;
else if (unlikely((unsigned long)mapping & PAGE_MAPPING_ANON))
mapping = NULL;
return mapping;
}
C 如果该页被映射到页表,将该页的从页表中去除。对应用户空间的堆栈的page cache。显然这一步是必须的。
if (page_mapped(page) && mapping) {
switch (try_to_unmap(page, 0)) {//执行取出页表映射操作
case SWAP_FAIL:
goto activate_locked;
case SWAP_AGAIN:
goto keep_locked;
case SWAP_SUCCESS:
; /* try to free the page below */
}
}
D 该页如果被修改过,则将其写入到磁盘,对应用户空间的堆栈显然是脏页,需要写入磁盘上的swap空间。其回写机制是通过调用struct address_space_operations *a_ops的writepage例程实现的。显然这对应上文提到
的swap_aops的writepage例程
if (PageDirty(page)) {
......
switch(pageout(page, mapping)) {//执行swap_writepage函数向块设备层提交写申请
}
}
自此该匿名页被换出到磁盘上的交换空间
===============================================================
讨论: linux_kernel_2_6@yahoo.com.cn
未经允许请勿用于商业用途
wangsen
===============================================================