bcachefs: Fix bkey format generation for 32 bit fields
authorKent Overstreet <kent.overstreet@gmail.com>
Sun, 21 Mar 2021 03:55:36 +0000 (23:55 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:54 +0000 (17:08 -0400)
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>
fs/bcachefs/bcachefs_format.h
fs/bcachefs/bkey.c
fs/bcachefs/move.c
fs/bcachefs/recovery.c

index e2df0f7182b4a7d3a184cf8c9e2e67e57bf5add7..0a615fe6c1c18baa8db0e12f74549d31e31a4cec 100644 (file)
@@ -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: */
index 6417307f42b9b481f6242d8e1be367f0d06e9092..aeac07e2cb320c40e3b5b95308bc8809f3fa0bfc 100644 (file)
@@ -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);
index ed18abf8bf1415f6aafcff8e2b9af1d2d8fdf943..de3554e3854bc867a965d0510b4007b17b2479b6 100644 (file)
@@ -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);
index e322dc35f99279b1dd3b8c9b6685a503aa43eb9c..edcf6389d2fdf31d25f86f76aa12fcb2b7c4f43e 100644 (file)
@@ -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);