struct gendisk          *disk;
 
        unsigned long           flags;
-#define BCACHE_DEV_CLOSING     0
-#define BCACHE_DEV_DETACHING   1
-#define BCACHE_DEV_UNLINK_DONE 2
-
+#define BCACHE_DEV_CLOSING             0
+#define BCACHE_DEV_DETACHING           1
+#define BCACHE_DEV_UNLINK_DONE         2
+#define BCACHE_DEV_WB_RUNNING          3
+#define BCACHE_DEV_RATE_DW_RUNNING     4
        unsigned                nr_stripes;
        unsigned                stripe_size;
        atomic_t                *stripe_sectors_dirty;
 
                pr_debug("error creating sysfs link");
 }
 
+/*
+ * If BCACHE_DEV_RATE_DW_RUNNING is set, it means routine of the delayed
+ * work dc->writeback_rate_update is running. Wait until the routine
+ * quits (BCACHE_DEV_RATE_DW_RUNNING is clear), then continue to
+ * cancel it. If BCACHE_DEV_RATE_DW_RUNNING is not clear after time_out
+ * seconds, give up waiting here and continue to cancel it too.
+ */
+static void cancel_writeback_rate_update_dwork(struct cached_dev *dc)
+{
+       int time_out = WRITEBACK_RATE_UPDATE_SECS_MAX * HZ;
+
+       do {
+               if (!test_bit(BCACHE_DEV_RATE_DW_RUNNING,
+                             &dc->disk.flags))
+                       break;
+               time_out--;
+               schedule_timeout_interruptible(1);
+       } while (time_out > 0);
+
+       if (time_out == 0)
+               pr_warn("give up waiting for dc->writeback_write_update to quit");
+
+       cancel_delayed_work_sync(&dc->writeback_rate_update);
+}
+
 static void cached_dev_detach_finish(struct work_struct *w)
 {
        struct cached_dev *dc = container_of(w, struct cached_dev, detach);
 
        mutex_lock(&bch_register_lock);
 
-       cancel_delayed_work_sync(&dc->writeback_rate_update);
+       if (test_and_clear_bit(BCACHE_DEV_WB_RUNNING, &dc->disk.flags))
+               cancel_writeback_rate_update_dwork(dc);
+
        if (!IS_ERR_OR_NULL(dc->writeback_thread)) {
                kthread_stop(dc->writeback_thread);
                dc->writeback_thread = NULL;
        closure_get(&dc->disk.cl);
 
        bch_writeback_queue(dc);
+
        cached_dev_put(dc);
 }
 
 {
        struct cached_dev *dc = container_of(cl, struct cached_dev, disk.cl);
 
-       cancel_delayed_work_sync(&dc->writeback_rate_update);
+       mutex_lock(&bch_register_lock);
+
+       if (test_and_clear_bit(BCACHE_DEV_WB_RUNNING, &dc->disk.flags))
+               cancel_writeback_rate_update_dwork(dc);
+
        if (!IS_ERR_OR_NULL(dc->writeback_thread))
                kthread_stop(dc->writeback_thread);
        if (dc->writeback_write_wq)
                destroy_workqueue(dc->writeback_write_wq);
 
-       mutex_lock(&bch_register_lock);
-
        if (atomic_read(&dc->running))
                bd_unlink_disk_holder(dc->bdev, dc->disk.disk);
        bcache_device_free(&dc->disk);
 
                bch_writeback_queue(dc);
 
        if (attr == &sysfs_writeback_percent)
-               schedule_delayed_work(&dc->writeback_rate_update,
+               if (!test_and_set_bit(BCACHE_DEV_WB_RUNNING, &dc->disk.flags))
+                       schedule_delayed_work(&dc->writeback_rate_update,
                                      dc->writeback_rate_update_seconds * HZ);
 
        mutex_unlock(&bch_register_lock);
 
                                             struct cached_dev,
                                             writeback_rate_update);
 
+       /*
+        * should check BCACHE_DEV_RATE_DW_RUNNING before calling
+        * cancel_delayed_work_sync().
+        */
+       set_bit(BCACHE_DEV_RATE_DW_RUNNING, &dc->disk.flags);
+       /* paired with where BCACHE_DEV_RATE_DW_RUNNING is tested */
+       smp_mb();
+
+       if (!test_bit(BCACHE_DEV_WB_RUNNING, &dc->disk.flags)) {
+               clear_bit(BCACHE_DEV_RATE_DW_RUNNING, &dc->disk.flags);
+               /* paired with where BCACHE_DEV_RATE_DW_RUNNING is tested */
+               smp_mb();
+               return;
+       }
+
        down_read(&dc->writeback_lock);
 
        if (atomic_read(&dc->has_dirty) &&
 
        up_read(&dc->writeback_lock);
 
-       schedule_delayed_work(&dc->writeback_rate_update,
+       if (test_bit(BCACHE_DEV_WB_RUNNING, &dc->disk.flags)) {
+               schedule_delayed_work(&dc->writeback_rate_update,
                              dc->writeback_rate_update_seconds * HZ);
+       }
+
+       /*
+        * should check BCACHE_DEV_RATE_DW_RUNNING before calling
+        * cancel_delayed_work_sync().
+        */
+       clear_bit(BCACHE_DEV_RATE_DW_RUNNING, &dc->disk.flags);
+       /* paired with where BCACHE_DEV_RATE_DW_RUNNING is tested */
+       smp_mb();
 }
 
 static unsigned writeback_delay(struct cached_dev *dc, unsigned sectors)
        dc->writeback_rate_p_term_inverse = 40;
        dc->writeback_rate_i_term_inverse = 10000;
 
+       WARN_ON(test_and_clear_bit(BCACHE_DEV_WB_RUNNING, &dc->disk.flags));
        INIT_DELAYED_WORK(&dc->writeback_rate_update, update_writeback_rate);
 }
 
                return PTR_ERR(dc->writeback_thread);
        }
 
+       WARN_ON(test_and_set_bit(BCACHE_DEV_WB_RUNNING, &dc->disk.flags));
        schedule_delayed_work(&dc->writeback_rate_update,
                              dc->writeback_rate_update_seconds * HZ);