diff options
Diffstat (limited to 'mm/backing-dev.c')
| -rw-r--r-- | mm/backing-dev.c | 107 | 
1 files changed, 25 insertions, 82 deletions
| diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 0ae0df55000b..7690ec77c722 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -14,19 +14,10 @@  static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0); -struct backing_dev_info default_backing_dev_info = { -	.name		= "default", -	.ra_pages	= VM_MAX_READAHEAD * 1024 / PAGE_CACHE_SIZE, -	.state		= 0, -	.capabilities	= BDI_CAP_MAP_COPY, -}; -EXPORT_SYMBOL_GPL(default_backing_dev_info); -  struct backing_dev_info noop_backing_dev_info = {  	.name		= "noop",  	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK,  }; -EXPORT_SYMBOL_GPL(noop_backing_dev_info);  static struct class *bdi_class; @@ -40,17 +31,6 @@ LIST_HEAD(bdi_list);  /* bdi_wq serves all asynchronous writeback tasks */  struct workqueue_struct *bdi_wq; -static void bdi_lock_two(struct bdi_writeback *wb1, struct bdi_writeback *wb2) -{ -	if (wb1 < wb2) { -		spin_lock(&wb1->list_lock); -		spin_lock_nested(&wb2->list_lock, 1); -	} else { -		spin_lock(&wb2->list_lock); -		spin_lock_nested(&wb1->list_lock, 1); -	} -} -  #ifdef CONFIG_DEBUG_FS  #include <linux/debugfs.h>  #include <linux/seq_file.h> @@ -264,9 +244,6 @@ static int __init default_bdi_init(void)  	if (!bdi_wq)  		return -ENOMEM; -	err = bdi_init(&default_backing_dev_info); -	if (!err) -		bdi_register(&default_backing_dev_info, NULL, "default");  	err = bdi_init(&noop_backing_dev_info);  	return err; @@ -355,19 +332,19 @@ EXPORT_SYMBOL(bdi_register_dev);   */  static void bdi_wb_shutdown(struct backing_dev_info *bdi)  { -	if (!bdi_cap_writeback_dirty(bdi)) +	/* Make sure nobody queues further work */ +	spin_lock_bh(&bdi->wb_lock); +	if (!test_and_clear_bit(BDI_registered, &bdi->state)) { +		spin_unlock_bh(&bdi->wb_lock);  		return; +	} +	spin_unlock_bh(&bdi->wb_lock);  	/*  	 * Make sure nobody finds us on the bdi_list anymore  	 */  	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 @@ -375,37 +352,22 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi)  	 */  	mod_delayed_work(bdi_wq, &bdi->wb.dwork, 0);  	flush_delayed_work(&bdi->wb.dwork); -	WARN_ON(!list_empty(&bdi->work_list)); -	WARN_ON(delayed_work_pending(&bdi->wb.dwork));  }  /* - * This bdi is going away now, make sure that no super_blocks point to it + * Called when the device behind @bdi has been removed or ejected. + * + * We can't really do much here except for reducing the dirty ratio at + * the moment.  In the future we should be able to set a flag so that + * the filesystem can handle errors at mark_inode_dirty time instead + * of only at writeback time.   */ -static void bdi_prune_sb(struct backing_dev_info *bdi) -{ -	struct super_block *sb; - -	spin_lock(&sb_lock); -	list_for_each_entry(sb, &super_blocks, s_list) { -		if (sb->s_bdi == bdi) -			sb->s_bdi = &default_backing_dev_info; -	} -	spin_unlock(&sb_lock); -} -  void bdi_unregister(struct backing_dev_info *bdi)  { -	if (bdi->dev) { -		bdi_set_min_ratio(bdi, 0); -		trace_writeback_bdi_unregister(bdi); -		bdi_prune_sb(bdi); +	if (WARN_ON_ONCE(!bdi->dev)) +		return; -		bdi_wb_shutdown(bdi); -		bdi_debug_unregister(bdi); -		device_unregister(bdi->dev); -		bdi->dev = NULL; -	} +	bdi_set_min_ratio(bdi, 0);  }  EXPORT_SYMBOL(bdi_unregister); @@ -474,37 +436,19 @@ void bdi_destroy(struct backing_dev_info *bdi)  {  	int i; -	/* -	 * Splice our entries to the default_backing_dev_info.  This -	 * condition shouldn't happen.  @wb must be empty at this point and -	 * dirty inodes on it might cause other issues.  This workaround is -	 * added by ce5f8e779519 ("writeback: splice dirty inode entries to -	 * default bdi on bdi_destroy()") without root-causing the issue. -	 * -	 * http://lkml.kernel.org/g/1253038617-30204-11-git-send-email-jens.axboe@oracle.com -	 * http://thread.gmane.org/gmane.linux.file-systems/35341/focus=35350 -	 * -	 * We should probably add WARN_ON() to find out whether it still -	 * happens and track it down if so. -	 */ -	if (bdi_has_dirty_io(bdi)) { -		struct bdi_writeback *dst = &default_backing_dev_info.wb; - -		bdi_lock_two(&bdi->wb, dst); -		list_splice(&bdi->wb.b_dirty, &dst->b_dirty); -		list_splice(&bdi->wb.b_io, &dst->b_io); -		list_splice(&bdi->wb.b_more_io, &dst->b_more_io); -		spin_unlock(&bdi->wb.list_lock); -		spin_unlock(&dst->list_lock); -	} - -	bdi_unregister(bdi); +	bdi_wb_shutdown(bdi); +	WARN_ON(!list_empty(&bdi->work_list));  	WARN_ON(delayed_work_pending(&bdi->wb.dwork)); +	if (bdi->dev) { +		bdi_debug_unregister(bdi); +		device_unregister(bdi->dev); +		bdi->dev = NULL; +	} +  	for (i = 0; i < NR_BDI_STAT_ITEMS; i++)  		percpu_counter_destroy(&bdi->bdi_stat[i]); -  	fprop_local_destroy_percpu(&bdi->completions);  }  EXPORT_SYMBOL(bdi_destroy); @@ -513,13 +457,12 @@ EXPORT_SYMBOL(bdi_destroy);   * For use from filesystems to quickly init and register a bdi associated   * with dirty writeback   */ -int bdi_setup_and_register(struct backing_dev_info *bdi, char *name, -			   unsigned int cap) +int bdi_setup_and_register(struct backing_dev_info *bdi, char *name)  {  	int err;  	bdi->name = name; -	bdi->capabilities = cap; +	bdi->capabilities = 0;  	err = bdi_init(bdi);  	if (err)  		return err; | 
