summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2023-03-16 18:04:28 +0300
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-23 00:09:57 +0300
commit2d33036ca9360bacef23ba32e7768ff9ea87f2be (patch)
tree1c425312eb2896e788276ed19a898c1feb469475
parent56cc033dfcf002eb8a957097fe7290546829b7c0 (diff)
downloadlinux-2d33036ca9360bacef23ba32e7768ff9ea87f2be.tar.xz
bcachefs: Fix for 'missing subvolume' error
Subvolumes, including their root inodes, get deleted asynchronously after an unlink. But we still need to ensure that we tell the VFS the inode has been deleted, otherwise VFS writeback could fire after asynchronous deletion has finished, and try to write to an inode/subvolume that no longer exists. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/fs.c30
1 files changed, 19 insertions, 11 deletions
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index 15ab77ebb8c6..828887abc261 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -442,19 +442,27 @@ int __bch2_unlink(struct inode *vdir, struct dentry *dentry,
bch2_trans_init(&trans, c, 4, 1024);
ret = commit_do(&trans, NULL, NULL,
- BTREE_INSERT_NOFAIL,
- bch2_unlink_trans(&trans,
- inode_inum(dir), &dir_u,
- &inode_u, &dentry->d_name,
- deleting_snapshot));
+ BTREE_INSERT_NOFAIL,
+ bch2_unlink_trans(&trans,
+ inode_inum(dir), &dir_u,
+ &inode_u, &dentry->d_name,
+ deleting_snapshot));
+ if (unlikely(ret))
+ goto err;
- if (likely(!ret)) {
- bch2_inode_update_after_write(&trans, dir, &dir_u,
- ATTR_MTIME|ATTR_CTIME);
- bch2_inode_update_after_write(&trans, inode, &inode_u,
- ATTR_MTIME);
- }
+ bch2_inode_update_after_write(&trans, dir, &dir_u,
+ ATTR_MTIME|ATTR_CTIME);
+ bch2_inode_update_after_write(&trans, inode, &inode_u,
+ ATTR_MTIME);
+ if (inode_u.bi_subvol) {
+ /*
+ * Subvolume deletion is asynchronous, but we still want to tell
+ * the VFS that it's been deleted here:
+ */
+ set_nlink(&inode->v, 0);
+ }
+err:
bch2_trans_exit(&trans);
bch2_unlock_inodes(INODE_UPDATE_LOCK, dir, inode);