在kernel中会为每个numa节点建一个内核线程kswapd,主要用于在内存不足时回收页面 static int __init kswapd_init(void) { int nid, ret; swap_setup(); #遍历所有的numa节点,每个numa节点调用kswapd_run for_each_node_state(nid, N_MEMORY) kswapd_run(nid); ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "mm/vmscan:online", kswapd_cpu_online, NULL); WARN_ON(ret < 0); return 0; } #开机自动运行 module_init(kswapd_init) kswapd_run的实现如下: int kswapd_run(int nid) { pg_data_t *pgdat = NODE_DATA(nid); int ret = 0; #如果这个numa节点已经有回收内存的线程,则退出。这里看到每个numa #节点只能由一个线程用来回收页面 if (pgdat->kswapd) return 0; #通过kernel_run 建立一个内核线程,并立刻开始运行,这个内核线程的name是kswapd + 节点id pgdat->kswapd = kthread_run(kswapd, pgdat, "kswapd%d", nid); if (IS_ERR(pgdat->kswapd)) { /* failure at boot is fatal */ BUG_ON(system_state < SYSTEM_RUNNING); pr_err("Failed to start kswapd on node %d\n", nid); ret = PTR_ERR(pgdat->kswapd); pgdat->kswapd = NULL; } return ret; } static int kswapd(void *p) { for ( ; ; ) { bool ret; kswapd_try_sleep: #可见这个内核线程一般情况下是在sleep kswapd_try_to_sleep(pgdat, alloc_order, reclaim_order, classzone_idx); fs_reclaim_acquire(GFP_KERNEL); #调用balance_pgdat 开始回收内存页面 reclaim_order = balance_pgdat(pgdat, alloc_order, classzone_idx); fs_reclaim_release(GFP_KERNEL); if (reclaim_order < alloc_order) goto kswapd_try_sleep; } } alloc_pages_node->__alloc_pages->__alloc_pages_nodemask->__alloc_pages_slowpath static inline struct page * __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, struct alloc_context *ac) { #从这里知道只有申请页面中包含__GFP_KSWAPD_RECLAIM时,在内存不足时才会调用wake_all_kswapds 来wakeup线程来回收页面 if (gfp_mask & __GFP_KSWAPD_RECLAIM) wake_all_kswapds(order, ac); }
页面回收线程
猜你喜欢
转载自blog.csdn.net/tiantao2012/article/details/80453668
今日推荐
周排行