bcachefs: Fixes for snapshot_tree.master_subvol
authorKent Overstreet <kent.overstreet@linux.dev>
Fri, 20 Dec 2024 09:46:00 +0000 (04:46 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Fri, 10 Jan 2025 04:38:41 +0000 (23:38 -0500)
Ensure that snapshot_tree.master_subvol is cleared when we delete the
master subvolume in a tree of snapshots, and allow for snapshot trees
that don't have a master subvolume in fsck.

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

index 1506445eaaf4ee4d4559b9ffea570f60deb5c44f..cf6b3256d18839f1a85c4dedf7b33c68ded3b143 100644 (file)
@@ -495,6 +495,9 @@ static int check_snapshot_tree(struct btree_trans *trans,
                goto err;
        }
 
+       if (!st.v->master_subvol)
+               goto out;
+
        ret = bch2_subvolume_get(trans, le32_to_cpu(st.v->master_subvol), false, &subvol);
        if (ret && !bch2_err_matches(ret, ENOENT))
                goto err;
@@ -538,6 +541,7 @@ static int check_snapshot_tree(struct btree_trans *trans,
                u->v.master_subvol = cpu_to_le32(subvol_id);
                st = snapshot_tree_i_to_s_c(u);
        }
+out:
 err:
 fsck_err:
        bch2_trans_iter_exit(trans, &snapshot_iter);
@@ -1037,13 +1041,11 @@ fsck_err:
 int bch2_snapshot_node_set_deleted(struct btree_trans *trans, u32 id)
 {
        struct btree_iter iter;
-       struct bkey_i_snapshot *s;
-       int ret = 0;
-
-       s = bch2_bkey_get_mut_typed(trans, &iter,
+       struct bkey_i_snapshot *s =
+               bch2_bkey_get_mut_typed(trans, &iter,
                                    BTREE_ID_snapshots, POS(0, id),
                                    0, snapshot);
-       ret = PTR_ERR_OR_ZERO(s);
+       int ret = PTR_ERR_OR_ZERO(s);
        if (unlikely(ret)) {
                bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT),
                                        trans->c, "missing snapshot %u", id);
index 0e756e35c3d9d935052559eb0ab3586ed781c77c..e3d0475232e53bcb451501294357f22c848432f7 100644 (file)
@@ -409,26 +409,56 @@ static int bch2_subvolumes_reparent(struct btree_trans *trans, u32 subvolid_to_d
  */
 static int __bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
 {
-       struct btree_iter iter;
-       struct bkey_s_c_subvolume subvol;
-       u32 snapid;
-       int ret = 0;
+       struct btree_iter subvol_iter = {}, snapshot_iter = {}, snapshot_tree_iter = {};
 
-       subvol = bch2_bkey_get_iter_typed(trans, &iter,
+       struct bkey_s_c_subvolume subvol =
+               bch2_bkey_get_iter_typed(trans, &subvol_iter,
                                BTREE_ID_subvolumes, POS(0, subvolid),
                                BTREE_ITER_cached|BTREE_ITER_intent,
                                subvolume);
-       ret = bkey_err(subvol);
+       int ret = bkey_err(subvol);
        bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT), trans->c,
                                "missing subvolume %u", subvolid);
        if (ret)
-               return ret;
+               goto err;
 
-       snapid = le32_to_cpu(subvol.v->snapshot);
+       u32 snapid = le32_to_cpu(subvol.v->snapshot);
+
+       struct bkey_s_c_snapshot snapshot =
+               bch2_bkey_get_iter_typed(trans, &snapshot_iter,
+                               BTREE_ID_snapshots, POS(0, snapid),
+                               0, snapshot);
+       ret = bkey_err(subvol);
+       bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT), trans->c,
+                               "missing snapshot %u", snapid);
+       if (ret)
+               goto err;
+
+       u32 treeid = le32_to_cpu(snapshot.v->tree);
 
-       ret =   bch2_btree_delete_at(trans, &iter, 0) ?:
+       struct bkey_s_c_snapshot_tree snapshot_tree =
+               bch2_bkey_get_iter_typed(trans, &snapshot_tree_iter,
+                               BTREE_ID_snapshot_trees, POS(0, treeid),
+                               0, snapshot_tree);
+
+       if (le32_to_cpu(snapshot_tree.v->master_subvol) == subvolid) {
+               struct bkey_i_snapshot_tree *snapshot_tree_mut =
+                       bch2_bkey_make_mut_typed(trans, &snapshot_tree_iter,
+                                                &snapshot_tree.s_c,
+                                                0, snapshot_tree);
+               ret = PTR_ERR_OR_ZERO(snapshot_tree_mut);
+               if (ret)
+                       goto err;
+
+               snapshot_tree_mut->v.master_subvol = 0;
+       }
+
+       ret =   bch2_btree_delete_at(trans, &subvol_iter, 0) ?:
                bch2_snapshot_node_set_deleted(trans, snapid);
-       bch2_trans_iter_exit(trans, &iter);
+err:
+       bch2_trans_iter_exit(trans, &snapshot_tree_iter);
+       bch2_trans_iter_exit(trans, &snapshot_iter);
+       bch2_trans_iter_exit(trans, &subvol_iter);
        return ret;
 }