本文共 2863 字,大约阅读时间需要 9 分钟。
add_to_swap函数是为匿名页面分配交换空间.
当对一个匿名页面page进行内存回收时,若该匿名页面page具有如下状态
1.该匿名页未被用户应用访问.(映射该匿名页的所有pte页表项的AF位为0)2.PageAnon(page) && !PageSwapCache(page)为true.(该page未被分配swap空间)
若此时页面回收则允许页面进行文件操作或磁盘I/0操作(sc->gfp_mask & __GFP_IO为true).则页面回收则会调用add_to_swap函数对page分配swap交换空间
执行步骤
1.通过get_swap_page在swap area中获取一个slot(页槽,一个页槽用于存储一个匿名页swap out到swap area中的内 容数据),并将该slot的位置信 息记录在swp_entry_t结构体entry中2.通过add_to_swap_cache函数将1步骤分配的slot与匿名页page关联 a.将匿名页page的flag成员的swap cache标志位置位 b.用匿名页page的private成员记录步骤1获取的slot在swap area中的位置信息(page->private = entry.val) c.通过swp_offset(entry)函数获取步骤1的slot在swap area中的偏移offset d.通过radix_tree_insert函数将匿名页page插入到对应swap area区域缓存管理器address_space的page_tree 容器中.
源码
//mm/swap_state.c/** * add_to_swap - allocate swap space for a page * @page: page we want to move to swap * * Allocate swap space for the page and add the page to the * swap cache. Caller needs to hold the page lock. */int add_to_swap(struct page *page, struct list_head *list){ swp_entry_t entry; int err; VM_BUG_ON_PAGE(!PageLocked(page), page); VM_BUG_ON_PAGE(!PageUptodate(page), page); /* *从swap磁盘区域获取一个slot(slot代表一个槽,每个槽对应内存区域的一个page),并将该槽的位置信息记录 *在swp_entry_t结构体entry中(通过entry可以在从一个swap磁盘区域定位到一个具体的slot,该slot用于存储 *匿名页page对应的数据). */ entry = get_swap_page(); ...... err = add_to_swap_cache(page, entry, __GFP_HIGH|__GFP_NOMEMALLOC|__GFP_NOWARN); ...... //成功返回1,失败返回0}
//mm/swap_state.c/* *int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask) * |--->__add_to_swap_cache(page, entry) *//* * __add_to_swap_cache resembles add_to_page_cache_locked on swapper_space, * but sets SwapCache flag and private instead of mapping and index. */int __add_to_swap_cache(struct page *page, swp_entry_t entry){ int error; //某个swap 内存区域的swap cache管理结构体struct address_space struct address_space *address_space; ..... get_page(page); //将匿名页page的flag成员的swap cache标志位置位 SetPageSwapCache(page); //匿名页page的private存储page对应的swap slot的位置信息 set_page_private(page, entry.val); //获取entry所在swap area区域的swap cache管理器,赋值给address_space address_space = swap_address_space(entry); //获取address_space缓存管理器中page_tree的自旋锁 spin_lock_irq(&address_space->tree_lock); //根据entry指向的slot在对应swap area的偏移,将page插入到缓存管理器的page_tree中 error = radix_tree_insert(&address_space->page_tree, swp_offset(entry), page); if (likely(!error)) { //page插入成功,缓存管理器address_sapce维护的swap cache中匿名缓存页数量++ address_space->nrpages++; __inc_node_page_state(page, NR_FILE_PAGES); INC_CACHE_INFO(add_total); } spin_unlock_irq(&address_space->tree_lock); if (unlikely(error)) { /* * Only the context which have set SWAP_HAS_CACHE flag * would call add_to_swap_cache(). * So add_to_swap_cache() doesn't returns -EEXIST. */ VM_BUG_ON(error == -EEXIST); set_page_private(page, 0UL); ClearPageSwapCache(page); put_page(page); } return error;}
转载地址:http://wpbgi.baihongyu.com/