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>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Hunter Shaffer 2023-09-25 00:02:56 -04:00 committed by Kent Overstreet
parent 1241df5872
commit 3f7b9713da
9 changed files with 330 additions and 164 deletions

View 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);

View 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: */

View 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;
}

View 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) \

View 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;
struct bch_member m = members_v1_get(mi, 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;
}
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);
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);
struct bch_member m = members_v1_get(mi, i);
member_to_text(out, m, gi, sb, i);
}
}
const struct bch_sb_field_ops bch_sb_field_ops_members = {
.validate = bch2_sb_members_validate,
.to_text = bch2_sb_members_to_text,
.validate = bch2_sb_members_v1_validate,
.to_text = bch2_sb_members_v1_to_text,
};
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;
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;
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;
}
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_v2 = {
.validate = bch2_sb_members_v2_validate,
.to_text = bch2_sb_members_v2_to_text,
};

View 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 */

View 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);

View 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);

View 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);