bcachefs: Option improvements
authorKent Overstreet <kent.overstreet@gmail.com>
Tue, 14 Dec 2021 19:24:41 +0000 (14:24 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:19 +0000 (17:09 -0400)
This adds flags for options that must be a power of two (block size and
btree node size), and options that are stored in the superblock as a
power of two (encoded extent max).

Also: options are now stored in memory in the same units they're
displayed in (bytes): we now convert when getting and setting from the
superblock.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
17 files changed:
fs/bcachefs/bcachefs.h
fs/bcachefs/btree_cache.h
fs/bcachefs/btree_io.c
fs/bcachefs/btree_update_interior.c
fs/bcachefs/btree_update_interior.h
fs/bcachefs/buckets.c
fs/bcachefs/compress.c
fs/bcachefs/extents.c
fs/bcachefs/fs.c
fs/bcachefs/io.c
fs/bcachefs/journal_io.c
fs/bcachefs/opts.c
fs/bcachefs/opts.h
fs/bcachefs/super-io.c
fs/bcachefs/super.c
fs/bcachefs/sysfs.c
fs/bcachefs/xattr.c

index 1ad5eafb2f7676b7e31e51f96bb5922ad2d63ca5..95b590d9ee7f6ffde7396b6e6353031b50cbcade 100644 (file)
@@ -928,10 +928,20 @@ static inline unsigned bucket_bytes(const struct bch_dev *ca)
 
 static inline unsigned block_bytes(const struct bch_fs *c)
 {
-       return c->opts.block_size << 9;
+       return c->opts.block_size;
 }
 
-static inline struct timespec64 bch2_time_to_timespec(struct bch_fs *c, s64 time)
+static inline unsigned block_sectors(const struct bch_fs *c)
+{
+       return c->opts.block_size >> 9;
+}
+
+static inline size_t btree_sectors(const struct bch_fs *c)
+{
+       return c->opts.btree_node_size >> 9;
+}
+
+static inline struct timespec64 bch2_time_to_timespec(const struct bch_fs *c, s64 time)
 {
        struct timespec64 t;
        s32 rem;
@@ -943,13 +953,13 @@ static inline struct timespec64 bch2_time_to_timespec(struct bch_fs *c, s64 time
        return t;
 }
 
-static inline s64 timespec_to_bch2_time(struct bch_fs *c, struct timespec64 ts)
+static inline s64 timespec_to_bch2_time(const struct bch_fs *c, struct timespec64 ts)
 {
        return (ts.tv_sec * c->sb.time_units_per_sec +
                (int) ts.tv_nsec / c->sb.nsec_per_time_unit) - c->sb.time_base_lo;
 }
 
-static inline s64 bch2_current_time(struct bch_fs *c)
+static inline s64 bch2_current_time(const struct bch_fs *c)
 {
        struct timespec64 now;
 
index 2f6e0ea87616c0c057358b1a93398ee5ff0500df..a08d12569075dab1b31eae17463254f96a43a4c7 100644 (file)
@@ -69,7 +69,7 @@ static inline bool btree_node_hashed(struct btree *b)
 
 static inline size_t btree_bytes(struct bch_fs *c)
 {
-       return c->opts.btree_node_size << 9;
+       return c->opts.btree_node_size;
 }
 
 static inline size_t btree_max_u64s(struct bch_fs *c)
@@ -84,7 +84,7 @@ static inline size_t btree_pages(struct bch_fs *c)
 
 static inline unsigned btree_blocks(struct bch_fs *c)
 {
-       return c->opts.btree_node_size >> c->block_bits;
+       return btree_sectors(c) >> c->block_bits;
 }
 
 #define BTREE_SPLIT_THRESHOLD(c)               (btree_max_u64s(c) * 2 / 3)
index 45f7ec41a8f174ecfe2f6ef1bb7603aae033c9c8..287c45253a3304d4bfa55d8536c5b2c5fe3b7241 100644 (file)
@@ -682,7 +682,7 @@ static int validate_bset(struct bch_fs *c, struct bch_dev *ca,
                     BTREE_ERR_FATAL, c, ca, b, i,
                     "BSET_SEPARATE_WHITEOUTS no longer supported");
 
-       if (btree_err_on(offset + sectors > c->opts.btree_node_size,
+       if (btree_err_on(offset + sectors > btree_sectors(c),
                         BTREE_ERR_FIXABLE, c, ca, b, i,
                         "bset past end of btree node")) {
                i->u64s = 0;
@@ -896,7 +896,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct bch_dev *ca,
                             b->data->keys.seq, bp->seq);
        }
 
-       while (b->written < (ptr_written ?: c->opts.btree_node_size)) {
+       while (b->written < (ptr_written ?: btree_sectors(c))) {
                unsigned sectors, whiteout_u64s = 0;
                struct nonce nonce;
                struct bch_csum csum;
@@ -1204,7 +1204,7 @@ static unsigned btree_node_sectors_written(struct bch_fs *c, void *data)
        if (le64_to_cpu(bn->magic) !=  bset_magic(c))
                return 0;
 
-       while (offset < c->opts.btree_node_size) {
+       while (offset < btree_sectors(c)) {
                if (!offset) {
                        offset += vstruct_sectors(bn, c->block_bits);
                } else {
@@ -1226,7 +1226,7 @@ static bool btree_node_has_extra_bsets(struct bch_fs *c, unsigned offset, void *
        if (!offset)
                return false;
 
-       while (offset < c->opts.btree_node_size) {
+       while (offset < btree_sectors(c)) {
                bne = data + (offset << 9);
                if (bne->keys.seq == bn->keys.seq)
                        return true;
@@ -1296,7 +1296,7 @@ fsck_err:
                        if (ra->err[i])
                                continue;
 
-                       while (offset < c->opts.btree_node_size) {
+                       while (offset < btree_sectors(c)) {
                                if (!offset) {
                                        sectors = vstruct_sectors(bn, c->block_bits);
                                } else {
@@ -1313,7 +1313,7 @@ fsck_err:
                                offset += sectors;
                        }
 
-                       while (offset < c->opts.btree_node_size) {
+                       while (offset < btree_sectors(c)) {
                                bne = ra->buf[i] + (offset << 9);
                                if (bne->keys.seq == bn->keys.seq) {
                                        if (!gap)
@@ -1793,8 +1793,8 @@ do_write:
        BUG_ON(btree_node_fake(b));
        BUG_ON((b->will_make_reachable != 0) != !b->written);
 
-       BUG_ON(b->written >= c->opts.btree_node_size);
-       BUG_ON(b->written & (c->opts.block_size - 1));
+       BUG_ON(b->written >= btree_sectors(c));
+       BUG_ON(b->written & (block_sectors(c) - 1));
        BUG_ON(bset_written(b, btree_bset_last(b)));
        BUG_ON(le64_to_cpu(b->data->magic) != bset_magic(c));
        BUG_ON(memcmp(&b->data->format, &b->format, sizeof(b->format)));
@@ -1867,7 +1867,7 @@ do_write:
        memset(data + bytes_to_write, 0,
               (sectors_to_write << 9) - bytes_to_write);
 
-       BUG_ON(b->written + sectors_to_write > c->opts.btree_node_size);
+       BUG_ON(b->written + sectors_to_write > btree_sectors(c));
        BUG_ON(BSET_BIG_ENDIAN(i) != CPU_BIG_ENDIAN);
        BUG_ON(i->seq != b->data->keys.seq);
 
index 3e6dd2ed1c030d8e67e9790d46a08cf68e58548f..fd4089d19ad2ef60350ee903f1707078af0298e6 100644 (file)
@@ -223,12 +223,12 @@ retry:
        if (IS_ERR(wp))
                return ERR_CAST(wp);
 
-       if (wp->sectors_free < c->opts.btree_node_size) {
+       if (wp->sectors_free < btree_sectors(c)) {
                struct open_bucket *ob;
                unsigned i;
 
                open_bucket_for_each(c, &wp->ptrs, ob, i)
-                       if (ob->sectors_free < c->opts.btree_node_size)
+                       if (ob->sectors_free < btree_sectors(c))
                                ob->sectors_free = 0;
 
                bch2_alloc_sectors_done(c, wp);
@@ -236,7 +236,7 @@ retry:
        }
 
        bkey_btree_ptr_v2_init(&tmp.k);
-       bch2_alloc_sectors_append_ptrs(c, wp, &tmp.k, c->opts.btree_node_size);
+       bch2_alloc_sectors_append_ptrs(c, wp, &tmp.k, btree_sectors(c));
 
        bch2_open_bucket_get(c, wp, &ob);
        bch2_alloc_sectors_done(c, wp);
@@ -1029,7 +1029,7 @@ retry:
        }
 
        ret = bch2_disk_reservation_get(c, &as->disk_res,
-                       nr_nodes * c->opts.btree_node_size,
+                       nr_nodes * btree_sectors(c),
                        c->opts.metadata_replicas,
                        disk_res_flags);
        if (ret)
index d4574161a733a1f56d0695ad2cdd74e63b13ce08..8cf59cee6e4e28461467f670dbad6b73f97c57f2 100644 (file)
@@ -218,7 +218,7 @@ static inline ssize_t __bch_btree_u64s_remaining(struct bch_fs *c,
 {
        ssize_t used = bset_byte_offset(b, end) / sizeof(u64) +
                b->whiteout_u64s;
-       ssize_t total = c->opts.btree_node_size << 6;
+       ssize_t total = c->opts.btree_node_size >> 3;
 
        /* Always leave one extra u64 for bch2_varint_decode: */
        used++;
index 4fef482ad60e7cff070d23440e34fe48ec45693c..0d9d723c24bb44cd1431399325940f5d21769f6e 100644 (file)
@@ -1000,7 +1000,7 @@ static int bch2_mark_extent(struct btree_trans *trans,
                ? BCH_DATA_btree
                : BCH_DATA_user;
        s64 sectors = bkey_is_btree_ptr(k.k)
-               ? c->opts.btree_node_size
+               ? btree_sectors(c)
                : k.k->size;
        s64 dirty_sectors = 0;
        bool stale;
@@ -1609,7 +1609,7 @@ static int bch2_trans_mark_extent(struct btree_trans *trans,
                ? BCH_DATA_btree
                : BCH_DATA_user;
        s64 sectors = bkey_is_btree_ptr(k.k)
-               ? c->opts.btree_node_size
+               ? btree_sectors(c)
                : k.k->size;
        s64 dirty_sectors = 0;
        bool stale;
@@ -2184,7 +2184,7 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
        alloc_heap      alloc_heap;
 
        size_t btree_reserve    = DIV_ROUND_UP(BTREE_NODE_RESERVE,
-                            ca->mi.bucket_size / c->opts.btree_node_size);
+                            ca->mi.bucket_size / btree_sectors(c));
        /* XXX: these should be tunable */
        size_t reserve_none     = max_t(size_t, 1, nbuckets >> 9);
        size_t copygc_reserve   = max_t(size_t, 2, nbuckets >> 6);
index 78757dcede364491113869096b226072f1dd7b94..2d5dc2394bab92eb71a283cad0530cc3cc877c31 100644 (file)
@@ -376,7 +376,7 @@ static unsigned __bio_compress(struct bch_fs *c,
        BUG_ON(!mempool_initialized(&c->compress_workspace[compression_type]));
 
        /* If it's only one block, don't bother trying to compress: */
-       if (bio_sectors(src) <= c->opts.block_size)
+       if (src->bi_iter.bi_size <= c->opts.block_size)
                return 0;
 
        dst_data = bio_map_or_bounce(c, dst, WRITE);
index 8592a0f6327eb8dcaf84d9a12cefbdec79b8be35..161ae4fd59d92eb924c74c49055881c94b19be6f 100644 (file)
@@ -1037,7 +1037,7 @@ const char *bch2_bkey_ptrs_invalid(const struct bch_fs *c, struct bkey_s_c k)
 
        if (k.k->type == KEY_TYPE_btree_ptr ||
            k.k->type == KEY_TYPE_btree_ptr_v2)
-               size_ondisk = c->opts.btree_node_size;
+               size_ondisk = btree_sectors(c);
 
        bkey_extent_entry_for_each(ptrs, entry) {
                if (__extent_entry_type(entry) >= BCH_EXTENT_ENTRY_MAX)
index 31adc0e0d4527601a85f3553b1c5c49e67f2b9b8..bbdfccf24e536a1b7123c115941ed2e915644d25 100644 (file)
@@ -868,8 +868,8 @@ static int bch2_fill_extent(struct bch_fs *c,
                        else
                                offset += p.crc.offset;
 
-                       if ((offset & (c->opts.block_size - 1)) ||
-                           (k.k->size & (c->opts.block_size - 1)))
+                       if ((offset & (block_sectors(c) - 1)) ||
+                           (k.k->size & (block_sectors(c) - 1)))
                                flags2 |= FIEMAP_EXTENT_NOT_ALIGNED;
 
                        ret = fiemap_fill_next_extent(info,
@@ -1683,7 +1683,7 @@ static int bch2_show_options(struct seq_file *seq, struct dentry *root)
                const struct bch_option *opt = &bch2_opt_table[i];
                u64 v = bch2_opt_get_by_id(&c->opts, i);
 
-               if (!(opt->mode & OPT_MOUNT))
+               if (!(opt->flags & OPT_MOUNT))
                        continue;
 
                if (v == bch2_opt_get_by_id(&bch2_opts_default, i))
index 814984ec608c11f74bb65d96d02b6a84e71edffc..1cfe433ded339d69400b52d823c91d90c880347d 100644 (file)
@@ -1357,7 +1357,7 @@ void bch2_write(struct closure *cl)
        bch2_keylist_init(&op->insert_keys, op->inline_keys);
        wbio_init(bio)->put_bio = false;
 
-       if (bio_sectors(bio) & (c->opts.block_size - 1)) {
+       if (bio->bi_iter.bi_size & (c->opts.block_size - 1)) {
                bch_err_inum_ratelimited(c, op->pos.inode,
                                         "misaligned write");
                op->error = -EIO;
@@ -2437,7 +2437,7 @@ int bch2_fs_io_init(struct bch_fs *c)
                        BIOSET_NEED_BVECS) ||
            mempool_init_page_pool(&c->bio_bounce_pages,
                                   max_t(unsigned,
-                                        c->opts.btree_node_size,
+                                        btree_sectors(c),
                                         c->sb.encoded_extent_max) /
                                   PAGE_SECTORS, 0) ||
            rhashtable_init(&c->promote_table, &bch_promote_params))
index 1a8c0a7eaca7cdb4836ef8674820faf003a53d7f..ae28cee127e34ebc27dc6ac239bad185a7faae10 100644 (file)
@@ -709,7 +709,7 @@ reread:
                case JOURNAL_ENTRY_NONE:
                        if (!saw_bad)
                                return 0;
-                       sectors = c->opts.block_size;
+                       sectors = block_sectors(c);
                        goto next_block;
                case JOURNAL_ENTRY_BAD:
                        saw_bad = true;
@@ -718,7 +718,7 @@ reread:
                         * field of the journal entry we read, so try reading
                         * again at next block boundary:
                         */
-                       sectors = c->opts.block_size;
+                       sectors = block_sectors(c);
                        break;
                default:
                        return ret;
index e81e07a383bb379afff9776bb50b7e98e7ccec5e..9b75c852bac87170341767f48f4cd95aa0df7428 100644 (file)
@@ -141,41 +141,27 @@ void bch2_opt_set_by_id(struct bch_opts *opts, enum bch_opt_id id, u64 v)
        }
 }
 
-/*
- * Initial options from superblock - here we don't want any options undefined,
- * any options the superblock doesn't specify are set to 0:
- */
-struct bch_opts bch2_opts_from_sb(struct bch_sb *sb)
-{
-       struct bch_opts opts = bch2_opts_empty();
-
-#define x(_name, _bits, _mode, _type, _sb_opt, ...)                    \
-       if (_sb_opt != NO_SB_OPT)                                       \
-               opt_set(opts, _name, _sb_opt(sb));
-       BCH_OPTS()
-#undef x
-
-       return opts;
-}
-
 const struct bch_option bch2_opt_table[] = {
-#define OPT_BOOL()             .type = BCH_OPT_BOOL
-#define OPT_UINT(_min, _max)   .type = BCH_OPT_UINT, .min = _min, .max = _max
-#define OPT_SECTORS(_min, _max)        .type = BCH_OPT_SECTORS, .min = _min, .max = _max
-#define OPT_STR(_choices)      .type = BCH_OPT_STR, .choices = _choices
+#define OPT_BOOL()             .type = BCH_OPT_BOOL, .min = 0, .max = 2
+#define OPT_UINT(_min, _max)   .type = BCH_OPT_UINT,                   \
+                               .min = _min, .max = _max
+#define OPT_STR(_choices)      .type = BCH_OPT_STR,                    \
+                               .min = 0, .max = ARRAY_SIZE(_choices),\
+                               .choices = _choices
 #define OPT_FN(_fn)            .type = BCH_OPT_FN,                     \
                                .parse = _fn##_parse,                   \
                                .to_text = _fn##_to_text
 
-#define x(_name, _bits, _mode, _type, _sb_opt, _default, _hint, _help) \
+#define x(_name, _bits, _flags, _type, _sb_opt, _default, _hint, _help)        \
        [Opt_##_name] = {                                               \
                .attr   = {                                             \
                        .name   = #_name,                               \
-                       .mode = (_mode) & OPT_RUNTIME ? 0644 : 0444,    \
+                       .mode = (_flags) & OPT_RUNTIME ? 0644 : 0444,   \
                },                                                      \
-               .mode   = _mode,                                        \
+               .flags  = _flags,                                       \
                .hint   = _hint,                                        \
                .help   = _help,                                        \
+               .get_sb = _sb_opt,                                      \
                .set_sb = SET_##_sb_opt,                                \
                _type                                                   \
        },
@@ -218,7 +204,41 @@ static int bch2_mount_opt_lookup(const char *name)
        return bch2_opt_lookup(name);
 }
 
-int bch2_opt_parse(struct bch_fs *c, const struct bch_option *opt,
+static int bch2_opt_validate(const struct bch_option *opt, const char *msg, u64 v)
+{
+       if (v < opt->min) {
+               if (msg)
+                       pr_err("invalid %s%s: too small (min %llu)",
+                              msg, opt->attr.name, opt->min);
+               return -ERANGE;
+       }
+
+       if (opt->max && v >= opt->max) {
+               if (msg)
+                       pr_err("invalid %s%s: too big (max %llu)",
+                              msg, opt->attr.name, opt->max);
+               return -ERANGE;
+       }
+
+       if ((opt->flags & OPT_SB_FIELD_SECTORS) && (v & 511)) {
+               if (msg)
+                       pr_err("invalid %s %s: not a multiple of 512",
+                              msg, opt->attr.name);
+               return -EINVAL;
+       }
+
+       if ((opt->flags & OPT_MUST_BE_POW_2) && !is_power_of_2(v)) {
+               if (msg)
+                       pr_err("invalid %s%s: must be a power of two",
+                              msg, opt->attr.name);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int bch2_opt_parse(struct bch_fs *c, const char *msg,
+                  const struct bch_option *opt,
                   const char *val, u64 *res)
 {
        ssize_t ret;
@@ -228,30 +248,13 @@ int bch2_opt_parse(struct bch_fs *c, const struct bch_option *opt,
                ret = kstrtou64(val, 10, res);
                if (ret < 0)
                        return ret;
-
-               if (*res > 1)
-                       return -ERANGE;
                break;
        case BCH_OPT_UINT:
-               ret = kstrtou64(val, 10, res);
+               ret = opt->flags & OPT_HUMAN_READABLE
+                       ? bch2_strtou64_h(val, res)
+                       : kstrtou64(val, 10, res);
                if (ret < 0)
                        return ret;
-
-               if (*res < opt->min || *res >= opt->max)
-                       return -ERANGE;
-               break;
-       case BCH_OPT_SECTORS:
-               ret = bch2_strtou64_h(val, res);
-               if (ret < 0)
-                       return ret;
-
-               if (*res & 511)
-                       return -EINVAL;
-
-               *res >>= 9;
-
-               if (*res < opt->min || *res >= opt->max)
-                       return -ERANGE;
                break;
        case BCH_OPT_STR:
                ret = match_string(opt->choices, -1, val);
@@ -264,10 +267,12 @@ int bch2_opt_parse(struct bch_fs *c, const struct bch_option *opt,
                if (!c)
                        return 0;
 
-               return opt->parse(c, val, res);
+               ret = opt->parse(c, val, res);
+               if (ret < 0)
+                       return ret;
        }
 
-       return 0;
+       return bch2_opt_validate(opt, msg, *res);
 }
 
 void bch2_opt_to_text(struct printbuf *out, struct bch_fs *c,
@@ -288,10 +293,10 @@ void bch2_opt_to_text(struct printbuf *out, struct bch_fs *c,
        switch (opt->type) {
        case BCH_OPT_BOOL:
        case BCH_OPT_UINT:
-               pr_buf(out, "%lli", v);
-               break;
-       case BCH_OPT_SECTORS:
-               bch2_hprint(out, v << 9);
+               if (opt->flags & OPT_HUMAN_READABLE)
+                       bch2_hprint(out, v);
+               else
+                       pr_buf(out, "%lli", v);
                break;
        case BCH_OPT_STR:
                if (flags & OPT_SHOW_FULL_LIST)
@@ -365,7 +370,8 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
                        if (id < 0)
                                goto bad_opt;
 
-                       ret = bch2_opt_parse(c, &bch2_opt_table[id], val, &v);
+                       ret = bch2_opt_parse(c, "mount option ",
+                                            &bch2_opt_table[id], val, &v);
                        if (ret < 0)
                                goto bad_val;
                } else {
@@ -385,7 +391,7 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
                                goto no_val;
                }
 
-               if (!(bch2_opt_table[id].mode & OPT_MOUNT))
+               if (!(bch2_opt_table[id].flags & OPT_MOUNT))
                        goto bad_opt;
 
                if (id == Opt_acl &&
@@ -420,6 +426,65 @@ out:
        return ret;
 }
 
+/*
+ * Initial options from superblock - here we don't want any options undefined,
+ * any options the superblock doesn't specify are set to 0:
+ */
+int bch2_opts_from_sb(struct bch_opts *opts, struct bch_sb *sb)
+{
+       unsigned id;
+       int ret;
+
+       for (id = 0; id < bch2_opts_nr; id++) {
+               const struct bch_option *opt = bch2_opt_table + id;
+               u64 v;
+
+               if (opt->get_sb == NO_SB_OPT)
+                       continue;
+
+               v = opt->get_sb(sb);
+
+               if (opt->flags & OPT_SB_FIELD_ILOG2)
+                       v = 1ULL << v;
+
+               if (opt->flags & OPT_SB_FIELD_SECTORS)
+                       v <<= 9;
+
+               ret = bch2_opt_validate(opt, "superblock option ", v);
+               if (ret)
+                       return ret;
+
+               bch2_opt_set_by_id(opts, id, v);
+       }
+
+       return 0;
+}
+
+void __bch2_opt_set_sb(struct bch_sb *sb, const struct bch_option *opt, u64 v)
+{
+       if (opt->set_sb == SET_NO_SB_OPT)
+               return;
+
+       if (opt->flags & OPT_SB_FIELD_SECTORS)
+               v >>= 9;
+
+       if (opt->flags & OPT_SB_FIELD_ILOG2)
+               v = ilog2(v);
+
+       opt->set_sb(sb, v);
+}
+
+void bch2_opt_set_sb(struct bch_fs *c, const struct bch_option *opt, u64 v)
+{
+       if (opt->set_sb == SET_NO_SB_OPT)
+               return;
+
+       mutex_lock(&c->sb_lock);
+       __bch2_opt_set_sb(c->disk_sb.sb, opt, v);
+       bch2_write_super(c);
+       mutex_unlock(&c->sb_lock);
+}
+
 /* io opts: */
 
 struct bch_io_opts bch2_opts_to_inode_opts(struct bch_opts src)
index bb2ecc778a8c2e36490d645f1cab07620f54b99a..45f73601e4a8559e0d71816f883189deffc013d2 100644 (file)
@@ -44,19 +44,22 @@ static inline const char *bch2_d_type_str(unsigned d_type)
 LE64_BITMASK(NO_SB_OPT,                struct bch_sb, flags[0], 0, 0);
 
 /* When can be set: */
-enum opt_mode {
+enum opt_flags {
        OPT_FS          = (1 << 0),     /* Filesystem option */
        OPT_DEVICE      = (1 << 1),     /* Device option */
        OPT_INODE       = (1 << 2),     /* Inode option */
        OPT_FORMAT      = (1 << 3),     /* May be specified at format time */
        OPT_MOUNT       = (1 << 4),     /* May be specified at mount time */
        OPT_RUNTIME     = (1 << 5),     /* May be specified at runtime */
+       OPT_HUMAN_READABLE = (1 << 6),
+       OPT_MUST_BE_POW_2 = (1 << 7),   /* Must be power of 2 */
+       OPT_SB_FIELD_SECTORS = (1 << 8),/* Superblock field is >> 9 of actual value */
+       OPT_SB_FIELD_ILOG2 = (1 << 9),  /* Superblock field is ilog2 of actual value */
 };
 
 enum opt_type {
        BCH_OPT_BOOL,
        BCH_OPT_UINT,
-       BCH_OPT_SECTORS,
        BCH_OPT_STR,
        BCH_OPT_FN,
 };
@@ -88,13 +91,15 @@ enum opt_type {
 
 #define BCH_OPTS()                                                     \
        x(block_size,                   u16,                            \
-         OPT_FS|OPT_FORMAT,                                            \
-         OPT_SECTORS(1, 128),                                          \
+         OPT_FS|OPT_FORMAT|                                            \
+         OPT_HUMAN_READABLE|OPT_MUST_BE_POW_2|OPT_SB_FIELD_SECTORS,    \
+         OPT_UINT(512, 1U << 16),                                      \
          BCH_SB_BLOCK_SIZE,            8,                              \
          "size",       NULL)                                           \
-       x(btree_node_size,              u16,                            \
-         OPT_FS|OPT_FORMAT,                                            \
-         OPT_SECTORS(1, 512),                                          \
+       x(btree_node_size,              u32,                            \
+         OPT_FS|OPT_FORMAT|                                            \
+         OPT_HUMAN_READABLE|OPT_MUST_BE_POW_2|OPT_SB_FIELD_SECTORS,    \
+         OPT_UINT(512, 1U << 20),                                      \
          BCH_SB_BTREE_NODE_SIZE,       512,                            \
          "size",       "Btree node size, default 256k")                \
        x(errors,                       u8,                             \
@@ -198,8 +203,9 @@ enum opt_type {
          BCH_SB_GC_RESERVE,            8,                              \
          "%",          "Percentage of disk space to reserve for copygc")\
        x(gc_reserve_bytes,             u64,                            \
-         OPT_FS|OPT_FORMAT|OPT_MOUNT|OPT_RUNTIME,                      \
-         OPT_SECTORS(0, U64_MAX),                                      \
+         OPT_FS|OPT_FORMAT|OPT_MOUNT|OPT_RUNTIME|                      \
+         OPT_HUMAN_READABLE|OPT_SB_FIELD_SECTORS,                      \
+         OPT_UINT(0, U64_MAX),                                         \
          BCH_SB_GC_RESERVE_BYTES,      0,                              \
          "%",          "Amount of disk space to reserve for copygc\n"  \
                        "Takes precedence over gc_reserve_percent if set")\
@@ -360,12 +366,12 @@ enum opt_type {
                        "for performance testing purposes")             \
        x(fs_size,                      u64,                            \
          OPT_DEVICE,                                                   \
-         OPT_SECTORS(0, S64_MAX),                                      \
+         OPT_UINT(0, S64_MAX),                                         \
          NO_SB_OPT,                    0,                              \
          "size",       "Size of filesystem on device")                 \
        x(bucket,                       u32,                            \
          OPT_DEVICE,                                                   \
-         OPT_SECTORS(0, S64_MAX),                                      \
+         OPT_UINT(0, S64_MAX),                                         \
          NO_SB_OPT,                    0,                              \
          "size",       "Size of filesystem on device")                 \
        x(durability,                   u8,                             \
@@ -424,13 +430,14 @@ struct printbuf;
 
 struct bch_option {
        struct attribute        attr;
+       u64                     (*get_sb)(const struct bch_sb *);
        void                    (*set_sb)(struct bch_sb *, u64);
-       enum opt_mode           mode;
        enum opt_type           type;
+       enum opt_flags          flags;
+       u64                     min, max;
 
        union {
        struct {
-               u64             min, max;
        };
        struct {
                const char * const *choices;
@@ -452,10 +459,13 @@ bool bch2_opt_defined_by_id(const struct bch_opts *, enum bch_opt_id);
 u64 bch2_opt_get_by_id(const struct bch_opts *, enum bch_opt_id);
 void bch2_opt_set_by_id(struct bch_opts *, enum bch_opt_id, u64);
 
-struct bch_opts bch2_opts_from_sb(struct bch_sb *);
+int bch2_opts_from_sb(struct bch_opts *, struct bch_sb *);
+void __bch2_opt_set_sb(struct bch_sb *, const struct bch_option *, u64);
+void bch2_opt_set_sb(struct bch_fs *, const struct bch_option *, u64);
 
 int bch2_opt_lookup(const char *);
-int bch2_opt_parse(struct bch_fs *, const struct bch_option *, const char *, u64 *);
+int bch2_opt_parse(struct bch_fs *, const char *, const struct bch_option *,
+                  const char *, u64 *);
 
 #define OPT_SHOW_FULL_LIST     (1 << 0)
 #define OPT_SHOW_MOUNT_STYLE   (1 << 1)
index 170f7d46fa34533964fc00a1069068cfd79c48f5..c831d32c26febd9adcbe1d66c7cdcfd916f948f4 100644 (file)
@@ -267,8 +267,7 @@ const char *bch2_sb_validate(struct bch_sb_handle *disk_sb)
 
        block_size = le16_to_cpu(sb->block_size);
 
-       if (!is_power_of_2(block_size) ||
-           block_size > PAGE_SECTORS)
+       if (block_size > PAGE_SECTORS)
                return "Bad block size";
 
        if (bch2_is_zero(sb->user_uuid.b, sizeof(sb->user_uuid)))
@@ -310,9 +309,6 @@ const char *bch2_sb_validate(struct bch_sb_handle *disk_sb)
        if (!BCH_SB_BTREE_NODE_SIZE(sb))
                return "Btree node size not set";
 
-       if (!is_power_of_2(BCH_SB_BTREE_NODE_SIZE(sb)))
-               return "Btree node size not a power of two";
-
        if (BCH_SB_GC_RESERVE(sb) < 5)
                return "gc reserve percentage too small";
 
@@ -627,8 +623,12 @@ got_super:
        err = "Superblock block size smaller than device block size";
        ret = -EINVAL;
        if (le16_to_cpu(sb->sb->block_size) << 9 <
-           bdev_logical_block_size(sb->bdev))
-               goto err;
+           bdev_logical_block_size(sb->bdev)) {
+               pr_err("error reading superblock: Superblock block size (%u) smaller than device block size (%u)",
+                      le16_to_cpu(sb->sb->block_size) << 9,
+                      bdev_logical_block_size(sb->bdev));
+               goto err_no_print;
+       }
 
        ret = 0;
        sb->have_layout = true;
@@ -636,8 +636,9 @@ out:
        pr_verbose_init(*opts, "ret %i", ret);
        return ret;
 err:
-       bch2_free_super(sb);
        pr_err("error reading superblock: %s", err);
+err_no_print:
+       bch2_free_super(sb);
        goto out;
 }
 
index afa1a8fa493b230ac4e8f855927e1b29f311c158..e1d4fe5a8e496c81bc71eb23eda34e0d203f12df 100644 (file)
@@ -762,10 +762,13 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
                SET_BCH_SB_JOURNAL_RECLAIM_DELAY(sb, 100);
 
        c->opts = bch2_opts_default;
-       bch2_opts_apply(&c->opts, bch2_opts_from_sb(sb));
+       ret = bch2_opts_from_sb(&c->opts, sb);
+       if (ret)
+               goto err;
+
        bch2_opts_apply(&c->opts, opts);
 
-       c->block_bits           = ilog2(c->opts.block_size);
+       c->block_bits           = ilog2(block_sectors(c));
        c->btree_foreground_merge_threshold = BTREE_FOREGROUND_MERGE_THRESHOLD(c);
 
        if (bch2_fs_init_fault("fs_alloc")) {
@@ -877,7 +880,7 @@ static void print_mount_opts(struct bch_fs *c)
                const struct bch_option *opt = &bch2_opt_table[i];
                u64 v = bch2_opt_get_by_id(&c->opts, i);
 
-               if (!(opt->mode & OPT_MOUNT))
+               if (!(opt->flags & OPT_MOUNT))
                        continue;
 
                if (v == bch2_opt_get_by_id(&bch2_opts_default, i))
@@ -1003,7 +1006,7 @@ static const char *bch2_dev_may_add(struct bch_sb *sb, struct bch_fs *c)
        if (!sb_mi)
                return "Invalid superblock: member info area missing";
 
-       if (le16_to_cpu(sb->block_size) != c->opts.block_size)
+       if (le16_to_cpu(sb->block_size) != block_sectors(c))
                return "mismatched block size";
 
        if (le16_to_cpu(sb_mi->members[sb->dev_idx].bucket_size) <
index 3f51eda749f08677a3108e854323bd269c451a4a..0a0798bae4d61ad00f6b802ff9124191cec91614 100644 (file)
@@ -626,7 +626,7 @@ STORE(bch2_fs_opts_dir)
        if (!tmp)
                return -ENOMEM;
 
-       ret = bch2_opt_parse(c, opt, strim(tmp), &v);
+       ret = bch2_opt_parse(c, NULL, opt, strim(tmp), &v);
        kfree(tmp);
 
        if (ret < 0)
@@ -636,13 +636,7 @@ STORE(bch2_fs_opts_dir)
        if (ret < 0)
                return ret;
 
-       if (opt->set_sb != SET_NO_SB_OPT) {
-               mutex_lock(&c->sb_lock);
-               opt->set_sb(c->disk_sb.sb, v);
-               bch2_write_super(c);
-               mutex_unlock(&c->sb_lock);
-       }
-
+       bch2_opt_set_sb(c, opt, v);
        bch2_opt_set_by_id(&c->opts, id, v);
 
        if ((id == Opt_background_target ||
@@ -665,7 +659,7 @@ int bch2_opts_create_sysfs_files(struct kobject *kobj)
        for (i = bch2_opt_table;
             i < bch2_opt_table + bch2_opts_nr;
             i++) {
-               if (!(i->mode & OPT_FS))
+               if (!(i->flags & OPT_FS))
                        continue;
 
                ret = sysfs_create_file(kobj, &i->attr);
index 21823ce6923797ac57f4ae758f9ce9584bdcf99d..a5122dbb2eb91bc986496233617aead8a5288568 100644 (file)
@@ -525,7 +525,7 @@ static int bch2_xattr_bcachefs_set(const struct xattr_handler *handler,
                memcpy(buf, value, size);
                buf[size] = '\0';
 
-               ret = bch2_opt_parse(c, opt, buf, &v);
+               ret = bch2_opt_parse(c, NULL, opt, buf, &v);
                kfree(buf);
 
                if (ret < 0)