bcachefs: Check subvol <-> inode pointers in check_subvol()
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 6 Feb 2024 03:20:12 +0000 (22:20 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 14 Mar 2024 01:22:23 +0000 (21:22 -0400)
Subvolumes and subvolume root inodes point to each other: this verifies
the subvolume -> inode -> subvolme path.

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

index ee298a47425fad16a99adb05f59e395b5618a6d0..418d731b47d217bdfff1e9766460a2bcf4a40269 100644 (file)
@@ -324,7 +324,7 @@ int bch2_inode_unpack(struct bkey_s_c k,
        return bch2_inode_unpack_slowpath(k, unpacked);
 }
 
-static int bch2_inode_peek_nowarn(struct btree_trans *trans,
+int bch2_inode_peek_nowarn(struct btree_trans *trans,
                    struct btree_iter *iter,
                    struct bch_inode_unpacked *inode,
                    subvol_inum inum, unsigned flags)
index b8da7ff8069d082020a20d213441779ba145f2e1..9a9353c001c2a5fa62e80dc1e2b2705cc8534ab5 100644 (file)
@@ -95,6 +95,8 @@ struct bkey_i *bch2_inode_to_v3(struct btree_trans *, struct bkey_i *);
 
 void bch2_inode_unpacked_to_text(struct printbuf *, struct bch_inode_unpacked *);
 
+int bch2_inode_peek_nowarn(struct btree_trans *, struct btree_iter *,
+                   struct bch_inode_unpacked *, subvol_inum, unsigned);
 int bch2_inode_peek(struct btree_trans *, struct btree_iter *,
                    struct bch_inode_unpacked *, subvol_inum, unsigned);
 
index 7c67c28d3ef88ff32d1805257faf37ebc79f0d2d..e7ee52c39990cc8dff2dafbd928a0da51f0f6d50 100644 (file)
@@ -42,6 +42,36 @@ static int check_subvol(struct btree_trans *trans,
                return ret ?: -BCH_ERR_transaction_restart_nested;
        }
 
+       struct bch_inode_unpacked inode;
+       struct btree_iter inode_iter = {};
+       ret = bch2_inode_peek_nowarn(trans, &inode_iter, &inode,
+                                   (subvol_inum) { k.k->p.offset, le64_to_cpu(subvol.v->inode) },
+                                   0);
+       bch2_trans_iter_exit(trans, &inode_iter);
+
+       if (ret && !bch2_err_matches(ret, ENOENT))
+               return ret;
+
+       if (fsck_err_on(ret, c, subvol_to_missing_root,
+                       "subvolume %llu points to missing subvolume root %llu:%u",
+                       k.k->p.offset, le64_to_cpu(subvol.v->inode),
+                       le32_to_cpu(subvol.v->snapshot))) {
+               ret = bch2_subvolume_delete(trans, iter->pos.offset);
+               bch_err_msg(c, ret, "deleting subvolume %llu", iter->pos.offset);
+               return ret ?: -BCH_ERR_transaction_restart_nested;
+       }
+
+       if (fsck_err_on(inode.bi_subvol != subvol.k->p.offset,
+                       c, subvol_root_wrong_bi_subvol,
+                       "subvol root %llu:%u has wrong bi_subvol field: got %u, should be %llu",
+                       inode.bi_inum, inode_iter.k.p.snapshot,
+                       inode.bi_subvol, subvol.k->p.offset)) {
+               inode.bi_subvol = subvol.k->p.offset;
+               ret = __bch2_fsck_write_inode(trans, &inode, le32_to_cpu(subvol.v->snapshot));
+               if (ret)
+                       goto err;
+       }
+
        if (!BCH_SUBVOLUME_SNAP(subvol.v)) {
                u32 snapshot_root = bch2_snapshot_root(c, le32_to_cpu(subvol.v->snapshot));
                u32 snapshot_tree;
@@ -73,6 +103,7 @@ static int check_subvol(struct btree_trans *trans,
                }
        }
 
+err:
 fsck_err:
        return ret;
 }