aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-rw-r--r--mm/backing-dev.c82
1 files changed, 18 insertions, 64 deletions
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 72e6eb96efe2..dbc66815a0fe 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -50,8 +50,6 @@ static struct timer_list sync_supers_timer;
50static int bdi_sync_supers(void *); 50static int bdi_sync_supers(void *);
51static void sync_supers_timer_fn(unsigned long); 51static void sync_supers_timer_fn(unsigned long);
52 52
53static void bdi_add_default_flusher_thread(struct backing_dev_info *bdi);
54
55#ifdef CONFIG_DEBUG_FS 53#ifdef CONFIG_DEBUG_FS
56#include <linux/debugfs.h> 54#include <linux/debugfs.h>
57#include <linux/seq_file.h> 55#include <linux/seq_file.h>
@@ -331,6 +329,7 @@ static int bdi_forker_thread(void *ptr)
331 set_user_nice(current, 0); 329 set_user_nice(current, 0);
332 330
333 for (;;) { 331 for (;;) {
332 bool fork = false;
334 struct task_struct *task; 333 struct task_struct *task;
335 struct backing_dev_info *bdi, *tmp; 334 struct backing_dev_info *bdi, *tmp;
336 335
@@ -349,23 +348,30 @@ static int bdi_forker_thread(void *ptr)
349 * a thread registered. If so, set that up. 348 * a thread registered. If so, set that up.
350 */ 349 */
351 list_for_each_entry_safe(bdi, tmp, &bdi_list, bdi_list) { 350 list_for_each_entry_safe(bdi, tmp, &bdi_list, bdi_list) {
351 if (!bdi_cap_writeback_dirty(bdi))
352 continue;
352 if (bdi->wb.task) 353 if (bdi->wb.task)
353 continue; 354 continue;
354 if (list_empty(&bdi->work_list) && 355 if (list_empty(&bdi->work_list) &&
355 !bdi_has_dirty_io(bdi)) 356 !bdi_has_dirty_io(bdi))
356 continue; 357 continue;
357 358
358 bdi_add_default_flusher_thread(bdi); 359 WARN(!test_bit(BDI_registered, &bdi->state),
360 "bdi %p/%s is not registered!\n", bdi, bdi->name);
361
362 list_del_rcu(&bdi->bdi_list);
363 fork = true;
364 break;
359 } 365 }
366 spin_unlock_bh(&bdi_lock);
360 367
361 /* Keep working if default bdi still has things to do */ 368 /* Keep working if default bdi still has things to do */
362 if (!list_empty(&me->bdi->work_list)) 369 if (!list_empty(&me->bdi->work_list))
363 __set_current_state(TASK_RUNNING); 370 __set_current_state(TASK_RUNNING);
364 371
365 if (list_empty(&bdi_pending_list)) { 372 if (!fork) {
366 unsigned long wait; 373 unsigned long wait;
367 374
368 spin_unlock_bh(&bdi_lock);
369 wait = msecs_to_jiffies(dirty_writeback_interval * 10); 375 wait = msecs_to_jiffies(dirty_writeback_interval * 10);
370 if (wait) 376 if (wait)
371 schedule_timeout(wait); 377 schedule_timeout(wait);
@@ -378,13 +384,13 @@ static int bdi_forker_thread(void *ptr)
378 __set_current_state(TASK_RUNNING); 384 __set_current_state(TASK_RUNNING);
379 385
380 /* 386 /*
381 * This is our real job - check for pending entries in 387 * Set the pending bit - if someone will try to unregister this
382 * bdi_pending_list, and create the threads that got added 388 * bdi - it'll wait on this bit.
383 */ 389 */
384 bdi = list_entry(bdi_pending_list.next, struct backing_dev_info, 390 set_bit(BDI_pending, &bdi->state);
385 bdi_list); 391
386 list_del_init(&bdi->bdi_list); 392 /* Make sure no one uses the picked bdi */
387 spin_unlock_bh(&bdi_lock); 393 synchronize_rcu();
388 394
389 task = kthread_run(bdi_writeback_thread, &bdi->wb, "flush-%s", 395 task = kthread_run(bdi_writeback_thread, &bdi->wb, "flush-%s",
390 dev_name(bdi->dev)); 396 dev_name(bdi->dev));
@@ -397,7 +403,7 @@ static int bdi_forker_thread(void *ptr)
397 * flush other bdi's to free memory. 403 * flush other bdi's to free memory.
398 */ 404 */
399 spin_lock_bh(&bdi_lock); 405 spin_lock_bh(&bdi_lock);
400 list_add_tail(&bdi->bdi_list, &bdi_pending_list); 406 list_add_tail_rcu(&bdi->bdi_list, &bdi_list);
401 spin_unlock_bh(&bdi_lock); 407 spin_unlock_bh(&bdi_lock);
402 408
403 bdi_flush_io(bdi); 409 bdi_flush_io(bdi);
@@ -408,57 +414,6 @@ static int bdi_forker_thread(void *ptr)
408 return 0; 414 return 0;
409} 415}
410 416
411static void bdi_add_to_pending(struct rcu_head *head)
412{
413 struct backing_dev_info *bdi;
414
415 bdi = container_of(head, struct backing_dev_info, rcu_head);
416 INIT_LIST_HEAD(&bdi->bdi_list);
417
418 spin_lock(&bdi_lock);
419 list_add_tail(&bdi->bdi_list, &bdi_pending_list);
420 spin_unlock(&bdi_lock);
421
422 /*
423 * We are now on the pending list, wake up bdi_forker_task()
424 * to finish the job and add us back to the active bdi_list
425 */
426 wake_up_process(default_backing_dev_info.wb.task);
427}
428
429/*
430 * Add the default flusher thread that gets created for any bdi
431 * that has dirty data pending writeout
432 */
433static void bdi_add_default_flusher_thread(struct backing_dev_info *bdi)
434{
435 if (!bdi_cap_writeback_dirty(bdi))
436 return;
437
438 if (WARN_ON(!test_bit(BDI_registered, &bdi->state))) {
439 printk(KERN_ERR "bdi %p/%s is not registered!\n",
440 bdi, bdi->name);
441 return;
442 }
443
444 /*
445 * Check with the helper whether to proceed adding a thread. Will only
446 * abort if we two or more simultanous calls to
447 * bdi_add_default_flusher_thread() occured, further additions will
448 * block waiting for previous additions to finish.
449 */
450 if (!test_and_set_bit(BDI_pending, &bdi->state)) {
451 list_del_rcu(&bdi->bdi_list);
452
453 /*
454 * We must wait for the current RCU period to end before
455 * moving to the pending list. So schedule that operation
456 * from an RCU callback.
457 */
458 call_rcu(&bdi->rcu_head, bdi_add_to_pending);
459 }
460}
461
462/* 417/*
463 * Remove bdi from bdi_list, and ensure that it is no longer visible 418 * Remove bdi from bdi_list, and ensure that it is no longer visible
464 */ 419 */
@@ -599,7 +554,6 @@ int bdi_init(struct backing_dev_info *bdi)
599 bdi->max_ratio = 100; 554 bdi->max_ratio = 100;
600 bdi->max_prop_frac = PROP_FRAC_BASE; 555 bdi->max_prop_frac = PROP_FRAC_BASE;
601 spin_lock_init(&bdi->wb_lock); 556 spin_lock_init(&bdi->wb_lock);
602 INIT_RCU_HEAD(&bdi->rcu_head);
603 INIT_LIST_HEAD(&bdi->bdi_list); 557 INIT_LIST_HEAD(&bdi->bdi_list);
604 INIT_LIST_HEAD(&bdi->work_list); 558 INIT_LIST_HEAD(&bdi->work_list);
605 559