]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
bcachefs: Kill BCH_DEV_OPT_SETTERS()
authorKent Overstreet <kent.overstreet@linux.dev>
Thu, 13 Mar 2025 16:05:50 +0000 (12:05 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Mon, 24 Mar 2025 13:50:35 +0000 (09:50 -0400)
Previously, device options had their superblock option field listed
separately, which was weird and easy to miss when defining options.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/opts.c
fs/bcachefs/opts.h
fs/bcachefs/sb-members_format.h
fs/bcachefs/super-io.c

index 6772faf385a50fe84f869171c82d333d9d03af45..ae47345f93c130590fa57d599cfddfef7093dfe6 100644 (file)
@@ -163,16 +163,6 @@ const char * const bch2_d_types[BCH_DT_MAX] = {
        [DT_SUBVOL]     = "subvol",
 };
 
-u64 BCH2_NO_SB_OPT(const struct bch_sb *sb)
-{
-       BUG();
-}
-
-void SET_BCH2_NO_SB_OPT(struct bch_sb *sb, u64 v)
-{
-       BUG();
-}
-
 void bch2_opts_apply(struct bch_opts *dst, struct bch_opts src)
 {
 #define x(_name, ...)                                          \
@@ -223,6 +213,21 @@ void bch2_opt_set_by_id(struct bch_opts *opts, enum bch_opt_id id, u64 v)
        }
 }
 
+/* dummy option, for options that aren't stored in the superblock */
+typedef u64 (*sb_opt_get_fn)(const struct bch_sb *);
+typedef void (*sb_opt_set_fn)(struct bch_sb *, u64);
+typedef u64 (*member_opt_get_fn)(const struct bch_member *);
+typedef void (*member_opt_set_fn)(struct bch_member *, u64);
+
+__maybe_unused static const sb_opt_get_fn      BCH2_NO_SB_OPT = NULL;
+__maybe_unused static const sb_opt_set_fn      SET_BCH2_NO_SB_OPT = NULL;
+__maybe_unused static const member_opt_get_fn  BCH2_NO_MEMBER_OPT = NULL;
+__maybe_unused static const member_opt_set_fn  SET_BCH2_NO_MEMBER_OPT = NULL;
+
+#define type_compatible_or_null(_p, _type)                             \
+       __builtin_choose_expr(                                          \
+               __builtin_types_compatible_p(typeof(_p), typeof(_type)), _p, NULL)
+
 const struct bch_option bch2_opt_table[] = {
 #define OPT_BOOL()             .type = BCH_OPT_BOOL, .min = 0, .max = 2
 #define OPT_UINT(_min, _max)   .type = BCH_OPT_UINT,                   \
@@ -239,15 +244,15 @@ const struct bch_option bch2_opt_table[] = {
 
 #define x(_name, _bits, _flags, _type, _sb_opt, _default, _hint, _help)        \
        [Opt_##_name] = {                                               \
-               .attr   = {                                             \
-                       .name   = #_name,                               \
-                       .mode = (_flags) & OPT_RUNTIME ? 0644 : 0444,   \
-               },                                                      \
-               .flags  = _flags,                                       \
-               .hint   = _hint,                                        \
-               .help   = _help,                                        \
-               .get_sb = _sb_opt,                                      \
-               .set_sb = SET_##_sb_opt,                                \
+               .attr.name      = #_name,                               \
+               .attr.mode      = (_flags) & OPT_RUNTIME ? 0644 : 0444, \
+               .flags          = _flags,                               \
+               .hint           = _hint,                                \
+               .help           = _help,                                \
+               .get_sb         = type_compatible_or_null(_sb_opt,      *BCH2_NO_SB_OPT),       \
+               .set_sb         = type_compatible_or_null(SET_##_sb_opt,*SET_BCH2_NO_SB_OPT),   \
+               .get_member     = type_compatible_or_null(_sb_opt,      *BCH2_NO_MEMBER_OPT),   \
+               .set_member     = type_compatible_or_null(SET_##_sb_opt,*SET_BCH2_NO_MEMBER_OPT),\
                _type                                                   \
        },
 
@@ -495,12 +500,8 @@ int bch2_opt_check_may_set(struct bch_fs *c, int id, u64 v)
 
 int bch2_opts_check_may_set(struct bch_fs *c)
 {
-       unsigned i;
-       int ret;
-
-       for (i = 0; i < bch2_opts_nr; i++) {
-               ret = bch2_opt_check_may_set(c, i,
-                               bch2_opt_get_by_id(&c->opts, i));
+       for (unsigned i = 0; i < bch2_opts_nr; i++) {
+               int ret = bch2_opt_check_may_set(c, i, bch2_opt_get_by_id(&c->opts, i));
                if (ret)
                        return ret;
        }
@@ -619,12 +620,25 @@ out:
        return ret;
 }
 
-u64 bch2_opt_from_sb(struct bch_sb *sb, enum bch_opt_id id)
+u64 bch2_opt_from_sb(struct bch_sb *sb, enum bch_opt_id id, int dev_idx)
 {
        const struct bch_option *opt = bch2_opt_table + id;
        u64 v;
 
-       v = opt->get_sb(sb);
+       if (dev_idx < 0) {
+               v = opt->get_sb(sb);
+       } else {
+               if (WARN(!bch2_member_exists(sb, dev_idx),
+                        "tried to set device option %s on nonexistent device %i",
+                        opt->attr.name, dev_idx))
+                       return 0;
+
+               struct bch_member m = bch2_sb_member_get(sb, dev_idx);
+               v = opt->get_member(&m);
+       }
+
+       if (opt->flags & OPT_SB_FIELD_ONE_BIAS)
+               --v;
 
        if (opt->flags & OPT_SB_FIELD_ILOG2)
                v = 1ULL << v;
@@ -641,35 +655,19 @@ u64 bch2_opt_from_sb(struct bch_sb *sb, enum bch_opt_id id)
  */
 int bch2_opts_from_sb(struct bch_opts *opts, struct bch_sb *sb)
 {
-       unsigned id;
-
-       for (id = 0; id < bch2_opts_nr; id++) {
+       for (unsigned id = 0; id < bch2_opts_nr; id++) {
                const struct bch_option *opt = bch2_opt_table + id;
 
-               if (opt->get_sb == BCH2_NO_SB_OPT)
-                       continue;
-
-               bch2_opt_set_by_id(opts, id, bch2_opt_from_sb(sb, id));
+               if (opt->get_sb)
+                       bch2_opt_set_by_id(opts, id, bch2_opt_from_sb(sb, id, -1));
        }
 
        return 0;
 }
 
-struct bch_dev_sb_opt_set {
-       void                    (*set_sb)(struct bch_member *, u64);
-};
-
-static const struct bch_dev_sb_opt_set bch2_dev_sb_opt_setters [] = {
-#define x(n, set)      [Opt_##n] = { .set_sb = SET_##set },
-       BCH_DEV_OPT_SETTERS()
-#undef x
-};
-
 void __bch2_opt_set_sb(struct bch_sb *sb, int dev_idx,
                       const struct bch_option *opt, u64 v)
 {
-       enum bch_opt_id id = opt - bch2_opt_table;
-
        if (opt->flags & OPT_SB_FIELD_SECTORS)
                v >>= 9;
 
@@ -679,24 +677,18 @@ void __bch2_opt_set_sb(struct bch_sb *sb, int dev_idx,
        if (opt->flags & OPT_SB_FIELD_ONE_BIAS)
                v++;
 
-       if (opt->flags & OPT_FS) {
-               if (opt->set_sb != SET_BCH2_NO_SB_OPT)
-                       opt->set_sb(sb, v);
-       }
+       if ((opt->flags & OPT_FS) && opt->set_sb)
+               opt->set_sb(sb, v);
 
-       if ((opt->flags & OPT_DEVICE) && dev_idx >= 0) {
+       if ((opt->flags & OPT_DEVICE) &&
+           opt->set_member &&
+           dev_idx >= 0) {
                if (WARN(!bch2_member_exists(sb, dev_idx),
                         "tried to set device option %s on nonexistent device %i",
                         opt->attr.name, dev_idx))
                        return;
 
-               struct bch_member *m = bch2_members_v2_get_mut(sb, dev_idx);
-
-               const struct bch_dev_sb_opt_set *set = bch2_dev_sb_opt_setters + id;
-               if (set->set_sb)
-                       set->set_sb(m, v);
-               else
-                       pr_err("option %s cannot be set via opt_set_sb()", opt->attr.name);
+               opt->set_member(bch2_members_v2_get_mut(sb, dev_idx), v);
        }
 }
 
index baa9c11acb1af71bf7ad915c3a35fc7d7553bac2..c0adfd5b4f1c35dff1835b3fb808d08d2abe3a27 100644 (file)
@@ -50,10 +50,6 @@ static inline const char *bch2_d_type_str(unsigned d_type)
  * apply the options from that struct that are defined.
  */
 
-/* dummy option, for options that aren't stored in the superblock */
-u64 BCH2_NO_SB_OPT(const struct bch_sb *);
-void SET_BCH2_NO_SB_OPT(struct bch_sb *, u64);
-
 /* When can be set: */
 enum opt_flags {
        OPT_FS                  = BIT(0),       /* Filesystem option */
@@ -318,11 +314,6 @@ enum fsck_err_opts {
          OPT_BOOL(),                                                   \
          BCH2_NO_SB_OPT,               false,                          \
          NULL,         "Don't kick drives out when splitbrain detected")\
-       x(discard,                      u8,                             \
-         OPT_FS|OPT_MOUNT|OPT_DEVICE,                                  \
-         OPT_BOOL(),                                                   \
-         BCH2_NO_SB_OPT,               true,                           \
-         NULL,         "Enable discard/TRIM support")                  \
        x(verbose,                      u8,                             \
          OPT_FS|OPT_MOUNT|OPT_RUNTIME,                                 \
          OPT_BOOL(),                                                   \
@@ -503,27 +494,37 @@ enum fsck_err_opts {
          BCH2_NO_SB_OPT,               false,                          \
          NULL,         "Skip submit_bio() for data reads and writes, " \
                        "for performance testing purposes")             \
-       x(fs_size,                      u64,                            \
+       x(state,                        u64,                            \
          OPT_DEVICE,                                                   \
+         OPT_STR(bch2_member_states),                                  \
+         BCH_MEMBER_STATE,             BCH_MEMBER_STATE_rw,            \
+         "state",      "rw,ro,failed,spare")                           \
+       x(fs_size,                      u64,                            \
+         OPT_DEVICE|OPT_HIDDEN,                                        \
          OPT_UINT(0, S64_MAX),                                         \
-         BCH2_NO_SB_OPT,               0,                              \
+         BCH2_NO_MEMBER_OPT,           0,                              \
          "size",       "Size of filesystem on device")                 \
-       x(bucket,                       u32,                            \
-         OPT_DEVICE,                                                   \
+       x(bucket_size,                  u32,                            \
+         OPT_DEVICE|OPT_HUMAN_READABLE|OPT_SB_FIELD_SECTORS,           \
          OPT_UINT(0, S64_MAX),                                         \
-         BCH2_NO_SB_OPT,               0,                              \
+         BCH_MEMBER_BUCKET_SIZE,       0,                              \
          "size",       "Specifies the bucket size; must be greater than the btree node size")\
        x(durability,                   u8,                             \
-         OPT_DEVICE|OPT_SB_FIELD_ONE_BIAS,                             \
+         OPT_DEVICE|OPT_RUNTIME|OPT_SB_FIELD_ONE_BIAS,                 \
          OPT_UINT(0, BCH_REPLICAS_MAX),                                \
-         BCH2_NO_SB_OPT,               1,                              \
+         BCH_MEMBER_DURABILITY,        1,                              \
          "n",          "Data written to this device will be considered\n"\
                        "to have already been replicated n times")      \
        x(data_allowed,                 u8,                             \
          OPT_DEVICE,                                                   \
          OPT_BITFIELD(__bch2_data_types),                              \
-         BCH2_NO_SB_OPT,               BIT(BCH_DATA_journal)|BIT(BCH_DATA_btree)|BIT(BCH_DATA_user),\
+         BCH_MEMBER_DATA_ALLOWED,      BIT(BCH_DATA_journal)|BIT(BCH_DATA_btree)|BIT(BCH_DATA_user),\
          "types",      "Allowed data types for this device: journal, btree, and/or user")\
+       x(discard,                      u8,                             \
+         OPT_MOUNT|OPT_DEVICE|OPT_RUNTIME,                             \
+         OPT_BOOL(),                                                   \
+         BCH_MEMBER_DISCARD,           true,                           \
+         NULL,         "Enable discard/TRIM support")                  \
        x(btree_node_prefetch,          u8,                             \
          OPT_FS|OPT_MOUNT|OPT_RUNTIME,                                 \
          OPT_BOOL(),                                                   \
@@ -531,11 +532,6 @@ enum fsck_err_opts {
          NULL,         "BTREE_ITER_prefetch casuse btree nodes to be\n"\
          " prefetched sequentially")
 
-#define BCH_DEV_OPT_SETTERS()                                          \
-       x(discard,              BCH_MEMBER_DISCARD)                     \
-       x(durability,           BCH_MEMBER_DURABILITY)                  \
-       x(data_allowed,         BCH_MEMBER_DATA_ALLOWED)
-
 struct bch_opts {
 #define x(_name, _bits, ...)   unsigned _name##_defined:1;
        BCH_OPTS()
@@ -592,8 +588,6 @@ struct printbuf;
 
 struct bch_option {
        struct attribute        attr;
-       u64                     (*get_sb)(const struct bch_sb *);
-       void                    (*set_sb)(struct bch_sb *, u64);
        enum opt_type           type;
        enum opt_flags          flags;
        u64                     min, max;
@@ -605,6 +599,12 @@ struct bch_option {
        const char              *hint;
        const char              *help;
 
+       u64                     (*get_sb)(const struct bch_sb *);
+       void                    (*set_sb)(struct bch_sb *, u64);
+
+       u64                     (*get_member)(const struct bch_member *);
+       void                    (*set_member)(struct bch_member *, u64);
+
 };
 
 extern const struct bch_option bch2_opt_table[];
@@ -613,7 +613,7 @@ 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);
 
-u64 bch2_opt_from_sb(struct bch_sb *, enum bch_opt_id);
+u64 bch2_opt_from_sb(struct bch_sb *, enum bch_opt_id, int);
 int bch2_opts_from_sb(struct bch_opts *, struct bch_sb *);
 void __bch2_opt_set_sb(struct bch_sb *, int, const struct bch_option *, u64);
 
index 2adf1221a440f2cad111e5b4b45b98972eb8637d..3affec823b3f7e044628a84ebd9770a2b0788b28 100644 (file)
@@ -79,6 +79,7 @@ struct bch_member {
 
 #define BCH_MEMBER_V1_BYTES    56
 
+LE16_BITMASK(BCH_MEMBER_BUCKET_SIZE,   struct bch_member, bucket_size,  0, 16)
 LE64_BITMASK(BCH_MEMBER_STATE,         struct bch_member, flags,  0,  4)
 /* 4-14 unused, was TIER, HAS_(META)DATA, REPLACEMENT */
 LE64_BITMASK(BCH_MEMBER_DISCARD,       struct bch_member, flags, 14, 15)
index f2e4428281a3e16764be5e242136e1e4e22b5132..572b06bfa0b8eabe2b0ce9158c26822aae97701a 100644 (file)
@@ -489,8 +489,8 @@ int bch2_sb_validate(struct bch_sb *sb, u64 read_offset,
        for (opt_id = 0; opt_id < bch2_opts_nr; opt_id++) {
                const struct bch_option *opt = bch2_opt_table + opt_id;
 
-               if (opt->get_sb != BCH2_NO_SB_OPT) {
-                       u64 v = bch2_opt_from_sb(sb, opt_id);
+               if (opt->get_sb) {
+                       u64 v = bch2_opt_from_sb(sb, opt_id, -1);
 
                        prt_printf(out, "Invalid option ");
                        ret = bch2_opt_validate(opt, v, out);
@@ -1473,8 +1473,8 @@ void bch2_sb_to_text(struct printbuf *out, struct bch_sb *sb,
                for (id = 0; id < bch2_opts_nr; id++) {
                        const struct bch_option *opt = bch2_opt_table + id;
 
-                       if (opt->get_sb != BCH2_NO_SB_OPT) {
-                               u64 v = bch2_opt_from_sb(sb, id);
+                       if (opt->get_sb) {
+                               u64 v = bch2_opt_from_sb(sb, id, -1);
 
                                prt_printf(out, "%s:\t", opt->attr.name);
                                bch2_opt_to_text(out, NULL, sb, opt, v,