Update bcachefs sources to 7bf1ac0d46 bcachefs: Correctly initialize new buckets on device resize

Signed-off-by: Hunter Shaffer <huntershaffer182456@gmail.com>
This commit is contained in:
Kent Overstreet 2023-10-07 17:23:13 -04:00 committed by Hunter Shaffer
parent 6b175a0224
commit 1251ea58a8
26 changed files with 543 additions and 305 deletions

View File

@ -1 +1 @@
a1b6677dca574a8bf904d9eea2b108474dc378d1 7bf1ac0d46ebede68561e0476f7af9c07ac21de8

View File

@ -414,7 +414,7 @@ int cmd_device_set_state(int argc, char *argv[])
if (ret) if (ret)
die("error opening %s: %s", dev_str, bch2_err_str(ret)); die("error opening %s: %s", dev_str, bch2_err_str(ret));
struct bch_member *m = bch2_sb_get_members(sb.sb)->members + sb.sb->dev_idx; struct bch_member *m = bch2_members_v2_get_mut(sb.sb, sb.sb->dev_idx);
SET_BCH_MEMBER_STATE(m, new_state); SET_BCH_MEMBER_STATE(m, new_state);
@ -510,16 +510,11 @@ int cmd_device_resize(int argc, char *argv[])
if (idx >= sb->nr_devices) if (idx >= sb->nr_devices)
die("error reading superblock: dev idx >= sb->nr_devices"); die("error reading superblock: dev idx >= sb->nr_devices");
struct bch_sb_field_members *mi = bch2_sb_get_members(sb); struct bch_member m = bch2_sb_member_get(sb, idx);
if (!mi)
die("error reading superblock: no member info");
/* could also just read this out of sysfs... meh */ u64 nbuckets = size / le16_to_cpu(m.bucket_size);
struct bch_member *m = mi->members + idx;
u64 nbuckets = size / le16_to_cpu(m->bucket_size); if (nbuckets < le64_to_cpu(m.nbuckets))
if (nbuckets < le64_to_cpu(m->nbuckets))
die("Shrinking not supported yet"); die("Shrinking not supported yet");
printf("resizing %s to %llu buckets\n", dev, nbuckets); printf("resizing %s to %llu buckets\n", dev, nbuckets);
@ -616,14 +611,9 @@ int cmd_device_resize_journal(int argc, char *argv[])
if (idx >= sb->nr_devices) if (idx >= sb->nr_devices)
die("error reading superblock: dev idx >= sb->nr_devices"); die("error reading superblock: dev idx >= sb->nr_devices");
struct bch_sb_field_members *mi = bch2_sb_get_members(sb); struct bch_member m = bch2_sb_member_get(sb, idx);
if (!mi)
die("error reading superblock: no member info");
/* could also just read this out of sysfs... meh */ u64 nbuckets = size / le16_to_cpu(m.bucket_size);
struct bch_member *m = mi->members + idx;
u64 nbuckets = size / le16_to_cpu(m->bucket_size);
printf("resizing journal on %s to %llu buckets\n", dev, nbuckets); printf("resizing journal on %s to %llu buckets\n", dev, nbuckets);
bchu_disk_resize_journal(fs, idx, nbuckets); bchu_disk_resize_journal(fs, idx, nbuckets);

View File

@ -245,7 +245,7 @@ int cmd_format(int argc, char *argv[])
buf.human_readable_units = true; buf.human_readable_units = true;
bch2_sb_to_text(&buf, sb, false, 1 << BCH_SB_FIELD_members); bch2_sb_to_text(&buf, sb, false, 1 << BCH_SB_FIELD_members_v2);
printf("%s", buf.buf); printf("%s", buf.buf);
printbuf_exit(&buf); printbuf_exit(&buf);
@ -305,8 +305,9 @@ int cmd_show_super(int argc, char *argv[])
{ "help", 0, NULL, 'h' }, { "help", 0, NULL, 'h' },
{ NULL } { NULL }
}; };
unsigned fields = 1 << BCH_SB_FIELD_members; unsigned fields = 0;
bool print_layout = false; bool print_layout = false;
bool print_default_fields = true;
int opt; int opt;
while ((opt = getopt_long(argc, argv, "f:lh", longopts, NULL)) != -1) while ((opt = getopt_long(argc, argv, "f:lh", longopts, NULL)) != -1)
@ -316,6 +317,7 @@ int cmd_show_super(int argc, char *argv[])
? ~0 ? ~0
: read_flag_list_or_die(optarg, : read_flag_list_or_die(optarg,
bch2_sb_fields, "superblock field"); bch2_sb_fields, "superblock field");
print_default_fields = false;
break; break;
case 'l': case 'l':
print_layout = true; print_layout = true;
@ -342,6 +344,11 @@ int cmd_show_super(int argc, char *argv[])
if (ret) if (ret)
die("Error opening %s: %s", dev, bch2_err_str(ret)); die("Error opening %s: %s", dev, bch2_err_str(ret));
if (print_default_fields)
fields = bch2_sb_get_members_v2(sb.sb)
? 1 << BCH_SB_FIELD_members_v2
: 1 << BCH_SB_FIELD_members_v1;
struct printbuf buf = PRINTBUF; struct printbuf buf = PRINTBUF;
buf.human_readable_units = true; buf.human_readable_units = true;

View File

@ -150,7 +150,6 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
{ {
struct bch_sb_handle sb = { NULL }; struct bch_sb_handle sb = { NULL };
struct dev_opts *i; struct dev_opts *i;
struct bch_sb_field_members *mi;
unsigned max_dev_block_size = 0; unsigned max_dev_block_size = 0;
unsigned opt_id; unsigned opt_id;
@ -222,12 +221,13 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
sb.sb->time_precision = cpu_to_le32(1); sb.sb->time_precision = cpu_to_le32(1);
/* Member info: */ /* Member info: */
mi = bch2_sb_resize_members(&sb, struct bch_sb_field_members_v2 *mi =
bch2_sb_resize_members_v2(&sb,
(sizeof(*mi) + sizeof(struct bch_member) * (sizeof(*mi) + sizeof(struct bch_member) *
nr_devs) / sizeof(u64)); nr_devs) / sizeof(u64));
mi->member_bytes = cpu_to_le16(sizeof(struct bch_member));
for (i = devs; i < devs + nr_devs; i++) { for (i = devs; i < devs + nr_devs; i++) {
struct bch_member *m = mi->members + (i - devs); struct bch_member *m = bch2_members_v2_get_mut(sb.sb, (i - devs));
uuid_generate(m->uuid.b); uuid_generate(m->uuid.b);
m->nbuckets = cpu_to_le64(i->nbuckets); m->nbuckets = cpu_to_le64(i->nbuckets);
@ -255,9 +255,7 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
* Recompute mi and m after each sb modification: its location * Recompute mi and m after each sb modification: its location
* in memory may have changed due to reallocation. * in memory may have changed due to reallocation.
*/ */
mi = bch2_sb_get_members(sb.sb); m = bch2_members_v2_get_mut(sb.sb, (i - devs));
m = mi->members + (i - devs);
SET_BCH_MEMBER_GROUP(m, idx + 1); SET_BCH_MEMBER_GROUP(m, idx + 1);
} }
@ -279,6 +277,8 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
SET_BCH_SB_ENCRYPTION_TYPE(sb.sb, 1); SET_BCH_SB_ENCRYPTION_TYPE(sb.sb, 1);
} }
bch_members_cpy_v2_v1(&sb);
for (i = devs; i < devs + nr_devs; i++) { for (i = devs; i < devs + nr_devs; i++) {
u64 size_sectors = i->size >> 9; u64 size_sectors = i->size >> 9;

View File

@ -1831,29 +1831,33 @@ void bch2_do_invalidates(struct bch_fs *c)
bch2_write_ref_put(c, BCH_WRITE_REF_invalidate); bch2_write_ref_put(c, BCH_WRITE_REF_invalidate);
} }
static int bch2_dev_freespace_init(struct bch_fs *c, struct bch_dev *ca, int bch2_dev_freespace_init(struct bch_fs *c, struct bch_dev *ca,
unsigned long *last_updated) u64 bucket_start, u64 bucket_end)
{ {
struct btree_trans *trans = bch2_trans_get(c); struct btree_trans *trans = bch2_trans_get(c);
struct btree_iter iter; struct btree_iter iter;
struct bkey_s_c k; struct bkey_s_c k;
struct bkey hole; struct bkey hole;
struct bpos end = POS(ca->dev_idx, ca->mi.nbuckets); struct bpos end = POS(ca->dev_idx, bucket_end);
struct bch_member *m; struct bch_member m;
unsigned long last_updated = jiffies;
int ret; int ret;
BUG_ON(bucket_start > bucket_end);
BUG_ON(bucket_end > ca->mi.nbuckets);
bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc, bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc,
POS(ca->dev_idx, ca->mi.first_bucket), POS(ca->dev_idx, max_t(u64, ca->mi.first_bucket, bucket_start)),
BTREE_ITER_PREFETCH); BTREE_ITER_PREFETCH);
/* /*
* Scan the alloc btree for every bucket on @ca, and add buckets to the * Scan the alloc btree for every bucket on @ca, and add buckets to the
* freespace/need_discard/need_gc_gens btrees as needed: * freespace/need_discard/need_gc_gens btrees as needed:
*/ */
while (1) { while (1) {
if (*last_updated + HZ * 10 < jiffies) { if (last_updated + HZ * 10 < jiffies) {
bch_info(ca, "%s: currently at %llu/%llu", bch_info(ca, "%s: currently at %llu/%llu",
__func__, iter.pos.offset, ca->mi.nbuckets); __func__, iter.pos.offset, ca->mi.nbuckets);
*last_updated = jiffies; last_updated = jiffies;
} }
bch2_trans_begin(trans); bch2_trans_begin(trans);
@ -1922,8 +1926,8 @@ bkey_err:
} }
mutex_lock(&c->sb_lock); mutex_lock(&c->sb_lock);
m = bch2_sb_get_members(c->disk_sb.sb)->members + ca->dev_idx; m = bch2_sb_member_get(c->disk_sb.sb, ca->dev_idx);
SET_BCH_MEMBER_FREESPACE_INITIALIZED(m, true); SET_BCH_MEMBER_FREESPACE_INITIALIZED(&m, true);
mutex_unlock(&c->sb_lock); mutex_unlock(&c->sb_lock);
return 0; return 0;
@ -1935,7 +1939,6 @@ int bch2_fs_freespace_init(struct bch_fs *c)
unsigned i; unsigned i;
int ret = 0; int ret = 0;
bool doing_init = false; bool doing_init = false;
unsigned long last_updated = jiffies;
/* /*
* We can crash during the device add path, so we need to check this on * We can crash during the device add path, so we need to check this on
@ -1951,7 +1954,7 @@ int bch2_fs_freespace_init(struct bch_fs *c)
doing_init = true; doing_init = true;
} }
ret = bch2_dev_freespace_init(c, ca, &last_updated); ret = bch2_dev_freespace_init(c, ca, 0, ca->mi.nbuckets);
if (ret) { if (ret) {
percpu_ref_put(&ca->ref); percpu_ref_put(&ca->ref);
bch_err_fn(c, ret); bch_err_fn(c, ret);

View File

@ -245,6 +245,7 @@ static inline const struct bch_backpointer *alloc_v4_backpointers_c(const struct
return (void *) ((u64 *) &a->v + BCH_ALLOC_V4_BACKPOINTERS_START(a)); return (void *) ((u64 *) &a->v + BCH_ALLOC_V4_BACKPOINTERS_START(a));
} }
int bch2_dev_freespace_init(struct bch_fs *, struct bch_dev *, u64, u64);
int bch2_fs_freespace_init(struct bch_fs *); int bch2_fs_freespace_init(struct bch_fs *);
void bch2_recalc_capacity(struct bch_fs *); void bch2_recalc_capacity(struct bch_fs *);

View File

@ -379,7 +379,7 @@ BCH_DEBUG_PARAMS()
#undef BCH_DEBUG_PARAM #undef BCH_DEBUG_PARAM
#ifndef CONFIG_BCACHEFS_DEBUG #ifndef CONFIG_BCACHEFS_DEBUG
#define BCH_DEBUG_PARAM(name, description) static const bool bch2_##name; #define BCH_DEBUG_PARAM(name, description) static const __maybe_unused bool bch2_##name;
BCH_DEBUG_PARAMS_DEBUG() BCH_DEBUG_PARAMS_DEBUG()
#undef BCH_DEBUG_PARAM #undef BCH_DEBUG_PARAM
#endif #endif

View File

@ -1222,7 +1222,7 @@ struct bch_sb_field {
#define BCH_SB_FIELDS() \ #define BCH_SB_FIELDS() \
x(journal, 0) \ x(journal, 0) \
x(members, 1) \ x(members_v1, 1) \
x(crypt, 2) \ x(crypt, 2) \
x(replicas_v0, 3) \ x(replicas_v0, 3) \
x(quota, 4) \ x(quota, 4) \
@ -1231,7 +1231,8 @@ struct bch_sb_field {
x(replicas, 7) \ x(replicas, 7) \
x(journal_seq_blacklist, 8) \ x(journal_seq_blacklist, 8) \
x(journal_v2, 9) \ x(journal_v2, 9) \
x(counters, 10) x(counters, 10) \
x(members_v2, 11)
enum bch_sb_field_type { enum bch_sb_field_type {
#define x(f, nr) BCH_SB_FIELD_##f = nr, #define x(f, nr) BCH_SB_FIELD_##f = nr,
@ -1264,10 +1265,23 @@ struct bch_sb_field_journal_v2 {
} d[]; } d[];
}; };
/* BCH_SB_FIELD_members: */ /* BCH_SB_FIELD_members_v1: */
#define BCH_MIN_NR_NBUCKETS (1 << 6) #define BCH_MIN_NR_NBUCKETS (1 << 6)
#define BCH_IOPS_MEASUREMENTS() \
x(seqread, 0) \
x(seqwrite, 1) \
x(randread, 2) \
x(randwrite, 3)
enum bch_iops_measurement {
#define x(t, n) BCH_IOPS_##t = n,
BCH_IOPS_MEASUREMENTS()
#undef x
BCH_IOPS_NR
};
struct bch_member { struct bch_member {
__uuid_t uuid; __uuid_t uuid;
__le64 nbuckets; /* device size */ __le64 nbuckets; /* device size */
@ -1276,17 +1290,20 @@ struct bch_member {
__le32 pad; __le32 pad;
__le64 last_mount; /* time_t */ __le64 last_mount; /* time_t */
__le64 flags[2]; __le64 flags;
__le32 iops[4];
}; };
LE64_BITMASK(BCH_MEMBER_STATE, struct bch_member, flags[0], 0, 4) #define BCH_MEMBER_V1_BYTES 56
LE64_BITMASK(BCH_MEMBER_STATE, struct bch_member, flags, 0, 4)
/* 4-14 unused, was TIER, HAS_(META)DATA, REPLACEMENT */ /* 4-14 unused, was TIER, HAS_(META)DATA, REPLACEMENT */
LE64_BITMASK(BCH_MEMBER_DISCARD, struct bch_member, flags[0], 14, 15) LE64_BITMASK(BCH_MEMBER_DISCARD, struct bch_member, flags, 14, 15)
LE64_BITMASK(BCH_MEMBER_DATA_ALLOWED, struct bch_member, flags[0], 15, 20) LE64_BITMASK(BCH_MEMBER_DATA_ALLOWED, struct bch_member, flags, 15, 20)
LE64_BITMASK(BCH_MEMBER_GROUP, struct bch_member, flags[0], 20, 28) LE64_BITMASK(BCH_MEMBER_GROUP, struct bch_member, flags, 20, 28)
LE64_BITMASK(BCH_MEMBER_DURABILITY, struct bch_member, flags[0], 28, 30) LE64_BITMASK(BCH_MEMBER_DURABILITY, struct bch_member, flags, 28, 30)
LE64_BITMASK(BCH_MEMBER_FREESPACE_INITIALIZED, LE64_BITMASK(BCH_MEMBER_FREESPACE_INITIALIZED,
struct bch_member, flags[0], 30, 31) struct bch_member, flags, 30, 31)
#if 0 #if 0
LE64_BITMASK(BCH_MEMBER_NR_READ_ERRORS, struct bch_member, flags[1], 0, 20); LE64_BITMASK(BCH_MEMBER_NR_READ_ERRORS, struct bch_member, flags[1], 0, 20);
@ -1306,9 +1323,16 @@ enum bch_member_state {
BCH_MEMBER_STATE_NR BCH_MEMBER_STATE_NR
}; };
struct bch_sb_field_members { struct bch_sb_field_members_v1 {
struct bch_sb_field field; 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: */ /* BCH_SB_FIELD_crypt: */

View File

@ -367,7 +367,6 @@ static inline int update_replicas(struct bch_fs *c, struct bkey_s_c k,
struct printbuf buf = PRINTBUF; struct printbuf buf = PRINTBUF;
percpu_down_read(&c->mark_lock); percpu_down_read(&c->mark_lock);
buf.atomic++;
idx = bch2_replicas_entry_idx(c, r); idx = bch2_replicas_entry_idx(c, r);
if (idx < 0 && if (idx < 0 &&
@ -795,7 +794,6 @@ static int mark_stripe_bucket(struct btree_trans *trans,
/* * XXX doesn't handle deletion */ /* * XXX doesn't handle deletion */
percpu_down_read(&c->mark_lock); percpu_down_read(&c->mark_lock);
buf.atomic++;
g = PTR_GC_BUCKET(ca, ptr); g = PTR_GC_BUCKET(ca, ptr);
if (g->dirty_sectors || if (g->dirty_sectors ||

View File

@ -70,12 +70,15 @@ union ulong_byte_assert {
static inline void bucket_unlock(struct bucket *b) static inline void bucket_unlock(struct bucket *b)
{ {
BUILD_BUG_ON(!((union ulong_byte_assert) { .ulong = 1UL << BUCKET_LOCK_BITNR }).byte); BUILD_BUG_ON(!((union ulong_byte_assert) { .ulong = 1UL << BUCKET_LOCK_BITNR }).byte);
bit_spin_unlock(BUCKET_LOCK_BITNR, (void *) &b->lock);
clear_bit_unlock(BUCKET_LOCK_BITNR, (void *) &b->lock);
wake_up_bit((void *) &b->lock, BUCKET_LOCK_BITNR);
} }
static inline void bucket_lock(struct bucket *b) static inline void bucket_lock(struct bucket *b)
{ {
bit_spin_lock(BUCKET_LOCK_BITNR, (void *) &b->lock); wait_on_bit_lock((void *) &b->lock, BUCKET_LOCK_BITNR,
TASK_UNINTERRUPTIBLE);
} }
static inline struct bucket_array *gc_bucket_array(struct bch_dev *ca) static inline struct bucket_array *gc_bucket_array(struct bch_dev *ca)

View File

@ -362,7 +362,7 @@ struct bch_csum bch2_checksum_merge(unsigned type, struct bch_csum a,
state.type = type; state.type = type;
bch2_checksum_init(&state); bch2_checksum_init(&state);
state.seed = (u64 __force) a.lo; state.seed = le64_to_cpu(a.lo);
BUG_ON(!bch2_checksum_mergeable(type)); BUG_ON(!bch2_checksum_mergeable(type));
@ -373,7 +373,7 @@ struct bch_csum bch2_checksum_merge(unsigned type, struct bch_csum a,
page_address(ZERO_PAGE(0)), page_len); page_address(ZERO_PAGE(0)), page_len);
b_len -= page_len; b_len -= page_len;
} }
a.lo = (__le64 __force) bch2_checksum_final(&state); a.lo = cpu_to_le64(bch2_checksum_final(&state));
a.lo ^= b.lo; a.lo ^= b.lo;
a.hi ^= b.hi; a.hi ^= b.hi;
return a; return a;
@ -534,16 +534,31 @@ static int __bch2_request_key(char *key_description, struct bch_key *key)
{ {
key_serial_t key_id; key_serial_t key_id;
key_id = request_key("user", key_description, NULL,
KEY_SPEC_SESSION_KEYRING);
if (key_id >= 0)
goto got_key;
key_id = request_key("user", key_description, NULL, key_id = request_key("user", key_description, NULL,
KEY_SPEC_USER_KEYRING); KEY_SPEC_USER_KEYRING);
if (key_id < 0) if (key_id >= 0)
goto got_key;
key_id = request_key("user", key_description, NULL,
KEY_SPEC_USER_SESSION_KEYRING);
if (key_id >= 0)
goto got_key;
return -errno; return -errno;
got_key:
if (keyctl_read(key_id, (void *) key, sizeof(*key)) != sizeof(*key)) if (keyctl_read(key_id, (void *) key, sizeof(*key)) != sizeof(*key))
return -1; return -1;
return 0; return 0;
} }
#include "../crypto.h"
#endif #endif
int bch2_request_key(struct bch_sb *sb, struct bch_key *key) int bch2_request_key(struct bch_sb *sb, struct bch_key *key)
@ -556,6 +571,20 @@ int bch2_request_key(struct bch_sb *sb, struct bch_key *key)
ret = __bch2_request_key(key_description.buf, key); ret = __bch2_request_key(key_description.buf, key);
printbuf_exit(&key_description); printbuf_exit(&key_description);
#ifndef __KERNEL__
if (ret) {
char *passphrase = read_passphrase("Enter passphrase: ");
struct bch_encrypted_key sb_key;
bch2_passphrase_check(sb, passphrase,
key, &sb_key);
ret = 0;
}
#endif
/* stash with memfd, pass memfd fd to mount */
return ret; return ret;
} }

View File

@ -25,19 +25,18 @@ static int bch2_sb_disk_groups_validate(struct bch_sb *sb,
struct bch_sb_field_disk_groups *groups = struct bch_sb_field_disk_groups *groups =
field_to_type(f, disk_groups); field_to_type(f, disk_groups);
struct bch_disk_group *g, *sorted = NULL; struct bch_disk_group *g, *sorted = NULL;
struct bch_sb_field_members *mi = bch2_sb_get_members(sb);
unsigned nr_groups = disk_groups_nr(groups); unsigned nr_groups = disk_groups_nr(groups);
unsigned i, len; unsigned i, len;
int ret = 0; int ret = 0;
for (i = 0; i < sb->nr_devices; i++) { for (i = 0; i < sb->nr_devices; i++) {
struct bch_member *m = mi->members + i; struct bch_member m = bch2_sb_member_get(sb, i);
unsigned group_id; unsigned group_id;
if (!BCH_MEMBER_GROUP(m)) if (!BCH_MEMBER_GROUP(&m))
continue; continue;
group_id = BCH_MEMBER_GROUP(m) - 1; group_id = BCH_MEMBER_GROUP(&m) - 1;
if (group_id >= nr_groups) { if (group_id >= nr_groups) {
prt_printf(err, "disk %u has invalid label %u (have %u)", prt_printf(err, "disk %u has invalid label %u (have %u)",
@ -152,14 +151,12 @@ const struct bch_sb_field_ops bch_sb_field_ops_disk_groups = {
int bch2_sb_disk_groups_to_cpu(struct bch_fs *c) int bch2_sb_disk_groups_to_cpu(struct bch_fs *c)
{ {
struct bch_sb_field_members *mi;
struct bch_sb_field_disk_groups *groups; struct bch_sb_field_disk_groups *groups;
struct bch_disk_groups_cpu *cpu_g, *old_g; struct bch_disk_groups_cpu *cpu_g, *old_g;
unsigned i, g, nr_groups; unsigned i, g, nr_groups;
lockdep_assert_held(&c->sb_lock); lockdep_assert_held(&c->sb_lock);
mi = bch2_sb_get_members(c->disk_sb.sb);
groups = bch2_sb_get_disk_groups(c->disk_sb.sb); groups = bch2_sb_get_disk_groups(c->disk_sb.sb);
nr_groups = disk_groups_nr(groups); nr_groups = disk_groups_nr(groups);
@ -182,13 +179,13 @@ int bch2_sb_disk_groups_to_cpu(struct bch_fs *c)
} }
for (i = 0; i < c->disk_sb.sb->nr_devices; i++) { for (i = 0; i < c->disk_sb.sb->nr_devices; i++) {
struct bch_member *m = mi->members + i; struct bch_member m = bch2_sb_member_get(c->disk_sb.sb, i);
struct bch_disk_group_cpu *dst; struct bch_disk_group_cpu *dst;
if (!bch2_member_exists(m)) if (!bch2_member_exists(&m))
continue; continue;
g = BCH_MEMBER_GROUP(m); g = BCH_MEMBER_GROUP(&m);
while (g) { while (g) {
dst = &cpu_g->entries[g - 1]; dst = &cpu_g->entries[g - 1];
__set_bit(i, dst->devs.d); __set_bit(i, dst->devs.d);
@ -443,7 +440,7 @@ int __bch2_dev_group_set(struct bch_fs *c, struct bch_dev *ca, const char *name)
if (ret) if (ret)
return 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); SET_BCH_MEMBER_GROUP(mi, v + 1);
return 0; return 0;
} }
@ -528,12 +525,11 @@ void bch2_opt_target_to_text(struct printbuf *out,
rcu_read_unlock(); rcu_read_unlock();
} else { } else {
struct bch_sb_field_members *mi = bch2_sb_get_members(sb); struct bch_member m = bch2_sb_member_get(sb, t.dev);
struct bch_member *m = mi->members + t.dev;
if (bch2_dev_exists(sb, mi, t.dev)) { if (bch2_dev_exists(sb, t.dev)) {
prt_printf(out, "Device "); prt_printf(out, "Device ");
pr_uuid(out, m->uuid.b); pr_uuid(out, m.uuid.b);
prt_printf(out, " (%u)", t.dev); prt_printf(out, " (%u)", t.dev);
} else { } else {
prt_printf(out, "Bad device %u", t.dev); prt_printf(out, "Bad device %u", t.dev);

View File

@ -91,6 +91,7 @@
x(ENOSPC, ENOSPC_sb_quota) \ x(ENOSPC, ENOSPC_sb_quota) \
x(ENOSPC, ENOSPC_sb_replicas) \ x(ENOSPC, ENOSPC_sb_replicas) \
x(ENOSPC, ENOSPC_sb_members) \ x(ENOSPC, ENOSPC_sb_members) \
x(ENOSPC, ENOSPC_sb_members_v2) \
x(ENOSPC, ENOSPC_sb_crypt) \ x(ENOSPC, ENOSPC_sb_crypt) \
x(ENOSPC, ENOSPC_btree_slot) \ x(ENOSPC, ENOSPC_btree_slot) \
x(ENOSPC, ENOSPC_snapshot_tree) \ x(ENOSPC, ENOSPC_snapshot_tree) \

View File

@ -1595,7 +1595,7 @@ static struct bch_fs *bch2_path_to_fs(const char *path)
static char **split_devs(const char *_dev_name, unsigned *nr) static char **split_devs(const char *_dev_name, unsigned *nr)
{ {
char *dev_name = NULL, **devs = NULL, *s; char *dev_name = NULL, **devs = NULL, *s;
size_t i, nr_devs = 0; size_t i = 0, nr_devs = 0;
dev_name = kstrdup(_dev_name, GFP_KERNEL); dev_name = kstrdup(_dev_name, GFP_KERNEL);
if (!dev_name) if (!dev_name)
@ -1610,9 +1610,7 @@ static char **split_devs(const char *_dev_name, unsigned *nr)
return NULL; return NULL;
} }
for (i = 0, s = dev_name; while ((s = strsep(&dev_name, ":")))
s;
(s = strchr(s, ':')) && (*s++ = '\0'))
devs[i++] = s; devs[i++] = s;
*nr = nr_devs; *nr = nr_devs;

View File

@ -780,6 +780,7 @@ static int bch2_inode_delete_keys(struct btree_trans *trans,
struct btree_iter iter; struct btree_iter iter;
struct bkey_s_c k; struct bkey_s_c k;
struct bkey_i delete; struct bkey_i delete;
struct bpos end = POS(inum.inum, U64_MAX);
u32 snapshot; u32 snapshot;
int ret = 0; int ret = 0;
@ -788,7 +789,7 @@ static int bch2_inode_delete_keys(struct btree_trans *trans,
* extent iterator: * extent iterator:
*/ */
bch2_trans_iter_init(trans, &iter, id, POS(inum.inum, 0), bch2_trans_iter_init(trans, &iter, id, POS(inum.inum, 0),
BTREE_ITER_INTENT|BTREE_ITER_NOT_EXTENTS); BTREE_ITER_INTENT);
while (1) { while (1) {
bch2_trans_begin(trans); bch2_trans_begin(trans);
@ -799,7 +800,7 @@ static int bch2_inode_delete_keys(struct btree_trans *trans,
bch2_btree_iter_set_snapshot(&iter, snapshot); bch2_btree_iter_set_snapshot(&iter, snapshot);
k = bch2_btree_iter_peek_upto(&iter, POS(inum.inum, U64_MAX)); k = bch2_btree_iter_peek_upto(&iter, end);
ret = bkey_err(k); ret = bkey_err(k);
if (ret) if (ret)
goto err; goto err;
@ -810,6 +811,11 @@ static int bch2_inode_delete_keys(struct btree_trans *trans,
bkey_init(&delete.k); bkey_init(&delete.k);
delete.k.p = iter.pos; delete.k.p = iter.pos;
if (iter.flags & BTREE_ITER_IS_EXTENTS)
bch2_key_resize(&delete.k,
bpos_min(end, k.k->p).offset -
iter.pos.offset);
ret = bch2_trans_update(trans, &iter, &delete, 0) ?: ret = bch2_trans_update(trans, &iter, &delete, 0) ?:
bch2_trans_commit(trans, NULL, NULL, bch2_trans_commit(trans, NULL, NULL,
BTREE_INSERT_NOFAIL); BTREE_INSERT_NOFAIL);

View File

@ -21,7 +21,7 @@ static int bch2_sb_journal_validate(struct bch_sb *sb,
struct printbuf *err) struct printbuf *err)
{ {
struct bch_sb_field_journal *journal = field_to_type(f, journal); struct bch_sb_field_journal *journal = field_to_type(f, journal);
struct bch_member *m = bch2_sb_get_members(sb)->members + sb->dev_idx; struct bch_member m = bch2_sb_member_get(sb, sb->dev_idx);
int ret = -BCH_ERR_invalid_sb_journal; int ret = -BCH_ERR_invalid_sb_journal;
unsigned nr; unsigned nr;
unsigned i; unsigned i;
@ -45,15 +45,15 @@ static int bch2_sb_journal_validate(struct bch_sb *sb,
goto err; goto err;
} }
if (b[0] < le16_to_cpu(m->first_bucket)) { if (b[0] < le16_to_cpu(m.first_bucket)) {
prt_printf(err, "journal bucket %llu before first bucket %u", prt_printf(err, "journal bucket %llu before first bucket %u",
b[0], le16_to_cpu(m->first_bucket)); b[0], le16_to_cpu(m.first_bucket));
goto err; goto err;
} }
if (b[nr - 1] >= le64_to_cpu(m->nbuckets)) { if (b[nr - 1] >= le64_to_cpu(m.nbuckets)) {
prt_printf(err, "journal bucket %llu past end of device (nbuckets %llu)", prt_printf(err, "journal bucket %llu past end of device (nbuckets %llu)",
b[nr - 1], le64_to_cpu(m->nbuckets)); b[nr - 1], le64_to_cpu(m.nbuckets));
goto err; goto err;
} }
@ -104,7 +104,7 @@ static int bch2_sb_journal_v2_validate(struct bch_sb *sb,
struct printbuf *err) struct printbuf *err)
{ {
struct bch_sb_field_journal_v2 *journal = field_to_type(f, journal_v2); struct bch_sb_field_journal_v2 *journal = field_to_type(f, journal_v2);
struct bch_member *m = bch2_sb_get_members(sb)->members + sb->dev_idx; struct bch_member m = bch2_sb_member_get(sb, sb->dev_idx);
int ret = -BCH_ERR_invalid_sb_journal; int ret = -BCH_ERR_invalid_sb_journal;
unsigned nr; unsigned nr;
unsigned i; unsigned i;
@ -130,15 +130,15 @@ static int bch2_sb_journal_v2_validate(struct bch_sb *sb,
goto err; goto err;
} }
if (b[0].start < le16_to_cpu(m->first_bucket)) { if (b[0].start < le16_to_cpu(m.first_bucket)) {
prt_printf(err, "journal bucket %llu before first bucket %u", prt_printf(err, "journal bucket %llu before first bucket %u",
b[0].start, le16_to_cpu(m->first_bucket)); b[0].start, le16_to_cpu(m.first_bucket));
goto err; goto err;
} }
if (b[nr - 1].end > le64_to_cpu(m->nbuckets)) { if (b[nr - 1].end > le64_to_cpu(m.nbuckets)) {
prt_printf(err, "journal bucket %llu past end of device (nbuckets %llu)", prt_printf(err, "journal bucket %llu past end of device (nbuckets %llu)",
b[nr - 1].end - 1, le64_to_cpu(m->nbuckets)); b[nr - 1].end - 1, le64_to_cpu(m.nbuckets));
goto err; goto err;
} }

View File

@ -12,6 +12,11 @@
#define x(t, n, ...) [n] = #t, #define x(t, n, ...) [n] = #t,
const char * const bch2_iops_measurements[] = {
BCH_IOPS_MEASUREMENTS()
NULL
};
const char * const bch2_error_actions[] = { const char * const bch2_error_actions[] = {
BCH_ERROR_ACTIONS() BCH_ERROR_ACTIONS()
NULL NULL

View File

@ -10,6 +10,7 @@
struct bch_fs; struct bch_fs;
extern const char * const bch2_iops_measurements[];
extern const char * const bch2_error_actions[]; extern const char * const bch2_error_actions[];
extern const char * const bch2_fsck_fix_opts[]; extern const char * const bch2_fsck_fix_opts[];
extern const char * const bch2_version_upgrade_opts[]; extern const char * const bch2_version_upgrade_opts[];

View File

@ -374,13 +374,12 @@ static int read_btree_roots(struct bch_fs *c)
ret = bch2_btree_root_read(c, i, &r->key, r->level); ret = bch2_btree_root_read(c, i, &r->key, r->level);
if (ret) { if (ret) {
__fsck_err(c, fsck_err(c,
btree_id_is_alloc(i)
? FSCK_CAN_IGNORE : 0,
"error reading btree root %s", "error reading btree root %s",
bch2_btree_ids[i]); bch2_btree_ids[i]);
if (btree_id_is_alloc(i)) if (btree_id_is_alloc(i))
c->sb.compat &= ~(1ULL << BCH_COMPAT_alloc_info); c->sb.compat &= ~(1ULL << BCH_COMPAT_alloc_info);
ret = 0;
} }
} }
@ -645,7 +644,7 @@ int bch2_fs_recovery(struct bch_fs *c)
{ {
struct bch_sb_field_clean *clean = NULL; struct bch_sb_field_clean *clean = NULL;
struct jset *last_journal_entry = NULL; struct jset *last_journal_entry = NULL;
u64 last_seq, blacklist_seq, journal_seq; u64 last_seq = 0, blacklist_seq, journal_seq;
bool write_sb = false; bool write_sb = false;
int ret = 0; int ret = 0;

View File

@ -805,7 +805,6 @@ static int bch2_cpu_replicas_validate(struct bch_replicas_cpu *cpu_r,
struct bch_sb *sb, struct bch_sb *sb,
struct printbuf *err) struct printbuf *err)
{ {
struct bch_sb_field_members *mi = bch2_sb_get_members(sb);
unsigned i, j; unsigned i, j;
sort_cmp_size(cpu_r->entries, sort_cmp_size(cpu_r->entries,
@ -837,7 +836,7 @@ static int bch2_cpu_replicas_validate(struct bch_replicas_cpu *cpu_r,
} }
for (j = 0; j < e->nr_devs; j++) for (j = 0; j < e->nr_devs; j++)
if (!bch2_dev_exists(sb, mi, e->devs[j])) { if (!bch2_dev_exists(sb, e->devs[j])) {
prt_printf(err, "invalid device %u in entry ", e->devs[j]); prt_printf(err, "invalid device %u in entry ", e->devs[j]);
bch2_replicas_entry_to_text(err, e); bch2_replicas_entry_to_text(err, e);
return -BCH_ERR_invalid_sb_replicas; return -BCH_ERR_invalid_sb_replicas;

View File

@ -2,77 +2,159 @@
#include "bcachefs.h" #include "bcachefs.h"
#include "disk_groups.h" #include "disk_groups.h"
#include "opts.h"
#include "replicas.h" #include "replicas.h"
#include "sb-members.h" #include "sb-members.h"
#include "super-io.h" #include "super-io.h"
/* Code for bch_sb_field_members: */ /* Code for bch_sb_field_members_v1: */
static int bch2_sb_members_validate(struct bch_sb *sb, static struct bch_member *members_v2_get_mut(struct bch_sb_field_members_v2 *mi, int i)
struct bch_sb_field *f,
struct printbuf *err)
{ {
struct bch_sb_field_members *mi = field_to_type(f, members); return (void *) mi->_members + (i * le16_to_cpu(mi->member_bytes));
unsigned i; }
if ((void *) (mi->members + sb->nr_devices) > struct bch_member *bch2_members_v2_get_mut(struct bch_sb *sb, int i)
vstruct_end(&mi->field)) { {
prt_printf(err, "too many devices for section size"); return members_v2_get_mut(bch2_sb_get_members_v2(sb), i);
return -BCH_ERR_invalid_sb_members; }
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_v1 *mi, int i)
{
return (void *) mi->_members + (i * BCH_MEMBER_V1_BYTES);
}
static struct bch_member members_v1_get(struct bch_sb_field_members_v1 *mi, int i)
{
struct bch_member ret, *p = members_v1_get_mut(mi, i);
memset(&ret, 0, sizeof(ret));
memcpy(&ret, p, min_t(size_t, sizeof(struct bch_member), sizeof(ret))); return ret;
}
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_v1 *mi1 = bch2_sb_get_members_v1(sb);
return members_v1_get(mi1, i);
}
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_v1 *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_v1(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);
} }
for (i = 0; i < sb->nr_devices; i++) { return sb_members_v2_resize_entries(c);
struct bch_member *m = mi->members + i; }
if (!bch2_member_exists(m)) int bch_members_cpy_v2_v1(struct bch_sb_handle *disk_sb)
continue; {
struct bch_sb_field_members_v1 *mi1;
struct bch_sb_field_members_v2 *mi2;
if (le64_to_cpu(m->nbuckets) > LONG_MAX) { mi1 = bch2_sb_resize_members_v1(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)", prt_printf(err, "device %u: too many buckets (got %llu, max %lu)",
i, le64_to_cpu(m->nbuckets), LONG_MAX); i, le64_to_cpu(m.nbuckets), LONG_MAX);
return -BCH_ERR_invalid_sb_members; return -BCH_ERR_invalid_sb_members;
} }
if (le64_to_cpu(m->nbuckets) - if (le64_to_cpu(m.nbuckets) -
le16_to_cpu(m->first_bucket) < BCH_MIN_NR_NBUCKETS) { le16_to_cpu(m.first_bucket) < BCH_MIN_NR_NBUCKETS) {
prt_printf(err, "device %u: not enough buckets (got %llu, max %u)", prt_printf(err, "device %u: not enough buckets (got %llu, max %u)",
i, le64_to_cpu(m->nbuckets), BCH_MIN_NR_NBUCKETS); i, le64_to_cpu(m.nbuckets), BCH_MIN_NR_NBUCKETS);
return -BCH_ERR_invalid_sb_members; return -BCH_ERR_invalid_sb_members;
} }
if (le16_to_cpu(m->bucket_size) < if (le16_to_cpu(m.bucket_size) <
le16_to_cpu(sb->block_size)) { le16_to_cpu(sb->block_size)) {
prt_printf(err, "device %u: bucket size %u smaller than block size %u", 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)); i, le16_to_cpu(m.bucket_size), le16_to_cpu(sb->block_size));
return -BCH_ERR_invalid_sb_members; return -BCH_ERR_invalid_sb_members;
} }
if (le16_to_cpu(m->bucket_size) < if (le16_to_cpu(m.bucket_size) <
BCH_SB_BTREE_NODE_SIZE(sb)) { BCH_SB_BTREE_NODE_SIZE(sb)) {
prt_printf(err, "device %u: bucket size %u smaller than btree node size %llu", 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)); i, le16_to_cpu(m.bucket_size), BCH_SB_BTREE_NODE_SIZE(sb));
return -BCH_ERR_invalid_sb_members; return -BCH_ERR_invalid_sb_members;
} }
}
return 0; return 0;
} }
static void bch2_sb_members_to_text(struct printbuf *out, struct bch_sb *sb, static void member_to_text(struct printbuf *out,
struct bch_sb_field *f) struct bch_member m,
struct bch_sb_field_disk_groups *gi,
struct bch_sb *sb,
int i)
{ {
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); unsigned data_have = bch2_sb_dev_has_data(sb, i);
u64 bucket_size = le16_to_cpu(m->bucket_size); u64 bucket_size = le16_to_cpu(m.bucket_size);
u64 device_size = le64_to_cpu(m->nbuckets) * bucket_size; u64 device_size = le64_to_cpu(m.nbuckets) * bucket_size;
if (!bch2_member_exists(m))
continue;
prt_printf(out, "Device:"); prt_printf(out, "Device:");
prt_tab(out); prt_tab(out);
@ -83,7 +165,7 @@ static void bch2_sb_members_to_text(struct printbuf *out, struct bch_sb *sb,
prt_printf(out, "UUID:"); prt_printf(out, "UUID:");
prt_tab(out); prt_tab(out);
pr_uuid(out, m->uuid.b); pr_uuid(out, m.uuid.b);
prt_newline(out); prt_newline(out);
prt_printf(out, "Size:"); prt_printf(out, "Size:");
@ -91,6 +173,13 @@ static void bch2_sb_members_to_text(struct printbuf *out, struct bch_sb *sb,
prt_units_u64(out, device_size << 9); prt_units_u64(out, device_size << 9);
prt_newline(out); prt_newline(out);
for (unsigned i = 0; i < BCH_IOPS_NR; i++) {
prt_printf(out, "%s iops:", bch2_iops_measurements[i]);
prt_tab(out);
prt_printf(out, "%u", le32_to_cpu(m.iops[i]));
prt_newline(out);
}
prt_printf(out, "Bucket size:"); prt_printf(out, "Bucket size:");
prt_tab(out); prt_tab(out);
prt_units_u64(out, bucket_size << 9); prt_units_u64(out, bucket_size << 9);
@ -98,18 +187,18 @@ static void bch2_sb_members_to_text(struct printbuf *out, struct bch_sb *sb,
prt_printf(out, "First bucket:"); prt_printf(out, "First bucket:");
prt_tab(out); prt_tab(out);
prt_printf(out, "%u", le16_to_cpu(m->first_bucket)); prt_printf(out, "%u", le16_to_cpu(m.first_bucket));
prt_newline(out); prt_newline(out);
prt_printf(out, "Buckets:"); prt_printf(out, "Buckets:");
prt_tab(out); prt_tab(out);
prt_printf(out, "%llu", le64_to_cpu(m->nbuckets)); prt_printf(out, "%llu", le64_to_cpu(m.nbuckets));
prt_newline(out); prt_newline(out);
prt_printf(out, "Last mount:"); prt_printf(out, "Last mount:");
prt_tab(out); prt_tab(out);
if (m->last_mount) if (m.last_mount)
pr_time(out, le64_to_cpu(m->last_mount)); pr_time(out, le64_to_cpu(m.last_mount));
else else
prt_printf(out, "(never)"); prt_printf(out, "(never)");
prt_newline(out); prt_newline(out);
@ -117,15 +206,15 @@ static void bch2_sb_members_to_text(struct printbuf *out, struct bch_sb *sb,
prt_printf(out, "State:"); prt_printf(out, "State:");
prt_tab(out); prt_tab(out);
prt_printf(out, "%s", prt_printf(out, "%s",
BCH_MEMBER_STATE(m) < BCH_MEMBER_STATE_NR BCH_MEMBER_STATE(&m) < BCH_MEMBER_STATE_NR
? bch2_member_states[BCH_MEMBER_STATE(m)] ? bch2_member_states[BCH_MEMBER_STATE(&m)]
: "unknown"); : "unknown");
prt_newline(out); prt_newline(out);
prt_printf(out, "Label:"); prt_printf(out, "Label:");
prt_tab(out); prt_tab(out);
if (BCH_MEMBER_GROUP(m)) { if (BCH_MEMBER_GROUP(&m)) {
unsigned idx = BCH_MEMBER_GROUP(m) - 1; unsigned idx = BCH_MEMBER_GROUP(&m) - 1;
if (idx < disk_groups_nr(gi)) if (idx < disk_groups_nr(gi))
prt_printf(out, "%s (%u)", prt_printf(out, "%s (%u)",
@ -139,8 +228,8 @@ static void bch2_sb_members_to_text(struct printbuf *out, struct bch_sb *sb,
prt_printf(out, "Data allowed:"); prt_printf(out, "Data allowed:");
prt_tab(out); prt_tab(out);
if (BCH_MEMBER_DATA_ALLOWED(m)) if (BCH_MEMBER_DATA_ALLOWED(&m))
prt_bitflags(out, bch2_data_types, BCH_MEMBER_DATA_ALLOWED(m)); prt_bitflags(out, bch2_data_types, BCH_MEMBER_DATA_ALLOWED(&m));
else else
prt_printf(out, "(none)"); prt_printf(out, "(none)");
prt_newline(out); prt_newline(out);
@ -155,19 +244,96 @@ static void bch2_sb_members_to_text(struct printbuf *out, struct bch_sb *sb,
prt_printf(out, "Discard:"); prt_printf(out, "Discard:");
prt_tab(out); prt_tab(out);
prt_printf(out, "%llu", BCH_MEMBER_DISCARD(m)); prt_printf(out, "%llu", BCH_MEMBER_DISCARD(&m));
prt_newline(out); prt_newline(out);
prt_printf(out, "Freespace initialized:"); prt_printf(out, "Freespace initialized:");
prt_tab(out); prt_tab(out);
prt_printf(out, "%llu", BCH_MEMBER_FREESPACE_INITIALIZED(m)); prt_printf(out, "%llu", BCH_MEMBER_FREESPACE_INITIALIZED(&m));
prt_newline(out); prt_newline(out);
printbuf_indent_sub(out, 2); 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_v1 *mi = field_to_type(f, members_v1);
unsigned i;
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 = members_v1_get(mi, i);
int ret = validate_member(err, m, sb, i);
if (ret)
return ret;
}
return 0;
}
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_v1 *mi = field_to_type(f, members_v1);
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_v1_get(mi, i);
member_to_text(out, m, gi, sb, i);
} }
} }
const struct bch_sb_field_ops bch_sb_field_ops_members = { const struct bch_sb_field_ops bch_sb_field_ops_members_v1 = {
.validate = bch2_sb_members_validate, .validate = bch2_sb_members_v1_validate,
.to_text = bch2_sb_members_to_text, .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,11 @@
#ifndef _BCACHEFS_SB_MEMBERS_H #ifndef _BCACHEFS_SB_MEMBERS_H
#define _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) static inline bool bch2_dev_is_online(struct bch_dev *ca)
{ {
return !percpu_ref_is_zero(&ca->io_ref); return !percpu_ref_is_zero(&ca->io_ref);
@ -171,6 +176,7 @@ static inline struct bch_devs_mask bch2_online_devs(struct bch_fs *c)
return devs; return devs;
} }
extern const struct bch_sb_field_ops bch_sb_field_ops_members; extern const struct bch_sb_field_ops bch_sb_field_ops_members_v1;
extern const struct bch_sb_field_ops bch_sb_field_ops_members_v2;
#endif /* _BCACHEFS_SB_MEMBERS_H */ #endif /* _BCACHEFS_SB_MEMBERS_H */

View File

@ -355,7 +355,7 @@ static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out,
{ {
struct bch_sb *sb = disk_sb->sb; struct bch_sb *sb = disk_sb->sb;
struct bch_sb_field *f; struct bch_sb_field *f;
struct bch_sb_field_members *mi; struct bch_sb_field_members_v1 *mi;
enum bch_opt_id opt_id; enum bch_opt_id opt_id;
u16 block_size; u16 block_size;
int ret; int ret;
@ -458,7 +458,7 @@ static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out,
} }
/* members must be validated first: */ /* members must be validated first: */
mi = bch2_sb_get_members(sb); mi = bch2_sb_get_members_v1(sb);
if (!mi) { if (!mi) {
prt_printf(out, "Invalid superblock: member info area missing"); prt_printf(out, "Invalid superblock: member info area missing");
return -BCH_ERR_invalid_sb_members_missing; return -BCH_ERR_invalid_sb_members_missing;
@ -469,7 +469,7 @@ static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out,
return ret; return ret;
vstruct_for_each(sb, f) { vstruct_for_each(sb, f) {
if (le32_to_cpu(f->type) == BCH_SB_FIELD_members) if (le32_to_cpu(f->type) == BCH_SB_FIELD_members_v1)
continue; continue;
ret = bch2_sb_field_validate(sb, f, out); ret = bch2_sb_field_validate(sb, f, out);
@ -485,7 +485,6 @@ static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out,
static void bch2_sb_update(struct bch_fs *c) static void bch2_sb_update(struct bch_fs *c)
{ {
struct bch_sb *src = c->disk_sb.sb; struct bch_sb *src = c->disk_sb.sb;
struct bch_sb_field_members *mi = bch2_sb_get_members(src);
struct bch_dev *ca; struct bch_dev *ca;
unsigned i; unsigned i;
@ -511,8 +510,10 @@ static void bch2_sb_update(struct bch_fs *c)
c->sb.features = le64_to_cpu(src->features[0]); c->sb.features = le64_to_cpu(src->features[0]);
c->sb.compat = le64_to_cpu(src->compat[0]); c->sb.compat = le64_to_cpu(src->compat[0]);
for_each_member_device(ca, c, i) for_each_member_device(ca, c, i) {
ca->mi = bch2_mi_to_cpu(mi->members + i); struct bch_member m = bch2_sb_member_get(src, i);
ca->mi = bch2_mi_to_cpu(&m);
}
} }
static int __copy_super(struct bch_sb_handle *dst_handle, struct bch_sb *src) static int __copy_super(struct bch_sb_handle *dst_handle, struct bch_sb *src)
@ -891,6 +892,7 @@ int bch2_write_super(struct bch_fs *c)
SET_BCH_SB_BIG_ENDIAN(c->disk_sb.sb, CPU_BIG_ENDIAN); SET_BCH_SB_BIG_ENDIAN(c->disk_sb.sb, CPU_BIG_ENDIAN);
bch2_sb_counters_from_cpu(c); bch2_sb_counters_from_cpu(c);
bch_members_cpy_v2_v1(&c->disk_sb);
for_each_online_member(ca, c, i) for_each_online_member(ca, c, i)
bch2_sb_from_fs(c, ca); bch2_sb_from_fs(c, ca);
@ -1125,7 +1127,6 @@ void bch2_sb_layout_to_text(struct printbuf *out, struct bch_sb_layout *l)
void bch2_sb_to_text(struct printbuf *out, struct bch_sb *sb, void bch2_sb_to_text(struct printbuf *out, struct bch_sb *sb,
bool print_layout, unsigned fields) bool print_layout, unsigned fields)
{ {
struct bch_sb_field_members *mi;
struct bch_sb_field *f; struct bch_sb_field *f;
u64 fields_have = 0; u64 fields_have = 0;
unsigned nr_devices = 0; unsigned nr_devices = 0;
@ -1133,15 +1134,8 @@ void bch2_sb_to_text(struct printbuf *out, struct bch_sb *sb,
if (!out->nr_tabstops) if (!out->nr_tabstops)
printbuf_tabstop_push(out, 44); printbuf_tabstop_push(out, 44);
mi = bch2_sb_get_members(sb); for (int i = 0; i < sb->nr_devices; i++)
if (mi) { nr_devices += bch2_dev_exists(sb, i);
struct bch_member *m;
for (m = mi->members;
m < mi->members + sb->nr_devices;
m++)
nr_devices += bch2_member_exists(m);
}
prt_printf(out, "External UUID:"); prt_printf(out, "External UUID:");
prt_tab(out); prt_tab(out);

View File

@ -6,6 +6,7 @@
#include "eytzinger.h" #include "eytzinger.h"
#include "super_types.h" #include "super_types.h"
#include "super.h" #include "super.h"
#include "sb-members.h"
#include <asm/byteorder.h> #include <asm/byteorder.h>
@ -89,7 +90,7 @@ static inline void bch2_check_set_feature(struct bch_fs *c, unsigned feat)
__bch2_check_set_feature(c, feat); __bch2_check_set_feature(c, feat);
} }
/* BCH_SB_FIELD_members: */ /* BCH_SB_FIELD_members_v1: */
static inline bool bch2_member_exists(struct bch_member *m) static inline bool bch2_member_exists(struct bch_member *m)
{ {
@ -97,11 +98,13 @@ static inline bool bch2_member_exists(struct bch_member *m)
} }
static inline bool bch2_dev_exists(struct bch_sb *sb, static inline bool bch2_dev_exists(struct bch_sb *sb,
struct bch_sb_field_members *mi,
unsigned dev) unsigned dev)
{ {
return dev < sb->nr_devices && if (dev < sb->nr_devices) {
bch2_member_exists(&mi->members[dev]); struct bch_member m = bch2_sb_member_get(sb, dev);
return bch2_member_exists(&m);
}
return false;
} }
static inline struct bch_member_cpu bch2_mi_to_cpu(struct bch_member *mi) static inline struct bch_member_cpu bch2_mi_to_cpu(struct bch_member *mi)

View File

@ -49,6 +49,7 @@
#include "recovery.h" #include "recovery.h"
#include "replicas.h" #include "replicas.h"
#include "sb-clean.h" #include "sb-clean.h"
#include "sb-members.h"
#include "snapshot.h" #include "snapshot.h"
#include "subvolume.h" #include "subvolume.h"
#include "super.h" #include "super.h"
@ -399,6 +400,10 @@ static int __bch2_fs_read_write(struct bch_fs *c, bool early)
bch_info(c, "going read-write"); bch_info(c, "going read-write");
ret = bch2_members_v2_init(c);
if (ret)
goto err;
ret = bch2_fs_mark_dirty(c); ret = bch2_fs_mark_dirty(c);
if (ret) if (ret)
goto err; goto err;
@ -662,7 +667,6 @@ err:
static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts) static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
{ {
struct bch_sb_field_members *mi;
struct bch_fs *c; struct bch_fs *c;
struct printbuf name = PRINTBUF; struct printbuf name = PRINTBUF;
unsigned i, iter_size; unsigned i, iter_size;
@ -858,9 +862,8 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
if (ret) if (ret)
goto err; goto err;
mi = bch2_sb_get_members(c->disk_sb.sb);
for (i = 0; i < c->sb.nr_devices; i++) for (i = 0; i < c->sb.nr_devices; i++)
if (bch2_dev_exists(c->disk_sb.sb, mi, i) && if (bch2_dev_exists(c->disk_sb.sb, i) &&
bch2_dev_alloc(c, i)) { bch2_dev_alloc(c, i)) {
ret = -EEXIST; ret = -EEXIST;
goto err; goto err;
@ -925,7 +928,6 @@ static void print_mount_opts(struct bch_fs *c)
int bch2_fs_start(struct bch_fs *c) int bch2_fs_start(struct bch_fs *c)
{ {
struct bch_sb_field_members *mi;
struct bch_dev *ca; struct bch_dev *ca;
time64_t now = ktime_get_real_seconds(); time64_t now = ktime_get_real_seconds();
unsigned i; unsigned i;
@ -939,12 +941,17 @@ int bch2_fs_start(struct bch_fs *c)
mutex_lock(&c->sb_lock); 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) for_each_online_member(ca, c, i)
bch2_sb_from_fs(c, ca); bch2_sb_from_fs(c, ca);
mi = bch2_sb_get_members(c->disk_sb.sb);
for_each_online_member(ca, c, i) 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); mutex_unlock(&c->sb_lock);
@ -997,16 +1004,12 @@ err:
static int bch2_dev_may_add(struct bch_sb *sb, struct bch_fs *c) static int bch2_dev_may_add(struct bch_sb *sb, struct bch_fs *c)
{ {
struct bch_sb_field_members *sb_mi; struct bch_member m = bch2_sb_member_get(sb, sb->dev_idx);
sb_mi = bch2_sb_get_members(sb);
if (!sb_mi)
return -BCH_ERR_member_info_missing;
if (le16_to_cpu(sb->block_size) != block_sectors(c)) if (le16_to_cpu(sb->block_size) != block_sectors(c))
return -BCH_ERR_mismatched_block_size; return -BCH_ERR_mismatched_block_size;
if (le16_to_cpu(sb_mi->members[sb->dev_idx].bucket_size) < if (le16_to_cpu(m.bucket_size) <
BCH_SB_BTREE_NODE_SIZE(c->disk_sb.sb)) BCH_SB_BTREE_NODE_SIZE(c->disk_sb.sb))
return -BCH_ERR_bucket_size_too_small; return -BCH_ERR_bucket_size_too_small;
@ -1017,12 +1020,11 @@ static int bch2_dev_in_fs(struct bch_sb *fs, struct bch_sb *sb)
{ {
struct bch_sb *newest = struct bch_sb *newest =
le64_to_cpu(fs->seq) > le64_to_cpu(sb->seq) ? fs : sb; le64_to_cpu(fs->seq) > le64_to_cpu(sb->seq) ? fs : sb;
struct bch_sb_field_members *mi = bch2_sb_get_members(newest);
if (!uuid_equal(&fs->uuid, &sb->uuid)) if (!uuid_equal(&fs->uuid, &sb->uuid))
return -BCH_ERR_device_not_a_member_of_filesystem; return -BCH_ERR_device_not_a_member_of_filesystem;
if (!bch2_dev_exists(newest, mi, sb->dev_idx)) if (!bch2_dev_exists(newest, sb->dev_idx))
return -BCH_ERR_device_has_been_removed; return -BCH_ERR_device_has_been_removed;
if (fs->block_size != sb->block_size) if (fs->block_size != sb->block_size)
@ -1192,15 +1194,14 @@ static void bch2_dev_attach(struct bch_fs *c, struct bch_dev *ca,
static int bch2_dev_alloc(struct bch_fs *c, unsigned dev_idx) static int bch2_dev_alloc(struct bch_fs *c, unsigned dev_idx)
{ {
struct bch_member *member = struct bch_member member = bch2_sb_member_get(c->disk_sb.sb, dev_idx);
bch2_sb_get_members(c->disk_sb.sb)->members + dev_idx;
struct bch_dev *ca = NULL; struct bch_dev *ca = NULL;
int ret = 0; int ret = 0;
if (bch2_fs_init_fault("dev_alloc")) if (bch2_fs_init_fault("dev_alloc"))
goto err; goto err;
ca = __bch2_dev_alloc(c, member); ca = __bch2_dev_alloc(c, &member);
if (!ca) if (!ca)
goto err; goto err;
@ -1335,7 +1336,6 @@ bool bch2_dev_state_allowed(struct bch_fs *c, struct bch_dev *ca,
static bool bch2_fs_may_start(struct bch_fs *c) static bool bch2_fs_may_start(struct bch_fs *c)
{ {
struct bch_sb_field_members *mi;
struct bch_dev *ca; struct bch_dev *ca;
unsigned i, flags = 0; unsigned i, flags = 0;
@ -1348,10 +1348,9 @@ static bool bch2_fs_may_start(struct bch_fs *c)
if (!c->opts.degraded && if (!c->opts.degraded &&
!c->opts.very_degraded) { !c->opts.very_degraded) {
mutex_lock(&c->sb_lock); mutex_lock(&c->sb_lock);
mi = bch2_sb_get_members(c->disk_sb.sb);
for (i = 0; i < c->disk_sb.sb->nr_devices; i++) { for (i = 0; i < c->disk_sb.sb->nr_devices; i++) {
if (!bch2_dev_exists(c->disk_sb.sb, mi, i)) if (!bch2_dev_exists(c->disk_sb.sb, i))
continue; continue;
ca = bch_dev_locked(c, i); ca = bch_dev_locked(c, i);
@ -1391,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, int __bch2_dev_set_state(struct bch_fs *c, struct bch_dev *ca,
enum bch_member_state new_state, int flags) enum bch_member_state new_state, int flags)
{ {
struct bch_sb_field_members *mi; struct bch_member *m;
int ret = 0; int ret = 0;
if (ca->mi.state == new_state) if (ca->mi.state == new_state)
@ -1406,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]); bch_notice(ca, "%s", bch2_member_states[new_state]);
mutex_lock(&c->sb_lock); mutex_lock(&c->sb_lock);
mi = bch2_sb_get_members(c->disk_sb.sb); m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
SET_BCH_MEMBER_STATE(&mi->members[ca->dev_idx], new_state); SET_BCH_MEMBER_STATE(m, new_state);
bch2_write_super(c); bch2_write_super(c);
mutex_unlock(&c->sb_lock); mutex_unlock(&c->sb_lock);
@ -1463,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) 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; unsigned dev_idx = ca->dev_idx, data;
int ret; int ret;
@ -1551,8 +1550,8 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
* this device must be gone: * this device must be gone:
*/ */
mutex_lock(&c->sb_lock); mutex_lock(&c->sb_lock);
mi = bch2_sb_get_members(c->disk_sb.sb); m = bch2_members_v2_get_mut(c->disk_sb.sb, dev_idx);
memset(&mi->members[dev_idx].uuid, 0, sizeof(mi->members[dev_idx].uuid)); memset(&m->uuid, 0, sizeof(m->uuid));
bch2_write_super(c); bch2_write_super(c);
@ -1575,7 +1574,7 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
struct bch_opts opts = bch2_opts_empty(); struct bch_opts opts = bch2_opts_empty();
struct bch_sb_handle sb; struct bch_sb_handle sb;
struct bch_dev *ca = NULL; struct bch_dev *ca = NULL;
struct bch_sb_field_members *mi; struct bch_sb_field_members_v2 *mi;
struct bch_member dev_mi; struct bch_member dev_mi;
unsigned dev_idx, nr_devices, u64s; unsigned dev_idx, nr_devices, u64s;
struct printbuf errbuf = PRINTBUF; struct printbuf errbuf = PRINTBUF;
@ -1588,7 +1587,7 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
goto err; goto err;
} }
dev_mi = bch2_sb_get_members(sb.sb)->members[sb.sb->dev_idx]; dev_mi = bch2_sb_member_get(sb.sb, sb.sb->dev_idx);
if (BCH_MEMBER_GROUP(&dev_mi)) { if (BCH_MEMBER_GROUP(&dev_mi)) {
bch2_disk_path_to_text(&label, sb.sb, BCH_MEMBER_GROUP(&dev_mi) - 1); bch2_disk_path_to_text(&label, sb.sb, BCH_MEMBER_GROUP(&dev_mi) - 1);
@ -1631,9 +1630,9 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
goto err_unlock; 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) + le32_to_cpu(mi->field.u64s) +
sizeof(dev_mi) / sizeof(u64))) { sizeof(dev_mi) / sizeof(u64))) {
ret = -BCH_ERR_ENOSPC_sb_members; ret = -BCH_ERR_ENOSPC_sb_members;
@ -1644,9 +1643,8 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
if (dynamic_fault("bcachefs:add:no_slot")) if (dynamic_fault("bcachefs:add:no_slot"))
goto no_slot; goto no_slot;
mi = bch2_sb_get_members(c->disk_sb.sb);
for (dev_idx = 0; dev_idx < BCH_SB_MEMBERS_MAX; dev_idx++) for (dev_idx = 0; dev_idx < BCH_SB_MEMBERS_MAX; dev_idx++)
if (!bch2_dev_exists(c->disk_sb.sb, mi, dev_idx)) if (!bch2_dev_exists(c->disk_sb.sb, dev_idx))
goto have_slot; goto have_slot;
no_slot: no_slot:
ret = -BCH_ERR_ENOSPC_sb_members; ret = -BCH_ERR_ENOSPC_sb_members;
@ -1655,20 +1653,21 @@ no_slot:
have_slot: have_slot:
nr_devices = max_t(unsigned, dev_idx + 1, c->sb.nr_devices); nr_devices = max_t(unsigned, dev_idx + 1, c->sb.nr_devices);
u64s = (sizeof(struct bch_sb_field_members) + u64s = DIV_ROUND_UP(sizeof(struct bch_sb_field_members_v2) +
sizeof(struct bch_member) * nr_devices) / sizeof(u64); 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) { if (!mi) {
ret = -BCH_ERR_ENOSPC_sb_members; ret = -BCH_ERR_ENOSPC_sb_members;
bch_err_msg(c, ret, "setting up new superblock"); bch_err_msg(c, ret, "setting up new superblock");
goto err_unlock; goto err_unlock;
} }
struct bch_member *m = bch2_members_v2_get_mut(c->disk_sb.sb, dev_idx);
/* success: */ /* success: */
mi->members[dev_idx] = dev_mi; *m = dev_mi;
mi->members[dev_idx].last_mount = cpu_to_le64(ktime_get_real_seconds()); m->last_mount = cpu_to_le64(ktime_get_real_seconds());
c->disk_sb.sb->nr_devices = nr_devices; c->disk_sb.sb->nr_devices = nr_devices;
ca->disk_sb.sb->dev_idx = dev_idx; ca->disk_sb.sb->dev_idx = dev_idx;
@ -1728,7 +1727,6 @@ int bch2_dev_online(struct bch_fs *c, const char *path)
{ {
struct bch_opts opts = bch2_opts_empty(); struct bch_opts opts = bch2_opts_empty();
struct bch_sb_handle sb = { NULL }; struct bch_sb_handle sb = { NULL };
struct bch_sb_field_members *mi;
struct bch_dev *ca; struct bch_dev *ca;
unsigned dev_idx; unsigned dev_idx;
int ret; int ret;
@ -1765,9 +1763,9 @@ int bch2_dev_online(struct bch_fs *c, const char *path)
__bch2_dev_read_write(c, ca); __bch2_dev_read_write(c, ca);
mutex_lock(&c->sb_lock); 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()); cpu_to_le64(ktime_get_real_seconds());
bch2_write_super(c); bch2_write_super(c);
@ -1809,10 +1807,12 @@ 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) int bch2_dev_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
{ {
struct bch_member *mi; struct bch_member *m;
u64 old_nbuckets;
int ret = 0; int ret = 0;
down_write(&c->state_lock); down_write(&c->state_lock);
old_nbuckets = ca->mi.nbuckets;
if (nbuckets < ca->mi.nbuckets) { if (nbuckets < ca->mi.nbuckets) {
bch_err(ca, "Cannot shrink yet"); bch_err(ca, "Cannot shrink yet");
@ -1839,12 +1839,24 @@ int bch2_dev_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
goto err; goto err;
mutex_lock(&c->sb_lock); mutex_lock(&c->sb_lock);
mi = &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);
mi->nbuckets = cpu_to_le64(nbuckets); m->nbuckets = cpu_to_le64(nbuckets);
bch2_write_super(c); bch2_write_super(c);
mutex_unlock(&c->sb_lock); mutex_unlock(&c->sb_lock);
if (ca->mi.freespace_initialized) {
ret = bch2_dev_freespace_init(c, ca, old_nbuckets, nbuckets);
if (ret)
goto err;
/*
* XXX: this is all wrong transactionally - we'll be able to do
* this correctly after the disk space accounting rewrite
*/
ca->usage_base->d[BCH_DATA_free].buckets += nbuckets - old_nbuckets;
}
bch2_recalc_capacity(c); bch2_recalc_capacity(c);
err: err:
up_write(&c->state_lock); up_write(&c->state_lock);
@ -1875,7 +1887,6 @@ struct bch_fs *bch2_fs_open(char * const *devices, unsigned nr_devices,
{ {
struct bch_sb_handle *sb = NULL; struct bch_sb_handle *sb = NULL;
struct bch_fs *c = NULL; struct bch_fs *c = NULL;
struct bch_sb_field_members *mi;
unsigned i, best_sb = 0; unsigned i, best_sb = 0;
struct printbuf errbuf = PRINTBUF; struct printbuf errbuf = PRINTBUF;
int ret = 0; int ret = 0;
@ -1906,12 +1917,10 @@ struct bch_fs *bch2_fs_open(char * const *devices, unsigned nr_devices,
le64_to_cpu(sb[best_sb].sb->seq)) le64_to_cpu(sb[best_sb].sb->seq))
best_sb = i; best_sb = i;
mi = bch2_sb_get_members(sb[best_sb].sb);
i = 0; i = 0;
while (i < nr_devices) { while (i < nr_devices) {
if (i != best_sb && if (i != best_sb &&
!bch2_dev_exists(sb[best_sb].sb, mi, sb[i].sb->dev_idx)) { !bch2_dev_exists(sb[best_sb].sb, sb[i].sb->dev_idx)) {
pr_info("%pg has been removed, skipping", sb[i].bdev); pr_info("%pg has been removed, skipping", sb[i].bdev);
bch2_free_super(&sb[i]); bch2_free_super(&sb[i]);
array_remove_item(sb, nr_devices, i); array_remove_item(sb, nr_devices, i);

View File

@ -962,7 +962,7 @@ STORE(bch2_dev)
bool v = strtoul_or_return(buf); bool v = strtoul_or_return(buf);
mutex_lock(&c->sb_lock); 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)) { if (v != BCH_MEMBER_DISCARD(mi)) {
SET_BCH_MEMBER_DISCARD(mi, v); SET_BCH_MEMBER_DISCARD(mi, v);
@ -975,7 +975,7 @@ STORE(bch2_dev)
u64 v = strtoul_or_return(buf); u64 v = strtoul_or_return(buf);
mutex_lock(&c->sb_lock); 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)) { if (v + 1 != BCH_MEMBER_DURABILITY(mi)) {
SET_BCH_MEMBER_DURABILITY(mi, v + 1); SET_BCH_MEMBER_DURABILITY(mi, v + 1);