Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bcache: add bucket_size_hi into struct cache_sb_disk for large bucket

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>

authored by

Coly Li and committed by
Jens Axboe
ffa47032 f9c32a5a

+52 -11
+1 -1
drivers/md/bcache/alloc.c
··· 87 87 { 88 88 struct cache *ca; 89 89 struct bucket *b; 90 - unsigned int next = c->nbuckets * c->sb.bucket_size / 1024; 90 + unsigned long next = c->nbuckets * c->sb.bucket_size / 1024; 91 91 unsigned int i; 92 92 int r; 93 93
+22
drivers/md/bcache/features.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Feature set bits and string conversion. 4 + * Inspired by ext4's features compat/incompat/ro_compat related code. 5 + * 6 + * Copyright 2020 Coly Li <colyli@suse.de> 7 + * 8 + */ 9 + #include <linux/bcache.h> 10 + #include "bcache.h" 11 + 12 + struct feature { 13 + int compat; 14 + unsigned int mask; 15 + const char *string; 16 + }; 17 + 18 + static struct feature feature_list[] = { 19 + {BCH_FEATURE_INCOMPAT, BCH_FEATURE_INCOMPAT_LARGE_BUCKET, 20 + "large_bucket"}, 21 + {0, 0, 0 }, 22 + };
+6 -3
drivers/md/bcache/features.h
··· 11 11 #define BCH_FEATURE_INCOMPAT 2 12 12 #define BCH_FEATURE_TYPE_MASK 0x03 13 13 14 + /* Feature set definition */ 15 + /* Incompat feature set */ 16 + #define BCH_FEATURE_INCOMPAT_LARGE_BUCKET 0x0001 /* 32bit bucket size */ 17 + 14 18 #define BCH_FEATURE_COMPAT_SUUP 0 15 19 #define BCH_FEATURE_RO_COMPAT_SUUP 0 16 - #define BCH_FEATURE_INCOMPAT_SUUP 0 20 + #define BCH_FEATURE_INCOMPAT_SUUP BCH_FEATURE_INCOMPAT_LARGE_BUCKET 17 21 18 22 #define BCH_HAS_COMPAT_FEATURE(sb, mask) \ 19 23 ((sb)->feature_compat & (mask)) ··· 25 21 ((sb)->feature_ro_compat & (mask)) 26 22 #define BCH_HAS_INCOMPAT_FEATURE(sb, mask) \ 27 23 ((sb)->feature_incompat & (mask)) 28 - 29 - /* Feature set definition */ 30 24 31 25 #define BCH_FEATURE_COMPAT_FUNCS(name, flagname) \ 32 26 static inline int bch_has_feature_##name(struct cache_sb *sb) \ ··· 77 75 ~BCH##_FEATURE_INCOMPAT_##flagname; \ 78 76 } 79 77 78 + BCH_FEATURE_INCOMPAT_FUNCS(large_bucket, LARGE_BUCKET); 80 79 #endif
+2 -2
drivers/md/bcache/movinggc.c
··· 206 206 mutex_lock(&c->bucket_lock); 207 207 208 208 for_each_cache(ca, c, i) { 209 - unsigned int sectors_to_move = 0; 210 - unsigned int reserve_sectors = ca->sb.bucket_size * 209 + unsigned long sectors_to_move = 0; 210 + unsigned long reserve_sectors = ca->sb.bucket_size * 211 211 fifo_used(&ca->free[RESERVE_MOVINGGC]); 212 212 213 213 ca->heap.used = 0;
+19 -4
drivers/md/bcache/super.c
··· 60 60 61 61 /* Superblock */ 62 62 63 + static unsigned int get_bucket_size(struct cache_sb *sb, struct cache_sb_disk *s) 64 + { 65 + unsigned int bucket_size = le16_to_cpu(s->bucket_size); 66 + 67 + if (sb->version >= BCACHE_SB_VERSION_CDEV_WITH_FEATURES && 68 + bch_has_feature_large_bucket(sb)) 69 + bucket_size |= le16_to_cpu(s->bucket_size_hi) << 16; 70 + 71 + return bucket_size; 72 + } 73 + 63 74 static const char *read_super_common(struct cache_sb *sb, struct block_device *bdev, 64 75 struct cache_sb_disk *s) 65 76 { ··· 79 68 80 69 sb->first_bucket= le16_to_cpu(s->first_bucket); 81 70 sb->nbuckets = le64_to_cpu(s->nbuckets); 82 - sb->bucket_size = le16_to_cpu(s->bucket_size); 71 + sb->bucket_size = get_bucket_size(sb, s); 83 72 84 73 sb->nr_in_set = le16_to_cpu(s->nr_in_set); 85 74 sb->nr_this_dev = le16_to_cpu(s->nr_this_dev); ··· 221 210 goto err; 222 211 break; 223 212 case BCACHE_SB_VERSION_CDEV_WITH_FEATURES: 224 - err = read_super_common(sb, bdev, s); 225 - if (err) 226 - goto err; 213 + /* 214 + * Feature bits are needed in read_super_common(), 215 + * convert them firstly. 216 + */ 227 217 sb->feature_compat = le64_to_cpu(s->feature_compat); 228 218 sb->feature_incompat = le64_to_cpu(s->feature_incompat); 229 219 sb->feature_ro_compat = le64_to_cpu(s->feature_ro_compat); 220 + err = read_super_common(sb, bdev, s); 221 + if (err) 222 + goto err; 230 223 break; 231 224 default: 232 225 err = "Unsupported superblock version";
+2 -1
include/uapi/linux/bcache.h
··· 213 213 __le16 keys; 214 214 }; 215 215 __le64 d[SB_JOURNAL_BUCKETS]; /* journal buckets */ 216 + __le16 bucket_size_hi; 216 217 }; 217 218 218 219 /* ··· 248 247 __u64 nbuckets; /* device size */ 249 248 250 249 __u16 block_size; /* sectors */ 251 - __u16 bucket_size; /* sectors */ 252 250 __u16 nr_in_set; 253 251 __u16 nr_this_dev; 252 + __u32 bucket_size; /* sectors */ 254 253 }; 255 254 struct { 256 255 /* Backing devices */