lru的加入与删除

LRU的全称是least recently used的缩写,在kernel中当内存紧张是总是有限换出page cache的页面
针对LRU换出页面的的算法旧版采用的是FIFO算法,新版采用的是second chance算法。
将page加入到lru中的flow如下:
lru_cache_add->__lru_cache_add->__pagevec_lru_add->pagevec_lru_move_fn->
void __pagevec_lru_add(struct pagevec *pvec)
{
	pagevec_lru_move_fn(pvec, __pagevec_lru_add_fn, NULL);
}
可见这里的回调函数是__pagevec_lru_add_fn

static void pagevec_lru_move_fn(struct pagevec *pvec,
	void (*move_fn)(struct page *page, struct lruvec *lruvec, void *arg),
	void *arg)
{
	int i;
	struct pglist_data *pgdat = NULL;
	struct lruvec *lruvec;
	unsigned long flags = 0;

	for (i = 0; i < pagevec_count(pvec); i++) {
		struct page *page = pvec->pages[i];
		struct pglist_data *pagepgdat = page_pgdat(page);

		if (pagepgdat != pgdat) {
			if (pgdat)
				spin_unlock_irqrestore(&pgdat->lru_lock, flags);
			pgdat = pagepgdat;
			spin_lock_irqsave(&pgdat->lru_lock, flags);
		}
		#注意这里的变量lruvec 是每个node节点都有一个。
		lruvec = mem_cgroup_page_lruvec(page, pgdat);
		(*move_fn)(page, lruvec, arg);
	}

}
加入我们没有定义cgroup的话
static inline struct lruvec *mem_cgroup_page_lruvec(struct page *page,
						    struct pglist_data *pgdat)
{
	return &pgdat->lruvec;
}
从这个函数很容易看出lruvec是没有个node 节点都有一个。从这里也可以知道lru的管理是一个numa node
每最大支持范围。

__pagevec_lru_add_fn->add_page_to_lru_list
static __always_inline void add_page_to_lru_list(struct page *page,
				struct lruvec *lruvec, enum lru_list lru)
{
	update_lru_size(lruvec, lru, page_zonenum(page), hpage_nr_pages(page));
	list_add(&page->lru, &lruvec->lists[lru]);
}
可见最后通过update_lru_size 来更新lru的size,然后在通过list_add 将page->lru 添加到lruvec->lists[lru] 中
当内存不足时会调用reclaim_clean_pages_from_list或者shrink_inactive_list 来回收lru中的页面,这两个函数最终
都会调用shrink_page_list
static unsigned long shrink_page_list(struct list_head *page_list,
				      struct pglist_data *pgdat,
				      struct scan_control *sc,
				      enum ttu_flags ttu_flags,
				      struct reclaim_stat *stat,
				      bool force_reclaim)
{
#调用下面这两个函数来从lru的list中删除page
		page = lru_to_page(page_list);
		list_del(&page->lru);
}
其中#define lru_to_page(head) (list_entry((head)->prev, struct page, lru)) 可以得到一个页面,然后调用list_del
来删除这个页面.

猜你喜欢

转载自blog.csdn.net/tiantao2012/article/details/80563575
LRU
今日推荐