本文共 1611 字,大约阅读时间需要 5 分钟。
在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_slowpathstatic 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);}
转载地址:http://wnnmi.baihongyu.com/