]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
bcache: add bucket_size_hi into struct cache_sb_disk for large bucket
authorColy Li <colyli@suse.de>
Sat, 25 Jul 2020 12:00:35 +0000 (20:00 +0800)
committerJens Axboe <axboe@kernel.dk>
Sat, 25 Jul 2020 13:38:21 +0000 (07:38 -0600)
The large bucket feature is to extend bucket_size from 16bit to 32bit.

When create cache device on zoned device (e.g. zoned NVMe SSD), making
a single bucket cover one or more zones of the zoned device is the
simplest way to support zoned device as cache by bcache.

But current maximum bucket size is 16MB and a typical zone size of zoned
device is 256MB, this is the major motiviation to extend bucket size to
a larger bit width.

This patch is the basic and first change to support large bucket size,
the major changes it makes are,
- Add BCH_FEATURE_INCOMPAT_LARGE_BUCKET for the large bucket feature,
  INCOMPAT means it introduces incompatible on-disk format change.
- Add BCH_FEATURE_INCOMPAT_FUNCS(large_bucket, LARGE_BUCKET) routines.
- Adds __le16 bucket_size_hi into struct cache_sb_disk at offset 0x8d0
  for the on-disk super block format.
- For the in-memory super block struct cache_sb, member bucket_size is
  extended from __u16 to __32.
- Add get_bucket_size() to combine the bucket_size and bucket_size_hi
  from struct cache_sb_disk into an unsigned int value.

Since we already have large bucket size helpers meta_bucket_pages(),
meta_bucket_bytes() and alloc_meta_bucket_pages(), they make sure when
bucket size > 8MB, the memory allocation for bcache meta data bucket
won't fail no matter how large the bucket size extended. So these meta
data buckets are handled properly when the bucket size width increase
from 16bit to 32bit, we don't need to worry about them.

Signed-off-by: Coly Li <colyli@suse.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/md/bcache/alloc.c
drivers/md/bcache/features.c [new file with mode: 0644]
drivers/md/bcache/features.h
drivers/md/bcache/movinggc.c
drivers/md/bcache/super.c
include/uapi/linux/bcache.h

index a1df0d95151c67b15d78802193be03530441d4d0..52035a78d836882c10ef0658cb190b11e8c904d1 100644 (file)
@@ -87,7 +87,7 @@ void bch_rescale_priorities(struct cache_set *c, int sectors)
 {
        struct cache *ca;
        struct bucket *b;
-       unsigned int next = c->nbuckets * c->sb.bucket_size / 1024;
+       unsigned long next = c->nbuckets * c->sb.bucket_size / 1024;
        unsigned int i;
        int r;
 
diff --git a/drivers/md/bcache/features.c b/drivers/md/bcache/features.c
new file mode 100644 (file)
index 0000000..ba53944
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Feature set bits and string conversion.
+ * Inspired by ext4's features compat/incompat/ro_compat related code.
+ *
+ * Copyright 2020 Coly Li <colyli@suse.de>
+ *
+ */
+#include <linux/bcache.h>
+#include "bcache.h"
+
+struct feature {
+       int             compat;
+       unsigned int    mask;
+       const char      *string;
+};
+
+static struct feature feature_list[] = {
+       {BCH_FEATURE_INCOMPAT, BCH_FEATURE_INCOMPAT_LARGE_BUCKET,
+               "large_bucket"},
+       {0, 0, 0 },
+};
index ae7df37b98625caf302203c41bf0fe891fdd6796..dca052cf5203ca09a6310bd7db846dce6333472f 100644 (file)
 #define BCH_FEATURE_INCOMPAT           2
 #define BCH_FEATURE_TYPE_MASK          0x03
 
+/* Feature set definition */
+/* Incompat feature set */
+#define BCH_FEATURE_INCOMPAT_LARGE_BUCKET      0x0001 /* 32bit bucket size */
+
 #define BCH_FEATURE_COMPAT_SUUP                0
 #define BCH_FEATURE_RO_COMPAT_SUUP     0
-#define BCH_FEATURE_INCOMPAT_SUUP      0
+#define BCH_FEATURE_INCOMPAT_SUUP      BCH_FEATURE_INCOMPAT_LARGE_BUCKET
 
 #define BCH_HAS_COMPAT_FEATURE(sb, mask) \
                ((sb)->feature_compat & (mask))
@@ -22,8 +26,6 @@
 #define BCH_HAS_INCOMPAT_FEATURE(sb, mask) \
                ((sb)->feature_incompat & (mask))
 
-/* Feature set definition */
-
 #define BCH_FEATURE_COMPAT_FUNCS(name, flagname) \
 static inline int bch_has_feature_##name(struct cache_sb *sb) \
 { \
@@ -75,4 +77,5 @@ static inline void bch_clear_feature_##name(struct cache_sb *sb) \
                ~BCH##_FEATURE_INCOMPAT_##flagname; \
 }
 
+BCH_FEATURE_INCOMPAT_FUNCS(large_bucket, LARGE_BUCKET);
 #endif
index b7dd2d75f58c6cdfaef10dbc1e479bab8b9f43f8..5872d64704709859bf51aff7fbebb3890ae6fd4e 100644 (file)
@@ -206,8 +206,8 @@ void bch_moving_gc(struct cache_set *c)
        mutex_lock(&c->bucket_lock);
 
        for_each_cache(ca, c, i) {
-               unsigned int sectors_to_move = 0;
-               unsigned int reserve_sectors = ca->sb.bucket_size *
+               unsigned long sectors_to_move = 0;
+               unsigned long reserve_sectors = ca->sb.bucket_size *
                             fifo_used(&ca->free[RESERVE_MOVINGGC]);
 
                ca->heap.used = 0;
index e4f05c4ddcdddd30522660049e18c676872c7e84..62c9681fe92f09fd6cd998ddd2850b25bf6b4d30 100644 (file)
@@ -60,6 +60,17 @@ struct workqueue_struct *bch_journal_wq;
 
 /* Superblock */
 
+static unsigned int get_bucket_size(struct cache_sb *sb, struct cache_sb_disk *s)
+{
+       unsigned int bucket_size = le16_to_cpu(s->bucket_size);
+
+       if (sb->version >= BCACHE_SB_VERSION_CDEV_WITH_FEATURES &&
+            bch_has_feature_large_bucket(sb))
+               bucket_size |= le16_to_cpu(s->bucket_size_hi) << 16;
+
+       return bucket_size;
+}
+
 static const char *read_super_common(struct cache_sb *sb,  struct block_device *bdev,
                                     struct cache_sb_disk *s)
 {
@@ -68,7 +79,7 @@ static const char *read_super_common(struct cache_sb *sb,  struct block_device *
 
        sb->first_bucket= le16_to_cpu(s->first_bucket);
        sb->nbuckets    = le64_to_cpu(s->nbuckets);
-       sb->bucket_size = le16_to_cpu(s->bucket_size);
+       sb->bucket_size = get_bucket_size(sb, s);
 
        sb->nr_in_set   = le16_to_cpu(s->nr_in_set);
        sb->nr_this_dev = le16_to_cpu(s->nr_this_dev);
@@ -210,12 +221,16 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev,
                        goto err;
                break;
        case BCACHE_SB_VERSION_CDEV_WITH_FEATURES:
-               err = read_super_common(sb, bdev, s);
-               if (err)
-                       goto err;
+               /*
+                * Feature bits are needed in read_super_common(),
+                * convert them firstly.
+                */
                sb->feature_compat = le64_to_cpu(s->feature_compat);
                sb->feature_incompat = le64_to_cpu(s->feature_incompat);
                sb->feature_ro_compat = le64_to_cpu(s->feature_ro_compat);
+               err = read_super_common(sb, bdev, s);
+               if (err)
+                       goto err;
                break;
        default:
                err = "Unsupported superblock version";
index 0ef984ea515a81dcf7382f27ed7f3d15081c3e2c..52e8bcb339811c93cfbc50588fa1e442f1d7a4bb 100644 (file)
@@ -213,6 +213,7 @@ struct cache_sb_disk {
                __le16          keys;
        };
        __le64                  d[SB_JOURNAL_BUCKETS];  /* journal buckets */
+       __le16                  bucket_size_hi;
 };
 
 /*
@@ -247,9 +248,9 @@ struct cache_sb {
                __u64           nbuckets;       /* device size */
 
                __u16           block_size;     /* sectors */
-               __u16           bucket_size;    /* sectors */
                __u16           nr_in_set;
                __u16           nr_this_dev;
+               __u32           bucket_size;    /* sectors */
        };
        struct {
                /* Backing devices */