diff options
author | Conrad Meyer <cem@FreeBSD.org> | 2019-02-15 22:50:31 +0000 |
---|---|---|
committer | Conrad Meyer <cem@FreeBSD.org> | 2019-02-15 22:50:31 +0000 |
commit | 09176f096b48d4e766fc4445623075ced92929b3 (patch) | |
tree | ecc83d4082b76a7ac3644b281edc206dbbf67ee1 /sys/fs | |
parent | 78a7722fbca9957189eeac93d13f42b9bcfb4c2e (diff) |
FUSE: Respect userspace FS "do-not-cache" of path components
The FUSE protocol demands that kernel implementations cache user filesystem
path components (lookup/cnp data) for a maximum period of time in the range
of [0, ULONG_MAX] seconds. In practice, typical requests are for 0, 1, or
10 seconds; or "a long time" to represent indefinite caching.
Historically, FreeBSD FUSE has ignored this client directive entirely. This
works fine for local-only filesystems, but causes consistency issues with
multi-writer network filesystems.
For now, respect 0 second cache TTLs and do not cache such metadata.
Non-zero metadata caching TTLs in the range [0.000000001, ULONG_MAX] seconds
are still cached indefinitely, because it is unclear how a userspace
filesystem could do anything sensible with those semantics even if
implemented.
Pass fuse_entry_out to fuse_vnode_get when available and only cache lookup
if the user filesystem did not set a zero second TTL.
PR: 230258 (inspired by; does not fix)
Notes
Notes:
svn path=/head/; revision=344184
Diffstat (limited to 'sys/fs')
-rw-r--r-- | sys/fs/fuse/fuse_internal.c | 2 | ||||
-rw-r--r-- | sys/fs/fuse/fuse_node.c | 5 | ||||
-rw-r--r-- | sys/fs/fuse/fuse_node.h | 1 | ||||
-rw-r--r-- | sys/fs/fuse/fuse_vfsops.c | 3 | ||||
-rw-r--r-- | sys/fs/fuse/fuse_vnops.c | 30 |
5 files changed, 17 insertions, 24 deletions
diff --git a/sys/fs/fuse/fuse_internal.c b/sys/fs/fuse/fuse_internal.c index f9111449a400..d556dc3fd96a 100644 --- a/sys/fs/fuse/fuse_internal.c +++ b/sys/fs/fuse/fuse_internal.c @@ -471,7 +471,7 @@ fuse_internal_newentry_core(struct vnode *dvp, if ((err = fuse_internal_checkentry(feo, vtyp))) { return err; } - err = fuse_vnode_get(mp, feo->nodeid, dvp, vpp, cnp, vtyp); + err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, vtyp); if (err) { fuse_internal_forget_send(mp, cnp->cn_thread, cnp->cn_cred, feo->nodeid, 1); diff --git a/sys/fs/fuse/fuse_node.c b/sys/fs/fuse/fuse_node.c index 8bc58f08e3cd..e8b16335272d 100644 --- a/sys/fs/fuse/fuse_node.c +++ b/sys/fs/fuse/fuse_node.c @@ -241,6 +241,7 @@ fuse_vnode_alloc(struct mount *mp, int fuse_vnode_get(struct mount *mp, + struct fuse_entry_out *feo, uint64_t nodeid, struct vnode *dvp, struct vnode **vpp, @@ -261,7 +262,9 @@ fuse_vnode_get(struct mount *mp, MPASS(!(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')); fuse_vnode_setparent(*vpp, dvp); } - if (dvp != NULL && cnp != NULL && (cnp->cn_flags & MAKEENTRY) != 0) { + if (dvp != NULL && cnp != NULL && (cnp->cn_flags & MAKEENTRY) != 0 && + feo != NULL && + (feo->entry_valid != 0 || feo->entry_valid_nsec != 0)) { ASSERT_VOP_LOCKED(*vpp, "fuse_vnode_get"); ASSERT_VOP_LOCKED(dvp, "fuse_vnode_get"); cache_enter(dvp, *vpp, cnp); diff --git a/sys/fs/fuse/fuse_node.h b/sys/fs/fuse/fuse_node.h index 81db2ea66758..eab470fd3b94 100644 --- a/sys/fs/fuse/fuse_node.h +++ b/sys/fs/fuse/fuse_node.h @@ -117,6 +117,7 @@ fuse_vnode_setparent(struct vnode *vp, struct vnode *dvp) void fuse_vnode_destroy(struct vnode *vp); int fuse_vnode_get(struct mount *mp, + struct fuse_entry_out *feo, uint64_t nodeid, struct vnode *dvp, struct vnode **vpp, diff --git a/sys/fs/fuse/fuse_vfsops.c b/sys/fs/fuse/fuse_vfsops.c index 5685b04ee0d8..ae17768ad2e6 100644 --- a/sys/fs/fuse/fuse_vfsops.c +++ b/sys/fs/fuse/fuse_vfsops.c @@ -444,7 +444,8 @@ fuse_vfsop_root(struct mount *mp, int lkflags, struct vnode **vpp) if (err == 0) *vpp = data->vroot; } else { - err = fuse_vnode_get(mp, FUSE_ROOT_ID, NULL, vpp, NULL, VDIR); + err = fuse_vnode_get(mp, NULL, FUSE_ROOT_ID, NULL, vpp, NULL, + VDIR); if (err == 0) { FUSE_LOCK(); MPASS(data->vroot == NULL || data->vroot == *vpp); diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c index 62b3f2009467..618b01944712 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -384,7 +384,7 @@ fuse_vnop_create(struct vop_create_args *ap) if ((err = fuse_internal_checkentry(feo, VREG))) { goto out; } - err = fuse_vnode_get(mp, feo->nodeid, dvp, vpp, cnp, VREG); + err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, VREG); if (err) { struct fuse_release_in *fri; uint64_t nodeid = feo->nodeid; @@ -857,8 +857,8 @@ calldaemon: vref(dvp); *vpp = dvp; } else { - err = fuse_vnode_get(dvp->v_mount, nid, dvp, - &vp, cnp, IFTOVT(fattr->mode)); + err = fuse_vnode_get(dvp->v_mount, feo, nid, + dvp, &vp, cnp, IFTOVT(fattr->mode)); if (err) goto out; *vpp = vp; @@ -893,12 +893,8 @@ calldaemon: err = EISDIR; goto out; } - err = fuse_vnode_get(vnode_mount(dvp), - nid, - dvp, - &vp, - cnp, - IFTOVT(fattr->mode)); + err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp, + &vp, cnp, IFTOVT(fattr->mode)); if (err) { goto out; } @@ -936,12 +932,8 @@ calldaemon: } } VOP_UNLOCK(dvp, 0); - err = fuse_vnode_get(vnode_mount(dvp), - nid, - NULL, - &vp, - cnp, - IFTOVT(fattr->mode)); + err = fuse_vnode_get(vnode_mount(dvp), feo, nid, NULL, + &vp, cnp, IFTOVT(fattr->mode)); vfs_unbusy(mp); vn_lock(dvp, ltype | LK_RETRY); if ((dvp->v_iflag & VI_DOOMED) != 0) { @@ -956,12 +948,8 @@ calldaemon: vref(dvp); *vpp = dvp; } else { - err = fuse_vnode_get(vnode_mount(dvp), - nid, - dvp, - &vp, - cnp, - IFTOVT(fattr->mode)); + err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp, + &vp, cnp, IFTOVT(fattr->mode)); if (err) { goto out; } |