diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2021-03-20 23:55:36 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:08:54 -0400 |
commit | e01dacf76c0c6a5fc6963b7857773b3d58740acb (patch) | |
tree | 6fd41c33ecef8708c2d1732cc68ad835475cfc2a /fs/bcachefs | |
parent | a4805d6672aac04784af132f0e11ac1dfb208079 (diff) | |
download | lwn-e01dacf76c0c6a5fc6963b7857773b3d58740acb.tar.gz lwn-e01dacf76c0c6a5fc6963b7857773b3d58740acb.zip |
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: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs')
-rw-r--r-- | fs/bcachefs/bcachefs_format.h | 5 | ||||
-rw-r--r-- | fs/bcachefs/bkey.c | 7 | ||||
-rw-r--r-- | fs/bcachefs/move.c | 28 | ||||
-rw-r--r-- | fs/bcachefs/recovery.c | 4 |
4 files changed, 39 insertions, 5 deletions
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h index e2df0f7182b4..0a615fe6c1c1 100644 --- a/fs/bcachefs/bcachefs_format.h +++ b/fs/bcachefs/bcachefs_format.h @@ -1371,9 +1371,10 @@ enum bch_sb_feature { }; enum bch_sb_compat { - BCH_COMPAT_FEAT_ALLOC_INFO = 0, - BCH_COMPAT_FEAT_ALLOC_METADATA = 1, + BCH_COMPAT_FEAT_ALLOC_INFO = 0, + BCH_COMPAT_FEAT_ALLOC_METADATA = 1, BCH_COMPAT_FEAT_EXTENTS_ABOVE_BTREE_UPDATES_DONE = 2, + BCH_COMPAT_FEAT_BFORMAT_OVERFLOW_DONE = 3, }; /* options: */ diff --git a/fs/bcachefs/bkey.c b/fs/bcachefs/bkey.c index 6417307f42b9..aeac07e2cb32 100644 --- a/fs/bcachefs/bkey.c +++ b/fs/bcachefs/bkey.c @@ -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, 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->field_offset[i] = cpu_to_le64(offset); diff --git a/fs/bcachefs/move.c b/fs/bcachefs/move.c index ed18abf8bf14..de3554e3854b 100644 --- a/fs/bcachefs/move.c +++ b/fs/bcachefs/move.c @@ -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); } +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, struct btree *b, struct bch_io_opts *io_opts, struct data_opts *data_opts) { 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->nr_replicas = 1; 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) if (!ret) { 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_BFORMAT_OVERFLOW_DONE; c->disk_sb.sb->version_min = c->disk_sb.sb->version; bch2_write_super(c); mutex_unlock(&c->sb_lock); diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c index e322dc35f992..edcf6389d2fd 100644 --- a/fs/bcachefs/recovery.c +++ b/fs/bcachefs/recovery.c @@ -1201,7 +1201,8 @@ use_clean: 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 }; bch_verbose(c, "scanning for old btree nodes"); @@ -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] |= 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_BFORMAT_OVERFLOW_DONE; bch2_write_super(c); mutex_unlock(&c->sb_lock); |