diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/backing-dev.c | 69 |
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; |