bcachefs: Don't rely on snapshot_tree.master_subvol for reattaching
authorKent Overstreet <kent.overstreet@linux.dev>
Sat, 21 Dec 2024 04:56:42 +0000 (23:56 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Fri, 10 Jan 2025 04:38:41 +0000 (23:38 -0500)
Previously, fsck used the snapshot tree's master subvol for finding the
root inode number - but the master subvol might have been deleting, and
setting a new one should be a user operation; meaning we can't rely on
it existing.

Fortunately, for finding the root inode number in a tree of snapshots,
finding any associated subvolume works.

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

index c0df2587a5804c66ebe5eaecb56871f490eb8f2e..4590cd0c7c90587a9c185acddf79ed3f16fddc34 100644 (file)
        x(ENOENT,                       ENOENT_dev_not_found)                   \
        x(ENOENT,                       ENOENT_dev_idx_not_found)               \
        x(ENOENT,                       ENOENT_inode_no_backpointer)            \
+       x(ENOENT,                       ENOENT_no_snapshot_tree_subvol)         \
        x(ENOTEMPTY,                    ENOTEMPTY_dir_not_empty)                \
        x(ENOTEMPTY,                    ENOTEMPTY_subvol_not_empty)             \
        x(EEXIST,                       EEXIST_str_hash_set)                    \
index ea8c8ed069408f081777763c37f7a50abe236acc..206fc046610a732c3afe85e8a1226efc702cf7e8 100644 (file)
@@ -205,6 +205,36 @@ err:
        return ret;
 }
 
+/*
+ * Find any subvolume associated with a tree of snapshots
+ * We can't rely on master_subvol - it might have been deleted.
+ */
+static int find_snapshot_tree_subvol(struct btree_trans *trans,
+                                    u32 tree_id, u32 *subvol)
+{
+       struct btree_iter iter;
+       struct bkey_s_c k;
+       int ret;
+
+       for_each_btree_key_norestart(trans, iter, BTREE_ID_snapshots, POS_MIN, 0, k, ret) {
+               if (k.k->type != KEY_TYPE_snapshot)
+                       continue;
+
+               struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot(k);
+               if (le32_to_cpu(s.v->tree) != tree_id)
+                       continue;
+
+               if (s.v->subvol) {
+                       *subvol = le32_to_cpu(s.v->subvol);
+                       goto found;
+               }
+       }
+       ret = -BCH_ERR_ENOENT_no_snapshot_tree_subvol;
+found:
+       bch2_trans_iter_exit(trans, &iter);
+       return ret;
+}
+
 /* Get lost+found, create if it doesn't exist: */
 static int lookup_lostfound(struct btree_trans *trans, u32 snapshot,
                            struct bch_inode_unpacked *lostfound,
@@ -223,19 +253,24 @@ static int lookup_lostfound(struct btree_trans *trans, u32 snapshot,
        if (ret)
                return ret;
 
-       subvol_inum root_inum = { .subvol = le32_to_cpu(st.master_subvol) };
+       u32 subvolid;
+       ret = find_snapshot_tree_subvol(trans,
+                               bch2_snapshot_tree(c, snapshot), &subvolid);
+       bch_err_msg(c, ret, "finding subvol associated with snapshot tree %u",
+                   bch2_snapshot_tree(c, snapshot));
+       if (ret)
+               return ret;
 
        struct bch_subvolume subvol;
-       ret = bch2_subvolume_get(trans, le32_to_cpu(st.master_subvol), false, &subvol);
-       bch_err_msg(c, ret, "looking up root subvol %u for snapshot %u",
-                   le32_to_cpu(st.master_subvol), snapshot);
+       ret = bch2_subvolume_get(trans, subvolid, false, &subvol);
+       bch_err_msg(c, ret, "looking up subvol %u for snapshot %u", subvolid, snapshot);
        if (ret)
                return ret;
 
        if (!subvol.inode) {
                struct btree_iter iter;
                struct bkey_i_subvolume *subvol = bch2_bkey_get_mut_typed(trans, &iter,
-                               BTREE_ID_subvolumes, POS(0, le32_to_cpu(st.master_subvol)),
+                               BTREE_ID_subvolumes, POS(0, subvolid),
                                0, subvolume);
                ret = PTR_ERR_OR_ZERO(subvol);
                if (ret)
@@ -245,13 +280,16 @@ static int lookup_lostfound(struct btree_trans *trans, u32 snapshot,
                bch2_trans_iter_exit(trans, &iter);
        }
 
-       root_inum.inum = le64_to_cpu(subvol.inode);
+       subvol_inum root_inum = {
+               .subvol = subvolid,
+               .inum = le64_to_cpu(subvol.inode)
+       };
 
        struct bch_inode_unpacked root_inode;
        struct bch_hash_info root_hash_info;
        ret = lookup_inode(trans, root_inum.inum, snapshot, &root_inode);
        bch_err_msg(c, ret, "looking up root inode %llu for subvol %u",
-                   root_inum.inum, le32_to_cpu(st.master_subvol));
+                   root_inum.inum, subvolid);
        if (ret)
                return ret;