参照元

説明

引数

返り値

参考

実装

/*
 * The background pageout daemon, started as a kernel thread
 * from the init process.
 *
 * This basically trickles out pages so that we have _some_
 * free memory available even if there is no other activity
 * that frees anything up. This is needed for things like routing
 * etc, where we otherwise might have all activity going on in
 * asynchronous contexts that cannot page things out.
 *
 * If there are applications that are active memory-allocators
 * (most normal use), this basically shouldn't matter.
 */
static int kswapd(void *p)
{
	unsigned long order;
	pg_data_t *pgdat = (pg_data_t*)p;
	struct task_struct *tsk = current;
	DEFINE_WAIT(wait);
	struct reclaim_state reclaim_state = {
		.reclaimed_slab = 0,
	};
	const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id);
	lockdep_set_current_reclaim_state(GFP_KERNEL);
	if (!cpumask_empty(cpumask))
		set_cpus_allowed_ptr(tsk, cpumask);
	current->reclaim_state = &reclaim_state;
	/*
	 * Tell the memory management that we're a "memory allocator",
	 * and that if we need more memory we should get access to it
	 * regardless (see "__alloc_pages()"). "kswapd" should
	 * never get caught in the normal page freeing logic.
	 *
	 * (Kswapd normally doesn't need memory anyway, but sometimes
	 * you need a small amount of memory in order to be able to
	 * page out something else, and this flag essentially protects
	 * us from recursively trying to free more memory as we're
	 * trying to free the first piece of memory in the first place).
	 */
	tsk->flags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD;
	set_freezable();
	order = 0;
	for ( ; ; ) {
		unsigned long new_order;
		int ret;

		prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
		new_order = pgdat->kswapd_max_order;
		pgdat->kswapd_max_order = 0;
		if (order < new_order) {
			/*
			 * Don't sleep if someone wants a larger 'order'
			 * allocation
			 */
			order = new_order;
		} else {
			if (!freezing(current) && !kthread_should_stop()) {
				long remaining = 0;
				/* Try to sleep for a short interval */
				if (!sleeping_prematurely(pgdat, order, remaining)) {
					remaining = schedule_timeout(HZ/10);
					finish_wait(&pgdat->kswapd_wait, &wait);
					prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
				}

				/*
				 * After a short sleep, check if it was a
				 * premature sleep. If not, then go fully
				 * to sleep until explicitly woken up
				 */
				if (!sleeping_prematurely(pgdat, order, remaining))
					schedule();
				else {
					if (remaining)
						count_vm_event(KSWAPD_LOW_WMARK_HIT_QUICKLY);
					else
						count_vm_event(KSWAPD_HIGH_WMARK_HIT_QUICKLY);
				}
			}

			order = pgdat->kswapd_max_order;
		}
		finish_wait(&pgdat->kswapd_wait, &wait);
		ret = try_to_freeze();
		if (kthread_should_stop())
			break;
		/*
		 * We can speed up thawing tasks if we don't call balance_pgdat
		 * after returning from the refrigerator
		 */
		if (!ret)
			balance_pgdat(pgdat, order);
	}
	return 0;
}

コメント


トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-09-13 (土) 08:26:42