Commit e01dacf7 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Fix bkey format generation for 32 bit fields

Having a packed format that can represent a field larger than the
unpacked type breaks bkey_packed_successor() assertions - we need to fix this to start using the snapshot filed.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent a4805d66
...@@ -1371,9 +1371,10 @@ enum bch_sb_feature { ...@@ -1371,9 +1371,10 @@ enum bch_sb_feature {
}; };
enum bch_sb_compat { enum bch_sb_compat {
BCH_COMPAT_FEAT_ALLOC_INFO = 0, BCH_COMPAT_FEAT_ALLOC_INFO = 0,
BCH_COMPAT_FEAT_ALLOC_METADATA = 1, BCH_COMPAT_FEAT_ALLOC_METADATA = 1,
BCH_COMPAT_FEAT_EXTENTS_ABOVE_BTREE_UPDATES_DONE = 2, BCH_COMPAT_FEAT_EXTENTS_ABOVE_BTREE_UPDATES_DONE = 2,
BCH_COMPAT_FEAT_BFORMAT_OVERFLOW_DONE = 3,
}; };
/* options: */ /* options: */
......
...@@ -554,7 +554,12 @@ void bch2_bkey_format_add_pos(struct bkey_format_state *s, struct bpos p) ...@@ -554,7 +554,12 @@ void bch2_bkey_format_add_pos(struct bkey_format_state *s, struct bpos p)
static void set_format_field(struct bkey_format *f, enum bch_bkey_fields i, static void set_format_field(struct bkey_format *f, enum bch_bkey_fields i,
unsigned bits, u64 offset) unsigned bits, u64 offset)
{ {
offset = bits == 64 ? 0 : min(offset, U64_MAX - ((1ULL << bits) - 1)); unsigned unpacked_bits = bch2_bkey_format_current.bits_per_field[i];
u64 unpacked_max = ~((~0ULL << 1) << (unpacked_bits - 1));
bits = min(bits, unpacked_bits);
offset = bits == unpacked_bits ? 0 : min(offset, unpacked_max - ((1ULL << bits) - 1));
f->bits_per_field[i] = bits; f->bits_per_field[i] = bits;
f->field_offset[i] = cpu_to_le64(offset); f->field_offset[i] = cpu_to_le64(offset);
......
...@@ -829,13 +829,38 @@ static enum data_cmd migrate_btree_pred(struct bch_fs *c, void *arg, ...@@ -829,13 +829,38 @@ static enum data_cmd migrate_btree_pred(struct bch_fs *c, void *arg,
return migrate_pred(c, arg, bkey_i_to_s_c(&b->key), io_opts, data_opts); return migrate_pred(c, arg, bkey_i_to_s_c(&b->key), io_opts, data_opts);
} }
static bool bformat_needs_redo(struct bkey_format *f)
{
unsigned i;
for (i = 0; i < f->nr_fields; i++) {
unsigned unpacked_bits = bch2_bkey_format_current.bits_per_field[i];
u64 unpacked_mask = ~((~0ULL << 1) << (unpacked_bits - 1));
u64 field_offset = le64_to_cpu(f->field_offset[i]);
if (f->bits_per_field[i] > unpacked_bits)
return true;
if ((f->bits_per_field[i] == unpacked_bits) && field_offset)
return true;
if (((field_offset + ((1ULL << f->bits_per_field[i]) - 1)) &
unpacked_mask) <
field_offset)
return true;
}
return false;
}
static enum data_cmd rewrite_old_nodes_pred(struct bch_fs *c, void *arg, static enum data_cmd rewrite_old_nodes_pred(struct bch_fs *c, void *arg,
struct btree *b, struct btree *b,
struct bch_io_opts *io_opts, struct bch_io_opts *io_opts,
struct data_opts *data_opts) struct data_opts *data_opts)
{ {
if (b->version_ondisk != c->sb.version || if (b->version_ondisk != c->sb.version ||
btree_node_need_rewrite(b)) { btree_node_need_rewrite(b) ||
bformat_needs_redo(&b->format)) {
data_opts->target = 0; data_opts->target = 0;
data_opts->nr_replicas = 1; data_opts->nr_replicas = 1;
data_opts->btree_insert_flags = 0; data_opts->btree_insert_flags = 0;
...@@ -856,6 +881,7 @@ int bch2_scan_old_btree_nodes(struct bch_fs *c, struct bch_move_stats *stats) ...@@ -856,6 +881,7 @@ int bch2_scan_old_btree_nodes(struct bch_fs *c, struct bch_move_stats *stats)
if (!ret) { if (!ret) {
mutex_lock(&c->sb_lock); mutex_lock(&c->sb_lock);
c->disk_sb.sb->compat[0] |= 1ULL << BCH_COMPAT_FEAT_EXTENTS_ABOVE_BTREE_UPDATES_DONE; c->disk_sb.sb->compat[0] |= 1ULL << BCH_COMPAT_FEAT_EXTENTS_ABOVE_BTREE_UPDATES_DONE;
c->disk_sb.sb->compat[0] |= 1ULL << BCH_COMPAT_FEAT_BFORMAT_OVERFLOW_DONE;
c->disk_sb.sb->version_min = c->disk_sb.sb->version; c->disk_sb.sb->version_min = c->disk_sb.sb->version;
bch2_write_super(c); bch2_write_super(c);
mutex_unlock(&c->sb_lock); mutex_unlock(&c->sb_lock);
......
...@@ -1201,7 +1201,8 @@ int bch2_fs_recovery(struct bch_fs *c) ...@@ -1201,7 +1201,8 @@ int bch2_fs_recovery(struct bch_fs *c)
bch_verbose(c, "quotas done"); bch_verbose(c, "quotas done");
} }
if (!(c->sb.compat & (1ULL << BCH_COMPAT_FEAT_EXTENTS_ABOVE_BTREE_UPDATES_DONE))) { if (!(c->sb.compat & (1ULL << BCH_COMPAT_FEAT_EXTENTS_ABOVE_BTREE_UPDATES_DONE)) ||
!(c->sb.compat & (1ULL << BCH_COMPAT_FEAT_BFORMAT_OVERFLOW_DONE))) {
struct bch_move_stats stats = { 0 }; struct bch_move_stats stats = { 0 };
bch_verbose(c, "scanning for old btree nodes"); bch_verbose(c, "scanning for old btree nodes");
...@@ -1287,6 +1288,7 @@ int bch2_fs_initialize(struct bch_fs *c) ...@@ -1287,6 +1288,7 @@ int bch2_fs_initialize(struct bch_fs *c)
c->disk_sb.sb->features[0] |= 1ULL << BCH_FEATURE_atomic_nlink; c->disk_sb.sb->features[0] |= 1ULL << BCH_FEATURE_atomic_nlink;
c->disk_sb.sb->features[0] |= BCH_SB_FEATURES_ALL; c->disk_sb.sb->features[0] |= BCH_SB_FEATURES_ALL;
c->disk_sb.sb->compat[0] |= 1ULL << BCH_COMPAT_FEAT_EXTENTS_ABOVE_BTREE_UPDATES_DONE; c->disk_sb.sb->compat[0] |= 1ULL << BCH_COMPAT_FEAT_EXTENTS_ABOVE_BTREE_UPDATES_DONE;
c->disk_sb.sb->compat[0] |= 1ULL << BCH_COMPAT_FEAT_BFORMAT_OVERFLOW_DONE;
bch2_write_super(c); bch2_write_super(c);
mutex_unlock(&c->sb_lock); mutex_unlock(&c->sb_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment