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
This commit is contained in:
Alan Somers 2019-04-09 17:23:34 +00:00
parent 3f2c630c74
commit ccb75e4939
4 changed files with 28 additions and 50 deletions

View File

@ -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)
{

View File

@ -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);
}
/*

View File

@ -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;

View File

@ -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";