aboutsummaryrefslogtreecommitdiff
path: root/sys/fs
diff options
context:
space:
mode:
authorAlan Somers <asomers@FreeBSD.org>2022-04-02 19:31:24 +0000
committerAlan Somers <asomers@FreeBSD.org>2022-04-06 22:16:52 +0000
commit32273253667b941c376cf08383006b3a0cbc5ca2 (patch)
tree9540c20df590918fdbb315395c1771d68f5e1800 /sys/fs
parent4710aa248bcdd77811540ad5695270254edfff55 (diff)
downloadsrc-32273253667b941c376cf08383006b3a0cbc5ca2.tar.gz
src-32273253667b941c376cf08383006b3a0cbc5ca2.zip
fusefs: fix two bugs regarding VOP_RECLAIM of the root inode
* We never send FUSE_LOOKUP for the root inode, since its inode number is hard-coded to 1. Therefore, we should not send FUSE_FORGET for it, lest the server see its lookup count fall below 0. * During VOP_RECLAIM, if we are reclaiming the root inode, we must clear the file system's vroot pointer. Otherwise it will be left pointing at a reclaimed vnode, which will cause future VOP_LOOKUP operations to fail. Previously we only cleared that pointer during VFS_UMOUNT. I don't know of any real-world way to trigger this bug. MFC after: 2 weeks Reviewed by: pfg Differential Revision: https://reviews.freebsd.org/D34753
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/fuse/fuse_vnops.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
index acded47f75a3..4374c854a5be 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -1980,7 +1980,24 @@ fuse_vnop_reclaim(struct vop_reclaim_args *ap)
fuse_filehandle_close(vp, fufh, td, NULL);
}
- if (!fuse_isdeadfs(vp) && fvdat->nlookup > 0) {
+ if (VTOI(vp) == 1) {
+ /*
+ * Don't send FUSE_FORGET for the root inode, because
+ * we never send FUSE_LOOKUP for it (see
+ * fuse_vfsop_root) and we don't want the server to see
+ * mismatched lookup counts.
+ */
+ struct fuse_data *data;
+ struct vnode *vroot;
+
+ data = fuse_get_mpdata(vnode_mount(vp));
+ FUSE_LOCK();
+ vroot = data->vroot;
+ data->vroot = NULL;
+ FUSE_UNLOCK();
+ if (vroot)
+ vrele(vroot);
+ } else if (!fuse_isdeadfs(vp) && fvdat->nlookup > 0) {
fuse_internal_forget_send(vnode_mount(vp), td, NULL, VTOI(vp),
fvdat->nlookup);
}