bcache: fix uninterruptible sleep in writeback thread
authorSlava Pestov <sp@daterainc.com>
Thu, 1 May 2014 20:48:57 +0000 (13:48 -0700)
committerKent Overstreet <kmo@daterainc.com>
Mon, 4 Aug 2014 22:23:03 +0000 (15:23 -0700)
There were two issues here:

- writeback thread did not start until the device first became dirty
- writeback thread used uninterruptible sleep once running

Without this patch I see kernel warnings printed and a load average of
1.52 after booting my test VM. With this patch the warnings are gone and
the load average is near 0.00 as expected.

Signed-off-by: Kent Overstreet <kmo@daterainc.com>
drivers/md/bcache/super.c
drivers/md/bcache/writeback.c
drivers/md/bcache/writeback.h

index 3b043a04d9bd712fcfcdbe34abfa18487bd35a3d..00cc42550f34307c37e0d92b7f74386470c0ffa7 100644 (file)
@@ -1042,6 +1042,9 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c)
         */
        atomic_set(&dc->count, 1);
 
+       if (bch_cached_dev_writeback_start(dc))
+               return -ENOMEM;
+
        if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) {
                bch_sectors_dirty_init(dc);
                atomic_set(&dc->has_dirty, 1);
index f4300e4c0114a0cc1abc3b90f757a03666d2637b..f1986bcd1bf05e1058e26946c600a6e2c1f5991d 100644 (file)
@@ -239,7 +239,7 @@ static void read_dirty(struct cached_dev *dc)
                if (KEY_START(&w->key) != dc->last_read ||
                    jiffies_to_msecs(delay) > 50)
                        while (!kthread_should_stop() && delay)
-                               delay = schedule_timeout_uninterruptible(delay);
+                               delay = schedule_timeout_interruptible(delay);
 
                dc->last_read   = KEY_OFFSET(&w->key);
 
@@ -436,7 +436,7 @@ static int bch_writeback_thread(void *arg)
                        while (delay &&
                               !kthread_should_stop() &&
                               !test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags))
-                               delay = schedule_timeout_uninterruptible(delay);
+                               delay = schedule_timeout_interruptible(delay);
                }
        }
 
@@ -478,7 +478,7 @@ void bch_sectors_dirty_init(struct cached_dev *dc)
        dc->disk.sectors_dirty_last = bcache_dev_sectors_dirty(&dc->disk);
 }
 
-int bch_cached_dev_writeback_init(struct cached_dev *dc)
+void bch_cached_dev_writeback_init(struct cached_dev *dc)
 {
        sema_init(&dc->in_flight, 64);
        init_rwsem(&dc->writeback_lock);
@@ -494,14 +494,20 @@ int bch_cached_dev_writeback_init(struct cached_dev *dc)
        dc->writeback_rate_d_term       = 30;
        dc->writeback_rate_p_term_inverse = 6000;
 
+       INIT_DELAYED_WORK(&dc->writeback_rate_update, update_writeback_rate);
+}
+
+int bch_cached_dev_writeback_start(struct cached_dev *dc)
+{
        dc->writeback_thread = kthread_create(bch_writeback_thread, dc,
                                              "bcache_writeback");
        if (IS_ERR(dc->writeback_thread))
                return PTR_ERR(dc->writeback_thread);
 
-       INIT_DELAYED_WORK(&dc->writeback_rate_update, update_writeback_rate);
        schedule_delayed_work(&dc->writeback_rate_update,
                              dc->writeback_rate_update_seconds * HZ);
 
+       bch_writeback_queue(dc);
+
        return 0;
 }
index e2f8598937ac41ff5c7577bc5e65aeb39de95386..0a9dab187b79c7ef0a4429c4616a6985d320b964 100644 (file)
@@ -85,6 +85,7 @@ static inline void bch_writeback_add(struct cached_dev *dc)
 void bcache_dev_sectors_dirty_add(struct cache_set *, unsigned, uint64_t, int);
 
 void bch_sectors_dirty_init(struct cached_dev *dc);
-int bch_cached_dev_writeback_init(struct cached_dev *);
+void bch_cached_dev_writeback_init(struct cached_dev *);
+int bch_cached_dev_writeback_start(struct cached_dev *);
 
 #endif