page reclaim 02:实现
本文简化描述, 忽略compound page, 忽略HUGEPAGE, 未开启CONFIGMEMCG, 未开启CONFIGSWAP. 若无特别说明, 本文仅讨论ARM体系的情况.
1. 数据结构
per zone : active list, inactive list
struct zone {
struct lruvec lruvec;
};
struct lruvec {
struct list_head lists[NR_LRU_LISTS];
...
};
per node :kswapd
kswapd_init -> for_each_node_state(nid, N_MEMORY) kswapd_run(nid)
kswapd_run -> pgdat->kswapd = kthread_run(kswapd, pgdat, "kswapd%d", nid);
per cpu :lru cache, 也就是struct pagevec
2. 调用逻辑
何时调用 shrinkactivelist, 何时调用 shrinkinactivelist ?
调用路径:
shrink_zones
|--shrink_zone -> shrink_lruvec
| |--for_each_evictable_lru //顺序是INACTIVE_xx, ACTIVE_xx, ..
| | |--shrink_list
| | | |--if active list, shrink_active_list
| | | |--else shrink_inactive_list
由于 shrinkactivelist 存在将page添加到inactive list的情况 , 若之后再 shrinkinactivelist 的话, 就是双重打击了, 故shrinklruvec()会 先调用 shrinkinactivelist, 后调用shrinkactive_list.
我们并不会总是shrinkactivelist, 只有在inactive list的page相对比较少时才会shrinkactivelist.
问题:如果shrinkinactivelist中把page移到active list, 那么, shrinkactivelist会不会又把该page挪到 inactive list?
答:我们是新添加到active list的, 队列是FIFO的方式, 所以, 只要nrtoscan不是很大, 就可以避免短时间内被扫描到.
由于page被回收, 相关页表项需要处理, 这部分需要rmap, 本文略去.
3. shrinkactivelist
shrink_active_list
|--lru_add_drain
|--isolate_lru_pages(, , &l_hold, )
| |--__isolate_lru_page isolate是让page还呆在lru上, 但清掉PG_lru
| |--list_move(&page->lru, l_hold); 挪到链表(list_head) l_hold
|--for each page in struct list_head l_hold
| |--page_referenced
| | |--page_referenced_file -> page_referenced_one -> ptep_clear_flush_young_notify -> pte_mkold
| | |--page_test_and_clear_young ARM体系是空操作
| |--ClearPageActive and list_add(&page->lru, &l_inactive);
| |--or list_add(&page->lru, &l_active) //不讨论
|--move_active_pages_to_lru(lruvec, &l_active, &l_hold, lru);
|--move_active_pages_to_lru(lruvec, &l_inactive, &l_hold, lru - LRU_ACTIVE);
| |--将l_inactive的page move到 lruvec->lists[lru - LRU_ACTIVE]中,
| |--put page, 如果为zero, 则__ClearPageActive + 从lru中移除 + 添加到l_hold中, 待后续执行free
|--free_hot_cold_page_list(&l_hold, 1);
上面的流程忽略Compound page. 所以, 常见的流程是: 从active list中移除, 添加到inactive list中. 如果page count为0, 就不必添加到list中, 而是free掉page. 对于可执行文件的page, 根据情况可重新放入active list.
关于moveactivepagestolru中put后, page count为0:
linux-3.10.86/mm/vmscan.c
move_active_pages_to_lru
{
/*
在buddy system中的page的_count为0.
从buddy system取下, page为1.
当前page还被isolate_lru_pages get.
所以, 如果if (put_page_testzero(page))成立, 那就可能发生下面的序列:
alloc page
isolate_lru_pages
free page
put_page_testzero
*/
if (put_page_testzero(page)) {
list_add(&page->lru, pages_to_free);
}
}
4. shrinkinactivelist
//忽略Compound Page
shrink_inactive_list(..., enum lru_list lru)
|--lru_add_drain
|--isolate_lru_pages(, &page_list, ) //挑出的page放入链表page_list
|--shrink_page_list(&page_list, ) //尝试reclaim, 根据情况可能给page设置PG_active.
| |--VM_BUG_ON(PageActive(page));
| |--page_check_references //判断是否进行reclaim, 是否设置active等
| | |--page_referenced
| |--case PAGEREF_ACTIVATE: ...
| |--case PAGEREF_KEEP: ...
| |--case PAGEREF_RECLAIM or PAGEREF_RECLAIM_CLEAN: ...
|--/*对page_list中的page, 根据page flag, 将其放入对应lru. 若->_count put后为0, 则放入链表, 后续free掉*/
|--putback_inactive_pages(, &page_list);
|-- /*现page_list中存放的是 putback_inactive_pages()检测put_page_testzero()成立的page*/
|--free_hot_cold_page_list(&page_list, )
4.1 shrinkpagelist
[Professional Linux Kernel Architecture] p1072
shrinkpagelist sends the page to the associated backing store (which means the page is synchronized, swapped out, or discarded)
[Professional Linux Kernel Architecture]p1074
shrinkpagelist returns the number of pages for which it succeeded to initiate writeout.
shrink_page_list
{
if (PageWriteback(page)) {
如果允许等待的话, wait_on_page_writeback(page);
}
若可回收, try_to_unmap
if (PageDirty(page)) {
//较少发生, 这里不讨论
}
if (page_has_private(page)) {
//不是重点, 这里不讨论
}
free_hot_cold_page
}
5. 常见问题
direct reclaim可能导致堆栈overflow的问题
mm: vmscan: do not writeback filesystem pages in direct reclaim
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=ee72886d8ed5d9de3fa0ed3b99a7ca7702576a96
本文地址: https://awakening-fong.github.io/posts/mm/reclaim_02_implement
转载请注明出处: https://awakening-fong.github.io
若无法评论, 请打开JavaScript, 并通过proxy.
blog comments powered by Disqus