bcachefs: New superblock section members_v2
authorHunter Shaffer <huntershaffer182456@gmail.com>
Mon, 25 Sep 2023 04:02:56 +0000 (00:02 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:10:15 +0000 (17:10 -0400)
members_v2 has dynamically resizable entries so that we can extend
bch_member. The members can no longer be accessed with simple array
indexing Instead members_v2_get is used to find a member's exact
location within the array and returns a copy of that member.
Alternatively member_v2_get_mut retrieves a mutable point to a member.

Signed-off-by: Hunter Shaffer <huntershaffer182456@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/alloc_background.c
fs/bcachefs/bcachefs_format.h
fs/bcachefs/disk_groups.c
fs/bcachefs/errcode.h
fs/bcachefs/sb-members.c
fs/bcachefs/sb-members.h
fs/bcachefs/super-io.c
fs/bcachefs/super.c
fs/bcachefs/sysfs.c

index 19ef7a4..4059d3d 100644 (file)
@@ -1922,7 +1922,7 @@ bkey_err:
        }
 
        mutex_lock(&c->sb_lock);
-       m = bch2_sb_get_members(c->disk_sb.sb)->members + ca->dev_idx;
+       m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
        SET_BCH_MEMBER_FREESPACE_INITIALIZED(m, true);
        mutex_unlock(&c->sb_lock);
 
index f0d1304..c1a9ba4 100644 (file)
@@ -1231,7 +1231,8 @@ struct bch_sb_field {
        x(replicas,     7)                      \
        x(journal_seq_blacklist, 8)             \
        x(journal_v2,   9)                      \
-       x(counters,     10)
+       x(counters,     10)                     \
+       x(members_v2,   11)
 
 enum bch_sb_field_type {
 #define x(f, nr)       BCH_SB_FIELD_##f = nr,
@@ -1279,6 +1280,8 @@ struct bch_member {
        __le64                  flags[2];
 };
 
+#define BCH_MEMBER_V1_BYTES    56
+
 LE64_BITMASK(BCH_MEMBER_STATE,         struct bch_member, flags[0],  0,  4)
 /* 4-14 unused, was TIER, HAS_(META)DATA, REPLACEMENT */
 LE64_BITMASK(BCH_MEMBER_DISCARD,       struct bch_member, flags[0], 14, 15)
@@ -1308,7 +1311,14 @@ enum bch_member_state {
 
 struct bch_sb_field_members {
        struct bch_sb_field     field;
-       struct bch_member       members[];
+       struct bch_member       _members[]; //Members are now variable size
+};
+
+struct bch_sb_field_members_v2 {
+       struct bch_sb_field     field;
+       __le16                  member_bytes; //size of single member entry
+       u8                      pad[6];
+       struct bch_member       _members[];
 };
 
 /* BCH_SB_FIELD_crypt: */
index 1bf47a6..43aad8b 100644 (file)
@@ -440,7 +440,7 @@ int __bch2_dev_group_set(struct bch_fs *c, struct bch_dev *ca, const char *name)
        if (ret)
                return ret;
 
-       mi = &bch2_sb_get_members(c->disk_sb.sb)->members[ca->dev_idx];
+       mi = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
        SET_BCH_MEMBER_GROUP(mi, v + 1);
        return 0;
 }
index 64f7176..7cc0837 100644 (file)
@@ -91,6 +91,7 @@
        x(ENOSPC,                       ENOSPC_sb_quota)                        \
        x(ENOSPC,                       ENOSPC_sb_replicas)                     \
        x(ENOSPC,                       ENOSPC_sb_members)                      \
+       x(ENOSPC,                       ENOSPC_sb_members_v2)                   \
        x(ENOSPC,                       ENOSPC_sb_crypt)                        \
        x(ENOSPC,                       ENOSPC_btree_slot)                      \
        x(ENOSPC,                       ENOSPC_snapshot_tree)                   \
index 0be51d0..bf9c6c6 100644 (file)
@@ -7,9 +7,28 @@
 #include "super-io.h"
 
 /* Code for bch_sb_field_members: */
+
+static struct bch_member *members_v2_get_mut(struct bch_sb_field_members_v2 *mi, int i)
+{
+       return (void *) mi->_members + (i * le16_to_cpu(mi->member_bytes));
+}
+
+struct bch_member *bch2_members_v2_get_mut(struct bch_sb *sb, int i)
+{
+       return members_v2_get_mut(bch2_sb_get_members_v2(sb), i);
+}
+
+static struct bch_member members_v2_get(struct bch_sb_field_members_v2 *mi, int i)
+{
+       struct bch_member ret, *p = members_v2_get_mut(mi, i);
+       memset(&ret, 0, sizeof(ret));
+       memcpy(&ret, p, min_t(size_t, le16_to_cpu(mi->member_bytes), sizeof(ret)));
+       return ret;
+}
+
 static struct bch_member *members_v1_get_mut(struct bch_sb_field_members *mi, int i)
 {
-       return mi->members + i;
+       return (void *) mi->_members + (i * BCH_MEMBER_V1_BYTES);
 }
 
 static struct bch_member members_v1_get(struct bch_sb_field_members *mi, int i)
@@ -21,170 +40,292 @@ static struct bch_member members_v1_get(struct bch_sb_field_members *mi, int i)
 
 struct bch_member bch2_sb_member_get(struct bch_sb *sb, int i)
 {
+       struct bch_sb_field_members_v2 *mi2 = bch2_sb_get_members_v2(sb);
+       if (mi2)
+               return members_v2_get(mi2, i);
        struct bch_sb_field_members *mi1 = bch2_sb_get_members(sb);
        return members_v1_get(mi1, i);
 }
 
-static int bch2_sb_members_validate(struct bch_sb *sb,
+static int sb_members_v2_resize_entries(struct bch_fs *c)
+{
+       struct bch_sb_field_members_v2 *mi = bch2_sb_get_members_v2(c->disk_sb.sb);
+
+       if (le16_to_cpu(mi->member_bytes) < sizeof(struct bch_member)) {
+               unsigned u64s = DIV_ROUND_UP((sizeof(*mi) + sizeof(mi->_members[0]) *
+                                             c->disk_sb.sb->nr_devices), 8);
+
+               mi = bch2_sb_resize_members_v2(&c->disk_sb, u64s);
+               if (!mi)
+                       return -BCH_ERR_ENOSPC_sb_members_v2;
+
+               for (int i = c->disk_sb.sb->nr_devices - 1; i >= 0; --i) {
+                       void *dst = (void *) mi->_members + (i * sizeof(struct bch_member));
+                       memmove(dst, members_v2_get_mut(mi, i), le16_to_cpu(mi->member_bytes));
+                       memset(dst + le16_to_cpu(mi->member_bytes),
+                              0, (sizeof(struct bch_member) - le16_to_cpu(mi->member_bytes)));
+               }
+               mi->member_bytes = cpu_to_le16(sizeof(struct bch_member));
+       }
+       return 0;
+}
+
+int bch2_members_v2_init(struct bch_fs *c)
+{
+       struct bch_sb_field_members *mi1;
+       struct bch_sb_field_members_v2 *mi2;
+
+       if (!bch2_sb_get_members_v2(c->disk_sb.sb)) {
+               mi2 = bch2_sb_resize_members_v2(&c->disk_sb,
+                               DIV_ROUND_UP(sizeof(*mi2) +
+                                            sizeof(struct bch_member) * c->sb.nr_devices,
+                                            sizeof(u64)));
+               mi1 = bch2_sb_get_members(c->disk_sb.sb);
+               memcpy(&mi2->_members[0], &mi1->_members[0],
+                      BCH_MEMBER_V1_BYTES * c->sb.nr_devices);
+               memset(&mi2->pad[0], 0, sizeof(mi2->pad));
+               mi2->member_bytes = cpu_to_le16(BCH_MEMBER_V1_BYTES);
+       }
+
+       return sb_members_v2_resize_entries(c);
+}
+
+int bch_members_cpy_v2_v1(struct bch_sb_handle *disk_sb)
+{
+       struct bch_sb_field_members *mi1;
+       struct bch_sb_field_members_v2 *mi2;
+
+       mi1 = bch2_sb_resize_members(disk_sb,
+                       DIV_ROUND_UP(sizeof(*mi1) + BCH_MEMBER_V1_BYTES *
+                                    disk_sb->sb->nr_devices, sizeof(u64)));
+       if (!mi1)
+               return -BCH_ERR_ENOSPC_sb_members;
+
+       mi2 = bch2_sb_get_members_v2(disk_sb->sb);
+
+       for (unsigned i = 0; i < disk_sb->sb->nr_devices; i++)
+               memcpy(members_v1_get_mut(mi1, i), members_v2_get_mut(mi2, i), BCH_MEMBER_V1_BYTES);
+
+       return 0;
+}
+
+static int validate_member(struct printbuf *err,
+                          struct bch_member m,
+                          struct bch_sb *sb,
+                          int i)
+{
+       if (le64_to_cpu(m.nbuckets) > LONG_MAX) {
+               prt_printf(err, "device %u: too many buckets (got %llu, max %lu)",
+                          i, le64_to_cpu(m.nbuckets), LONG_MAX);
+               return -BCH_ERR_invalid_sb_members;
+       }
+
+       if (le64_to_cpu(m.nbuckets) -
+           le16_to_cpu(m.first_bucket) < BCH_MIN_NR_NBUCKETS) {
+               prt_printf(err, "device %u: not enough buckets (got %llu, max %u)",
+                          i, le64_to_cpu(m.nbuckets), BCH_MIN_NR_NBUCKETS);
+               return -BCH_ERR_invalid_sb_members;
+       }
+
+       if (le16_to_cpu(m.bucket_size) <
+           le16_to_cpu(sb->block_size)) {
+               prt_printf(err, "device %u: bucket size %u smaller than block size %u",
+                          i, le16_to_cpu(m.bucket_size), le16_to_cpu(sb->block_size));
+               return -BCH_ERR_invalid_sb_members;
+       }
+
+       if (le16_to_cpu(m.bucket_size) <
+           BCH_SB_BTREE_NODE_SIZE(sb)) {
+               prt_printf(err, "device %u: bucket size %u smaller than btree node size %llu",
+                          i, le16_to_cpu(m.bucket_size), BCH_SB_BTREE_NODE_SIZE(sb));
+               return -BCH_ERR_invalid_sb_members;
+       }
+
+       return 0;
+}
+
+static void member_to_text(struct printbuf *out,
+                          struct bch_member m,
+                          struct bch_sb_field_disk_groups *gi,
+                          struct bch_sb *sb,
+                          int i)
+{
+       unsigned data_have = bch2_sb_dev_has_data(sb, i);
+       u64 bucket_size = le16_to_cpu(m.bucket_size);
+       u64 device_size = le64_to_cpu(m.nbuckets) * bucket_size;
+
+
+       prt_printf(out, "Device:");
+       prt_tab(out);
+       prt_printf(out, "%u", i);
+       prt_newline(out);
+
+       printbuf_indent_add(out, 2);
+
+       prt_printf(out, "UUID:");
+       prt_tab(out);
+       pr_uuid(out, m.uuid.b);
+       prt_newline(out);
+
+       prt_printf(out, "Size:");
+       prt_tab(out);
+       prt_units_u64(out, device_size << 9);
+       prt_newline(out);
+
+       prt_printf(out, "Bucket size:");
+       prt_tab(out);
+       prt_units_u64(out, bucket_size << 9);
+       prt_newline(out);
+
+       prt_printf(out, "First bucket:");
+       prt_tab(out);
+       prt_printf(out, "%u", le16_to_cpu(m.first_bucket));
+       prt_newline(out);
+
+       prt_printf(out, "Buckets:");
+       prt_tab(out);
+       prt_printf(out, "%llu", le64_to_cpu(m.nbuckets));
+       prt_newline(out);
+
+       prt_printf(out, "Last mount:");
+       prt_tab(out);
+       if (m.last_mount)
+               pr_time(out, le64_to_cpu(m.last_mount));
+       else
+               prt_printf(out, "(never)");
+       prt_newline(out);
+
+       prt_printf(out, "State:");
+       prt_tab(out);
+       prt_printf(out, "%s",
+                  BCH_MEMBER_STATE(&m) < BCH_MEMBER_STATE_NR
+                  ? bch2_member_states[BCH_MEMBER_STATE(&m)]
+                  : "unknown");
+       prt_newline(out);
+
+       prt_printf(out, "Label:");
+       prt_tab(out);
+       if (BCH_MEMBER_GROUP(&m)) {
+               unsigned idx = BCH_MEMBER_GROUP(&m) - 1;
+
+               if (idx < disk_groups_nr(gi))
+                       prt_printf(out, "%s (%u)",
+                                  gi->entries[idx].label, idx);
+               else
+                       prt_printf(out, "(bad disk labels section)");
+       } else {
+               prt_printf(out, "(none)");
+       }
+       prt_newline(out);
+
+       prt_printf(out, "Data allowed:");
+       prt_tab(out);
+       if (BCH_MEMBER_DATA_ALLOWED(&m))
+               prt_bitflags(out, bch2_data_types, BCH_MEMBER_DATA_ALLOWED(&m));
+       else
+               prt_printf(out, "(none)");
+       prt_newline(out);
+
+       prt_printf(out, "Has data:");
+       prt_tab(out);
+       if (data_have)
+               prt_bitflags(out, bch2_data_types, data_have);
+       else
+               prt_printf(out, "(none)");
+       prt_newline(out);
+
+       prt_printf(out, "Discard:");
+       prt_tab(out);
+       prt_printf(out, "%llu", BCH_MEMBER_DISCARD(&m));
+       prt_newline(out);
+
+       prt_printf(out, "Freespace initialized:");
+       prt_tab(out);
+       prt_printf(out, "%llu", BCH_MEMBER_FREESPACE_INITIALIZED(&m));
+       prt_newline(out);
+
+       printbuf_indent_sub(out, 2);
+}
+
+static int bch2_sb_members_v1_validate(struct bch_sb *sb,
                                    struct bch_sb_field *f,
                                    struct printbuf *err)
 {
        struct bch_sb_field_members *mi = field_to_type(f, members);
        unsigned i;
 
-       if ((void *) (mi->members + sb->nr_devices) >
+       if ((void *) members_v1_get_mut(mi, sb->nr_devices)  >
            vstruct_end(&mi->field)) {
                prt_printf(err, "too many devices for section size");
                return -BCH_ERR_invalid_sb_members;
        }
 
        for (i = 0; i < sb->nr_devices; i++) {
-               struct bch_member *m = mi->members + i;
-
-               if (!bch2_member_exists(m))
-                       continue;
-
-               if (le64_to_cpu(m->nbuckets) > LONG_MAX) {
-                       prt_printf(err, "device %u: too many buckets (got %llu, max %lu)",
-                              i, le64_to_cpu(m->nbuckets), LONG_MAX);
-                       return -BCH_ERR_invalid_sb_members;
-               }
-
-               if (le64_to_cpu(m->nbuckets) -
-                   le16_to_cpu(m->first_bucket) < BCH_MIN_NR_NBUCKETS) {
-                       prt_printf(err, "device %u: not enough buckets (got %llu, max %u)",
-                              i, le64_to_cpu(m->nbuckets), BCH_MIN_NR_NBUCKETS);
-                       return -BCH_ERR_invalid_sb_members;
-               }
-
-               if (le16_to_cpu(m->bucket_size) <
-                   le16_to_cpu(sb->block_size)) {
-                       prt_printf(err, "device %u: bucket size %u smaller than block size %u",
-                              i, le16_to_cpu(m->bucket_size), le16_to_cpu(sb->block_size));
-                       return -BCH_ERR_invalid_sb_members;
-               }
+               struct bch_member m = members_v1_get(mi, i);
 
-               if (le16_to_cpu(m->bucket_size) <
-                   BCH_SB_BTREE_NODE_SIZE(sb)) {
-                       prt_printf(err, "device %u: bucket size %u smaller than btree node size %llu",
-                              i, le16_to_cpu(m->bucket_size), BCH_SB_BTREE_NODE_SIZE(sb));
-                       return -BCH_ERR_invalid_sb_members;
-               }
+               int ret = validate_member(err, m, sb, i);
+               if (ret)
+                       return ret;
        }
 
        return 0;
 }
 
-static void bch2_sb_members_to_text(struct printbuf *out, struct bch_sb *sb,
-                                   struct bch_sb_field *f)
+static void bch2_sb_members_v1_to_text(struct printbuf *out, struct bch_sb *sb,
+                                      struct bch_sb_field *f)
 {
        struct bch_sb_field_members *mi = field_to_type(f, members);
        struct bch_sb_field_disk_groups *gi = bch2_sb_get_disk_groups(sb);
        unsigned i;
 
        for (i = 0; i < sb->nr_devices; i++) {
-               struct bch_member *m = mi->members + i;
-               unsigned data_have = bch2_sb_dev_has_data(sb, i);
-               u64 bucket_size = le16_to_cpu(m->bucket_size);
-               u64 device_size = le64_to_cpu(m->nbuckets) * bucket_size;
-
-               if (!bch2_member_exists(m))
-                       continue;
-
-               prt_printf(out, "Device:");
-               prt_tab(out);
-               prt_printf(out, "%u", i);
-               prt_newline(out);
-
-               printbuf_indent_add(out, 2);
-
-               prt_printf(out, "UUID:");
-               prt_tab(out);
-               pr_uuid(out, m->uuid.b);
-               prt_newline(out);
-
-               prt_printf(out, "Size:");
-               prt_tab(out);
-               prt_units_u64(out, device_size << 9);
-               prt_newline(out);
-
-               prt_printf(out, "Bucket size:");
-               prt_tab(out);
-               prt_units_u64(out, bucket_size << 9);
-               prt_newline(out);
-
-               prt_printf(out, "First bucket:");
-               prt_tab(out);
-               prt_printf(out, "%u", le16_to_cpu(m->first_bucket));
-               prt_newline(out);
-
-               prt_printf(out, "Buckets:");
-               prt_tab(out);
-               prt_printf(out, "%llu", le64_to_cpu(m->nbuckets));
-               prt_newline(out);
-
-               prt_printf(out, "Last mount:");
-               prt_tab(out);
-               if (m->last_mount)
-                       pr_time(out, le64_to_cpu(m->last_mount));
-               else
-                       prt_printf(out, "(never)");
-               prt_newline(out);
-
-               prt_printf(out, "State:");
-               prt_tab(out);
-               prt_printf(out, "%s",
-                      BCH_MEMBER_STATE(m) < BCH_MEMBER_STATE_NR
-                      ? bch2_member_states[BCH_MEMBER_STATE(m)]
-                      : "unknown");
-               prt_newline(out);
-
-               prt_printf(out, "Label:");
-               prt_tab(out);
-               if (BCH_MEMBER_GROUP(m)) {
-                       unsigned idx = BCH_MEMBER_GROUP(m) - 1;
-
-                       if (idx < disk_groups_nr(gi))
-                               prt_printf(out, "%s (%u)",
-                                      gi->entries[idx].label, idx);
-                       else
-                               prt_printf(out, "(bad disk labels section)");
-               } else {
-                       prt_printf(out, "(none)");
-               }
-               prt_newline(out);
+               struct bch_member m = members_v1_get(mi, i);
+               member_to_text(out, m, gi, sb, i);
+       }
+}
 
-               prt_printf(out, "Data allowed:");
-               prt_tab(out);
-               if (BCH_MEMBER_DATA_ALLOWED(m))
-                       prt_bitflags(out, bch2_data_types, BCH_MEMBER_DATA_ALLOWED(m));
-               else
-                       prt_printf(out, "(none)");
-               prt_newline(out);
+const struct bch_sb_field_ops bch_sb_field_ops_members = {
+       .validate       = bch2_sb_members_v1_validate,
+       .to_text        = bch2_sb_members_v1_to_text,
+};
 
-               prt_printf(out, "Has data:");
-               prt_tab(out);
-               if (data_have)
-                       prt_bitflags(out, bch2_data_types, data_have);
-               else
-                       prt_printf(out, "(none)");
-               prt_newline(out);
+static void bch2_sb_members_v2_to_text(struct printbuf *out, struct bch_sb *sb,
+                                      struct bch_sb_field *f)
+{
+       struct bch_sb_field_members_v2 *mi = field_to_type(f, members_v2);
+       struct bch_sb_field_disk_groups *gi = bch2_sb_get_disk_groups(sb);
+       unsigned i;
 
-               prt_printf(out, "Discard:");
-               prt_tab(out);
-               prt_printf(out, "%llu", BCH_MEMBER_DISCARD(m));
-               prt_newline(out);
+       for (i = 0; i < sb->nr_devices; i++) {
+               struct bch_member m = members_v2_get(mi, i);
+               member_to_text(out, m, gi, sb, i);
+       }
+}
+
+static int bch2_sb_members_v2_validate(struct bch_sb *sb,
+                                      struct bch_sb_field *f,
+                                      struct printbuf *err)
+{
+       struct bch_sb_field_members_v2 *mi = field_to_type(f, members_v2);
+       size_t mi_bytes = (void *) members_v2_get_mut(mi, sb->nr_devices) -
+               (void *) mi;
 
-               prt_printf(out, "Freespace initialized:");
-               prt_tab(out);
-               prt_printf(out, "%llu", BCH_MEMBER_FREESPACE_INITIALIZED(m));
-               prt_newline(out);
+       if (mi_bytes > vstruct_bytes(&mi->field)) {
+               prt_printf(err, "section too small (%zu > %zu)",
+                          mi_bytes, vstruct_bytes(&mi->field));
+               return -BCH_ERR_invalid_sb_members;
+       }
 
-               printbuf_indent_sub(out, 2);
+       for (unsigned i = 0; i < sb->nr_devices; i++) {
+               int ret = validate_member(err, members_v2_get(mi, i), sb, i);
+               if (ret)
+                       return ret;
        }
+
+       return 0;
 }
 
-const struct bch_sb_field_ops bch_sb_field_ops_members = {
-       .validate       = bch2_sb_members_validate,
-       .to_text        = bch2_sb_members_to_text,
+const struct bch_sb_field_ops bch_sb_field_ops_members_v2 = {
+       .validate       = bch2_sb_members_v2_validate,
+       .to_text        = bch2_sb_members_v2_to_text,
 };
index 85d1af6..72958fa 100644 (file)
@@ -2,6 +2,9 @@
 #ifndef _BCACHEFS_SB_MEMBERS_H
 #define _BCACHEFS_SB_MEMBERS_H
 
+int bch2_members_v2_init(struct bch_fs *c);
+int bch_members_cpy_v2_v1(struct bch_sb_handle *disk_sb);
+struct bch_member *bch2_members_v2_get_mut(struct bch_sb *sb, int i);
 struct bch_member bch2_sb_member_get(struct bch_sb *sb, int i);
 
 static inline bool bch2_dev_is_online(struct bch_dev *ca)
@@ -173,6 +176,8 @@ static inline struct bch_devs_mask bch2_online_devs(struct bch_fs *c)
        return devs;
 }
 
+extern const struct bch_sb_field_ops bch_sb_field_ops_members_v2;
+
 extern const struct bch_sb_field_ops bch_sb_field_ops_members;
 
 #endif /* _BCACHEFS_SB_MEMBERS_H */
index 16e3a8a..8bb9c9a 100644 (file)
@@ -892,6 +892,7 @@ int bch2_write_super(struct bch_fs *c)
        SET_BCH_SB_BIG_ENDIAN(c->disk_sb.sb, CPU_BIG_ENDIAN);
 
        bch2_sb_counters_from_cpu(c);
+       bch_members_cpy_v2_v1(&c->disk_sb);
 
        for_each_online_member(ca, c, i)
                bch2_sb_from_fs(c, ca);
index 7ba1eba..c91c3f7 100644 (file)
@@ -400,6 +400,10 @@ static int __bch2_fs_read_write(struct bch_fs *c, bool early)
 
        bch_info(c, "going read-write");
 
+       ret = bch2_members_v2_init(c);
+       if (ret)
+               goto err;
+
        ret = bch2_fs_mark_dirty(c);
        if (ret)
                goto err;
@@ -924,7 +928,6 @@ static void print_mount_opts(struct bch_fs *c)
 
 int bch2_fs_start(struct bch_fs *c)
 {
-       struct bch_sb_field_members *mi;
        struct bch_dev *ca;
        time64_t now = ktime_get_real_seconds();
        unsigned i;
@@ -938,12 +941,17 @@ int bch2_fs_start(struct bch_fs *c)
 
        mutex_lock(&c->sb_lock);
 
+       ret = bch2_members_v2_init(c);
+       if (ret) {
+               mutex_unlock(&c->sb_lock);
+               goto err;
+       }
+
        for_each_online_member(ca, c, i)
                bch2_sb_from_fs(c, ca);
 
-       mi = bch2_sb_get_members(c->disk_sb.sb);
        for_each_online_member(ca, c, i)
-               mi->members[ca->dev_idx].last_mount = cpu_to_le64(now);
+               bch2_members_v2_get_mut(c->disk_sb.sb, i)->last_mount = cpu_to_le64(now);
 
        mutex_unlock(&c->sb_lock);
 
@@ -1382,7 +1390,7 @@ static void __bch2_dev_read_write(struct bch_fs *c, struct bch_dev *ca)
 int __bch2_dev_set_state(struct bch_fs *c, struct bch_dev *ca,
                         enum bch_member_state new_state, int flags)
 {
-       struct bch_sb_field_members *mi;
+       struct bch_member *m;
        int ret = 0;
 
        if (ca->mi.state == new_state)
@@ -1397,8 +1405,8 @@ int __bch2_dev_set_state(struct bch_fs *c, struct bch_dev *ca,
        bch_notice(ca, "%s", bch2_member_states[new_state]);
 
        mutex_lock(&c->sb_lock);
-       mi = bch2_sb_get_members(c->disk_sb.sb);
-       SET_BCH_MEMBER_STATE(&mi->members[ca->dev_idx], new_state);
+       m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
+       SET_BCH_MEMBER_STATE(m, new_state);
        bch2_write_super(c);
        mutex_unlock(&c->sb_lock);
 
@@ -1454,7 +1462,7 @@ static int bch2_dev_remove_alloc(struct bch_fs *c, struct bch_dev *ca)
 
 int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
 {
-       struct bch_sb_field_members *mi;
+       struct bch_member *m;
        unsigned dev_idx = ca->dev_idx, data;
        int ret;
 
@@ -1542,8 +1550,8 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
         * this device must be gone:
         */
        mutex_lock(&c->sb_lock);
-       mi = bch2_sb_get_members(c->disk_sb.sb);
-       memset(&mi->members[dev_idx].uuid, 0, sizeof(mi->members[dev_idx].uuid));
+       m = bch2_members_v2_get_mut(c->disk_sb.sb, dev_idx);
+       memset(&m->uuid, 0, sizeof(m->uuid));
 
        bch2_write_super(c);
 
@@ -1566,7 +1574,7 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
        struct bch_opts opts = bch2_opts_empty();
        struct bch_sb_handle sb;
        struct bch_dev *ca = NULL;
-       struct bch_sb_field_members *mi;
+       struct bch_sb_field_members_v2 *mi;
        struct bch_member dev_mi;
        unsigned dev_idx, nr_devices, u64s;
        struct printbuf errbuf = PRINTBUF;
@@ -1622,9 +1630,9 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
                goto err_unlock;
        }
 
-       mi = bch2_sb_get_members(ca->disk_sb.sb);
+       mi = bch2_sb_get_members_v2(ca->disk_sb.sb);
 
-       if (!bch2_sb_resize_members(&ca->disk_sb,
+       if (!bch2_sb_resize_members_v2(&ca->disk_sb,
                                le32_to_cpu(mi->field.u64s) +
                                sizeof(dev_mi) / sizeof(u64))) {
                ret = -BCH_ERR_ENOSPC_sb_members;
@@ -1645,20 +1653,21 @@ no_slot:
 
 have_slot:
        nr_devices = max_t(unsigned, dev_idx + 1, c->sb.nr_devices);
-       u64s = (sizeof(struct bch_sb_field_members) +
-               sizeof(struct bch_member) * nr_devices) / sizeof(u64);
+       u64s = DIV_ROUND_UP(sizeof(struct bch_sb_field_members_v2) +
+                           le16_to_cpu(mi->member_bytes) * nr_devices, sizeof(u64));
 
-       mi = bch2_sb_resize_members(&c->disk_sb, u64s);
+       mi = bch2_sb_resize_members_v2(&c->disk_sb, u64s);
        if (!mi) {
                ret = -BCH_ERR_ENOSPC_sb_members;
                bch_err_msg(c, ret, "setting up new superblock");
                goto err_unlock;
        }
+       struct bch_member *m = bch2_members_v2_get_mut(c->disk_sb.sb, dev_idx);
 
        /* success: */
 
-       mi->members[dev_idx] = dev_mi;
-       mi->members[dev_idx].last_mount = cpu_to_le64(ktime_get_real_seconds());
+       *m = dev_mi;
+       m->last_mount = cpu_to_le64(ktime_get_real_seconds());
        c->disk_sb.sb->nr_devices       = nr_devices;
 
        ca->disk_sb.sb->dev_idx = dev_idx;
@@ -1718,7 +1727,6 @@ int bch2_dev_online(struct bch_fs *c, const char *path)
 {
        struct bch_opts opts = bch2_opts_empty();
        struct bch_sb_handle sb = { NULL };
-       struct bch_sb_field_members *mi;
        struct bch_dev *ca;
        unsigned dev_idx;
        int ret;
@@ -1755,9 +1763,9 @@ int bch2_dev_online(struct bch_fs *c, const char *path)
                __bch2_dev_read_write(c, ca);
 
        mutex_lock(&c->sb_lock);
-       mi = bch2_sb_get_members(c->disk_sb.sb);
+       struct bch_member *m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
 
-       mi->members[ca->dev_idx].last_mount =
+       m->last_mount =
                cpu_to_le64(ktime_get_real_seconds());
 
        bch2_write_super(c);
@@ -1799,7 +1807,7 @@ int bch2_dev_offline(struct bch_fs *c, struct bch_dev *ca, int flags)
 
 int bch2_dev_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
 {
-       struct bch_member *mi;
+       struct bch_member *m;
        int ret = 0;
 
        down_write(&c->state_lock);
@@ -1829,8 +1837,8 @@ int bch2_dev_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
                goto err;
 
        mutex_lock(&c->sb_lock);
-       mi = &bch2_sb_get_members(c->disk_sb.sb)->members[ca->dev_idx];
-       mi->nbuckets = cpu_to_le64(nbuckets);
+       m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
+       m->nbuckets = cpu_to_le64(nbuckets);
 
        bch2_write_super(c);
        mutex_unlock(&c->sb_lock);
index b700be5..eb764b9 100644 (file)
@@ -962,7 +962,7 @@ STORE(bch2_dev)
                bool v = strtoul_or_return(buf);
 
                mutex_lock(&c->sb_lock);
-               mi = &bch2_sb_get_members(c->disk_sb.sb)->members[ca->dev_idx];
+               mi = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
 
                if (v != BCH_MEMBER_DISCARD(mi)) {
                        SET_BCH_MEMBER_DISCARD(mi, v);
@@ -975,7 +975,7 @@ STORE(bch2_dev)
                u64 v = strtoul_or_return(buf);
 
                mutex_lock(&c->sb_lock);
-               mi = &bch2_sb_get_members(c->disk_sb.sb)->members[ca->dev_idx];
+               mi = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
 
                if (v + 1 != BCH_MEMBER_DURABILITY(mi)) {
                        SET_BCH_MEMBER_DURABILITY(mi, v + 1);