From ccb75e4939f8302d251a78488960aa16becba2d4 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 9 Apr 2019 17:23:34 +0000 Subject: [PATCH] fusefs: implement entry cache timeouts Follow-up to r346046. These two commits implement fuse cache timeouts for both entries and attributes. They also remove the vfs.fusefs.lookup_cache enable sysctl, which is no longer needed now that cache timeouts are honored. PR: 235773 Sponsored by: The FreeBSD Foundation --- sys/fs/fuse/fuse_internal.h | 2 -- sys/fs/fuse/fuse_node.c | 23 +++++++--------- sys/fs/fuse/fuse_vnops.c | 50 ++++++++++++----------------------- tests/sys/fs/fusefs/lookup.cc | 3 +-- 4 files changed, 28 insertions(+), 50 deletions(-) diff --git a/sys/fs/fuse/fuse_internal.h b/sys/fs/fuse/fuse_internal.h index 8baf666a403d..49064994831b 100644 --- a/sys/fs/fuse/fuse_internal.h +++ b/sys/fs/fuse/fuse_internal.h @@ -68,8 +68,6 @@ #include "fuse_ipc.h" #include "fuse_node.h" -extern int fuse_lookup_cache_expire; - static inline bool vfs_isrdonly(struct mount *mp) { diff --git a/sys/fs/fuse/fuse_node.c b/sys/fs/fuse/fuse_node.c index 20338684bd5a..520cb41eea1a 100644 --- a/sys/fs/fuse/fuse_node.c +++ b/sys/fs/fuse/fuse_node.c @@ -291,24 +291,21 @@ fuse_vnode_get(struct mount *mp, if (dvp != NULL && cnp != NULL && (cnp->cn_flags & MAKEENTRY) != 0 && feo != NULL && (feo->entry_valid != 0 || feo->entry_valid_nsec != 0)) { + struct timespec duration, now, timeout; + ASSERT_VOP_LOCKED(*vpp, "fuse_vnode_get"); ASSERT_VOP_LOCKED(dvp, "fuse_vnode_get"); - if (fuse_lookup_cache_expire) { - struct timespec duration, now, timeout; - getnanouptime(&now); - if (feo->entry_valid >= INT_MAX || - feo->entry_valid + now.tv_sec + 2 >= INT_MAX) { - timeout.tv_sec = INT_MAX; - } else { - duration.tv_sec = feo->entry_valid; - duration.tv_nsec = feo->entry_valid_nsec; - timespecadd(&duration, &now, &timeout); - } - cache_enter_time(dvp, *vpp, cnp, &timeout, NULL); + getnanouptime(&now); + if (feo->entry_valid >= INT_MAX || + feo->entry_valid + now.tv_sec + 2 >= INT_MAX) { + timeout.tv_sec = INT_MAX; } else { - cache_enter(dvp, *vpp, cnp); + duration.tv_sec = feo->entry_valid; + duration.tv_nsec = feo->entry_valid_nsec; + timespecadd(&duration, &now, &timeout); } + cache_enter_time(dvp, *vpp, cnp, &timeout, NULL); } /* diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c index 90bcbeedb71b..1cdfcb712817 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -195,12 +195,6 @@ static 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"); -int fuse_lookup_cache_expire = 0; - -SYSCTL_INT(_vfs_fusefs, OID_AUTO, lookup_cache_expire, CTLFLAG_RW, - &fuse_lookup_cache_expire, 0, - "if non-zero, expire fuse lookup cache entries at the proper time"); - /* * XXX: This feature is highly experimental and can bring to instabilities, * needs revisiting before to be enabled by default. @@ -681,6 +675,8 @@ fuse_vnop_link(struct vop_link_args *ap) return err; } +SDT_PROBE_DEFINE3(fuse, , vnops, cache_lookup, + "int", "struct timespec*", "struct timespec*"); /* struct vnop_lookup_args { struct vnodeop_desc *a_desc; @@ -750,21 +746,26 @@ fuse_vnop_lookup(struct vop_lookup_args *ap) fdisp_init(&fdi, 0); op = FUSE_GETATTR; goto calldaemon; - } else if (fuse_lookup_cache_expire) { + } else { struct timespec now, timeout; err = cache_lookup(dvp, vpp, cnp, &timeout, NULL); + getnanouptime(&now); + SDT_PROBE3(fuse, , vnops, cache_lookup, err, &timeout, &now); switch (err) { - case -1: /* positive match */ - getnanouptime(&now); - if (timespeccmp(&timeout, &now, <=)) { + if (timespeccmp(&timeout, &now, >)) { atomic_add_acq_long(&fuse_lookup_cache_hits, 1); } else { /* Cache timeout */ atomic_add_acq_long(&fuse_lookup_cache_misses, 1); - cache_purge(*vpp); + fuse_internal_vnode_disappear(*vpp); + if (dvp != *vpp) + vput(*vpp); + else + vrele(*vpp); + *vpp = NULL; break; } return 0; @@ -775,34 +776,15 @@ fuse_vnop_lookup(struct vop_lookup_args *ap) case ENOENT: /* negative match */ getnanouptime(&now); - if (timespeccmp(&timeout, &now, >)) { + if (timespeccmp(&timeout, &now, <=)) { /* Cache timeout */ - printf("Purging vnode %p name=%s\n", *vpp, - cnp->cn_nameptr); - fuse_internal_vnode_disappear(*vpp); + cache_purge_negative(dvp); break; } /* fall through */ default: return err; } - } else { - err = cache_lookup(dvp, vpp, cnp, NULL, NULL); - switch (err) { - - case -1: /* positive match */ - atomic_add_acq_long(&fuse_lookup_cache_hits, 1); - return 0; - - case 0: /* no match in cache */ - atomic_add_acq_long(&fuse_lookup_cache_misses, 1); - break; - - case ENOENT: /* negative match */ - /* fall through */ - default: - return err; - } } nid = VTOI(dvp); fdisp_init(&fdi, cnp->cn_namelen + 1); @@ -817,13 +799,15 @@ fuse_vnop_lookup(struct vop_lookup_args *ap) } lookup_err = fdisp_wait_answ(&fdi); - if ((op == FUSE_LOOKUP) && !lookup_err) { /* lookup call succeeded */ + if ((op == FUSE_LOOKUP) && !lookup_err) { + /* lookup call succeeded */ nid = ((struct fuse_entry_out *)fdi.answ)->nodeid; if (!nid) { /* * zero nodeid is the same as "not found", * but it's also cacheable (which we keep * keep on doing not as of writing this) + * See PR 236226 */ fdi.answ_stat = ENOENT; lookup_err = ENOENT; diff --git a/tests/sys/fs/fusefs/lookup.cc b/tests/sys/fs/fusefs/lookup.cc index 9b1d966df6f2..59c95da1b536 100644 --- a/tests/sys/fs/fusefs/lookup.cc +++ b/tests/sys/fs/fusefs/lookup.cc @@ -211,8 +211,7 @@ TEST_F(Lookup, entry_cache_negative_timeout) * If lookup returns a finite but non-zero entry cache timeout, then we should * discard the cached inode and requery the daemon */ -/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=235773 */ -TEST_F(Lookup, DISABLED_entry_cache_timeout) +TEST_F(Lookup, entry_cache_timeout) { const char FULLPATH[] = "mountpoint/some_file.txt"; const char RELPATH[] = "some_file.txt";