1 /* 2 * mm/pdflush.c - worker threads for writing back filesystem data 3 * 4 * Copyright (C) 2002, Linus Torvalds. 5 * 6 * 09Apr2002 akpm@zip.com.au 7 * Initial version 8 * 29Feb2004 kaos@sgi.com 9 * Move worker thread creation to kthread to avoid chewing 10 * up stack space with nested calls to kernel_thread. 11 */ 12 13 #include <linux/sched.h> 14 #include <linux/list.h> 15 #include <linux/signal.h> 16 #include <linux/spinlock.h> 17 #include <linux/gfp.h> 18 #include <linux/init.h> 19 #include <linux/module.h> 20 #include <linux/suspend.h> 21 #include <linux/fs.h> // Needed by writeback.h 22 #include <linux/writeback.h> // Prototypes pdflush_operation() 23 #include <linux/kthread.h> 24 25 26 /* 27 * Minimum and maximum number of pdflush instances 28 */ 29 #define MIN_PDFLUSH_THREADS 2 30 #define MAX_PDFLUSH_THREADS 8 31 32 static void start_one_pdflush_thread(void); 33 34 35 /* 36 * The pdflush threads are worker threads for writing back dirty data. 37 * Ideally, we'd like one thread per active disk spindle. But the disk 38 * topology is very hard to divine at this level. Instead, we take 39 * care in various places to prevent more than one pdflush thread from 40 * performing writeback against a single filesystem. pdflush threads 41 * have the PF_FLUSHER flag set in current->flags to aid in this. 42 */ 43 44 /* 45 * All the pdflush threads. Protected by pdflush_lock 46 */ 47 static LIST_HEAD(pdflush_list); 48 static spinlock_t pdflush_lock = SPIN_LOCK_UNLOCKED; 49 50 /* 51 * The count of currently-running pdflush threads. Protected 52 * by pdflush_lock. 53 * 54 * Readable by sysctl, but not writable. Published to userspace at 55 * /proc/sys/vm/nr_pdflush_threads. 56 */ 57 int nr_pdflush_threads = 0; 58 59 /* 60 * The time at which the pdflush thread pool last went empty 61 */ 62 static unsigned long last_empty_jifs; 63 64 /* 65 * The pdflush thread. 66 * 67 * Thread pool management algorithm: 68 * 69 * - The minimum and maximum number of pdflush instances are bound 70 * by MIN_PDFLUSH_THREADS and MAX_PDFLUSH_THREADS. 71 * 72 * - If there have been no idle pdflush instances for 1 second, create 73 * a new one. 74 * 75 * - If the least-recently-went-to-sleep pdflush thread has been asleep 76 * for more than one second, terminate a thread. 77 */ 78 79 /* 80 * A structure for passing work to a pdflush thread. Also for passing 81 * state information between pdflush threads. Protected by pdflush_lock. 82 */ 83 struct pdflush_work { 84 struct task_struct *who; /* The thread */ 85 void (*fn)(unsigned long); /* A callback function */ 86 unsigned long arg0; /* An argument to the callback */ 87 struct list_head list; /* On pdflush_list, when idle */ 88 unsigned long when_i_went_to_sleep; 89 }; 90 91 static int __pdflush(struct pdflush_work *my_work) 92 { 93 current->flags |= PF_FLUSHER; 94 my_work->fn = NULL; 95 my_work->who = current; 96 INIT_LIST_HEAD(&my_work->list); 97 98 spin_lock_irq(&pdflush_lock); 99 nr_pdflush_threads++; 100 for ( ; ; ) { 101 struct pdflush_work *pdf; 102 103 set_current_state(TASK_INTERRUPTIBLE); 104 list_move(&my_work->list, &pdflush_list); 105 my_work->when_i_went_to_sleep = jiffies; 106 spin_unlock_irq(&pdflush_lock); 107 108 schedule(); 109 if (current->flags & PF_FREEZE) { 110 refrigerator(PF_FREEZE); 111 spin_lock_irq(&pdflush_lock); 112 continue; 113 } 114 115 spin_lock_irq(&pdflush_lock); 116 if (!list_empty(&my_work->list)) { 117 printk("pdflush: bogus wakeup!\n"); 118 my_work->fn = NULL; 119 continue; 120 } 121 if (my_work->fn == NULL) { 122 printk("pdflush: NULL work function\n"); 123 continue; 124 } 125 spin_unlock_irq(&pdflush_lock); 126 127 (*my_work->fn)(my_work->arg0); 128 129 /* 130 * Thread creation: For how long have there been zero 131 * available threads? 132 */ 133 if (jiffies - last_empty_jifs > 1 * HZ) { 134 /* unlocked list_empty() test is OK here */ 135 if (list_empty(&pdflush_list)) { 136 /* unlocked test is OK here */ 137 if (nr_pdflush_threads < MAX_PDFLUSH_THREADS) 138 start_one_pdflush_thread(); 139 } 140 } 141 142 spin_lock_irq(&pdflush_lock); 143 my_work->fn = NULL; 144 145 /* 146 * Thread destruction: For how long has the sleepiest 147 * thread slept? 148 */ 149 if (list_empty(&pdflush_list)) 150 continue; 151 if (nr_pdflush_threads <= MIN_PDFLUSH_THREADS) 152 continue; 153 pdf = list_entry(pdflush_list.prev, struct pdflush_work, list); 154 if (jiffies - pdf->when_i_went_to_sleep > 1 * HZ) { 155 /* Limit exit rate */ 156 pdf->when_i_went_to_sleep = jiffies; 157 break; /* exeunt */ 158 } 159 } 160 nr_pdflush_threads--; 161 spin_unlock_irq(&pdflush_lock); 162 return 0; 163 } 164 165 /* 166 * Of course, my_work wants to be just a local in __pdflush(). It is 167 * separated out in this manner to hopefully prevent the compiler from 168 * performing unfortunate optimisations against the auto variables. Because 169 * these are visible to other tasks and CPUs. (No problem has actually 170 * been observed. This is just paranoia). 171 */ 172 static int pdflush(void *dummy) 173 { 174 struct pdflush_work my_work; 175 176 /* 177 * pdflush can spend a lot of time doing encryption via dm-crypt. We 178 * don't want to do that at keventd's priority. 179 */ 180 set_user_nice(current, 0); 181 return __pdflush(&my_work); 182 } 183 184 /* 185 * Attempt to wake up a pdflush thread, and get it to do some work for you. 186 * Returns zero if it indeed managed to find a worker thread, and passed your 187 * payload to it. 188 */ 189 int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0) 190 { 191 unsigned long flags; 192 int ret = 0; 193 194 if (fn == NULL) 195 BUG(); /* Hard to diagnose if it's deferred */ 196 197 spin_lock_irqsave(&pdflush_lock, flags); 198 if (list_empty(&pdflush_list)) { 199 spin_unlock_irqrestore(&pdflush_lock, flags); 200 ret = -1; 201 } else { 202 struct pdflush_work *pdf; 203 204 pdf = list_entry(pdflush_list.next, struct pdflush_work, list); 205 list_del_init(&pdf->list); 206 if (list_empty(&pdflush_list)) 207 last_empty_jifs = jiffies; 208 pdf->fn = fn; 209 pdf->arg0 = arg0; 210 wake_up_process(pdf->who); 211 spin_unlock_irqrestore(&pdflush_lock, flags); 212 } 213 return ret; 214 } 215 216 static void start_one_pdflush_thread(void) 217 { 218 kthread_run(pdflush, NULL, "pdflush"); 219 } 220 221 static int __init pdflush_init(void) 222 { 223 int i; 224 225 for (i = 0; i < MIN_PDFLUSH_THREADS; i++) 226 start_one_pdflush_thread(); 227 return 0; 228 } 229 230 module_init(pdflush_init); 231
This page was automatically generated by LXR 0.3.1. • Linux is a registered trademark of Linus Torvalds