svn commit: r344186 - head/sys/fs/fuse

Conrad Meyer cem at FreeBSD.org
Fri Feb 15 22:52:51 UTC 2019


Author: cem
Date: Fri Feb 15 22:52:49 2019
New Revision: 344186
URL: https://svnweb.freebsd.org/changeset/base/344186

Log:
  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)

Modified:
  head/sys/fs/fuse/fuse_io.c
  head/sys/fs/fuse/fuse_ipc.h
  head/sys/fs/fuse/fuse_node.c

Modified: head/sys/fs/fuse/fuse_io.c
==============================================================================
--- head/sys/fs/fuse/fuse_io.c	Fri Feb 15 22:51:09 2019	(r344185)
+++ head/sys/fs/fuse/fuse_io.c	Fri Feb 15 22:52:49 2019	(r344186)
@@ -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);
@@ -363,7 +369,7 @@ fuse_write_directbackend(struct vnode *vp, struct uio 
 		uio->uio_resid += diff;
 		uio->uio_offset -= diff;
 		if (uio->uio_offset > fvdat->filesize &&
-		    fuse_data_cache_enable) {
+		    fuse_data_cache_mode != FUSE_CACHE_UC) {
 			fuse_vnode_setsize(vp, cred, uio->uio_offset);
 			fvdat->flag &= ~FN_SIZECHANGE;
 		}

Modified: head/sys/fs/fuse/fuse_ipc.h
==============================================================================
--- head/sys/fs/fuse/fuse_ipc.h	Fri Feb 15 22:51:09 2019	(r344185)
+++ head/sys/fs/fuse/fuse_ipc.h	Fri Feb 15 22:52:49 2019	(r344186)
@@ -214,7 +214,13 @@ struct fuse_data {
 #define FSESS_NO_MMAP             0x0800 /* disable mmap */
 #define FSESS_BROKENIO            0x1000 /* fix broken io */
 
-extern int fuse_data_cache_enable;
+enum fuse_data_cache_mode {
+	FUSE_CACHE_UC,
+	FUSE_CACHE_WT,
+	FUSE_CACHE_WB,
+};
+
+extern int fuse_data_cache_mode;
 extern int fuse_data_cache_invalidate;
 extern int fuse_mmap_enable;
 extern int fuse_sync_resize;
@@ -248,7 +254,7 @@ fsess_opt_datacache(struct mount *mp)
 {
     struct fuse_data *data = fuse_get_mpdata(mp);
 
-    return (fuse_data_cache_enable ||
+    return (fuse_data_cache_mode != FUSE_CACHE_UC &&
         (data->dataflags & FSESS_NO_DATACACHE) == 0);
 }
 
@@ -257,7 +263,7 @@ fsess_opt_mmap(struct mount *mp)
 {
     struct fuse_data *data = fuse_get_mpdata(mp);
 
-    if (!(fuse_mmap_enable && fuse_data_cache_enable))
+    if (!fuse_mmap_enable || fuse_data_cache_mode == FUSE_CACHE_UC)
         return 0;
     return ((data->dataflags & (FSESS_NO_DATACACHE | FSESS_NO_MMAP)) == 0);
 }

Modified: head/sys/fs/fuse/fuse_node.c
==============================================================================
--- head/sys/fs/fuse/fuse_node.c	Fri Feb 15 22:51:09 2019	(r344185)
+++ head/sys/fs/fuse/fuse_node.c	Fri Feb 15 22:52:49 2019	(r344186)
@@ -94,16 +94,19 @@ __FBSDID("$FreeBSD$");
 
 MALLOC_DEFINE(M_FUSEVN, "fuse_vnode", "fuse vnode private data");
 
+static int sysctl_fuse_cache_mode(SYSCTL_HANDLER_ARGS);
+
 static int fuse_node_count = 0;
 
 SYSCTL_INT(_vfs_fuse, OID_AUTO, node_count, CTLFLAG_RD,
     &fuse_node_count, 0, "Count of FUSE vnodes");
 
-int	fuse_data_cache_enable = 1;
+int	fuse_data_cache_mode = FUSE_CACHE_WT;
 
-SYSCTL_INT(_vfs_fuse, OID_AUTO, data_cache_enable, CTLFLAG_RW,
-    &fuse_data_cache_enable, 0,
-    "enable caching of FUSE file data (including dirty data)");
+SYSCTL_PROC(_vfs_fuse, OID_AUTO, data_cache_mode, CTLTYPE_INT|CTLFLAG_RW,
+    &fuse_data_cache_mode, 0, sysctl_fuse_cache_mode, "I",
+    "Zero: disable caching of FUSE file data; One: write-through caching "
+    "(default); Two: write-back caching (generally unsafe)");
 
 int	fuse_data_cache_invalidate = 0;
 
@@ -116,7 +119,7 @@ int	fuse_mmap_enable = 1;
 
 SYSCTL_INT(_vfs_fuse, OID_AUTO, mmap_enable, CTLFLAG_RW,
     &fuse_mmap_enable, 0,
-    "If non-zero, and data_cache_enable is also non-zero, enable mmap(2) of "
+    "If non-zero, and data_cache_mode is also non-zero, enable mmap(2) of "
     "FUSE files");
 
 int	fuse_refresh_size = 0;
@@ -140,6 +143,28 @@ SYSCTL_INT(_vfs_fuse, OID_AUTO, fix_broken_io, CTLFLAG
     "If non-zero, print a diagnostic warning if a userspace filesystem returns"
     " EIO on reads of recently extended portions of files");
 
+static int
+sysctl_fuse_cache_mode(SYSCTL_HANDLER_ARGS)
+{
+	int val, error;
+
+	val = *(int *)arg1;
+	error = sysctl_handle_int(oidp, &val, 0, req);
+	if (error || !req->newptr)
+		return (error);
+
+	switch (val) {
+	case FUSE_CACHE_UC:
+	case FUSE_CACHE_WT:
+	case FUSE_CACHE_WB:
+		*(int *)arg1 = val;
+		break;
+	default:
+		return (EDOM);
+	}
+	return (0);
+}
+
 static void
 fuse_vnode_init(struct vnode *vp, struct fuse_vnode_data *fvdat,
     uint64_t nodeid, enum vtype vtyp)
@@ -375,7 +400,7 @@ fuse_vnode_refreshsize(struct vnode *vp, struct ucred 
 	struct vattr va;
 
 	if ((fvdat->flag & FN_SIZECHANGE) != 0 ||
-	    fuse_data_cache_enable == 0 ||
+	    fuse_data_cache_mode == FUSE_CACHE_UC ||
 	    (fuse_refresh_size == 0 && fvdat->filesize != 0))
 		return;
 


More information about the svn-src-head mailing list