diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2021-09-30 20:09:08 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:09:13 -0400 |
commit | 7bd68c73044f1ba39f505082bbed3b2e26f69a13 (patch) | |
tree | 31f2ddc21449891c29d64af7ce8087622e7a04c7 /fs/bcachefs/fs-common.c | |
parent | 107fe5af562303cda985c6bb72d36dbcd2076f06 (diff) |
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.c | 30 |
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, |