Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 6 Sep 2019 17:56:25 +0000 (UTC)
From:      Alan Somers <asomers@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r351943 - stable/12/sys/fs/fuse
Message-ID:  <201909061756.x86HuPMx006351@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: asomers
Date: Fri Sep  6 17:56:24 2019
New Revision: 351943
URL: https://svnweb.freebsd.org/changeset/base/351943

Log:
  MFC r344183-r344187, r344333-r344334, r344407, r344857, r344865 (by cem)
  
  r344183:
  FUSE: Respect userspace FS "do-not-cache" of file attributes
  
  The FUSE protocol demands that kernel implementations cache user filesystem
  file attributes (vattr 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.
  
  In the future, as an optimization, we should implement notify_inval_entry,
  etc, which provide userspace filesystems a way of evicting the kernel cache.
  
  One potentially bogus access to invalid cached attribute data was left in
  fuse_io_strategy.  It is restricted behind the undocumented and non-default
  "vfs.fuse.fix_broken_io" sysctl or "brokenio" mount option; maybe these are
  deadcode and can be eliminated?
  
  Some minor APIs changed to facilitate this:
  
  1. Attribute cache validity is tracked in FUSE inodes ("fuse_vnode_data").
  
  2. cache_attrs() respects the provided TTL and only caches in the FUSE
  inode if TTL > 0.  It also grows an "out" argument, which, if non-NULL,
  stores the translated fuse_attr (even if not suitable for caching).
  
  3. FUSE VTOVA(vp) returns NULL if the vnode's cache is invalid, to help
  avoid programming mistakes.
  
  4. A VOP_LINK check for potential nlink overflow prior to invoking the FUSE
  link op was weakened (only performed when we have a valid attr cache).  The
  check is racy in a multi-writer network filesystem anyway -- classic TOCTOU.
  We have to trust any userspace filesystem that rejects local caching to
  account for it correctly.
  
  PR:		230258 (inspired by; does not fix)
  
  r344184:
  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)
  
  r344185:
  FUSE: Only "dirty" cached file size when data is dirty
  
  Most users of fuse_vnode_setsize() set the cached fvdat->filesize and update
  the buf cache bounds as a result of either a read from the underlying FUSE
  filesystem, or as part of a write-through type operation (like truncate =>
  VOP_SETATTR).  In these cases, do not set the FN_SIZECHANGE flag, which
  indicates that an inode's data is dirty (in particular, that the local buf
  cache and fvdat->filesize have dirty extended data).
  
  PR:		230258 (related)
  
  r344186:
  FUSE: The FUSE design expects writethrough caching
  
  At least prior to 7.23 (which adds FUSE_WRITEBACK_CACHE), the FUSE protocol
  specifies only clean data to be cached.
  
  Prior to this change, we implement and default to writeback caching.  This
  is ok enough for local only filesystems without hardlinks, but violates the
  general design contract with FUSE and breaks distributed filesystems or
  concurrent access to hardlinks of the same inode.
  
  In this change, add cache mode as an extension of cache enable/disable.  The
  new modes are UC (was: cache disabled), WT (default), and WB (was: cache
  enabled).
  
  For now, WT caching is implemented as write-around, which meets the goal of
  only caching clean data.  WT can be better than WA for workloads that
  frequently read data that was recently written, but WA is trivial to
  implement.  Note that this has no effect on O_WRONLY-opened files, which
  were already coerced to write-around.
  
  Refs:
    * https://sourceforge.net/p/fuse/mailman/message/8902254/
    * https://github.com/vgough/encfs/issues/315
  
  PR:		230258 (inspired by)
  
  r344187:
  FUSE: Refresh cached file size when it changes (lookup)
  
  The cached fvdat->filesize is indepedent of the (mostly unused)
  cached_attrs, and we failed to update it when a cached (but perhaps
  inactive) vnode was found during VOP_LOOKUP to have a different size than
  cached.
  
  As noted in the code comment, this can occur in distributed filesystems or
  with other kinds of irregular file behavior (anything is possible in FUSE).
  
  We do something similar in fuse_vnop_getattr already.
  
  PR:		230258 (as reported in description; other issues explored in
  			comments are not all resolved)
  Reported by:	MooseFS FreeBSD Team <freebsd AT moosefs.com>
  Submitted by:	Jakub Kruszona-Zawadzki <acid AT moosefs.com> (earlier version)
  
  r344333:
  fuse: add descriptions for remaining sysctls
  
  (Except reclaim revoked; I don't know what that goal of that one is.)
  
  r344334:
  Fuse: whitespace and style(9) cleanup
  
  Take a pass through fixing some of the most egregious whitespace issues in
  fs/fuse.  Also fix some style(9) warts while here.  Not 100% cleaned up, but
  somewhat less painful to look at and edit.
  
  No functional change.
  
  r344407:
  fuse: Fix a regression introduced in r337165
  
  On systems with non-default DFLTPHYS and/or MAXBSIZE, FUSE would attempt to
  use a buf cache block size in excess of permitted size.  This did not affect
  most configurations, since DFLTPHYS and MAXBSIZE both default to 64kB.
  The issue was discovered and reported using a custom kernel with a DFLTPHYS
  of 512kB.
  
  PR:		230260 (comment #9)
  Reported by:	ken@
  
  r344857:
  FUSE: Prevent trivial panic
  
  When open(2) was invoked against a FUSE filesystem with an unexpected flags
  value (no O_RDONLY / O_RDWR / O_WRONLY), an assertion fired, causing panic.
  
  For now, prevent the panic by rejecting such VOP_OPENs with EINVAL.
  
  This is not considered the correct long term fix, but does prevent an
  unprivileged denial-of-service.
  
  PR:		236329
  Reported by:	asomers
  Reviewed by:	asomers
  Sponsored by:	Dell EMC Isilon
  
  r344865:
  fuse: switch from DFLTPHYS/MAXBSIZE to maxcachebuf
  
  On GENERIC kernels with empty loader.conf, there is no functional change.
  DFLTPHYS and MAXBSIZE are both 64kB at the moment.  This change allows
  larger bufcache block sizes to be used when either MAXBSIZE (custom kernel)
  or the loader.conf tunable vfs.maxbcachebuf (GENERIC) is adjusted higher
  than the default.
  
  Suggested by:	ken@

Modified:
  stable/12/sys/fs/fuse/fuse.h
  stable/12/sys/fs/fuse/fuse_device.c
  stable/12/sys/fs/fuse/fuse_file.c
  stable/12/sys/fs/fuse/fuse_file.h
  stable/12/sys/fs/fuse/fuse_internal.c
  stable/12/sys/fs/fuse/fuse_internal.h
  stable/12/sys/fs/fuse/fuse_io.c
  stable/12/sys/fs/fuse/fuse_ipc.c
  stable/12/sys/fs/fuse/fuse_ipc.h
  stable/12/sys/fs/fuse/fuse_node.c
  stable/12/sys/fs/fuse/fuse_node.h
  stable/12/sys/fs/fuse/fuse_vfsops.c
  stable/12/sys/fs/fuse/fuse_vnops.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/fs/fuse/fuse.h
==============================================================================
--- stable/12/sys/fs/fuse/fuse.h	Fri Sep  6 17:54:51 2019	(r351942)
+++ stable/12/sys/fs/fuse/fuse.h	Fri Sep  6 17:56:24 2019	(r351943)
@@ -197,26 +197,27 @@ do {						\
 #define FUSE_TRACE                      0
 #endif
 
-#define DEBUGX(cond, fmt, ...) do {                     \
-    if (((cond))) {                                     \
-        printf("%s: " fmt, __func__, ## __VA_ARGS__);   \
-    } } while (0)
+#define DEBUGX(cond, fmt, ...) do {					\
+	if (((cond))) {							\
+		printf("%s: " fmt, __func__, ## __VA_ARGS__);		\
+	}								\
+} while (0)
 
-#define fuse_lck_mtx_lock(mtx) do {                                     \
-    DEBUGX(FUSE_DEBUG_LOCK, "0:   lock(%s): %s@%d by %d\n",             \
-        __STRING(mtx), __func__, __LINE__, curthread->td_proc->p_pid);  \
-    mtx_lock(&(mtx));                                                   \
-    DEBUGX(FUSE_DEBUG_LOCK, "1:   lock(%s): %s@%d by %d\n",             \
-        __STRING(mtx), __func__, __LINE__, curthread->td_proc->p_pid);  \
-    } while (0)
+#define fuse_lck_mtx_lock(mtx) do {						\
+	DEBUGX(FUSE_DEBUG_LOCK, "0:   lock(%s): %s@%d by %d\n",			\
+	    __STRING(mtx), __func__, __LINE__, curthread->td_proc->p_pid);	\
+	mtx_lock(&(mtx));							\
+	DEBUGX(FUSE_DEBUG_LOCK, "1:   lock(%s): %s@%d by %d\n",			\
+	    __STRING(mtx), __func__, __LINE__, curthread->td_proc->p_pid);	\
+} while (0)
 
-#define fuse_lck_mtx_unlock(mtx) do {                                   \
-    DEBUGX(FUSE_DEBUG_LOCK, "0: unlock(%s): %s@%d by %d\n",             \
-        __STRING(mtx), __func__, __LINE__, curthread->td_proc->p_pid);  \
-    mtx_unlock(&(mtx));                                                 \
-    DEBUGX(FUSE_DEBUG_LOCK, "1: unlock(%s): %s@%d by %d\n",             \
-        __STRING(mtx), __func__, __LINE__, curthread->td_proc->p_pid);  \
-    } while (0)
+#define fuse_lck_mtx_unlock(mtx) do {						\
+	DEBUGX(FUSE_DEBUG_LOCK, "0: unlock(%s): %s@%d by %d\n",			\
+	    __STRING(mtx), __func__, __LINE__, curthread->td_proc->p_pid);	\
+	mtx_unlock(&(mtx));							\
+	DEBUGX(FUSE_DEBUG_LOCK, "1: unlock(%s): %s@%d by %d\n",			\
+	    __STRING(mtx), __func__, __LINE__, curthread->td_proc->p_pid);	\
+} while (0)
 
 void fuse_ipc_init(void);
 void fuse_ipc_destroy(void);

Modified: stable/12/sys/fs/fuse/fuse_device.c
==============================================================================
--- stable/12/sys/fs/fuse/fuse_device.c	Fri Sep  6 17:54:51 2019	(r351942)
+++ stable/12/sys/fs/fuse/fuse_device.c	Fri Sep  6 17:56:24 2019	(r351943)
@@ -317,7 +317,7 @@ again:
 	return (err);
 }
 
-static __inline int
+static inline int
 fuse_ohead_audit(struct fuse_out_header *ohead, struct uio *uio)
 {
 	FS_DEBUG("Out header -- len: %i, error: %i, unique: %llu; iovecs: %d\n",

Modified: stable/12/sys/fs/fuse/fuse_file.c
==============================================================================
--- stable/12/sys/fs/fuse/fuse_file.c	Fri Sep  6 17:54:51 2019	(r351942)
+++ stable/12/sys/fs/fuse/fuse_file.c	Fri Sep  6 17:56:24 2019	(r351943)
@@ -88,14 +88,11 @@ __FBSDID("$FreeBSD$");
 static int fuse_fh_count = 0;
 
 SYSCTL_INT(_vfs_fusefs, OID_AUTO, filehandle_count, CTLFLAG_RD,
-    &fuse_fh_count, 0, "");
+    &fuse_fh_count, 0, "number of open FUSE filehandles");
 
 int
-fuse_filehandle_open(struct vnode *vp,
-    fufh_type_t fufh_type,
-    struct fuse_filehandle **fufhp,
-    struct thread *td,
-    struct ucred *cred)
+fuse_filehandle_open(struct vnode *vp, fufh_type_t fufh_type,
+    struct fuse_filehandle **fufhp, struct thread *td, struct ucred *cred)
 {
 	struct fuse_dispatcher fdi;
 	struct fuse_open_in *foi;
@@ -114,8 +111,8 @@ fuse_filehandle_open(struct vnode *vp,
 		/* NOTREACHED */
 	}
 	/*
-         * Note that this means we are effectively FILTERING OUT open() flags.
-         */
+	 * Note that this means we are effectively FILTERING OUT open() flags.
+	 */
 	oflags = fuse_filehandle_xlate_to_oflags(fufh_type);
 
 	if (vnode_isdir(vp)) {
@@ -159,10 +156,8 @@ out:
 }
 
 int
-fuse_filehandle_close(struct vnode *vp,
-    fufh_type_t fufh_type,
-    struct thread *td,
-    struct ucred *cred)
+fuse_filehandle_close(struct vnode *vp, fufh_type_t fufh_type,
+    struct thread *td, struct ucred *cred)
 {
 	struct fuse_dispatcher fdi;
 	struct fuse_release_in *fri;
@@ -265,10 +260,8 @@ fuse_filehandle_getrw(struct vnode *vp, fufh_type_t fu
 }
 
 void
-fuse_filehandle_init(struct vnode *vp,
-    fufh_type_t fufh_type,
-    struct fuse_filehandle **fufhp,
-    uint64_t fh_id)
+fuse_filehandle_init(struct vnode *vp, fufh_type_t fufh_type,
+    struct fuse_filehandle **fufhp, uint64_t fh_id)
 {
 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
 	struct fuse_filehandle *fufh;

Modified: stable/12/sys/fs/fuse/fuse_file.h
==============================================================================
--- stable/12/sys/fs/fuse/fuse_file.h	Fri Sep  6 17:54:51 2019	(r351942)
+++ stable/12/sys/fs/fuse/fuse_file.h	Fri Sep  6 17:56:24 2019	(r351943)
@@ -67,75 +67,65 @@
 #include <sys/vnode.h>
 
 typedef enum fufh_type {
-    FUFH_INVALID = -1,
-    FUFH_RDONLY  = 0,
-    FUFH_WRONLY  = 1,
-    FUFH_RDWR    = 2,
-    FUFH_MAXTYPE = 3,
+	FUFH_INVALID = -1,
+	FUFH_RDONLY  = 0,
+	FUFH_WRONLY  = 1,
+	FUFH_RDWR    = 2,
+	FUFH_MAXTYPE = 3,
 } fufh_type_t;
+_Static_assert(FUFH_RDONLY == O_RDONLY, "RDONLY");
+_Static_assert(FUFH_WRONLY == O_WRONLY, "WRONLY");
+_Static_assert(FUFH_RDWR == O_RDWR, "RDWR");
 
 struct fuse_filehandle {
-    uint64_t fh_id;
-    fufh_type_t fh_type;
+	uint64_t fh_id;
+	fufh_type_t fh_type;
 };
 
 #define FUFH_IS_VALID(f)  ((f)->fh_type != FUFH_INVALID)
 
-static __inline__
-fufh_type_t
+static inline fufh_type_t
 fuse_filehandle_xlate_from_mmap(int fflags)
 {
-    if (fflags & (PROT_READ | PROT_WRITE)) {
-        return FUFH_RDWR;
-    } else if (fflags & (PROT_WRITE)) {
-        return FUFH_WRONLY;
-    } else if ((fflags & PROT_READ) || (fflags & PROT_EXEC)) {
-        return FUFH_RDONLY;
-    } else {
-        return FUFH_INVALID;
-    }
+	if (fflags & (PROT_READ | PROT_WRITE))
+		return FUFH_RDWR;
+	else if (fflags & (PROT_WRITE))
+		return FUFH_WRONLY;
+	else if ((fflags & PROT_READ) || (fflags & PROT_EXEC))
+		return FUFH_RDONLY;
+	else
+		return FUFH_INVALID;
 }
 
-static __inline__
-fufh_type_t
+static inline fufh_type_t
 fuse_filehandle_xlate_from_fflags(int fflags)
 {
-    if ((fflags & FREAD) && (fflags & FWRITE)) {
-        return FUFH_RDWR;
-    } else if (fflags & (FWRITE)) {
-        return FUFH_WRONLY;
-    } else if (fflags & (FREAD)) {
-        return FUFH_RDONLY;
-    } else {
-        panic("FUSE: What kind of a flag is this (%x)?", fflags);
-    }
+	if ((fflags & FREAD) && (fflags & FWRITE))
+		return FUFH_RDWR;
+	else if (fflags & (FWRITE))
+		return FUFH_WRONLY;
+	else if (fflags & (FREAD))
+		return FUFH_RDONLY;
+	else
+		panic("FUSE: What kind of a flag is this (%x)?", fflags);
 }
 
-static __inline__
-int
+static inline int
 fuse_filehandle_xlate_to_oflags(fufh_type_t type)
 {
-    int oflags = -1;
+	int oflags = -1;
 
-    switch (type) {
+	switch (type) {
+	case FUFH_RDONLY:
+	case FUFH_WRONLY:
+	case FUFH_RDWR:
+		oflags = type;
+		break;
+	default:
+		break;
+	}
 
-    case FUFH_RDONLY:
-        oflags = O_RDONLY;
-        break;
-
-    case FUFH_WRONLY:
-        oflags = O_WRONLY;
-        break;
-
-    case FUFH_RDWR:
-        oflags = O_RDWR;
-        break;
-
-    default:
-        break;
-    }
-
-    return oflags;
+	return oflags;
 }
 
 int fuse_filehandle_valid(struct vnode *vp, fufh_type_t fufh_type);

Modified: stable/12/sys/fs/fuse/fuse_internal.c
==============================================================================
--- stable/12/sys/fs/fuse/fuse_internal.c	Fri Sep  6 17:54:51 2019	(r351942)
+++ stable/12/sys/fs/fuse/fuse_internal.c	Fri Sep  6 17:56:24 2019	(r351943)
@@ -373,7 +373,6 @@ fuse_internal_readdir_processdata(struct uio *uio,
 
 /* remove */
 
-#define INVALIDATE_CACHED_VATTRS_UPON_UNLINK 1
 int
 fuse_internal_remove(struct vnode *dvp,
     struct vnode *vp,
@@ -381,16 +380,12 @@ fuse_internal_remove(struct vnode *dvp,
     enum fuse_opcode op)
 {
 	struct fuse_dispatcher fdi;
+	struct fuse_vnode_data *fvdat;
+	int err;
 
-	struct vattr *vap = VTOVA(vp);
+	err = 0;
+	fvdat = VTOFUD(vp);
 
-#if INVALIDATE_CACHED_VATTRS_UPON_UNLINK
-	int need_invalidate = 0;
-	uint64_t target_nlink = 0;
-
-#endif
-	int err = 0;
-
 	debug_printf("dvp=%p, cnp=%p, op=%d\n", vp, cnp, op);
 
 	fdisp_init(&fdi, cnp->cn_namelen + 1);
@@ -399,13 +394,6 @@ fuse_internal_remove(struct vnode *dvp,
 	memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
 	((char *)fdi.indata)[cnp->cn_namelen] = '\0';
 
-#if INVALIDATE_CACHED_VATTRS_UPON_UNLINK
-	if (vap->va_nlink > 1) {
-		need_invalidate = 1;
-		target_nlink = vap->va_nlink;
-	}
-#endif
-
 	err = fdisp_wait_answ(&fdi);
 	fdisp_destroy(&fdi);
 	return err;
@@ -483,13 +471,13 @@ 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);
 		return err;
 	}
-	cache_attrs(*vpp, feo);
+	cache_attrs(*vpp, feo, NULL);
 
 	return err;
 }
@@ -563,6 +551,7 @@ fuse_internal_vnode_disappear(struct vnode *vp)
 
 	ASSERT_VOP_ELOCKED(vp, "fuse_internal_vnode_disappear");
 	fvdat->flag |= FN_REVOKED;
+	fvdat->valid_attr_cache = false;
 	cache_purge(vp);
 }
 

Modified: stable/12/sys/fs/fuse/fuse_internal.h
==============================================================================
--- stable/12/sys/fs/fuse/fuse_internal.h	Fri Sep  6 17:54:51 2019	(r351942)
+++ stable/12/sys/fs/fuse/fuse_internal.h	Fri Sep  6 17:56:24 2019	(r351943)
@@ -68,116 +68,114 @@
 #include "fuse_ipc.h"
 #include "fuse_node.h"
 
-static __inline int
+static inline bool
 vfs_isrdonly(struct mount *mp)
 {
-    return ((mp->mnt_flag & MNT_RDONLY) != 0 ? 1 : 0);
+	return ((mp->mnt_flag & MNT_RDONLY) != 0);
 }
 
-static __inline struct mount *
+static inline struct mount *
 vnode_mount(struct vnode *vp)
 {
 	return (vp->v_mount);
 }
 
-static __inline int
+static inline bool
 vnode_mountedhere(struct vnode *vp)
 {
-	return (vp->v_mountedhere != NULL ? 1 : 0);
+	return (vp->v_mountedhere != NULL);
 }
 
-static __inline enum vtype
+static inline enum vtype
 vnode_vtype(struct vnode *vp)
 {
-    return (vp->v_type);
+	return (vp->v_type);
 }
 
-static __inline int
+static inline bool
 vnode_isvroot(struct vnode *vp)
 {
-    return ((vp->v_vflag & VV_ROOT) != 0 ? 1 : 0);
+	return ((vp->v_vflag & VV_ROOT) != 0);
 }
 
-static __inline int
+static inline bool
 vnode_isreg(struct vnode *vp)
 {
-    return (vp->v_type == VREG ? 1 : 0);
+	return (vp->v_type == VREG);
 }
 
-static __inline int
+static inline bool
 vnode_isdir(struct vnode *vp)
 {
-    return (vp->v_type == VDIR ? 1 : 0);
+	return (vp->v_type == VDIR);
 }
 
-static __inline int
+static inline bool
 vnode_islnk(struct vnode *vp)
 {
-    return (vp->v_type == VLNK ? 1 : 0);
+	return (vp->v_type == VLNK);
 }
 
-static __inline ssize_t
+static inline ssize_t
 uio_resid(struct uio *uio)
 {
-    return (uio->uio_resid);
+	return (uio->uio_resid);
 }
 
-static __inline off_t
+static inline off_t
 uio_offset(struct uio *uio)
 {
-    return (uio->uio_offset);
+	return (uio->uio_offset);
 }
 
-static __inline void
+static inline void
 uio_setoffset(struct uio *uio, off_t offset)
 {
-    uio->uio_offset = offset;
+	uio->uio_offset = offset;
 }
 
-static __inline void
+static inline void
 uio_setresid(struct uio *uio, ssize_t resid)
 {
-    uio->uio_resid = resid;
+	uio->uio_resid = resid;
 }
 
 /* miscellaneous */
 
-static __inline__
-int
+static inline bool
 fuse_isdeadfs(struct vnode *vp)
 {
-    struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
+	struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
 
-    return (data->dataflags & FSESS_DEAD);
+	return (data->dataflags & FSESS_DEAD);
 }
 
-static __inline__
-int
+static inline uint64_t
 fuse_iosize(struct vnode *vp)
 {
-    return vp->v_mount->mnt_stat.f_iosize;
+	return (vp->v_mount->mnt_stat.f_iosize);
 }
 
 /* access */
 
-#define FVP_ACCESS_NOOP   0x01
+#define FVP_ACCESS_NOOP		0x01
 
-#define FACCESS_VA_VALID   0x01
-#define FACCESS_DO_ACCESS  0x02
-#define FACCESS_STICKY     0x04
-#define FACCESS_CHOWN      0x08
-#define FACCESS_NOCHECKSPY 0x10
-#define FACCESS_SETGID     0x12
+#define FACCESS_VA_VALID	0x01
+#define FACCESS_DO_ACCESS	0x02
+#define FACCESS_STICKY		0x04
+#define FACCESS_CHOWN		0x08
+#define FACCESS_NOCHECKSPY	0x10
+#define FACCESS_SETGID		0x12
 
-#define FACCESS_XQUERIES FACCESS_STICKY | FACCESS_CHOWN | FACCESS_SETGID
+#define FACCESS_XQUERIES	(FACCESS_STICKY | FACCESS_CHOWN | FACCESS_SETGID)
 
 struct fuse_access_param {
-    uid_t    xuid;
-    gid_t    xgid;
-    uint32_t facc_flags;
+	uid_t		xuid;
+	gid_t		xgid;
+	uint32_t	facc_flags;
 };
 
-static __inline int
+static inline int
 fuse_match_cred(struct ucred *basecred, struct ucred *usercred)
 {
 	if (basecred->cr_uid == usercred->cr_uid             &&
@@ -186,181 +184,162 @@ fuse_match_cred(struct ucred *basecred, struct ucred *
 	    basecred->cr_groups[0] == usercred->cr_groups[0] &&
 	    basecred->cr_groups[0] == usercred->cr_rgid      &&
 	    basecred->cr_groups[0] == usercred->cr_svgid)
-		return 0;
+		return (0);
 
-	return EPERM;
+	return (EPERM);
 }
 
-int
-fuse_internal_access(struct vnode *vp,
-                     mode_t mode,
-                     struct fuse_access_param *facp,
-                     struct thread *td,
-                     struct ucred *cred);
+int fuse_internal_access(struct vnode *vp, mode_t mode,
+    struct fuse_access_param *facp, struct thread *td, struct ucred *cred);
 
 /* attributes */
 
-static __inline
-void
-fuse_internal_attr_fat2vat(struct mount *mp,
-                           struct fuse_attr *fat,
-                           struct vattr *vap)
+/*
+ * Cache FUSE attributes 'fat', with nominal expiration
+ * 'attr_valid'.'attr_valid_nsec', in attr cache associated with vnode 'vp'.
+ * Optionally, if argument 'vap' is not NULL, store a copy of the converted
+ * attributes there as well.
+ *
+ * If the nominal attribute cache TTL is zero, do not cache on the 'vp' (but do
+ * return the result to the caller).
+ */
+static inline void
+fuse_internal_attr_fat2vat(struct vnode *vp, struct fuse_attr *fat,
+    uint64_t attr_valid, uint32_t attr_valid_nsec, struct vattr *vap)
 {
-    DEBUGX(FUSE_DEBUG_INTERNAL,
-        "node #%ju, mode 0%o\n", (uintmax_t)fat->ino, fat->mode);
+	struct mount *mp;
+	struct fuse_vnode_data *fvdat;
+	struct vattr *vp_cache_at;
 
-    vattr_null(vap);
+	mp = vnode_mount(vp);
+	fvdat = VTOFUD(vp);
 
-    vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
-    vap->va_fileid = fat->ino;
-    vap->va_mode = fat->mode & ~S_IFMT;
-    vap->va_nlink     = fat->nlink;
-    vap->va_uid       = fat->uid;
-    vap->va_gid       = fat->gid;
-    vap->va_rdev      = fat->rdev;
-    vap->va_size      = fat->size;
-    vap->va_atime.tv_sec  = fat->atime; /* XXX on some platforms cast from 64 bits to 32 */
-    vap->va_atime.tv_nsec = fat->atimensec;
-    vap->va_mtime.tv_sec  = fat->mtime;
-    vap->va_mtime.tv_nsec = fat->mtimensec;
-    vap->va_ctime.tv_sec  = fat->ctime;
-    vap->va_ctime.tv_nsec = fat->ctimensec;
-    vap->va_blocksize = PAGE_SIZE;
-    vap->va_type = IFTOVT(fat->mode);
+	DEBUGX(FUSE_DEBUG_INTERNAL, "node #%ju, mode 0%o\n",
+	    (uintmax_t)fat->ino, fat->mode);
 
-#if (S_BLKSIZE == 512)
-    /* Optimize this case */
-    vap->va_bytes = fat->blocks << 9;
-#else
-    vap->va_bytes = fat->blocks * S_BLKSIZE;
-#endif
+	/* Honor explicit do-not-cache requests from user filesystems. */
+	if (attr_valid == 0 && attr_valid_nsec == 0)
+		fvdat->valid_attr_cache = false;
+	else
+		fvdat->valid_attr_cache = true;
 
-    vap->va_flags = 0;
+	vp_cache_at = VTOVA(vp);
+
+	if (vap == NULL && vp_cache_at == NULL)
+		return;
+
+	if (vap == NULL)
+		vap = vp_cache_at;
+
+	vattr_null(vap);
+
+	vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
+	vap->va_fileid = fat->ino;
+	vap->va_mode = fat->mode & ~S_IFMT;
+	vap->va_nlink     = fat->nlink;
+	vap->va_uid       = fat->uid;
+	vap->va_gid       = fat->gid;
+	vap->va_rdev      = fat->rdev;
+	vap->va_size      = fat->size;
+	/* XXX on i386, seconds are truncated to 32 bits */
+	vap->va_atime.tv_sec  = fat->atime;
+	vap->va_atime.tv_nsec = fat->atimensec;
+	vap->va_mtime.tv_sec  = fat->mtime;
+	vap->va_mtime.tv_nsec = fat->mtimensec;
+	vap->va_ctime.tv_sec  = fat->ctime;
+	vap->va_ctime.tv_nsec = fat->ctimensec;
+	vap->va_blocksize = PAGE_SIZE;
+	vap->va_type = IFTOVT(fat->mode);
+	vap->va_bytes = fat->blocks * S_BLKSIZE;
+	vap->va_flags = 0;
+
+	if (vap != vp_cache_at && vp_cache_at != NULL)
+		memcpy(vp_cache_at, vap, sizeof(*vap));
 }
 
 
-#define	cache_attrs(vp, fuse_out)					\
-	fuse_internal_attr_fat2vat(vnode_mount(vp), &(fuse_out)->attr,	\
-	    VTOVA(vp));
+#define	cache_attrs(vp, fuse_out, vap_out)				\
+	fuse_internal_attr_fat2vat((vp), &(fuse_out)->attr,		\
+	    (fuse_out)->attr_valid, (fuse_out)->attr_valid_nsec, (vap_out))
 
 /* fsync */
 
-int
-fuse_internal_fsync(struct vnode           *vp,
-                    struct thread          *td,
-                    struct ucred           *cred,
-                    struct fuse_filehandle *fufh);
+int fuse_internal_fsync(struct vnode *vp, struct thread *td,
+    struct ucred *cred, struct fuse_filehandle *fufh);
+int fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio);
 
-int
-fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio);
-
 /* readdir */
 
 struct pseudo_dirent {
-    uint32_t d_namlen;
+	uint32_t d_namlen;
 };
 
-int
-fuse_internal_readdir(struct vnode           *vp,
-                      struct uio             *uio,
-                      struct fuse_filehandle *fufh,
-                      struct fuse_iov        *cookediov);
+int fuse_internal_readdir(struct vnode *vp, struct uio *uio,
+    struct fuse_filehandle *fufh, struct fuse_iov *cookediov);
+int fuse_internal_readdir_processdata(struct uio *uio, size_t reqsize,
+    void *buf, size_t bufsize, void *param);
 
-int
-fuse_internal_readdir_processdata(struct uio *uio,
-                                  size_t reqsize,
-                                  void *buf,
-                                  size_t bufsize,
-                                  void *param);
-
 /* remove */
 
-int
-fuse_internal_remove(struct vnode *dvp,
-                     struct vnode *vp,
-                     struct componentname *cnp,
-                     enum fuse_opcode op);
+int fuse_internal_remove(struct vnode *dvp, struct vnode *vp,
+    struct componentname *cnp, enum fuse_opcode op);
 
 /* rename */
 
-int
-fuse_internal_rename(struct vnode *fdvp,
-                     struct componentname *fcnp,
-                     struct vnode *tdvp,
-                     struct componentname *tcnp);
+int fuse_internal_rename(struct vnode *fdvp, struct componentname *fcnp,
+    struct vnode *tdvp, struct componentname *tcnp);
+
 /* revoke */
 
-void
-fuse_internal_vnode_disappear(struct vnode *vp);
+void fuse_internal_vnode_disappear(struct vnode *vp);
 
 /* strategy */
 
 /* entity creation */
 
-static __inline
-int
+static inline int
 fuse_internal_checkentry(struct fuse_entry_out *feo, enum vtype vtyp)
 {
-    DEBUGX(FUSE_DEBUG_INTERNAL,
-        "feo=%p, vtype=%d\n", feo, vtyp);
+	DEBUGX(FUSE_DEBUG_INTERNAL,
+	    "feo=%p, vtype=%d\n", feo, vtyp);
 
-    if (vtyp != IFTOVT(feo->attr.mode)) {
-        DEBUGX(FUSE_DEBUG_INTERNAL,
-            "EINVAL -- %x != %x\n", vtyp, IFTOVT(feo->attr.mode));
-        return EINVAL;
-    }
+	if (vtyp != IFTOVT(feo->attr.mode)) {
+		DEBUGX(FUSE_DEBUG_INTERNAL,
+		    "EINVAL -- %x != %x\n", vtyp, IFTOVT(feo->attr.mode));
+		return (EINVAL);
+	}
 
-    if (feo->nodeid == FUSE_NULL_ID) {
-        DEBUGX(FUSE_DEBUG_INTERNAL,
-            "EINVAL -- feo->nodeid is NULL\n");
-        return EINVAL;
-    }
+	if (feo->nodeid == FUSE_NULL_ID) {
+		DEBUGX(FUSE_DEBUG_INTERNAL,
+		    "EINVAL -- feo->nodeid is NULL\n");
+		return (EINVAL);
+	}
 
-    if (feo->nodeid == FUSE_ROOT_ID) {
-        DEBUGX(FUSE_DEBUG_INTERNAL,
-            "EINVAL -- feo->nodeid is FUSE_ROOT_ID\n");
-        return EINVAL;
-    }
+	if (feo->nodeid == FUSE_ROOT_ID) {
+		DEBUGX(FUSE_DEBUG_INTERNAL,
+		    "EINVAL -- feo->nodeid is FUSE_ROOT_ID\n");
+		return (EINVAL);
+	}
 
-    return 0;
+	return (0);
 }
 
-int
-fuse_internal_newentry(struct vnode *dvp,
-                       struct vnode **vpp,
-                       struct componentname *cnp,
-                       enum fuse_opcode op,
-                       void *buf,
-                       size_t bufsize,
-                       enum vtype vtyp);
+int fuse_internal_newentry(struct vnode *dvp, struct vnode **vpp,
+    struct componentname *cnp, enum fuse_opcode op, void *buf, size_t bufsize,
+    enum vtype vtyp);
 
-void
-fuse_internal_newentry_makerequest(struct mount *mp,
-                                   uint64_t dnid,
-                                   struct componentname *cnp,
-                                   enum fuse_opcode op,
-                                   void *buf,
-                                   size_t bufsize,
-                                   struct fuse_dispatcher *fdip);
+void fuse_internal_newentry_makerequest(struct mount *mp, uint64_t dnid,
+    struct componentname *cnp, enum fuse_opcode op, void *buf, size_t bufsize,
+    struct fuse_dispatcher *fdip);
 
-int
-fuse_internal_newentry_core(struct vnode *dvp,
-                            struct vnode **vpp,
-                            struct componentname   *cnp,
-                            enum vtype vtyp,
-                            struct fuse_dispatcher *fdip);
+int fuse_internal_newentry_core(struct vnode *dvp, struct vnode **vpp,
+    struct componentname *cnp, enum vtype vtyp, struct fuse_dispatcher *fdip);
 
 /* entity destruction */
 
-int
-fuse_internal_forget_callback(struct fuse_ticket *tick, struct uio *uio);
-
-void
-fuse_internal_forget_send(struct mount *mp,
-                          struct thread *td,
-                          struct ucred *cred,
-                          uint64_t nodeid,
-                          uint64_t nlookup);
+int fuse_internal_forget_callback(struct fuse_ticket *tick, struct uio *uio);
+void fuse_internal_forget_send(struct mount *mp, struct thread *td,
+    struct ucred *cred, uint64_t nodeid, uint64_t nlookup);
 
 /* fuse start/stop */
 

Modified: stable/12/sys/fs/fuse/fuse_io.c
==============================================================================
--- stable/12/sys/fs/fuse/fuse_io.c	Fri Sep  6 17:54:51 2019	(r351942)
+++ stable/12/sys/fs/fuse/fuse_io.c	Fri Sep  6 17:56:24 2019	(r351943)
@@ -155,7 +155,13 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, in
 		}
 		break;
 	case UIO_WRITE:
-		if (directio) {
+		/*
+		 * Kludge: simulate write-through caching via write-around
+		 * caching.  Same effect, as far as never caching dirty data,
+		 * but slightly pessimal in that newly written data is not
+		 * cached.
+		 */
+		if (directio || fuse_data_cache_mode == FUSE_CACHE_WT) {
 			FS_DEBUG("direct write of vnode %ju via file handle %ju\n",
 			    (uintmax_t)VTOILLU(vp), (uintmax_t)fufh->fh_id);
 			err = fuse_write_directbackend(vp, uio, cred, fufh, ioflag);
@@ -192,7 +198,7 @@ fuse_read_biobackend(struct vnode *vp, struct uio *uio
 	if (uio->uio_offset < 0)
 		return (EINVAL);
 
-	bcount = MIN(MAXBSIZE, biosize);
+	bcount = biosize;
 	filesize = VTOFUD(vp)->filesize;
 
 	do {
@@ -362,8 +368,11 @@ fuse_write_directbackend(struct vnode *vp, struct uio 
 		}
 		uio->uio_resid += diff;
 		uio->uio_offset -= diff;
-		if (uio->uio_offset > fvdat->filesize)
+		if (uio->uio_offset > fvdat->filesize &&
+		    fuse_data_cache_mode != FUSE_CACHE_UC) {
 			fuse_vnode_setsize(vp, uio->uio_offset);
+			fvdat->flag &= ~FN_SIZECHANGE;
+		}
 	}
 
 	fdisp_destroy(&fdi);
@@ -655,6 +664,7 @@ fuse_io_strategy(struct vnode *vp, struct buf *bp)
 		uiop->uio_offset = ((off_t)bp->b_blkno) * biosize;
 		error = fuse_read_directbackend(vp, uiop, cred, fufh);
 
+		/* XXXCEM: Potentially invalid access to cached_attrs here */
 		if ((!error && uiop->uio_resid) ||
 		    (fsess_opt_brokenio(vnode_mount(vp)) && error == EIO &&
 		    uiop->uio_offset < fvdat->filesize && fvdat->filesize > 0 &&

Modified: stable/12/sys/fs/fuse/fuse_ipc.c
==============================================================================
--- stable/12/sys/fs/fuse/fuse_ipc.c	Fri Sep  6 17:54:51 2019	(r351942)
+++ stable/12/sys/fs/fuse/fuse_ipc.c	Fri Sep  6 17:56:24 2019	(r351943)
@@ -91,19 +91,11 @@ static struct fuse_ticket *fticket_alloc(struct fuse_d
 static void fticket_refresh(struct fuse_ticket *ftick);
 static void fticket_destroy(struct fuse_ticket *ftick);
 static int fticket_wait_answer(struct fuse_ticket *ftick);
-static __inline__ int 
+static inline int 
 fticket_aw_pull_uio(struct fuse_ticket *ftick,
     struct uio *uio);
 
 static int fuse_body_audit(struct fuse_ticket *ftick, size_t blen);
-static __inline__ void 
-fuse_setup_ihead(struct fuse_in_header *ihead,
-    struct fuse_ticket *ftick,
-    uint64_t nid,
-    enum fuse_opcode op,
-    size_t blen,
-    pid_t pid,
-    struct ucred *cred);
 
 static fuse_handler_t fuse_standard_handler;
 
@@ -274,19 +266,19 @@ fticket_fini(void *mem, int size)
 	mtx_destroy(&ftick->tk_aw_mtx);
 }
 
-static __inline struct fuse_ticket *
+static inline struct fuse_ticket *
 fticket_alloc(struct fuse_data *data)
 {
 	return uma_zalloc_arg(ticket_zone, data, M_WAITOK);
 }
 
-static __inline void
+static inline void
 fticket_destroy(struct fuse_ticket *ftick)
 {
 	return uma_zfree(ticket_zone, ftick);
 }
 
-static	__inline__
+static	inline
 void
 fticket_refresh(struct fuse_ticket *ftick)
 {
@@ -354,7 +346,7 @@ out:
 	return err;
 }
 
-static	__inline__
+static	inline
 int
 fticket_aw_pull_uio(struct fuse_ticket *ftick, struct uio *uio)
 {
@@ -717,13 +709,9 @@ fuse_body_audit(struct fuse_ticket *ftick, size_t blen
 	return err;
 }
 
-static void
-fuse_setup_ihead(struct fuse_in_header *ihead,
-    struct fuse_ticket *ftick,
-    uint64_t nid,
-    enum fuse_opcode op,
-    size_t blen,
-    pid_t pid,
+static inline void
+fuse_setup_ihead(struct fuse_in_header *ihead, struct fuse_ticket *ftick,
+    uint64_t nid, enum fuse_opcode op, size_t blen, pid_t pid,
     struct ucred *cred)
 {
 	ihead->len = sizeof(*ihead) + blen;
@@ -767,12 +755,8 @@ fuse_standard_handler(struct fuse_ticket *ftick, struc
 }
 
 void
-fdisp_make_pid(struct fuse_dispatcher *fdip,
-    enum fuse_opcode op,
-    struct mount *mp,
-    uint64_t nid,
-    pid_t pid,
-    struct ucred *cred)
+fdisp_make_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op,
+    struct mount *mp, uint64_t nid, pid_t pid, struct ucred *cred)
 {
 	struct fuse_data *data = fuse_get_mpdata(mp);
 
@@ -792,12 +776,8 @@ fdisp_make_pid(struct fuse_dispatcher *fdip,
 }
 
 void
-fdisp_make(struct fuse_dispatcher *fdip,
-    enum fuse_opcode op,
-    struct mount *mp,
-    uint64_t nid,
-    struct thread *td,
-    struct ucred *cred)
+fdisp_make(struct fuse_dispatcher *fdip, enum fuse_opcode op, struct mount *mp,
+    uint64_t nid, struct thread *td, struct ucred *cred)
 {
 	RECTIFY_TDCR(td, cred);
 
@@ -805,11 +785,8 @@ fdisp_make(struct fuse_dispatcher *fdip,
 }
 
 void
-fdisp_make_vp(struct fuse_dispatcher *fdip,
-    enum fuse_opcode op,
-    struct vnode *vp,
-    struct thread *td,
-    struct ucred *cred)
+fdisp_make_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op,
+    struct vnode *vp, struct thread *td, struct ucred *cred)
 {
 	debug_printf("fdip=%p, op=%d, vp=%p\n", fdip, op, vp);
 	RECTIFY_TDCR(td, cred);

Modified: stable/12/sys/fs/fuse/fuse_ipc.h
==============================================================================
--- stable/12/sys/fs/fuse/fuse_ipc.h	Fri Sep  6 17:54:51 2019	(r351942)
+++ stable/12/sys/fs/fuse/fuse_ipc.h	Fri Sep  6 17:56:24 2019	(r351943)
@@ -64,10 +64,10 @@
 #include <sys/refcount.h>
 
 struct fuse_iov {
-    void   *base;
-    size_t  len;
-    size_t  allocated_size;
-    int     credit;
+	void   *base;
+	size_t  len;
+	size_t  allocated_size;
+	int     credit;
 };
 
 void fiov_init(struct fuse_iov *fiov, size_t size);
@@ -75,23 +75,22 @@ void fiov_teardown(struct fuse_iov *fiov);
 void fiov_refresh(struct fuse_iov *fiov);
 void fiov_adjust(struct fuse_iov *fiov, size_t size);
 
-#define FUSE_DIMALLOC(fiov, spc1, spc2, amnt)          \
-do {                                                   \
-    fiov_adjust(fiov, (sizeof(*(spc1)) + (amnt)));     \
-    (spc1) = (fiov)->base;                             \
-    (spc2) = (char *)(fiov)->base + (sizeof(*(spc1))); \
+#define FUSE_DIMALLOC(fiov, spc1, spc2, amnt) do {		\
+	fiov_adjust(fiov, (sizeof(*(spc1)) + (amnt)));		\
+	(spc1) = (fiov)->base;					\
+	(spc2) = (char *)(fiov)->base + (sizeof(*(spc1)));	\
 } while (0)
 
 #define FU_AT_LEAST(siz) max((siz), 160)
 
-#define FUSE_ASSERT_AW_DONE(ftick)                                      \
-    KASSERT((ftick)->tk_aw_link.tqe_next == NULL &&                     \
-        (ftick)->tk_aw_link.tqe_prev == NULL,                           \
-        ("FUSE: ticket still on answer delivery list %p", (ftick)))     \
+#define FUSE_ASSERT_AW_DONE(ftick)					\
+	KASSERT((ftick)->tk_aw_link.tqe_next == NULL &&			\
+	    (ftick)->tk_aw_link.tqe_prev == NULL,			\
+	    ("FUSE: ticket still on answer delivery list %p", (ftick)))
 
-#define FUSE_ASSERT_MS_DONE(ftick)                                      \
-    KASSERT((ftick)->tk_ms_link.stqe_next == NULL,                      \
-        ("FUSE: ticket still on message list %p", (ftick)))
+#define FUSE_ASSERT_MS_DONE(ftick)				\
+	KASSERT((ftick)->tk_ms_link.stqe_next == NULL,		\
+	    ("FUSE: ticket still on message list %p", (ftick)))
 
 struct fuse_ticket;
 struct fuse_data;
@@ -99,66 +98,62 @@ struct fuse_data;
 typedef int fuse_handler_t(struct fuse_ticket *ftick, struct uio *uio);
 
 struct fuse_ticket {
-    /* fields giving the identity of the ticket */
-    uint64_t                     tk_unique;
-    struct fuse_data            *tk_data;
-    int                          tk_flag;
-    u_int                        tk_refcount;
+	/* fields giving the identity of the ticket */
+	uint64_t			tk_unique;
+	struct fuse_data		*tk_data;
+	int				tk_flag;
+	u_int				tk_refcount;
 
-    /* fields for initiating an upgoing message */
-    struct fuse_iov              tk_ms_fiov;
-    void                        *tk_ms_bufdata;
-    size_t                       tk_ms_bufsize;
-    enum { FT_M_FIOV, FT_M_BUF } tk_ms_type;
-    STAILQ_ENTRY(fuse_ticket)    tk_ms_link;
+	/* fields for initiating an upgoing message */
+	struct fuse_iov			tk_ms_fiov;
+	void				*tk_ms_bufdata;
+	size_t				tk_ms_bufsize;
+	enum { FT_M_FIOV, FT_M_BUF }	tk_ms_type;
+	STAILQ_ENTRY(fuse_ticket)	tk_ms_link;
 
-    /* fields for handling answers coming from userspace */
-    struct fuse_iov              tk_aw_fiov;
-    void                        *tk_aw_bufdata;
-    size_t                       tk_aw_bufsize;
-    enum { FT_A_FIOV, FT_A_BUF } tk_aw_type;
+	/* fields for handling answers coming from userspace */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201909061756.x86HuPMx006351>