summaryrefslogtreecommitdiffstats
path: root/fs/bcachefs/fs-common.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-09-30 20:09:08 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:09:13 -0400
commit7bd68c73044f1ba39f505082bbed3b2e26f69a13 (patch)
tree31f2ddc21449891c29d64af7ce8087622e7a04c7 /fs/bcachefs/fs-common.c
parent107fe5af562303cda985c6bb72d36dbcd2076f06 (diff)
downloadlinux-7bd68c73044f1ba39f505082bbed3b2e26f69a13.tar.gz
linux-7bd68c73044f1ba39f505082bbed3b2e26f69a13.tar.bz2
linux-7bd68c73044f1ba39f505082bbed3b2e26f69a13.zip
bcachefs: Snapshot deletion fix
When we delete a snapshot, we unlink the inode but we don't want to run the inode_rm path - the unlink path deletes the subvolume directly, which does everything we need. Also allowing the inode_rm path to run was getting us "missing subvolume" errors. There's still another bug with snapshot deletion: we need to make snapshot deletion a multi stage process, where we unlink the root dentry, then tear down the page cache, then delete the snapshot. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Diffstat (limited to 'fs/bcachefs/fs-common.c')
-rw-r--r--fs/bcachefs/fs-common.c30
1 files changed, 23 insertions, 7 deletions
diff --git a/fs/bcachefs/fs-common.c b/fs/bcachefs/fs-common.c
index 00c7ba17f6c8..c49de741e1e3 100644
--- a/fs/bcachefs/fs-common.c
+++ b/fs/bcachefs/fs-common.c
@@ -267,18 +267,33 @@ int bch2_unlink_trans(struct btree_trans *trans,
if (ret)
goto err;
- if (deleting_snapshot == 1 && !inode_u->bi_subvol) {
- ret = -ENOENT;
- goto err;
- }
-
if (deleting_snapshot <= 0 && S_ISDIR(inode_u->bi_mode)) {
ret = bch2_empty_dir_trans(trans, inum);
if (ret)
goto err;
}
- if (inode_u->bi_subvol) {
+ if (deleting_snapshot < 0 &&
+ inode_u->bi_subvol) {
+ struct bch_subvolume s;
+
+ ret = bch2_subvolume_get(trans, inode_u->bi_subvol, true,
+ BTREE_ITER_CACHED|
+ BTREE_ITER_WITH_UPDATES,
+ &s);
+ if (ret)
+ goto err;
+
+ if (BCH_SUBVOLUME_SNAP(&s))
+ deleting_snapshot = 1;
+ }
+
+ if (deleting_snapshot == 1) {
+ if (!inode_u->bi_subvol) {
+ ret = -ENOENT;
+ goto err;
+ }
+
ret = bch2_subvolume_delete(trans, inode_u->bi_subvol,
deleting_snapshot);
if (ret)
@@ -297,6 +312,8 @@ int bch2_unlink_trans(struct btree_trans *trans,
ret = bch2_btree_iter_traverse(&dirent_iter);
if (ret)
goto err;
+ } else {
+ bch2_inode_nlink_dec(inode_u);
}
if (inode_u->bi_dir == dirent_iter.pos.inode &&
@@ -307,7 +324,6 @@ int bch2_unlink_trans(struct btree_trans *trans,
dir_u->bi_mtime = dir_u->bi_ctime = inode_u->bi_ctime = now;
dir_u->bi_nlink -= is_subdir_for_nlink(inode_u);
- bch2_inode_nlink_dec(inode_u);
ret = bch2_hash_delete_at(trans, bch2_dirent_hash_desc,
&dir_hash, &dirent_iter,