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:
parent
3f2c630c74
commit
ccb75e4939
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
|
Loading…
Reference in New Issue
Block a user