bcache: Stripe size isn't necessarily a power of two
authorKent Overstreet <kmo@daterainc.com>
Sat, 17 Aug 2013 09:13:15 +0000 (02:13 -0700)
committerKent Overstreet <kmo@daterainc.com>
Mon, 11 Nov 2013 05:55:55 +0000 (21:55 -0800)
Originally I got this right... except that the divides didn't use
do_div(), which broke 32 bit kernels. When I went to fix that, I forgot
that the raid stripe size usually isn't a power of two... doh

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

index 5786156..6e836f2 100644 (file)
@@ -437,7 +437,7 @@ struct bcache_device {
        int                     flush_done;
 
        uint64_t                nr_stripes;
-       unsigned                stripe_size_bits;
+       unsigned                stripe_size;
        atomic_t                *stripe_sectors_dirty;
 
        unsigned long           sectors_dirty_last;
index 74f2e90..d3169c0 100644 (file)
@@ -761,11 +761,10 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size,
        struct request_queue *q;
        size_t n;
 
-       if (!d->stripe_size_bits)
-               d->stripe_size_bits = 31;
+       if (!d->stripe_size)
+               d->stripe_size = 1 << 31;
 
-       d->nr_stripes = round_up(sectors, 1 << d->stripe_size_bits) >>
-               d->stripe_size_bits;
+       d->nr_stripes = DIV_ROUND_UP_ULL(sectors, d->stripe_size);
 
        if (!d->nr_stripes || d->nr_stripes > SIZE_MAX / sizeof(atomic_t))
                return -ENOMEM;
index 4211d82..b3a66f1 100644 (file)
@@ -157,7 +157,7 @@ SHOW(__bch_cached_dev)
        sysfs_hprint(dirty_data,
                     bcache_dev_sectors_dirty(&dc->disk) << 9);
 
-       sysfs_hprint(stripe_size,       (1 << dc->disk.stripe_size_bits) << 9);
+       sysfs_hprint(stripe_size,       dc->disk.stripe_size << 9);
        var_printf(partial_stripes_expensive,   "%u");
 
        var_printf(sequential_merge,    "%i");
index ba3ee48..b842fbf 100644 (file)
@@ -114,25 +114,25 @@ static bool dirty_pred(struct keybuf *buf, struct bkey *k)
 
 static bool dirty_full_stripe_pred(struct keybuf *buf, struct bkey *k)
 {
-       uint64_t stripe;
+       uint64_t stripe = KEY_START(k);
        unsigned nr_sectors = KEY_SIZE(k);
        struct cached_dev *dc = container_of(buf, struct cached_dev,
                                             writeback_keys);
-       unsigned stripe_size = 1 << dc->disk.stripe_size_bits;
 
        if (!KEY_DIRTY(k))
                return false;
 
-       stripe = KEY_START(k) >> dc->disk.stripe_size_bits;
-       while (1) {
-               if (atomic_read(dc->disk.stripe_sectors_dirty + stripe) !=
-                   stripe_size)
-                       return false;
+       do_div(stripe, dc->disk.stripe_size);
 
-               if (nr_sectors <= stripe_size)
+       while (1) {
+               if (atomic_read(dc->disk.stripe_sectors_dirty + stripe) ==
+                   dc->disk.stripe_size)
                        return true;
 
-               nr_sectors -= stripe_size;
+               if (nr_sectors <= dc->disk.stripe_size)
+                       return false;
+
+               nr_sectors -= dc->disk.stripe_size;
                stripe++;
        }
 }
@@ -186,11 +186,12 @@ static void refill_dirty(struct closure *cl)
 
                for (i = 0; i < dc->disk.nr_stripes; i++)
                        if (atomic_read(dc->disk.stripe_sectors_dirty + i) ==
-                           1 << dc->disk.stripe_size_bits)
+                           dc->disk.stripe_size)
                                goto full_stripes;
 
                goto normal_refill;
 full_stripes:
+               searched_from_start = false;    /* not searching entire btree */
                bch_refill_keybuf(dc->disk.c, buf, &end,
                                  dirty_full_stripe_pred);
        } else {
@@ -252,19 +253,19 @@ void bcache_dev_sectors_dirty_add(struct cache_set *c, unsigned inode,
                                  uint64_t offset, int nr_sectors)
 {
        struct bcache_device *d = c->devices[inode];
-       unsigned stripe_size, stripe_offset;
-       uint64_t stripe;
+       unsigned stripe_offset;
+       uint64_t stripe = offset;
 
        if (!d)
                return;
 
-       stripe_size = 1 << d->stripe_size_bits;
-       stripe = offset >> d->stripe_size_bits;
-       stripe_offset = offset & (stripe_size - 1);
+       do_div(stripe, d->stripe_size);
+
+       stripe_offset = offset & (d->stripe_size - 1);
 
        while (nr_sectors) {
                int s = min_t(unsigned, abs(nr_sectors),
-                             stripe_size - stripe_offset);
+                             d->stripe_size - stripe_offset);
 
                if (nr_sectors < 0)
                        s = -s;
index c91f61b..3496188 100644 (file)
@@ -18,16 +18,18 @@ static inline bool bcache_dev_stripe_dirty(struct bcache_device *d,
                                           uint64_t offset,
                                           unsigned nr_sectors)
 {
-       uint64_t stripe = offset >> d->stripe_size_bits;
+       uint64_t stripe = offset;
+
+       do_div(stripe, d->stripe_size);
 
        while (1) {
                if (atomic_read(d->stripe_sectors_dirty + stripe))
                        return true;
 
-               if (nr_sectors <= 1 << d->stripe_size_bits)
+               if (nr_sectors <= d->stripe_size)
                        return false;
 
-               nr_sectors -= 1 << d->stripe_size_bits;
+               nr_sectors -= d->stripe_size;
                stripe++;
        }
 }