mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
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:
parent
1241df5872
commit
3f7b9713da
@ -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);
|
||||
|
||||
|
@ -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: */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) \
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user