From 6ff7f297f88fc91c91b1853d4300e2f4b0f993a0 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 3 Jun 2019 20:45:32 +0000 Subject: [PATCH] fusefs: don't require FUSE_EXPORT_SUPPORT for async invalidation In r348560 I thought that FUSE_EXPORT_SUPPORT was required for cases where the node to be invalidated (or the parent of the entry to be invalidated) wasn't cached. But I realize now that that's not the case. During entry invalidation, if the parent isn't in the vfs hash table, then it must've been reclaimed. And since fuse_vnop_reclaim does a cache_purge, that means the entry to be invalidated has already been removed from the namecache. And during inode invalidation, if the inode to be invalidated isn't in the vfs hash table, then it too must've been reclaimed. In that case it will have no buffer cache to invalidate. Sponsored by: The FreeBSD Foundation --- sys/fs/fuse/fuse_internal.c | 31 +++++-------------------------- sys/fs/fuse/fuse_vfsops.c | 12 ++++++++++++ tests/sys/fs/fusefs/notify.cc | 5 ----- 3 files changed, 17 insertions(+), 31 deletions(-) diff --git a/sys/fs/fuse/fuse_internal.c b/sys/fs/fuse/fuse_internal.c index 6de36a3e492e..788543fc39b4 100644 --- a/sys/fs/fuse/fuse_internal.c +++ b/sys/fs/fuse/fuse_internal.c @@ -364,31 +364,17 @@ fuse_internal_fsync(struct vnode *vp, } /* Asynchronous invalidation */ -SDT_PROBE_DEFINE1(fusefs, , internal, invalidate_without_export, - "struct mount*"); SDT_PROBE_DEFINE2(fusefs, , internal, invalidate_cache_hit, "struct vnode*", "struct vnode*"); int fuse_internal_invalidate_entry(struct mount *mp, struct uio *uio) { struct fuse_notify_inval_entry_out fnieo; - struct fuse_data *data = fuse_get_mpdata(mp); struct componentname cn; struct vnode *dvp, *vp; char name[PATH_MAX]; int err; - if (!(data->dataflags & FSESS_EXPORT_SUPPORT)) { - /* - * Linux allows file systems without export support to use - * asynchronous notification because its inode cache is indexed - * purely by the inode number. But FreeBSD's vnode is cache - * requires access to the entire vnode structure. - */ - SDT_PROBE1(fusefs, , internal, invalidate_without_export, mp); - return (EINVAL); - } - if ((err = uiomove(&fnieo, sizeof(fnieo), uio)) != 0) return (err); @@ -405,6 +391,11 @@ fuse_internal_invalidate_entry(struct mount *mp, struct uio *uio) else err = fuse_internal_get_cached_vnode( mp, fnieo.parent, LK_SHARED, &dvp); + /* + * If dvp is not in the cache, then it must've been reclaimed. And + * since fuse_vnop_reclaim does a cache_purge, name's entry must've + * been invalidated already. So we can safely return if dvp == NULL + */ if (err != 0 || dvp == NULL) return (err); /* @@ -432,21 +423,9 @@ int fuse_internal_invalidate_inode(struct mount *mp, struct uio *uio) { struct fuse_notify_inval_inode_out fniio; - struct fuse_data *data = fuse_get_mpdata(mp); struct vnode *vp; int err; - if (!(data->dataflags & FSESS_EXPORT_SUPPORT)) { - /* - * Linux allows file systems without export support to use - * asynchronous notification because its inode cache is indexed - * purely by the inode number. But FreeBSD's vnode is cache - * requires access to the entire vnode structure. - */ - SDT_PROBE1(fusefs, , internal, invalidate_without_export, mp); - return (EINVAL); - } - if ((err = uiomove(&fniio, sizeof(fniio), uio)) != 0) return (err); diff --git a/sys/fs/fuse/fuse_vfsops.c b/sys/fs/fuse/fuse_vfsops.c index 36382118ccd0..b059e65c7f57 100644 --- a/sys/fs/fuse/fuse_vfsops.c +++ b/sys/fs/fuse/fuse_vfsops.c @@ -519,9 +519,12 @@ fuse_vfsop_unmount(struct mount *mp, int mntflags) return 0; } +SDT_PROBE_DEFINE1(fusefs, , vfsops, invalidate_without_export, + "struct mount*"); static int fuse_vfsop_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { + struct fuse_data *data = fuse_get_mpdata(mp); uint64_t nodeid = ino; struct thread *td = curthread; struct fuse_dispatcher fdi; @@ -532,6 +535,15 @@ fuse_vfsop_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) enum vtype vtyp; int error; + if (!(data->dataflags & FSESS_EXPORT_SUPPORT)) { + /* + * Unreachable unless you do something stupid, like export a + * nullfs mount of a fusefs file system. + */ + SDT_PROBE1(fusefs, , vfsops, invalidate_without_export, mp); + return (EOPNOTSUPP); + } + error = fuse_internal_get_cached_vnode(mp, ino, flags, vpp); if (error || *vpp != NULL) return error; diff --git a/tests/sys/fs/fusefs/notify.cc b/tests/sys/fs/fusefs/notify.cc index 9b702b37e8ad..da6417ed613f 100644 --- a/tests/sys/fs/fusefs/notify.cc +++ b/tests/sys/fs/fusefs/notify.cc @@ -50,11 +50,6 @@ using namespace testing; class Notify: public FuseTest { public: -virtual void SetUp() { - m_init_flags = FUSE_EXPORT_SUPPORT; - FuseTest::SetUp(); -} - void expect_lookup(uint64_t parent, const char *relpath, uint64_t ino, off_t size, Sequence &seq) {