aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2010-07-25 07:29:19 -0400
committerJens Axboe <jaxboe@fusionio.com>2010-08-07 12:53:56 -0400
commitadf392407076b85816d48714fb8eeaedb2157884 (patch)
treee926a18b55e67724e0267fe359caf51d530d5b09 /mm
parentecd584030da67ede1bf17955746a6ce834d9fc6b (diff)
writeback: restructure bdi forker loop a little
This patch re-structures the bdi forker a little: 1. Add 'bdi_cap_flush_forker(bdi)' condition check to the bdi loop. The reason for this is that the forker thread can start _before_ the 'BDI_registered' flag is set (see 'bdi_register()'), so the WARN() statement will fire for the default bdi. I observed this warning at boot-up. 2. Introduce an enum 'action' and use "switch" statement in the outer loop. This is a preparation to the further patch which will teach the forker thread killing bdi threads, so we'll have another case in the "switch" statement. This change was suggested by Christoph Hellwig. This patch is just a small step towards the coming change where the forker thread will kill the bdi threads. It should simplify reviewing the following changes, which would otherwise be larger. This patch also amends comments a little. Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'mm')
-rw-r--r--mm/backing-dev.c69
1 files changed, 39 insertions, 30 deletions
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 672c17bb32db..e104e32c2ee8 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -329,9 +329,12 @@ static int bdi_forker_thread(void *ptr)
329 set_user_nice(current, 0); 329 set_user_nice(current, 0);
330 330
331 for (;;) { 331 for (;;) {
332 bool fork = false;
333 struct task_struct *task; 332 struct task_struct *task;
334 struct backing_dev_info *bdi; 333 struct backing_dev_info *bdi;
334 enum {
335 NO_ACTION, /* Nothing to do */
336 FORK_THREAD, /* Fork bdi thread */
337 } action = NO_ACTION;
335 338
336 /* 339 /*
337 * Temporary measure, we want to make sure we don't see 340 * Temporary measure, we want to make sure we don't see
@@ -348,25 +351,31 @@ static int bdi_forker_thread(void *ptr)
348 * a thread registered. If so, set that up. 351 * a thread registered. If so, set that up.
349 */ 352 */
350 list_for_each_entry(bdi, &bdi_list, bdi_list) { 353 list_for_each_entry(bdi, &bdi_list, bdi_list) {
351 if (!bdi_cap_writeback_dirty(bdi)) 354 bool have_dirty_io;
352 continue; 355
353 if (bdi->wb.task) 356 if (!bdi_cap_writeback_dirty(bdi) ||
354 continue; 357 bdi_cap_flush_forker(bdi))
355 if (list_empty(&bdi->work_list) &&
356 !bdi_has_dirty_io(bdi))
357 continue; 358 continue;
358 359
359 WARN(!test_bit(BDI_registered, &bdi->state), 360 WARN(!test_bit(BDI_registered, &bdi->state),
360 "bdi %p/%s is not registered!\n", bdi, bdi->name); 361 "bdi %p/%s is not registered!\n", bdi, bdi->name);
361 362
362 fork = true; 363 have_dirty_io = !list_empty(&bdi->work_list) ||
364 wb_has_dirty_io(&bdi->wb);
363 365
364 /* 366 /*
365 * Set the pending bit - if someone will try to 367 * If the bdi has work to do, but the thread does not
366 * unregister this bdi - it'll wait on this bit. 368 * exist - create it.
367 */ 369 */
368 set_bit(BDI_pending, &bdi->state); 370 if (!bdi->wb.task && have_dirty_io) {
369 break; 371 /*
372 * Set the pending bit - if someone will try to
373 * unregister this bdi - it'll wait on this bit.
374 */
375 set_bit(BDI_pending, &bdi->state);
376 action = FORK_THREAD;
377 break;
378 }
370 } 379 }
371 spin_unlock_bh(&bdi_lock); 380 spin_unlock_bh(&bdi_lock);
372 381
@@ -374,30 +383,30 @@ static int bdi_forker_thread(void *ptr)
374 if (!list_empty(&me->bdi->work_list)) 383 if (!list_empty(&me->bdi->work_list))
375 __set_current_state(TASK_RUNNING); 384 __set_current_state(TASK_RUNNING);
376 385
377 if (!fork) { 386 switch (action) {
378 unsigned long wait; 387 case FORK_THREAD:
388 __set_current_state(TASK_RUNNING);
389 task = kthread_run(bdi_writeback_thread, &bdi->wb, "flush-%s",
390 dev_name(bdi->dev));
391 if (IS_ERR(task)) {
392 /*
393 * If thread creation fails, force writeout of
394 * the bdi from the thread.
395 */
396 bdi_flush_io(bdi);
397 } else
398 bdi->wb.task = task;
399 break;
379 400
380 wait = msecs_to_jiffies(dirty_writeback_interval * 10); 401 case NO_ACTION:
381 if (wait) 402 if (dirty_writeback_interval)
382 schedule_timeout(wait); 403 schedule_timeout(msecs_to_jiffies(dirty_writeback_interval * 10));
383 else 404 else
384 schedule(); 405 schedule();
385 try_to_freeze(); 406 try_to_freeze();
407 /* Back to the main loop */
386 continue; 408 continue;
387 } 409 }
388
389 __set_current_state(TASK_RUNNING);
390
391 task = kthread_run(bdi_writeback_thread, &bdi->wb, "flush-%s",
392 dev_name(bdi->dev));
393 if (IS_ERR(task)) {
394 /*
395 * If thread creation fails, force writeout of the bdi
396 * from the thread.
397 */
398 bdi_flush_io(bdi);
399 } else
400 bdi->wb.task = task;
401 } 410 }
402 411
403 return 0; 412 return 0;