aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
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;