bcachefs: Add repair code for out of order keys in a btree node.
authorKent Overstreet <kent.overstreet@gmail.com>
Mon, 29 Mar 2021 04:19:05 +0000 (00:19 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:58 +0000 (17:08 -0400)
This just drops the offending key - in the bug report where this was
seen, it was clearly a single bit memory error, and fsck will fix the
missing key.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_io.c

index bc09f937742582c86910605e571d467136f34d74..fc94782afb605e09b1cc70164a8d00a60826a63d 100644 (file)
@@ -578,6 +578,10 @@ static int validate_bset(struct bch_fs *c, struct bch_dev *ca,
                mutex_unlock(&c->sb_lock);
        }
 
+       btree_err_on(BSET_SEPARATE_WHITEOUTS(i),
+                    BTREE_ERR_FATAL, c, ca, b, i,
+                    "BSET_SEPARATE_WHITEOUTS no longer supported");
+
        if (btree_err_on(b->written + sectors > c->opts.btree_node_size,
                         BTREE_ERR_FIXABLE, c, ca, b, i,
                         "bset past end of btree node")) {
@@ -660,14 +664,8 @@ static int validate_bset_keys(struct bch_fs *c, struct btree *b,
 {
        unsigned version = le16_to_cpu(i->version);
        struct bkey_packed *k, *prev = NULL;
-       bool seen_non_whiteout = false;
        int ret = 0;
 
-       if (!BSET_SEPARATE_WHITEOUTS(i)) {
-               seen_non_whiteout = true;
-               *whiteout_u64s = 0;
-       }
-
        for (k = i->start;
             k != vstruct_last(i);) {
                struct bkey_s u;
@@ -719,18 +717,7 @@ static int validate_bset_keys(struct bch_fs *c, struct btree *b,
                                    BSET_BIG_ENDIAN(i), write,
                                    &b->format, k);
 
-               /*
-                * with the separate whiteouts thing (used for extents), the
-                * second set of keys actually can have whiteouts too, so we
-                * can't solely go off bkey_deleted()...
-                */
-
-               if (!seen_non_whiteout &&
-                   (!bkey_deleted(k) ||
-                    (prev && bkey_iter_cmp(b, prev, k) > 0))) {
-                       *whiteout_u64s = k->_data - i->_data;
-                       seen_non_whiteout = true;
-               } else if (prev && bkey_iter_cmp(b, prev, k) > 0) {
+               if (prev && bkey_iter_cmp(b, prev, k) > 0) {
                        char buf1[80];
                        char buf2[80];
                        struct bkey up = bkey_unpack_key(b, prev);
@@ -739,10 +726,15 @@ static int validate_bset_keys(struct bch_fs *c, struct btree *b,
                        bch2_bkey_to_text(&PBUF(buf2), u.k);
 
                        bch2_dump_bset(c, b, i, 0);
-                       btree_err(BTREE_ERR_FATAL, c, NULL, b, i,
-                                 "keys out of order: %s > %s",
-                                 buf1, buf2);
-                       /* XXX: repair this */
+
+                       if (btree_err(BTREE_ERR_FIXABLE, c, NULL, b, i,
+                                     "keys out of order: %s > %s",
+                                     buf1, buf2)) {
+                               i->u64s = cpu_to_le16(le16_to_cpu(i->u64s) - k->u64s);
+                               memmove_u64s_down(k, bkey_next(k),
+                                                 (u64 *) vstruct_end(i) - (u64 *) k);
+                               continue;
+                       }
                }
 
                prev = k;