|
@@ -359,15 +359,8 @@ static void wb_shutdown(struct bdi_writeback *wb)
|
|
|
spin_lock_bh(&wb->work_lock);
|
|
|
if (!test_and_clear_bit(WB_registered, &wb->state)) {
|
|
|
spin_unlock_bh(&wb->work_lock);
|
|
|
- /*
|
|
|
- * Wait for wb shutdown to finish if someone else is just
|
|
|
- * running wb_shutdown(). Otherwise we could proceed to wb /
|
|
|
- * bdi destruction before wb_shutdown() is finished.
|
|
|
- */
|
|
|
- wait_on_bit(&wb->state, WB_shutting_down, TASK_UNINTERRUPTIBLE);
|
|
|
return;
|
|
|
}
|
|
|
- set_bit(WB_shutting_down, &wb->state);
|
|
|
spin_unlock_bh(&wb->work_lock);
|
|
|
|
|
|
cgwb_remove_from_bdi_list(wb);
|
|
@@ -379,12 +372,6 @@ static void wb_shutdown(struct bdi_writeback *wb)
|
|
|
mod_delayed_work(bdi_wq, &wb->dwork, 0);
|
|
|
flush_delayed_work(&wb->dwork);
|
|
|
WARN_ON(!list_empty(&wb->work_list));
|
|
|
- /*
|
|
|
- * Make sure bit gets cleared after shutdown is finished. Matches with
|
|
|
- * the barrier provided by test_and_clear_bit() above.
|
|
|
- */
|
|
|
- smp_wmb();
|
|
|
- clear_and_wake_up_bit(WB_shutting_down, &wb->state);
|
|
|
}
|
|
|
|
|
|
static void wb_exit(struct bdi_writeback *wb)
|
|
@@ -508,10 +495,12 @@ static void cgwb_release_workfn(struct work_struct *work)
|
|
|
struct bdi_writeback *wb = container_of(work, struct bdi_writeback,
|
|
|
release_work);
|
|
|
|
|
|
+ mutex_lock(&wb->bdi->cgwb_release_mutex);
|
|
|
wb_shutdown(wb);
|
|
|
|
|
|
css_put(wb->memcg_css);
|
|
|
css_put(wb->blkcg_css);
|
|
|
+ mutex_unlock(&wb->bdi->cgwb_release_mutex);
|
|
|
|
|
|
fprop_local_destroy_percpu(&wb->memcg_completions);
|
|
|
percpu_ref_exit(&wb->refcnt);
|
|
@@ -697,6 +686,7 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi)
|
|
|
|
|
|
INIT_RADIX_TREE(&bdi->cgwb_tree, GFP_ATOMIC);
|
|
|
bdi->cgwb_congested_tree = RB_ROOT;
|
|
|
+ mutex_init(&bdi->cgwb_release_mutex);
|
|
|
|
|
|
ret = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL);
|
|
|
if (!ret) {
|
|
@@ -717,7 +707,10 @@ static void cgwb_bdi_unregister(struct backing_dev_info *bdi)
|
|
|
spin_lock_irq(&cgwb_lock);
|
|
|
radix_tree_for_each_slot(slot, &bdi->cgwb_tree, &iter, 0)
|
|
|
cgwb_kill(*slot);
|
|
|
+ spin_unlock_irq(&cgwb_lock);
|
|
|
|
|
|
+ mutex_lock(&bdi->cgwb_release_mutex);
|
|
|
+ spin_lock_irq(&cgwb_lock);
|
|
|
while (!list_empty(&bdi->wb_list)) {
|
|
|
wb = list_first_entry(&bdi->wb_list, struct bdi_writeback,
|
|
|
bdi_node);
|
|
@@ -726,6 +719,7 @@ static void cgwb_bdi_unregister(struct backing_dev_info *bdi)
|
|
|
spin_lock_irq(&cgwb_lock);
|
|
|
}
|
|
|
spin_unlock_irq(&cgwb_lock);
|
|
|
+ mutex_unlock(&bdi->cgwb_release_mutex);
|
|
|
}
|
|
|
|
|
|
/**
|