diff options
author | Alan Somers <asomers@FreeBSD.org> | 2019-05-31 21:22:58 +0000 |
---|---|---|
committer | Alan Somers <asomers@FreeBSD.org> | 2019-05-31 21:22:58 +0000 |
commit | 0d2bf489968deeb94dbd81de24ddf7e946271c9c (patch) | |
tree | b94e9dcad96987e809ad5b749fe5059931b9a130 /sys/fs | |
parent | a34cdd26d02ffdb4134e5945b902921697b6ceff (diff) |
fusefs: check the vnode cache when looking up files for the NFS server
FUSE allows entries to be cached for a limited amount of time. fusefs's
vnop_lookup method already implements that using the timeout functionality
of cache_lookup/cache_enter_time. However, lookups for the NFS server go
through a separate path: vfs_vget. That path can't use the same timeout
functionality because cache_lookup/cache_enter_time only work on pathnames,
whereas vfs_vget works by inode number.
This commit adds entry timeout information to the fuse vnode structure, and
checks it during vfs_vget. This allows the NFS server to take advantage of
cached entries. It's also the same path that FUSE's asynchronous cache
invalidation operations will use.
Sponsored by: The FreeBSD Foundation
Notes
Notes:
svn path=/projects/fuse2/; revision=348485
Diffstat (limited to 'sys/fs')
-rw-r--r-- | sys/fs/fuse/fuse_internal.c | 1 | ||||
-rw-r--r-- | sys/fs/fuse/fuse_internal.h | 3 | ||||
-rw-r--r-- | sys/fs/fuse/fuse_node.h | 5 | ||||
-rw-r--r-- | sys/fs/fuse/fuse_vfsops.c | 29 | ||||
-rw-r--r-- | sys/fs/fuse/fuse_vnops.c | 11 |
5 files changed, 40 insertions, 9 deletions
diff --git a/sys/fs/fuse/fuse_internal.c b/sys/fs/fuse/fuse_internal.c index ff001029c9b4..1c00a8164d5a 100644 --- a/sys/fs/fuse/fuse_internal.c +++ b/sys/fs/fuse/fuse_internal.c @@ -750,6 +750,7 @@ fuse_internal_vnode_disappear(struct vnode *vp) ASSERT_VOP_ELOCKED(vp, "fuse_internal_vnode_disappear"); fvdat->flag |= FN_REVOKED; bintime_clear(&fvdat->attr_cache_timeout); + bintime_clear(&fvdat->entry_cache_timeout); cache_purge(vp); } diff --git a/sys/fs/fuse/fuse_internal.h b/sys/fs/fuse/fuse_internal.h index 3b0f674dd959..a963c79cc1d8 100644 --- a/sys/fs/fuse/fuse_internal.h +++ b/sys/fs/fuse/fuse_internal.h @@ -68,6 +68,9 @@ #include "fuse_ipc.h" #include "fuse_node.h" +extern u_long fuse_lookup_cache_hits; +extern u_long fuse_lookup_cache_misses; + static inline bool vfs_isrdonly(struct mount *mp) { diff --git a/sys/fs/fuse/fuse_node.h b/sys/fs/fuse/fuse_node.h index 25551c520ab6..81bf6e3b70d4 100644 --- a/sys/fs/fuse/fuse_node.h +++ b/sys/fs/fuse/fuse_node.h @@ -97,6 +97,11 @@ struct fuse_vnode_data { /** meta **/ /* The monotonic time after which the attr cache is invalid */ struct bintime attr_cache_timeout; + /* + * Monotonic time after which the entry is invalid. Used for lookups + * by nodeid instead of pathname. + */ + struct bintime entry_cache_timeout; struct vattr cached_attrs; uint64_t nlookup; enum vtype vtype; diff --git a/sys/fs/fuse/fuse_vfsops.c b/sys/fs/fuse/fuse_vfsops.c index 4bd736c1fca6..07026e1aaf35 100644 --- a/sys/fs/fuse/fuse_vfsops.c +++ b/sys/fs/fuse/fuse_vfsops.c @@ -527,19 +527,34 @@ fuse_vfsop_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) struct fuse_dispatcher fdi; struct fuse_entry_out *feo; struct fuse_vnode_data *fvdat; + struct bintime now; const char dot[] = "."; off_t filesize; enum vtype vtyp; int error; + error = vfs_hash_get(mp, fuse_vnode_hash(nodeid), flags, td, vpp, + fuse_vnode_cmp, &nodeid); + if (error) + return error; /* - * TODO Check the vnode cache, verifying entry cache timeout. Normally - * done during VOP_LOOKUP + * Check the entry cache timeout. We have to do this within fusefs + * instead of by using cache_enter_time/cache_lookup because those + * routines are only intended to work with pathnames, not inodes */ - /*error = vfs_hash_get(mp, fuse_vnode_hash(nodeid), LK_EXCLUSIVE, td, vpp,*/ - /*fuse_vnode_cmp, &nodeid);*/ - /*if (error || *vpp != NULL)*/ - /*return error;*/ + if (*vpp != NULL) { + getbinuptime(&now); + if (bintime_cmp(&(VTOFUD(*vpp)->entry_cache_timeout), &now, >)){ + atomic_add_acq_long(&fuse_lookup_cache_hits, 1); + return 0; + } else { + /* Entry cache timeout */ + atomic_add_acq_long(&fuse_lookup_cache_misses, 1); + cache_purge(*vpp); + vput(*vpp); + *vpp = NULL; + } + } /* Do a LOOKUP, using nodeid as the parent and "." as filename */ fdisp_init(&fdi, sizeof(dot)); @@ -585,6 +600,8 @@ fuse_vfsop_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) fuse_internal_cache_attrs(*vpp, td->td_ucred, &feo->attr, feo->attr_valid, feo->attr_valid_nsec, NULL); + fuse_validity_2_bintime(feo->entry_valid, feo->entry_valid_nsec, + &fvdat->entry_cache_timeout); out: fdisp_destroy(&fdi); return error; diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c index ecfc02422964..3caccdf54ad8 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -218,12 +218,12 @@ struct vop_vector fuse_vnops = { .vop_vptofh = fuse_vnop_vptofh, }; -static u_long fuse_lookup_cache_hits = 0; +u_long fuse_lookup_cache_hits = 0; SYSCTL_ULONG(_vfs_fusefs, OID_AUTO, lookup_cache_hits, CTLFLAG_RD, &fuse_lookup_cache_hits, 0, "number of positive cache hits in lookup"); -static u_long fuse_lookup_cache_misses = 0; +u_long fuse_lookup_cache_misses = 0; SYSCTL_ULONG(_vfs_fusefs, OID_AUTO, lookup_cache_misses, CTLFLAG_RD, &fuse_lookup_cache_misses, 0, "number of cache misses in lookup"); @@ -965,6 +965,8 @@ fuse_vnop_lookup(struct vop_lookup_args *ap) /* Cache timeout */ atomic_add_acq_long(&fuse_lookup_cache_misses, 1); + bintime_clear( + &VTOFUD(*vpp)->entry_cache_timeout); cache_purge(*vpp); if (dvp != *vpp) vput(*vpp); @@ -1103,6 +1105,9 @@ fuse_vnop_lookup(struct vop_lookup_args *ap) MPASS(feo != NULL); fuse_internal_cache_attrs(*vpp, cred, &feo->attr, feo->attr_valid, feo->attr_valid_nsec, NULL); + fuse_validity_2_bintime(feo->entry_valid, + feo->entry_valid_nsec, + &fvdat->entry_cache_timeout); if ((nameiop == DELETE || nameiop == RENAME) && islastcn) @@ -2536,7 +2541,7 @@ fuse_vnop_print(struct vop_print_args *ap) * Get an NFS filehandle for a FUSE file. * * This will only work for FUSE file systems that guarantee the uniqueness of - * nodeid:generation, which most don't + * nodeid:generation, which most don't. */ /* vop_vptofh { |