summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHunter Shaffer <huntershaffer182456@gmail.com>2023-09-25 00:02:56 -0400
committerHunter Shaffer <huntershaffer182456@gmail.com>2023-09-26 20:58:43 -0400
commitdac01c712c567cb8e8967353d93ff05982925593 (patch)
tree441b94b0691ed27ea1df3fb383a864ca23a2a2ff
parent9d96c5b6d737ce849eb8244e79232c12248d6978 (diff)
bcachefs: New superblock section members_v2
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>
-rw-r--r--fs/bcachefs/alloc_background.c2
-rw-r--r--fs/bcachefs/bcachefs_format.h14
-rw-r--r--fs/bcachefs/disk_groups.c2
-rw-r--r--fs/bcachefs/errcode.h1
-rw-r--r--fs/bcachefs/sb-members.c403
-rw-r--r--fs/bcachefs/sb-members.h5
-rw-r--r--fs/bcachefs/super-io.c1
-rw-r--r--fs/bcachefs/super.c57
-rw-r--r--fs/bcachefs/sysfs.c4
9 files changed, 329 insertions, 160 deletions
diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c
index 19ef7a444c23..4059d3d4b7f5 100644
--- a/fs/bcachefs/alloc_background.c
+++ b/fs/bcachefs/alloc_background.c
@@ -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);
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h
index f0d130440baa..c1a9ba451f04 100644
--- a/fs/bcachefs/bcachefs_format.h
+++ b/fs/bcachefs/bcachefs_format.h
@@ -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: */
diff --git a/fs/bcachefs/disk_groups.c b/fs/bcachefs/disk_groups.c
index fc5926cf3616..5d6e216d9487 100644
--- a/fs/bcachefs/disk_groups.c
+++ b/fs/bcachefs/disk_groups.c
@@ -442,7 +442,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;
}
diff --git a/fs/bcachefs/errcode.h b/fs/bcachefs/errcode.h
index 64f7176c2a4e..7cc083776a2e 100644
--- a/fs/bcachefs/errcode.h
+++ b/fs/bcachefs/errcode.h
@@ -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) \
diff --git a/fs/bcachefs/sb-members.c b/fs/bcachefs/sb-members.c
index 0be51d082043..dfce0d788a0f 100644
--- a/fs/bcachefs/sb-members.c
+++ b/fs/bcachefs/sb-members.c
@@ -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)) {
+ mi1 = bch2_sb_get_members(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)));
+ 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,
};
diff --git a/fs/bcachefs/sb-members.h b/fs/bcachefs/sb-members.h
index 85d1af6a990c..72958facbb4f 100644
--- a/fs/bcachefs/sb-members.h
+++ b/fs/bcachefs/sb-members.h
@@ -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 */
diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c
index 16e3a8aa290d..8bb9c9a67fe5 100644
--- a/fs/bcachefs/super-io.c
+++ b/fs/bcachefs/super-io.c
@@ -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);
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
index 8b17ca562956..e026c4435d68 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -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;
@@ -923,7 +927,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;
@@ -937,12 +940,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);
@@ -1381,7 +1389,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)
@@ -1396,8 +1404,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);
@@ -1453,7 +1461,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;
@@ -1541,8 +1549,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);
@@ -1565,7 +1573,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;
@@ -1621,9 +1629,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;
@@ -1643,21 +1651,25 @@ no_slot:
goto err_unlock;
have_slot:
+ mi = bch2_sb_get_members_v2(c->disk_sb.sb);
+ BUG_ON(le16_to_cpu(mi->member_bytes) < sizeof(struct bch_member));
+
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;
@@ -1717,7 +1729,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;
@@ -1754,9 +1765,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);
@@ -1798,7 +1809,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);
@@ -1828,8 +1839,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);
diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c
index 1abc61cb3f7e..9a858105d3f7 100644
--- a/fs/bcachefs/sysfs.c
+++ b/fs/bcachefs/sysfs.c
@@ -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);