bcachefs: Check for dirents to overwritten inodes
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 31 Dec 2024 20:59:02 +0000 (15:59 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Fri, 10 Jan 2025 04:38:42 +0000 (23:38 -0500)
This fixes various "dirent to missing inode" errors.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/fsck.c
fs/bcachefs/sb-errors_format.h

index 206fc046610a732c3afe85e8a1226efc702cf7e8..3917d75f3c987e167fa5711ae3082b903afeb6aa 100644 (file)
@@ -832,11 +832,13 @@ struct inode_walker {
        struct bpos                     last_pos;
 
        DARRAY(struct inode_walker_entry) inodes;
+       snapshot_id_list                deletes;
 };
 
 static void inode_walker_exit(struct inode_walker *w)
 {
        darray_exit(&w->inodes);
+       darray_exit(&w->deletes);
 }
 
 static struct inode_walker inode_walker_init(void)
@@ -960,8 +962,9 @@ static int get_visible_inodes(struct btree_trans *trans,
        int ret;
 
        w->inodes.nr = 0;
+       w->deletes.nr = 0;
 
-       for_each_btree_key_norestart(trans, iter, BTREE_ID_inodes, POS(0, inum),
+       for_each_btree_key_reverse_norestart(trans, iter, BTREE_ID_inodes, SPOS(0, inum, s->pos.snapshot),
                           BTREE_ITER_all_snapshots, k, ret) {
                if (k.k->p.offset != inum)
                        break;
@@ -969,10 +972,13 @@ static int get_visible_inodes(struct btree_trans *trans,
                if (!ref_visible(c, s, s->pos.snapshot, k.k->p.snapshot))
                        continue;
 
-               if (bkey_is_inode(k.k))
-                       add_inode(c, w, k);
+               if (snapshot_list_has_ancestor(c, &w->deletes, k.k->p.snapshot))
+                       continue;
 
-               if (k.k->p.snapshot >= s->pos.snapshot)
+               ret = bkey_is_inode(k.k)
+                       ? add_inode(c, w, k)
+                       : snapshot_list_add(c, &w->deletes, k.k->p.snapshot);
+               if (ret)
                        break;
        }
        bch2_trans_iter_exit(trans, &iter);
@@ -2380,6 +2386,30 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
                        if (ret)
                                goto err;
                }
+
+               darray_for_each(target->deletes, i)
+                       if (fsck_err_on(!snapshot_list_has_id(&s->ids, *i),
+                                       trans, dirent_to_overwritten_inode,
+                                       "dirent points to inode overwritten in snapshot %u:\n%s",
+                                       *i,
+                                       (printbuf_reset(&buf),
+                                        bch2_bkey_val_to_text(&buf, c, k),
+                                        buf.buf))) {
+                               struct btree_iter delete_iter;
+                               bch2_trans_iter_init(trans, &delete_iter,
+                                                    BTREE_ID_dirents,
+                                                    SPOS(k.k->p.inode, k.k->p.offset, *i),
+                                                    BTREE_ITER_intent);
+                               ret =   bch2_btree_iter_traverse(&delete_iter) ?:
+                                       bch2_hash_delete_at(trans, bch2_dirent_hash_desc,
+                                                         hash_info,
+                                                         &delete_iter,
+                                                         BTREE_UPDATE_internal_snapshot_node);
+                               bch2_trans_iter_exit(trans, &delete_iter);
+                               if (ret)
+                                       goto err;
+
+                       }
        }
 
        ret = bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc);
index e26317c367f74575af88e222c9718a14274db5d9..80b6d589808ba84dbdceba7a1ae12f0613e27203 100644 (file)
@@ -256,6 +256,7 @@ enum bch_fsck_flags {
        x(dirent_in_missing_dir_inode,                          227,    0)              \
        x(dirent_in_non_dir_inode,                              228,    0)              \
        x(dirent_to_missing_inode,                              229,    0)              \
+       x(dirent_to_overwritten_inode,                          302,    0)              \
        x(dirent_to_missing_subvol,                             230,    0)              \
        x(dirent_to_itself,                                     231,    0)              \
        x(quota_type_invalid,                                   232,    0)              \
@@ -312,7 +313,7 @@ enum bch_fsck_flags {
        x(logged_op_but_clean,                                  283,    FSCK_AUTOFIX)   \
        x(compression_opt_not_marked_in_sb,                     295,    FSCK_AUTOFIX)   \
        x(compression_type_not_marked_in_sb,                    296,    FSCK_AUTOFIX)   \
-       x(MAX,                                                  302,    0)
+       x(MAX,                                                  303,    0)
 
 enum bch_sb_error_id {
 #define x(t, n, ...) BCH_FSCK_ERR_##t = n,