We're going to be doing some snapshot deletion performance improvements,
and those will strictly require that if an extent/dirent/xattr is
present, an inode is present in that snapshot ID.

We already check for this, but we don't repair it on disk: this patch
adds that repair and turns it into a real fsck_err().

Signed-off-by: Kent Overstreet <[email protected]>
---
 fs/bcachefs/fsck.c             | 44 ++++++++++++++++------------------
 fs/bcachefs/sb-errors_format.h |  3 ++-
 2 files changed, 23 insertions(+), 24 deletions(-)

diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
index f0aa3c7479e1..dd88113a7c70 100644
--- a/fs/bcachefs/fsck.c
+++ b/fs/bcachefs/fsck.c
@@ -862,9 +862,9 @@ static int get_inodes_all_snapshots(struct btree_trans 
*trans,
 }
 
 static struct inode_walker_entry *
-lookup_inode_for_snapshot(struct bch_fs *c, struct inode_walker *w, struct 
bkey_s_c k)
+lookup_inode_for_snapshot(struct btree_trans *trans, struct inode_walker *w, 
struct bkey_s_c k)
 {
-       bool is_whiteout = k.k->type == KEY_TYPE_whiteout;
+       struct bch_fs *c = trans->c;
 
        struct inode_walker_entry *i;
        __darray_for_each(w->inodes, i)
@@ -875,34 +875,32 @@ lookup_inode_for_snapshot(struct bch_fs *c, struct 
inode_walker *w, struct bkey_
 found:
        BUG_ON(k.k->p.snapshot > i->inode.bi_snapshot);
 
-       if (k.k->p.snapshot != i->inode.bi_snapshot && !is_whiteout) {
-               struct inode_walker_entry new = *i;
-
-               new.inode.bi_snapshot   = k.k->p.snapshot;
-               new.count               = 0;
-               new.i_size              = 0;
-
-               struct printbuf buf = PRINTBUF;
-               bch2_bkey_val_to_text(&buf, c, k);
+       struct printbuf buf = PRINTBUF;
+       int ret = 0;
 
-               bch_info(c, "have key for inode %llu:%u but have inode in 
ancestor snapshot %u\n"
+       if (fsck_err_on(k.k->p.snapshot != i->inode.bi_snapshot,
+                       trans, snapshot_key_missing_inode_snapshot,
+                        "have key for inode %llu:%u but have inode in ancestor 
snapshot %u\n"
                         "unexpected because we should always update the inode 
when we update a key in that inode\n"
                         "%s",
-                        w->last_pos.inode, k.k->p.snapshot, 
i->inode.bi_snapshot, buf.buf);
-               printbuf_exit(&buf);
+                        w->last_pos.inode, k.k->p.snapshot, 
i->inode.bi_snapshot,
+                        (bch2_bkey_val_to_text(&buf, c, k),
+                         buf.buf))) {
+               struct bch_inode_unpacked new = i->inode;
 
-               while (i > w->inodes.data && i[-1].inode.bi_snapshot > 
k.k->p.snapshot)
-                       --i;
+               new.bi_snapshot = k.k->p.snapshot;
 
-               size_t pos = i - w->inodes.data;
-               int ret = darray_insert_item(&w->inodes, pos, new);
-               if (ret)
-                       return ERR_PTR(ret);
-
-               i = w->inodes.data + pos;
+               ret = __bch2_fsck_write_inode(trans, &new) ?:
+                       bch2_trans_commit(trans, NULL, NULL, 0) ?:
+                       -BCH_ERR_transaction_restart_nested;
+               goto fsck_err;
        }
 
+       printbuf_exit(&buf);
        return i;
+fsck_err:
+       printbuf_exit(&buf);
+       return ERR_PTR(ret);
 }
 
 static struct inode_walker_entry *walk_inode(struct btree_trans *trans,
@@ -917,7 +915,7 @@ static struct inode_walker_entry *walk_inode(struct 
btree_trans *trans,
 
        w->last_pos = k.k->p;
 
-       return lookup_inode_for_snapshot(trans->c, w, k);
+       return lookup_inode_for_snapshot(trans, w, k);
 }
 
 static int get_visible_inodes(struct btree_trans *trans,
diff --git a/fs/bcachefs/sb-errors_format.h b/fs/bcachefs/sb-errors_format.h
index 6389f6e0f8dc..82bc1906aa00 100644
--- a/fs/bcachefs/sb-errors_format.h
+++ b/fs/bcachefs/sb-errors_format.h
@@ -216,6 +216,7 @@ enum bch_fsck_flags {
        x(inode_str_hash_invalid,                               194,    0)      
        \
        x(inode_v3_fields_start_bad,                            195,    0)      
        \
        x(inode_snapshot_mismatch,                              196,    0)      
        \
+       x(snapshot_key_missing_inode_snapshot,                  314,    
FSCK_AUTOFIX)   \
        x(inode_unlinked_but_clean,                             197,    0)      
        \
        x(inode_unlinked_but_nlink_nonzero,                     198,    0)      
        \
        x(inode_unlinked_and_not_open,                          281,    0)      
        \
@@ -323,7 +324,7 @@ enum bch_fsck_flags {
        x(dirent_stray_data_after_cf_name,                      305,    0)      
        \
        x(rebalance_work_incorrectly_set,                       309,    
FSCK_AUTOFIX)   \
        x(rebalance_work_incorrectly_unset,                     310,    
FSCK_AUTOFIX)   \
-       x(MAX,                                                  314,    0)
+       x(MAX,                                                  315,    0)
 
 enum bch_sb_error_id {
 #define x(t, n, ...) BCH_FSCK_ERR_##t = n,
-- 
2.49.0


Reply via email to