diff options
Diffstat (limited to 'mm/backing-dev.c')
| -rw-r--r-- | mm/backing-dev.c | 36 | 
1 files changed, 30 insertions, 6 deletions
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 2df8ddcb0ca0..619984fc07ec 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -480,6 +480,10 @@ static void cgwb_release_workfn(struct work_struct *work)  						release_work);  	struct backing_dev_info *bdi = wb->bdi; +	spin_lock_irq(&cgwb_lock); +	list_del_rcu(&wb->bdi_node); +	spin_unlock_irq(&cgwb_lock); +  	wb_shutdown(wb);  	css_put(wb->memcg_css); @@ -575,6 +579,7 @@ static int cgwb_create(struct backing_dev_info *bdi,  		ret = radix_tree_insert(&bdi->cgwb_tree, memcg_css->id, wb);  		if (!ret) {  			atomic_inc(&bdi->usage_cnt); +			list_add_tail_rcu(&wb->bdi_node, &bdi->wb_list);  			list_add(&wb->memcg_node, memcg_cgwb_list);  			list_add(&wb->blkcg_node, blkcg_cgwb_list);  			css_get(memcg_css); @@ -676,7 +681,7 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi)  static void cgwb_bdi_destroy(struct backing_dev_info *bdi)  {  	struct radix_tree_iter iter; -	struct bdi_writeback_congested *congested, *congested_n; +	struct rb_node *rbn;  	void **slot;  	WARN_ON(test_bit(WB_registered, &bdi->wb.state)); @@ -686,9 +691,11 @@ static void cgwb_bdi_destroy(struct backing_dev_info *bdi)  	radix_tree_for_each_slot(slot, &bdi->cgwb_tree, &iter, 0)  		cgwb_kill(*slot); -	rbtree_postorder_for_each_entry_safe(congested, congested_n, -					&bdi->cgwb_congested_tree, rb_node) { -		rb_erase(&congested->rb_node, &bdi->cgwb_congested_tree); +	while ((rbn = rb_first(&bdi->cgwb_congested_tree))) { +		struct bdi_writeback_congested *congested = +			rb_entry(rbn, struct bdi_writeback_congested, rb_node); + +		rb_erase(rbn, &bdi->cgwb_congested_tree);  		congested->bdi = NULL;	/* mark @congested unlinked */  	} @@ -764,15 +771,22 @@ static void cgwb_bdi_destroy(struct backing_dev_info *bdi) { }  int bdi_init(struct backing_dev_info *bdi)  { +	int ret; +  	bdi->dev = NULL;  	bdi->min_ratio = 0;  	bdi->max_ratio = 100;  	bdi->max_prop_frac = FPROP_FRAC_BASE;  	INIT_LIST_HEAD(&bdi->bdi_list); +	INIT_LIST_HEAD(&bdi->wb_list);  	init_waitqueue_head(&bdi->wb_waitq); -	return cgwb_bdi_init(bdi); +	ret = cgwb_bdi_init(bdi); + +	list_add_tail_rcu(&bdi->wb.bdi_node, &bdi->wb_list); + +	return ret;  }  EXPORT_SYMBOL(bdi_init); @@ -823,7 +837,7 @@ static void bdi_remove_from_list(struct backing_dev_info *bdi)  	synchronize_rcu_expedited();  } -void bdi_destroy(struct backing_dev_info *bdi) +void bdi_unregister(struct backing_dev_info *bdi)  {  	/* make sure nobody finds us on the bdi_list anymore */  	bdi_remove_from_list(bdi); @@ -835,9 +849,19 @@ void bdi_destroy(struct backing_dev_info *bdi)  		device_unregister(bdi->dev);  		bdi->dev = NULL;  	} +} +void bdi_exit(struct backing_dev_info *bdi) +{ +	WARN_ON_ONCE(bdi->dev);  	wb_exit(&bdi->wb);  } + +void bdi_destroy(struct backing_dev_info *bdi) +{ +	bdi_unregister(bdi); +	bdi_exit(bdi); +}  EXPORT_SYMBOL(bdi_destroy);  /*  | 
