bcache: Fix sysfs splat on shutdown with flash only devs
authorKent Overstreet <kmo@daterainc.com>
Thu, 22 Aug 2013 00:49:09 +0000 (17:49 -0700)
committerKent Overstreet <kmo@daterainc.com>
Mon, 11 Nov 2013 05:56:41 +0000 (21:56 -0800)
Whoops.

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

index ab0b2150fed67700faa8ed283f56f4b798d42bd9..97ef126b68bba17db78a4f786419c44ff0299aaf 100644 (file)
@@ -266,12 +266,10 @@ struct bcache_device {
 
        struct gendisk          *disk;
 
-       /* If nonzero, we're closing */
-       atomic_t                closing;
-
-       /* If nonzero, we're detaching/unregistering from cache set */
-       atomic_t                detaching;
-       int                     flush_done;
+       unsigned long           flags;
+#define BCACHE_DEV_CLOSING     0
+#define BCACHE_DEV_DETACHING   1
+#define BCACHE_DEV_UNLINK_DONE 2
 
        unsigned                nr_stripes;
        unsigned                stripe_size;
index f645da61189aef79ac9f38c8d9a16051669fe1a2..9f5a1386f77a5d964344b619a7a2577bd4a38462 100644 (file)
@@ -512,7 +512,7 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio)
        struct task_struct *task = current;
        struct io *i;
 
-       if (atomic_read(&dc->disk.detaching) ||
+       if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) ||
            c->gc_stats.in_use > CUTOFF_CACHE_ADD ||
            (bio->bi_rw & REQ_DISCARD))
                goto skip;
index 43fcfe38be1108c102567b24e2f308793080d31e..fa1d53087f882521ebadadd47eae02d983c08f81 100644 (file)
@@ -621,7 +621,7 @@ static void prio_read(struct cache *ca, uint64_t bucket)
 static int open_dev(struct block_device *b, fmode_t mode)
 {
        struct bcache_device *d = b->bd_disk->private_data;
-       if (atomic_read(&d->closing))
+       if (test_bit(BCACHE_DEV_CLOSING, &d->flags))
                return -ENXIO;
 
        closure_get(&d->cl);
@@ -650,20 +650,24 @@ static const struct block_device_operations bcache_ops = {
 
 void bcache_device_stop(struct bcache_device *d)
 {
-       if (!atomic_xchg(&d->closing, 1))
+       if (!test_and_set_bit(BCACHE_DEV_CLOSING, &d->flags))
                closure_queue(&d->cl);
 }
 
 static void bcache_device_unlink(struct bcache_device *d)
 {
-       unsigned i;
-       struct cache *ca;
+       lockdep_assert_held(&bch_register_lock);
 
-       sysfs_remove_link(&d->c->kobj, d->name);
-       sysfs_remove_link(&d->kobj, "cache");
+       if (d->c && !test_and_set_bit(BCACHE_DEV_UNLINK_DONE, &d->flags)) {
+               unsigned i;
+               struct cache *ca;
 
-       for_each_cache(ca, d->c, i)
-               bd_unlink_disk_holder(ca->bdev, d->disk);
+               sysfs_remove_link(&d->c->kobj, d->name);
+               sysfs_remove_link(&d->kobj, "cache");
+
+               for_each_cache(ca, d->c, i)
+                       bd_unlink_disk_holder(ca->bdev, d->disk);
+       }
 }
 
 static void bcache_device_link(struct bcache_device *d, struct cache_set *c,
@@ -687,19 +691,16 @@ static void bcache_device_detach(struct bcache_device *d)
 {
        lockdep_assert_held(&bch_register_lock);
 
-       if (atomic_read(&d->detaching)) {
+       if (test_bit(BCACHE_DEV_DETACHING, &d->flags)) {
                struct uuid_entry *u = d->c->uuids + d->id;
 
                SET_UUID_FLASH_ONLY(u, 0);
                memcpy(u->uuid, invalid_uuid, 16);
                u->invalidated = cpu_to_le32(get_seconds());
                bch_uuid_write(d->c);
-
-               atomic_set(&d->detaching, 0);
        }
 
-       if (!d->flush_done)
-               bcache_device_unlink(d);
+       bcache_device_unlink(d);
 
        d->c->devices[d->id] = NULL;
        closure_put(&d->c->caching);
@@ -879,7 +880,7 @@ static void cached_dev_detach_finish(struct work_struct *w)
        struct closure cl;
        closure_init_stack(&cl);
 
-       BUG_ON(!atomic_read(&dc->disk.detaching));
+       BUG_ON(!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags));
        BUG_ON(atomic_read(&dc->count));
 
        mutex_lock(&bch_register_lock);
@@ -893,6 +894,8 @@ static void cached_dev_detach_finish(struct work_struct *w)
        bcache_device_detach(&dc->disk);
        list_move(&dc->list, &uncached_devices);
 
+       clear_bit(BCACHE_DEV_DETACHING, &dc->disk.flags);
+
        mutex_unlock(&bch_register_lock);
 
        pr_info("Caching disabled for %s", bdevname(dc->bdev, buf));
@@ -905,10 +908,10 @@ void bch_cached_dev_detach(struct cached_dev *dc)
 {
        lockdep_assert_held(&bch_register_lock);
 
-       if (atomic_read(&dc->disk.closing))
+       if (test_bit(BCACHE_DEV_CLOSING, &dc->disk.flags))
                return;
 
-       if (atomic_xchg(&dc->disk.detaching, 1))
+       if (test_and_set_bit(BCACHE_DEV_DETACHING, &dc->disk.flags))
                return;
 
        /*
@@ -1064,11 +1067,7 @@ static void cached_dev_flush(struct closure *cl)
        struct bcache_device *d = &dc->disk;
 
        mutex_lock(&bch_register_lock);
-       d->flush_done = 1;
-
-       if (d->c)
-               bcache_device_unlink(d);
-
+       bcache_device_unlink(d);
        mutex_unlock(&bch_register_lock);
 
        bch_cache_accounting_destroy(&dc->accounting);
index 4b672449ffafa960de6276f28aca5d42bda67023..194d43782ea4e2e26519f8a84e09f89f1e25befd 100644 (file)
@@ -370,7 +370,7 @@ STORE(__bch_flash_dev)
        }
 
        if (attr == &sysfs_unregister) {
-               atomic_set(&d->detaching, 1);
+               set_bit(BCACHE_DEV_DETACHING, &d->flags);
                bcache_device_stop(d);
        }
 
index 22e21dc9a0376c8c407ecfecaedb4bef104b7ef2..99053b1251bea1049c627580f3614d1c18f89b60 100644 (file)
@@ -89,7 +89,7 @@ static unsigned writeback_delay(struct cached_dev *dc, unsigned sectors)
 {
        uint64_t ret;
 
-       if (atomic_read(&dc->disk.detaching) ||
+       if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) ||
            !dc->writeback_percent)
                return 0;
 
@@ -404,7 +404,7 @@ static int bch_writeback_thread(void *arg)
        while (!kthread_should_stop()) {
                down_write(&dc->writeback_lock);
                if (!atomic_read(&dc->has_dirty) ||
-                   (!atomic_read(&dc->disk.detaching) &&
+                   (!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) &&
                     !dc->writeback_running)) {
                        up_write(&dc->writeback_lock);
                        set_current_state(TASK_INTERRUPTIBLE);
@@ -437,7 +437,7 @@ static int bch_writeback_thread(void *arg)
 
                        while (delay &&
                               !kthread_should_stop() &&
-                              !atomic_read(&dc->disk.detaching))
+                              !test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags))
                                delay = schedule_timeout_interruptible(delay);
                }
        }
index fe7d9d56492b339a1d31c3b91e0c7c3d07034c9a..c9ddcf4614b9300701c9867033c82bc13cadf472 100644 (file)
@@ -45,7 +45,7 @@ static inline bool should_writeback(struct cached_dev *dc, struct bio *bio,
        unsigned in_use = dc->disk.c->gc_stats.in_use;
 
        if (cache_mode != CACHE_MODE_WRITEBACK ||
-           atomic_read(&dc->disk.detaching) ||
+           test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) ||
            in_use > CUTOFF_WRITEBACK_SYNC)
                return false;