|
@@ -356,8 +356,15 @@ 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);
|
|
@@ -369,6 +376,12 @@ 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_bit(WB_shutting_down, &wb->state);
|
|
|
}
|
|
|
|
|
|
static void wb_exit(struct bdi_writeback *wb)
|
|
@@ -699,12 +712,21 @@ static void cgwb_bdi_destroy(struct backing_dev_info *bdi)
|
|
|
{
|
|
|
struct radix_tree_iter iter;
|
|
|
void **slot;
|
|
|
+ struct bdi_writeback *wb;
|
|
|
|
|
|
WARN_ON(test_bit(WB_registered, &bdi->wb.state));
|
|
|
|
|
|
spin_lock_irq(&cgwb_lock);
|
|
|
radix_tree_for_each_slot(slot, &bdi->cgwb_tree, &iter, 0)
|
|
|
cgwb_kill(*slot);
|
|
|
+
|
|
|
+ while (!list_empty(&bdi->wb_list)) {
|
|
|
+ wb = list_first_entry(&bdi->wb_list, struct bdi_writeback,
|
|
|
+ bdi_node);
|
|
|
+ spin_unlock_irq(&cgwb_lock);
|
|
|
+ wb_shutdown(wb);
|
|
|
+ spin_lock_irq(&cgwb_lock);
|
|
|
+ }
|
|
|
spin_unlock_irq(&cgwb_lock);
|
|
|
|
|
|
/*
|