]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/fs-common.c
Update bcachefs sources to 39a84c99af2d bcachefs: Clamp replicas_required to replicas
[bcachefs-tools-debian] / libbcachefs / fs-common.c
index 1c1ea0f0c692a6fdd4c262ef184bbcdda32d154f..255857ca583734ceff89aa3df38e6523080c4dde 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);
@@ -242,7 +243,7 @@ int bch2_unlink_trans(struct btree_trans *trans,
                      struct bch_inode_unpacked *dir_u,
                      struct bch_inode_unpacked *inode_u,
                      const struct qstr *name,
-                     bool deleting_snapshot)
+                     bool deleting_subvol)
 {
        struct bch_fs *c = trans->c;
        struct btree_iter dir_iter = { NULL };
@@ -260,8 +261,8 @@ int bch2_unlink_trans(struct btree_trans *trans,
 
        dir_hash = bch2_hash_info_init(c, dir_u);
 
-       ret = __bch2_dirent_lookup_trans(trans, &dirent_iter, dir, &dir_hash,
-                                        name, &inum, BTREE_ITER_INTENT);
+       ret = bch2_dirent_lookup_trans(trans, &dirent_iter, dir, &dir_hash,
+                                      name, &inum, BTREE_ITER_INTENT);
        if (ret)
                goto err;
 
@@ -270,18 +271,25 @@ int bch2_unlink_trans(struct btree_trans *trans,
        if (ret)
                goto err;
 
-       if (!deleting_snapshot && S_ISDIR(inode_u->bi_mode)) {
+       if (!deleting_subvol && S_ISDIR(inode_u->bi_mode)) {
                ret = bch2_empty_dir_trans(trans, inum);
                if (ret)
                        goto err;
        }
 
-       if (deleting_snapshot && !inode_u->bi_subvol) {
+       if (deleting_subvol && !inode_u->bi_subvol) {
                ret = -BCH_ERR_ENOENT_not_subvol;
                goto err;
        }
 
-       if (deleting_snapshot || inode_u->bi_subvol) {
+       if (inode_u->bi_subvol) {
+               /* Recursive subvolume destroy not allowed (yet?) */
+               ret = bch2_subvol_has_children(trans, inode_u->bi_subvol);
+               if (ret)
+                       goto err;
+       }
+
+       if (deleting_subvol || inode_u->bi_subvol) {
                ret = bch2_subvolume_unlink(trans, inode_u->bi_subvol);
                if (ret)
                        goto err;
@@ -349,6 +357,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 +434,36 @@ 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 ||
+            (dst_inum.inum && !dst_inode_u->bi_subvol))) {
+               ret = -EXDEV;
+               goto err;
+       }
+
+       if (src_inode_u->bi_parent_subvol)
+               src_inode_u->bi_parent_subvol = dst_dir.subvol;
+
+       if ((mode == BCH_RENAME_EXCHANGE) &&
+           dst_inode_u->bi_parent_subvol)
+               dst_inode_u->bi_parent_subvol = src_dir.subvol;
+
        src_inode_u->bi_dir             = dst_dir_u->bi_inum;
        src_inode_u->bi_dir_offset      = dst_offset;