bcachefs: Fix for 'missing subvolume' error
authorKent Overstreet <kent.overstreet@linux.dev>
Thu, 16 Mar 2023 15:04:28 +0000 (11:04 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:57 +0000 (17:09 -0400)
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>
fs/bcachefs/fs.c

index 15ab77ebb8c626e41012541e5e9152e1243caca5..828887abc26194a4600350f19102427a95275770 100644 (file)
@@ -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);