aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter W Morreale <pmorreale@novell.com>2009-04-06 22:00:28 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-07 11:31:03 -0400
commita56ed663047fc9927ec8b35750d23ece54f85dc7 (patch)
treeb992006bf34124f746f01530113803b175177782
parent9133df726fdd3df0ca9efcaaae22442198851d65 (diff)
mm: fix pdflush thread creation upper bound
Fix a race on creating pdflush threads. Without the patch, it is possible to create more than MAX_PDFLUSH_THREADS threads, and this has been observed in practice on IO loaded SMP machines. The fix involves moving the lock around to protect the check against the thread count and correctly dealing with thread creation failure. This fix also _mostly_ repairs a race condition on how quickly the threads are created. The original intent was to create a pdflush thread (up to the max allowed) every second. Without this patch is is possible to create NCPUS pdflush threads concurrently. The 'mostly' caveat is because an assumption is made that thread creation will be successful. If we fail to create the thread, the miss is not considered fatal. (we will try again in 1 second) Signed-off-by: Peter W Morreale <pmorreale@novell.com> Reviewed-by: Rik van Riel <riel@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/pdflush.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/mm/pdflush.c b/mm/pdflush.c
index 118905e3d788..235ac440c44e 100644
--- a/mm/pdflush.c
+++ b/mm/pdflush.c
@@ -98,7 +98,6 @@ static int __pdflush(struct pdflush_work *my_work)
98 INIT_LIST_HEAD(&my_work->list); 98 INIT_LIST_HEAD(&my_work->list);
99 99
100 spin_lock_irq(&pdflush_lock); 100 spin_lock_irq(&pdflush_lock);
101 nr_pdflush_threads++;
102 for ( ; ; ) { 101 for ( ; ; ) {
103 struct pdflush_work *pdf; 102 struct pdflush_work *pdf;
104 103
@@ -126,20 +125,26 @@ static int __pdflush(struct pdflush_work *my_work)
126 125
127 (*my_work->fn)(my_work->arg0); 126 (*my_work->fn)(my_work->arg0);
128 127
128 spin_lock_irq(&pdflush_lock);
129
129 /* 130 /*
130 * Thread creation: For how long have there been zero 131 * Thread creation: For how long have there been zero
131 * available threads? 132 * available threads?
133 *
134 * To throttle creation, we reset last_empty_jifs.
132 */ 135 */
133 if (time_after(jiffies, last_empty_jifs + 1 * HZ)) { 136 if (time_after(jiffies, last_empty_jifs + 1 * HZ)) {
134 /* unlocked list_empty() test is OK here */
135 if (list_empty(&pdflush_list)) { 137 if (list_empty(&pdflush_list)) {
136 /* unlocked test is OK here */ 138 if (nr_pdflush_threads < MAX_PDFLUSH_THREADS) {
137 if (nr_pdflush_threads < MAX_PDFLUSH_THREADS) 139 last_empty_jifs = jiffies;
140 nr_pdflush_threads++;
141 spin_unlock_irq(&pdflush_lock);
138 start_one_pdflush_thread(); 142 start_one_pdflush_thread();
143 spin_lock_irq(&pdflush_lock);
144 }
139 } 145 }
140 } 146 }
141 147
142 spin_lock_irq(&pdflush_lock);
143 my_work->fn = NULL; 148 my_work->fn = NULL;
144 149
145 /* 150 /*
@@ -236,13 +241,26 @@ int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0)
236 241
237static void start_one_pdflush_thread(void) 242static void start_one_pdflush_thread(void)
238{ 243{
239 kthread_run(pdflush, NULL, "pdflush"); 244 struct task_struct *k;
245
246 k = kthread_run(pdflush, NULL, "pdflush");
247 if (unlikely(IS_ERR(k))) {
248 spin_lock_irq(&pdflush_lock);
249 nr_pdflush_threads--;
250 spin_unlock_irq(&pdflush_lock);
251 }
240} 252}
241 253
242static int __init pdflush_init(void) 254static int __init pdflush_init(void)
243{ 255{
244 int i; 256 int i;
245 257
258 /*
259 * Pre-set nr_pdflush_threads... If we fail to create,
260 * the count will be decremented.
261 */
262 nr_pdflush_threads = MIN_PDFLUSH_THREADS;
263
246 for (i = 0; i < MIN_PDFLUSH_THREADS; i++) 264 for (i = 0; i < MIN_PDFLUSH_THREADS; i++)
247 start_one_pdflush_thread(); 265 start_one_pdflush_thread();
248 return 0; 266 return 0;