diff options
Diffstat (limited to 'mm/backing-dev.c')
| -rw-r--r-- | mm/backing-dev.c | 18 | 
1 files changed, 13 insertions, 5 deletions
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index ce682f7a4f2..1706cbbdf5f 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -288,13 +288,19 @@ int bdi_has_dirty_io(struct backing_dev_info *bdi)   * Note, we wouldn't bother setting up the timer, but this function is on the   * fast-path (used by '__mark_inode_dirty()'), so we save few context switches   * by delaying the wake-up. + * + * We have to be careful not to postpone flush work if it is scheduled for + * earlier. Thus we use queue_delayed_work().   */  void bdi_wakeup_thread_delayed(struct backing_dev_info *bdi)  {  	unsigned long timeout;  	timeout = msecs_to_jiffies(dirty_writeback_interval * 10); -	mod_delayed_work(bdi_wq, &bdi->wb.dwork, timeout); +	spin_lock_bh(&bdi->wb_lock); +	if (test_bit(BDI_registered, &bdi->state)) +		queue_delayed_work(bdi_wq, &bdi->wb.dwork, timeout); +	spin_unlock_bh(&bdi->wb_lock);  }  /* @@ -307,9 +313,6 @@ static void bdi_remove_from_list(struct backing_dev_info *bdi)  	spin_unlock_bh(&bdi_lock);  	synchronize_rcu_expedited(); - -	/* bdi_list is now unused, clear it to mark @bdi dying */ -	INIT_LIST_HEAD(&bdi->bdi_list);  }  int bdi_register(struct backing_dev_info *bdi, struct device *parent, @@ -360,6 +363,11 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi)  	 */  	bdi_remove_from_list(bdi); +	/* Make sure nobody queues further work */ +	spin_lock_bh(&bdi->wb_lock); +	clear_bit(BDI_registered, &bdi->state); +	spin_unlock_bh(&bdi->wb_lock); +  	/*  	 * Drain work list and shutdown the delayed_work.  At this point,  	 * @bdi->bdi_list is empty telling bdi_Writeback_workfn() that @bdi @@ -549,7 +557,7 @@ void clear_bdi_congested(struct backing_dev_info *bdi, int sync)  	bit = sync ? BDI_sync_congested : BDI_async_congested;  	if (test_and_clear_bit(bit, &bdi->state))  		atomic_dec(&nr_bdi_congested[sync]); -	smp_mb__after_clear_bit(); +	smp_mb__after_atomic();  	if (waitqueue_active(wqh))  		wake_up(wqh);  }  | 
