⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pdflush.c

📁 最新最稳定的Linux内存管理模块源代码
💻 C
字号:
/* * mm/pdflush.c - worker threads for writing back filesystem data * * Copyright (C) 2002, Linus Torvalds. * * 09Apr2002	Andrew Morton *		Initial version * 29Feb2004	kaos@sgi.com *		Move worker thread creation to kthread to avoid chewing *		up stack space with nested calls to kernel_thread. */#include <linux/sched.h>#include <linux/list.h>#include <linux/signal.h>#include <linux/spinlock.h>#include <linux/gfp.h>#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>		/* Needed by writeback.h	  */#include <linux/writeback.h>	/* Prototypes pdflush_operation() */#include <linux/kthread.h>#include <linux/cpuset.h>#include <linux/freezer.h>/* * Minimum and maximum number of pdflush instances */#define MIN_PDFLUSH_THREADS	2#define MAX_PDFLUSH_THREADS	8static void start_one_pdflush_thread(void);/* * The pdflush threads are worker threads for writing back dirty data. * Ideally, we'd like one thread per active disk spindle.  But the disk * topology is very hard to divine at this level.   Instead, we take * care in various places to prevent more than one pdflush thread from * performing writeback against a single filesystem.  pdflush threads * have the PF_FLUSHER flag set in current->flags to aid in this. *//* * All the pdflush threads.  Protected by pdflush_lock */static LIST_HEAD(pdflush_list);static DEFINE_SPINLOCK(pdflush_lock);/* * The count of currently-running pdflush threads.  Protected * by pdflush_lock. * * Readable by sysctl, but not writable.  Published to userspace at * /proc/sys/vm/nr_pdflush_threads. */int nr_pdflush_threads = 0;/* * The time at which the pdflush thread pool last went empty */static unsigned long last_empty_jifs;/* * The pdflush thread. * * Thread pool management algorithm: *  * - The minimum and maximum number of pdflush instances are bound *   by MIN_PDFLUSH_THREADS and MAX_PDFLUSH_THREADS. *  * - If there have been no idle pdflush instances for 1 second, create *   a new one. *  * - If the least-recently-went-to-sleep pdflush thread has been asleep *   for more than one second, terminate a thread. *//* * A structure for passing work to a pdflush thread.  Also for passing * state information between pdflush threads.  Protected by pdflush_lock. */struct pdflush_work {	struct task_struct *who;	/* The thread */	void (*fn)(unsigned long);	/* A callback function */	unsigned long arg0;		/* An argument to the callback */	struct list_head list;		/* On pdflush_list, when idle */	unsigned long when_i_went_to_sleep;};static int __pdflush(struct pdflush_work *my_work){	current->flags |= PF_FLUSHER | PF_SWAPWRITE;	set_freezable();	my_work->fn = NULL;	my_work->who = current;	INIT_LIST_HEAD(&my_work->list);	spin_lock_irq(&pdflush_lock);	nr_pdflush_threads++;	for ( ; ; ) {		struct pdflush_work *pdf;		set_current_state(TASK_INTERRUPTIBLE);		list_move(&my_work->list, &pdflush_list);		my_work->when_i_went_to_sleep = jiffies;		spin_unlock_irq(&pdflush_lock);		schedule();		try_to_freeze();		spin_lock_irq(&pdflush_lock);		if (!list_empty(&my_work->list)) {			/*			 * Someone woke us up, but without removing our control			 * structure from the global list.  swsusp will do this			 * in try_to_freeze()->refrigerator().  Handle it.			 */			my_work->fn = NULL;			continue;		}		if (my_work->fn == NULL) {			printk("pdflush: bogus wakeup\n");			continue;		}		spin_unlock_irq(&pdflush_lock);		(*my_work->fn)(my_work->arg0);		/*		 * Thread creation: For how long have there been zero		 * available threads?		 */		if (time_after(jiffies, last_empty_jifs + 1 * HZ)) {			/* unlocked list_empty() test is OK here */			if (list_empty(&pdflush_list)) {				/* unlocked test is OK here */				if (nr_pdflush_threads < MAX_PDFLUSH_THREADS)					start_one_pdflush_thread();			}		}		spin_lock_irq(&pdflush_lock);		my_work->fn = NULL;		/*		 * Thread destruction: For how long has the sleepiest		 * thread slept?		 */		if (list_empty(&pdflush_list))			continue;		if (nr_pdflush_threads <= MIN_PDFLUSH_THREADS)			continue;		pdf = list_entry(pdflush_list.prev, struct pdflush_work, list);		if (time_after(jiffies, pdf->when_i_went_to_sleep + 1 * HZ)) {			/* Limit exit rate */			pdf->when_i_went_to_sleep = jiffies;			break;					/* exeunt */		}	}	nr_pdflush_threads--;	spin_unlock_irq(&pdflush_lock);	return 0;}/* * Of course, my_work wants to be just a local in __pdflush().  It is * separated out in this manner to hopefully prevent the compiler from * performing unfortunate optimisations against the auto variables.  Because * these are visible to other tasks and CPUs.  (No problem has actually * been observed.  This is just paranoia). */static int pdflush(void *dummy){	struct pdflush_work my_work;	cpumask_var_t cpus_allowed;	/*	 * Since the caller doesn't even check kthread_run() worked, let's not	 * freak out too much if this fails.	 */	if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) {		printk(KERN_WARNING "pdflush failed to allocate cpumask\n");		return 0;	}	/*	 * pdflush can spend a lot of time doing encryption via dm-crypt.  We	 * don't want to do that at keventd's priority.	 */	set_user_nice(current, 0);	/*	 * Some configs put our parent kthread in a limited cpuset,	 * which kthread() overrides, forcing cpus_allowed == CPU_MASK_ALL.	 * Our needs are more modest - cut back to our cpusets cpus_allowed.	 * This is needed as pdflush's are dynamically created and destroyed.	 * The boottime pdflush's are easily placed w/o these 2 lines.	 */	cpuset_cpus_allowed(current, cpus_allowed);	set_cpus_allowed_ptr(current, cpus_allowed);	free_cpumask_var(cpus_allowed);	return __pdflush(&my_work);}/* * Attempt to wake up a pdflush thread, and get it to do some work for you. * Returns zero if it indeed managed to find a worker thread, and passed your * payload to it. */int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0){	unsigned long flags;	int ret = 0;	BUG_ON(fn == NULL);	/* Hard to diagnose if it's deferred */	spin_lock_irqsave(&pdflush_lock, flags);	if (list_empty(&pdflush_list)) {		ret = -1;	} else {		struct pdflush_work *pdf;		pdf = list_entry(pdflush_list.next, struct pdflush_work, list);		list_del_init(&pdf->list);		if (list_empty(&pdflush_list))			last_empty_jifs = jiffies;		pdf->fn = fn;		pdf->arg0 = arg0;		wake_up_process(pdf->who);	}	spin_unlock_irqrestore(&pdflush_lock, flags);	return ret;}static void start_one_pdflush_thread(void){	kthread_run(pdflush, NULL, "pdflush");}static int __init pdflush_init(void){	int i;	for (i = 0; i < MIN_PDFLUSH_THREADS; i++)		start_one_pdflush_thread();	return 0;}module_init(pdflush_init);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -