aboutsummaryrefslogtreecommitdiff
path: root/sys/fs
diff options
context:
space:
mode:
authorConrad Meyer <cem@FreeBSD.org>2019-02-15 22:50:31 +0000
committerConrad Meyer <cem@FreeBSD.org>2019-02-15 22:50:31 +0000
commit09176f096b48d4e766fc4445623075ced92929b3 (patch)
treeecc83d4082b76a7ac3644b281edc206dbbf67ee1 /sys/fs
parent78a7722fbca9957189eeac93d13f42b9bcfb4c2e (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.c2
-rw-r--r--sys/fs/fuse/fuse_node.c5
-rw-r--r--sys/fs/fuse/fuse_node.h1
-rw-r--r--sys/fs/fuse/fuse_vfsops.c3
-rw-r--r--sys/fs/fuse/fuse_vnops.c30
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;
}