bcachefs: bch_subvolume::fs_path_parent
authorKent Overstreet <kent.overstreet@linux.dev>
Thu, 8 Feb 2024 23:39:42 +0000 (18:39 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 14 Mar 2024 01:22:24 +0000 (21:22 -0400)
Record the filesystem path heirarchy for subvolumes in bch_subvolume

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/bcachefs_format.h
fs/bcachefs/fs-common.c
fs/bcachefs/fsck.c
fs/bcachefs/sb-downgrade.c
fs/bcachefs/subvolume.c
fs/bcachefs/subvolume.h
fs/bcachefs/subvolume_format.h

index 14f613617913e1a3ef0e93c51caa041041f822c2..772eff5555f716da716ca40d76e71675c9d9128f 100644 (file)
@@ -840,7 +840,8 @@ struct bch_sb_field_downgrade {
        x(snapshot_skiplists,           BCH_VERSION(1,  1))             \
        x(deleted_inodes,               BCH_VERSION(1,  2))             \
        x(rebalance_work,               BCH_VERSION(1,  3))             \
-       x(member_seq,                   BCH_VERSION(1,  4))
+       x(member_seq,                   BCH_VERSION(1,  4))             \
+       x(subvolume_fs_parent,          BCH_VERSION(1,  5))
 
 enum bcachefs_metadata_version {
        bcachefs_metadata_version_min = 9,
index 523507e38887bf9fd4aaacf6ece326d04e6edd16..2aa3881105972be8666224bc1e24cdbff06e5626 100644 (file)
@@ -107,6 +107,7 @@ int bch2_create_trans(struct btree_trans *trans,
                u32 new_subvol, dir_snapshot;
 
                ret = bch2_subvolume_create(trans, new_inode->bi_inum,
+                                           dir.subvol,
                                            snapshot_src.subvol,
                                            &new_subvol, &snapshot,
                                            (flags & BCH_CREATE_SNAPSHOT_RO) != 0);
@@ -349,6 +350,22 @@ bool bch2_reinherit_attrs(struct bch_inode_unpacked *dst_u,
        return ret;
 }
 
+static int subvol_update_parent(struct btree_trans *trans, u32 subvol, u32 new_parent)
+{
+       struct btree_iter iter;
+       struct bkey_i_subvolume *s =
+               bch2_bkey_get_mut_typed(trans, &iter,
+                       BTREE_ID_subvolumes, POS(0, subvol),
+                       BTREE_ITER_CACHED, subvolume);
+       int ret = PTR_ERR_OR_ZERO(s);
+       if (ret)
+               return ret;
+
+       s->v.fs_path_parent = cpu_to_le32(new_parent);
+       bch2_trans_iter_exit(trans, &iter);
+       return 0;
+}
+
 int bch2_rename_trans(struct btree_trans *trans,
                      subvol_inum src_dir, struct bch_inode_unpacked *src_dir_u,
                      subvol_inum dst_dir, struct bch_inode_unpacked *dst_dir_u,
@@ -410,6 +427,21 @@ int bch2_rename_trans(struct btree_trans *trans,
                        goto err;
        }
 
+       if (src_inode_u->bi_subvol &&
+           dst_dir.subvol != src_inode_u->bi_parent_subvol) {
+               ret = subvol_update_parent(trans, src_inode_u->bi_subvol, dst_dir.subvol);
+               if (ret)
+                       goto err;
+       }
+
+       if (mode == BCH_RENAME_EXCHANGE &&
+           dst_inode_u->bi_subvol &&
+           src_dir.subvol != dst_inode_u->bi_parent_subvol) {
+               ret = subvol_update_parent(trans, dst_inode_u->bi_subvol, src_dir.subvol);
+               if (ret)
+                       goto err;
+       }
+
        /* Can't move across subvolumes, unless it's a subvolume root: */
        if (src_dir.subvol != dst_dir.subvol &&
            (!src_inode_u->bi_subvol ||
index 572ff61c036d7f05066f7759b175d849e1ed5ef4..797a5711216c37052aef6e9630d86266029a459c 100644 (file)
@@ -1744,11 +1744,12 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
                                  struct bkey_s_c_dirent d)
 {
        struct bch_fs *c = trans->c;
+       struct btree_iter subvol_iter = {};
        struct bch_inode_unpacked subvol_root;
        u32 parent_subvol = le32_to_cpu(d.v->d_parent_subvol);
        u32 target_subvol = le32_to_cpu(d.v->d_child_subvol);
-       u32 target_snapshot, parent_snapshot;
-       u64 target_inum, parent_inum;
+       u32 parent_snapshot;
+       u64 parent_inum;
        struct printbuf buf = PRINTBUF;
        int ret = 0;
 
@@ -1777,8 +1778,11 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
                new_dirent->v.d_parent_subvol = cpu_to_le32(new_parent_subvol);
        }
 
-       ret = subvol_lookup(trans, target_subvol,
-                           &target_snapshot, &target_inum);
+       struct bkey_s_c_subvolume s =
+               bch2_bkey_get_iter_typed(trans, &subvol_iter,
+                                        BTREE_ID_subvolumes, POS(0, target_subvol),
+                                        0, subvolume);
+       ret = bkey_err(s.s_c);
        if (ret && !bch2_err_matches(ret, ENOENT))
                return ret;
 
@@ -1791,8 +1795,24 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
                goto out;
        }
 
-       ret = lookup_inode(trans, target_inum,
-                          &subvol_root, &target_snapshot);
+       if (fsck_err_on(le32_to_cpu(s.v->fs_path_parent) != parent_subvol,
+                       c, subvol_fs_path_parent_wrong,
+                       "subvol with wrong fs_path_parent, should be be %u\n%s",
+                       parent_subvol,
+                       (bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf))) {
+               struct bkey_i_subvolume *n =
+                       bch2_bkey_make_mut_typed(trans, &subvol_iter, &s.s_c, 0, subvolume);
+               ret = PTR_ERR_OR_ZERO(n);
+               if (ret)
+                       goto err;
+
+               n->v.fs_path_parent = cpu_to_le32(parent_subvol);
+       }
+
+       u64 target_inum = le64_to_cpu(s.v->inode);
+       u32 target_snapshot = le32_to_cpu(s.v->snapshot);
+
+       ret = lookup_inode(trans, target_inum, &subvol_root, &target_snapshot);
        if (ret && !bch2_err_matches(ret, ENOENT))
                return ret;
 
@@ -1814,6 +1834,7 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
 out:
 err:
 fsck_err:
+       bch2_trans_iter_exit(trans, &subvol_iter);
        printbuf_exit(&buf);
        return ret;
 }
index 441dcb1bf160e917d531d1a5ea955cf0238f0844..12ee83e9e2518ebeacd44c49496a2de1a92be91e 100644 (file)
          BIT_ULL(BCH_RECOVERY_PASS_check_inodes),              \
          BCH_FSCK_ERR_unlinked_inode_not_on_deleted_list)      \
        x(rebalance_work,                                       \
-         BIT_ULL(BCH_RECOVERY_PASS_set_fs_needs_rebalance))
+         BIT_ULL(BCH_RECOVERY_PASS_set_fs_needs_rebalance))    \
+       x(subvolume_fs_parent,                                  \
+         BIT_ULL(BCH_RECOVERY_PASS_check_dirents),             \
+         BCH_FSCK_ERR_subvol_fs_path_parent_wrong)
 
 #define DOWNGRADE_TABLE()
 
index a0be103b48fe03f2bf9d627e417f33b61922dc10..d365e84367a3d8c675acd05821961dd3189320f6 100644 (file)
@@ -20,6 +20,7 @@ static int check_subvol(struct btree_trans *trans,
        struct bch_fs *c = trans->c;
        struct bkey_s_c_subvolume subvol;
        struct bch_snapshot snapshot;
+       struct printbuf buf = PRINTBUF;
        unsigned snapid;
        int ret = 0;
 
@@ -42,6 +43,20 @@ static int check_subvol(struct btree_trans *trans,
                return ret ?: -BCH_ERR_transaction_restart_nested;
        }
 
+       if (fsck_err_on(subvol.k->p.offset == BCACHEFS_ROOT_SUBVOL &&
+                       subvol.v->fs_path_parent,
+                       c, subvol_root_fs_path_parent_nonzero,
+                       "root subvolume has nonzero fs_path_parent\n%s",
+                       (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
+               struct bkey_i_subvolume *n =
+                       bch2_bkey_make_mut_typed(trans, iter, &subvol.s_c, 0, subvolume);
+               ret = PTR_ERR_OR_ZERO(n);
+               if (ret)
+                       goto err;
+
+               n->v.fs_path_parent = 0;
+       }
+
        struct bch_inode_unpacked inode;
        struct btree_iter inode_iter = {};
        ret = bch2_inode_peek_nowarn(trans, &inode_iter, &inode,
@@ -102,9 +117,9 @@ static int check_subvol(struct btree_trans *trans,
                        SET_BCH_SUBVOLUME_SNAP(&s->v, true);
                }
        }
-
 err:
 fsck_err:
+       printbuf_exit(&buf);
        return ret;
 }
 
@@ -143,8 +158,10 @@ void bch2_subvolume_to_text(struct printbuf *out, struct bch_fs *c,
                   le64_to_cpu(s.v->inode),
                   le32_to_cpu(s.v->snapshot));
 
-       if (bkey_val_bytes(s.k) > offsetof(struct bch_subvolume, creation_parent))
+       if (bkey_val_bytes(s.k) > offsetof(struct bch_subvolume, creation_parent)) {
                prt_printf(out, " creation_parent %u", le32_to_cpu(s.v->creation_parent));
+               prt_printf(out, " fs_parent %u", le32_to_cpu(s.v->fs_path_parent));
+       }
 }
 
 static __always_inline int
@@ -391,6 +408,7 @@ int bch2_subvolume_unlink(struct btree_trans *trans, u32 subvolid)
 }
 
 int bch2_subvolume_create(struct btree_trans *trans, u64 inode,
+                         u32 parent_subvolid,
                          u32 src_subvolid,
                          u32 *new_subvolid,
                          u32 *new_snapshotid,
@@ -451,6 +469,7 @@ int bch2_subvolume_create(struct btree_trans *trans, u64 inode,
        new_subvol->v.snapshot          = cpu_to_le32(new_nodes[0]);
        new_subvol->v.inode             = cpu_to_le64(inode);
        new_subvol->v.creation_parent   = cpu_to_le32(src_subvolid);
+       new_subvol->v.fs_path_parent    = cpu_to_le32(parent_subvolid);
        new_subvol->v.otime.lo          = cpu_to_le64(bch2_current_time(c));
        new_subvol->v.otime.hi          = 0;
 
index a6f56f66e27cb7699402f089ef89a2f1355077c4..a2b0dc1303c2551cd98f31e7af52ad9af3dc1463 100644 (file)
@@ -30,8 +30,7 @@ int bch2_delete_dead_snapshots(struct bch_fs *);
 void bch2_delete_dead_snapshots_async(struct bch_fs *);
 
 int bch2_subvolume_unlink(struct btree_trans *, u32);
-int bch2_subvolume_create(struct btree_trans *, u64, u32,
-                         u32 *, u32 *, bool);
+int bch2_subvolume_create(struct btree_trans *, u64, u32, u32, u32 *, u32 *, bool);
 
 int bch2_fs_subvolumes_init(struct bch_fs *);
 
index b81cf0c6119d87b3fa0bd96eeb40f6a096aa38e1..e029df7ba89f5244b65c99d021252d753207d3bd 100644 (file)
@@ -20,7 +20,7 @@ struct bch_subvolume {
         * this subvolume:
         */
        __le32                  creation_parent;
-       __le32                  pad;
+       __le32                  fs_path_parent;
        bch_le128               otime;
 };