Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 7 Aug 2019 00:38:26 +0000 (UTC)
From:      Alan Somers <asomers@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r350665 - in head: . etc/mtree sbin/mount_fusefs share/man/man5 sys/fs/fuse sys/sys tests/sys/fs tests/sys/fs/fusefs
Message-ID:  <201908070038.x770cQZE007711@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: asomers
Date: Wed Aug  7 00:38:26 2019
New Revision: 350665
URL: https://svnweb.freebsd.org/changeset/base/350665

Log:
  fusefs: merge from projects/fuse2
  
  This commit imports the new fusefs driver. It raises the protocol level
  from 7.8 to 7.23, fixes many bugs, adds a test suite for the driver, and
  adds many new features. New features include:
  
  * Optional kernel-side permissions checks (-o default_permissions)
  * Implement VOP_MKNOD, VOP_BMAP, and VOP_ADVLOCK
  * Allow interrupting FUSE operations
  * Support named pipes and unix-domain sockets in fusefs file systems
  * Forward UTIME_NOW during utimensat(2) to the daemon
  * kqueue support for /dev/fuse
  * Allow updating mounts with "mount -u"
  * Allow exporting fusefs file systems over NFS
  * Server-initiated invalidation of the name cache or data cache
  * Respect RLIMIT_FSIZE
  * Try to support servers as old as protocol 7.4
  
  Performance enhancements include:
  
  * Implement FUSE's FOPEN_KEEP_CACHE and FUSE_ASYNC_READ flags
  * Cache file attributes
  * Cache lookup entries, both positive and negative
  * Server-selectable cache modes: writethrough, writeback, or uncached
  * Write clustering
  * Readahead
  * Use counter(9) for statistical reporting
  
  PR:		199934 216391 233783 234581 235773 235774 235775
  PR:		236226 236231 236236 236291 236329 236381 236405
  PR:		236327 236466 236472 236473 236474 236530 236557
  PR:		236560 236844 237052 237181 237588 238565
  Reviewed by:	bcr (man pages)
  Reviewed by:	cem, ngie, rpokala, glebius, kib, bde, emaste (post-commit
  		review on project branch)
  MFC after:	3 weeks
  Relnotes:	yes
  Sponsored by:	The FreeBSD Foundation
  Pull Request:	https://reviews.freebsd.org/D21110

Added:
  head/tests/sys/fs/fusefs/
     - copied from r350621, projects/fuse2/tests/sys/fs/fusefs/
Deleted:
  head/sys/fs/fuse/fuse_param.h
Modified:
  head/MAINTAINERS   (contents, props changed)
  head/UPDATING
  head/etc/mtree/BSD.tests.dist
  head/sbin/mount_fusefs/mount_fusefs.8
  head/sbin/mount_fusefs/mount_fusefs.c
  head/share/man/man5/fusefs.5
  head/sys/fs/fuse/fuse.h
  head/sys/fs/fuse/fuse_device.c
  head/sys/fs/fuse/fuse_file.c
  head/sys/fs/fuse/fuse_file.h
  head/sys/fs/fuse/fuse_internal.c
  head/sys/fs/fuse/fuse_internal.h
  head/sys/fs/fuse/fuse_io.c
  head/sys/fs/fuse/fuse_io.h
  head/sys/fs/fuse/fuse_ipc.c
  head/sys/fs/fuse/fuse_ipc.h
  head/sys/fs/fuse/fuse_kernel.h
  head/sys/fs/fuse/fuse_main.c
  head/sys/fs/fuse/fuse_node.c
  head/sys/fs/fuse/fuse_node.h
  head/sys/fs/fuse/fuse_vfsops.c
  head/sys/fs/fuse/fuse_vnops.c
  head/sys/sys/param.h
  head/tests/sys/fs/Makefile
Directory Properties:
  head/   (props changed)

Modified: head/MAINTAINERS
==============================================================================
--- head/MAINTAINERS	Tue Aug  6 23:22:25 2019	(r350664)
+++ head/MAINTAINERS	Wed Aug  7 00:38:26 2019	(r350665)
@@ -53,6 +53,7 @@ contrib/pjdfstest	asomers,ngie,pjd,#test	Pre-commit re
 etc/mail	gshapiro	Pre-commit review requested.  Keep in sync with -STABLE.
 etc/sendmail	gshapiro	Pre-commit review requested.  Keep in sync with -STABLE.
 fetch		des	Pre-commit review requested, email only.
+fusefs(5)	asomers	Pre-commit review requested.
 geli		pjd	Pre-commit review requested (both sys/geom/eli/ and sbin/geom/class/eli/).
 isci(4)		jimharris	Pre-commit review requested.
 iwm(4)		adrian	Pre-commit review requested, send to freebsd-wireless@freebsd.org

Modified: head/UPDATING
==============================================================================
--- head/UPDATING	Tue Aug  6 23:22:25 2019	(r350664)
+++ head/UPDATING	Wed Aug  7 00:38:26 2019	(r350665)
@@ -26,6 +26,18 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
 	disable the most expensive debugging functionality run
 	"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
 
+20190727:
+	The vfs.fusefs.sync_unmount and vfs.fusefs.init_backgrounded sysctls
+	and the "-o sync_unmount" and "-o init_backgrounded" mount options have
+	been removed from mount_fusefs(8).  You can safely remove them from
+	your scripts, because they had no effect.
+
+	The vfs.fusefs.fix_broken_io, vfs.fusefs.sync_resize,
+	vfs.fusefs.refresh_size, vfs.fusefs.mmap_enable,
+	vfs.fusefs.reclaim_revoked, and vfs.fusefs.data_cache_invalidate
+	sysctls have been removed.  If you felt the need to set any of them to
+	a non-default value, please tell asomers@FreeBSD.org why.
+
 20190713:
 	Default permissions on the /var/account/acct file (and copies of it 
 	rotated by periodic daily scripts) are changed from 0644 to 0640 

Modified: head/etc/mtree/BSD.tests.dist
==============================================================================
--- head/etc/mtree/BSD.tests.dist	Tue Aug  6 23:22:25 2019	(r350664)
+++ head/etc/mtree/BSD.tests.dist	Wed Aug  7 00:38:26 2019	(r350665)
@@ -731,6 +731,8 @@
         file
         ..
         fs
+            fusefs
+            ..
             tmpfs
             ..
         ..

Modified: head/sbin/mount_fusefs/mount_fusefs.8
==============================================================================
--- head/sbin/mount_fusefs/mount_fusefs.8	Tue Aug  6 23:22:25 2019	(r350664)
+++ head/sbin/mount_fusefs/mount_fusefs.8	Wed Aug  7 00:38:26 2019	(r350665)
@@ -3,6 +3,11 @@
 .\" Copyright (c) 2005, 2006 Csaba Henk
 .\" All rights reserved.
 .\"
+.\" Copyright (c) 2019 The FreeBSD Foundation
+.\"
+.\" Portions of this documentation were written by BFF Storage Systems under
+.\" sponsorship from the FreeBSD Foundation.
+.\"
 .\" Redistribution and use in source and binary forms, with or without
 .\" modification, are permitted provided that the following conditions
 .\" are met:
@@ -29,7 +34,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 17, 2018
+.Dd July 31, 2019
 .Dt MOUNT_FUSEFS 8
 .Os
 .Sh NAME
@@ -108,27 +113,27 @@ Intended for use in scripts and the
 .Xr sudoers 5
 file.
 .It Fl S , Ic --safe
-Run in safe mode (i.e. reject invoking a filesystem daemon)
+Run in safe mode (i.e., reject invoking a filesystem daemon).
 .It Fl v
-Be verbose
-.It Fl D, Ic --daemon Ar daemon
+Be verbose.
+.It Fl D , Ic --daemon Ar daemon
 Call the specified
-.Ar daemon
-.It Fl O, Ic --daemon_opts Ar opts
+.Ar daemon .
+.It Fl O , Ic --daemon_opts Ar opts
 Add
 .Ar opts
-to the daemon's command line
-.It Fl s, Ic --special Ar special
+to the daemon's command line.
+.It Fl s , Ic --special Ar special
 Use
 .Ar special
-as special
-.It Fl m, Ic --mountpath Ar node
+as special.
+.It Fl m , Ic --mountpath Ar node
 Mount on
-.Ar node
-.It Fl h, Ic --help
-Show help
-.It Fl V, Ic --version
-Show version information
+.Ar node .
+.It Fl h , Ic --help
+Show help.
+.It Fl V , Ic --version
+Show version information.
 .It Fl o
 Mount options are specified via
 .Fl o .
@@ -136,23 +141,38 @@ The following options are available (and also their ne
 by prefixing them with
 .Dq no ) :
 .Bl -tag -width indent
-.It Cm default_permissions
-Enable traditional (file mode based) permission checking in kernel
 .It Cm allow_other
 Do not apply
 .Sx STRICT ACCESS POLICY .
-Only root can use this option
+Only root can use this option.
+.It Cm async
+I/O to the file system may be done asynchronously.
+Writes may be delayed and/or reordered.
+.It Cm default_permissions
+Enable traditional (file mode based) permission checking in kernel.
+.It Cm intr
+Allow signals to interrupt operations that are blocked waiting for a reply from the server.
+When this option is in use, system calls may fail with
+.Er EINTR
+whenever a signal is received.
 .It Cm max_read Ns = Ns Ar n
 Limit size of read requests to
-.Ar n
+.Ar n .
+.It Cm neglect_shares
+Do not refuse unmounting if there are secondary mounts.
 .It Cm private
 Refuse shared mounting of the daemon.
 This is the default behaviour, to allow sharing, expicitly use
-.Fl o Cm noprivate
-.It Cm neglect_shares
-Do not refuse unmounting if there are secondary mounts
+.Fl o Cm noprivate .
 .It Cm push_symlinks_in
-Prefix absolute symlinks with the mountpoint
+Prefix absolute symlinks with the mountpoint.
+.It Cm subtype Ns = Ns Ar fsname
+Suffix
+.Ar fsname
+to the file system name as reported by
+.Xr statfs 2 .
+This option can be used to identify the file system implemented by
+.Ar fuse_daemon .
 .El
 .El
 .Pp
@@ -167,11 +187,11 @@ However, there are some which do require in-kernel sup
 Currently the options supported by the kernel are:
 .Bl -tag -width indent
 .It Cm direct_io
-Bypass the buffer cache system
+Bypass the buffer cache system.
 .It Cm kernel_cache
 By default cached buffers of a given file are flushed at each
 .Xr open 2 .
-This option disables this behaviour
+This option disables this behaviour.
 .El
 .Sh DAEMON MOUNTS
 Usually users do not need to use
@@ -194,7 +214,7 @@ only if the filesystem daemon has the same credentials
 real gid) as the user.
 .Pp
 This is applied for Fuse mounts by default and only root can mount without
-the strict access policy (i.e. the
+the strict access policy (i.e., the
 .Cm allow_other
 mount option).
 .Pp
@@ -206,7 +226,7 @@ Users might opt to willingly relax strict access polic
 are concerned) by doing their own secondary mount (See
 .Sx SHARED MOUNTS ) .
 .Sh SHARED MOUNTS
-A Fuse daemon can be shared (i.e. mounted multiple times).
+A Fuse daemon can be shared (i.e., mounted multiple times).
 When doing the first (primary) mount, the spawner and the mounter of the daemon
 must have the same uid, or the mounter should be the superuser.
 .Pp
@@ -225,7 +245,7 @@ is used or not.
 .Pp
 The device name of a secondary mount is the device name of the corresponding
 primary mount, followed by a '#' character and the index of the secondary
-mount; e.g.
+mount; e.g.,
 .Pa /dev/fuse0#3 .
 .Sh SECURITY
 System administrators might want to use a custom mount policy (ie., one going
@@ -239,7 +259,7 @@ However, given that
 is capable of invoking an arbitrary program, one must be careful when doing this.
 .Nm
 is designed in a way such that it makes that easy.
-For this purpose, there are options which disable certain risky features (i.e.
+For this purpose, there are options which disable certain risky features (
 .Fl S
 and
 .Fl A ) ,
@@ -342,7 +362,7 @@ does not call any external utility and also provides a
 was written as the part of the
 .Fx
 implementation of the Fuse userspace filesystem framework (see
-.Xr https://github.com/libfuse/libfuse )
+.Lk https://github.com/libfuse/libfuse )
 and first appeared in the
 .Pa sysutils/fusefs-kmod
 port, supporting

Modified: head/sbin/mount_fusefs/mount_fusefs.c
==============================================================================
--- head/sbin/mount_fusefs/mount_fusefs.c	Tue Aug  6 23:22:25 2019	(r350664)
+++ head/sbin/mount_fusefs/mount_fusefs.c	Wed Aug  7 00:38:26 2019	(r350665)
@@ -5,6 +5,11 @@
  * Copyright (c) 2005 Csaba Henk 
  * All rights reserved.
  *
+ * Copyright (c) 2019 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by BFF Storage Systems under
+ * sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -60,7 +65,6 @@ void	__usage_short(void);
 void	usage(void);
 void	helpmsg(void);
 void	showversion(void);
-int	init_backgrounded(void);
 
 static struct mntopt mopts[] = {
 	#define ALTF_PRIVATE 0x01
@@ -73,8 +77,6 @@ static struct mntopt mopts[] = {
 	{ "max_read=",           0, ALTF_MAXREAD, 1 },
 	#define ALTF_SUBTYPE 0x40
 	{ "subtype=",            0, ALTF_SUBTYPE, 1 },
-	#define ALTF_SYNC_UNMOUNT 0x80
-	{ "sync_unmount",        0, ALTF_SYNC_UNMOUNT, 1 },
 	/*
 	 * MOPT_AUTOMOUNTED, included by MOPT_STDOPTS, does not fit into
 	 * the 'flags' argument to nmount(2).  We have to abuse altflags
@@ -82,6 +84,8 @@ static struct mntopt mopts[] = {
 	 */
 	#define ALTF_AUTOMOUNTED 0x100
 	{ "automounted",	0, ALTF_AUTOMOUNTED, 1 },
+	#define ALTF_INTR 0x200
+	{ "intr",		0, ALTF_INTR, 1 },
 	/* Linux specific options, we silently ignore them */
 	{ "fsname=",             0, 0x00, 1 },
 	{ "fd=",                 0, 0x00, 1 },
@@ -91,6 +95,8 @@ static struct mntopt mopts[] = {
 	{ "large_read",          0, 0x00, 1 },
 	/* "nonempty", just the first two chars are stripped off during parsing */
 	{ "nempty",              0, 0x00, 1 },
+	{ "async",               0, MNT_ASYNC, 0},
+	{ "noasync",             1, MNT_ASYNC, 0},
 	MOPT_STDOPTS,
 	MOPT_END
 };
@@ -107,7 +113,7 @@ static struct mntval mvals[] = {
 	{ 0, NULL, 0 }
 };
 
-#define DEFAULT_MOUNT_FLAGS ALTF_PRIVATE | ALTF_SYNC_UNMOUNT
+#define DEFAULT_MOUNT_FLAGS ALTF_PRIVATE
 
 int
 main(int argc, char *argv[])
@@ -409,12 +415,6 @@ main(int argc, char *argv[])
 		}
 	}
 
-	if (fd >= 0 && ! init_backgrounded() && close(fd) < 0) {
-		if (pid)
-			kill(pid, SIGKILL);
-		err(1, "failed to close fuse device");
-	}
-
 	/* Prepare the options vector for nmount(). build_iovec() is declared
 	 * in mntopts.h. */
 	sprintf(fdstr, "%d", fd);
@@ -471,6 +471,7 @@ helpmsg(void)
 	        "    -o allow_other         allow access to other users\n"
 	        /* "    -o nonempty            allow mounts over non-empty file/dir\n" */
 	        "    -o default_permissions enable permission checking by kernel\n"
+		"    -o intr                interruptible mount\n"
 		/*
 	        "    -o fsname=NAME         set filesystem name\n"
 	        "    -o large_read          issue large read requests (2.4 only)\n"
@@ -481,7 +482,6 @@ helpmsg(void)
 	        "    -o neglect_shares      don't report EBUSY when unmount attempted\n"
 	        "                           in presence of secondary mounts\n" 
 	        "    -o push_symlinks_in    prefix absolute symlinks with mountpoint\n"
-	        "    -o sync_unmount        do unmount synchronously\n"
 	        );
 	exit(EX_USAGE);
 }
@@ -491,18 +491,4 @@ showversion(void)
 {
 	puts("mount_fusefs [fuse4bsd] version: " FUSE4BSD_VERSION);
 	exit(EX_USAGE);
-}
-
-int
-init_backgrounded(void)
-{
-	int ibg;
-	size_t len;
-
-	len = sizeof(ibg);
-
-	if (sysctlbyname("vfs.fusefs.init_backgrounded", &ibg, &len, NULL, 0))
-		return (0);
-
-	return (ibg);
 }

Modified: head/share/man/man5/fusefs.5
==============================================================================
--- head/share/man/man5/fusefs.5	Tue Aug  6 23:22:25 2019	(r350664)
+++ head/share/man/man5/fusefs.5	Wed Aug  7 00:38:26 2019	(r350665)
@@ -3,8 +3,8 @@
 .\"
 .\" Copyright (c) 2019 The FreeBSD Foundation
 .\"
-.\" This software was developed by BFF Storage Systems, LLC under sponsorship
-.\" from the FreeBSD Foundation.
+.\" This documentation was written by BFF Storage Systems, LLC under
+.\" sponsorship from the FreeBSD Foundation.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
 .\" modification, are permitted provided that the following conditions
@@ -28,7 +28,7 @@
 .\" SUCH DAMAGE.
 .\"
 .\" $FreeBSD$
-.Dd April 13, 2019
+.Dd July 31, 2019
 .Dt FUSEFS 5
 .Os
 .Sh NAME
@@ -60,11 +60,9 @@ Finally, the
 API is portable.
 Many daemons can run on multiple operating systems with minimal modifications.
 .Sh SYSCTL VARIABLES
-The following variables are available as both
+The following
 .Xr sysctl 8
-variables and
-.Xr loader 8
-tunables:
+variables are available:
 .Bl -tag -width indent
 .It Va vfs.fusefs.kernelabi_major
 Major version of the FUSE kernel ABI supported by this driver.
@@ -73,7 +71,7 @@ Minor version of the FUSE kernel ABI supported by this
 .It Va vfs.fusefs.data_cache_mode
 Controls how
 .Nm
-will cache file data.
+will cache file data for pre-7.23 file systems.
 A value of 0 will disable caching entirely.
 Every data access will be forwarded to the daemon.
 A value of 1 will select write-through caching.
@@ -84,33 +82,26 @@ Reads and writes will both be cached, and writes will 
 to the daemon by the page daemon.
 Write-back caching is usually unsafe, especially for FUSE file systems that
 require network access.
-.It Va vfs.fusefs.lookup_cache_enable
-Controls whether
-.Nm
-will cache lookup responses from the file system.
-FUSE file systems indicate whether lookup responses should be cacheable, but
-it may be useful to globally disable caching them if a file system is
-misbehaving.
+.Pp
+FUSE file systems using protocol 7.23 or later specify their cache behavior
+on a per-mountpoint basis, ignoring this sysctl.
+.It Va vfs.fusefs.stats.filehandle_count
+Current number of open FUSE file handles.
+.It Va vfs.fusefs.stats.lookup_cache_hits
+Total number of lookup cache hits.
+.It Va vfs.fusefs.stats.lookup_cache_misses
+Total number of lookup cache misses.
+.It Va vfs.fusefs.stats.node_count
+Current number of allocated FUSE vnodes.
+.It Va vfs.fusefs.stats.ticket_count
+Current number of allocated FUSE tickets, which is roughly equal to the number
+of FUSE operations currently being processed by daemons.
 .\" Undocumented sysctls
 .\" ====================
-.\" Counters: I intend to rename to vfs.fusefs.stats.* for clarity
-.\" vfs.fusefs.lookup_cache_{hits, misses}
-.\" vfs.fusefs.filehandle_count
-.\" vfs.fusefs.ticker_count
-.\" vfs.fusefs.node_count
-.\"
-.\" vfs.fusefs.version - useless since the driver moved in-tree
-.\" vfs.fusefs.reclaim_revoked: I don't understand it well-enough
-.\" vfs.fusefs.sync_unmount: dead code
 .\" vfs.fusefs.enforce_dev_perms: I don't understand it well enough.
-.\" vfs.fusefs.init_backgrounded: dead code
 .\" vfs.fusefs.iov_credit: I don't understand it well enough
 .\" vfs.fusefs.iov_permanent_bufsize: I don't understand it well enough
-.\" vfs.fusefs.fix_broken_io: I don't understand it well enough
-.\" vfs.fusefs.sync_resize: useless and should be removed
-.\" vfs.fusefs.refresh_size: probably useless?
-.\" vfs.fusefs.mmap_enable: why is this optional?
-.\" vfs.fusefs.data_cache_invalidate: what is this needed for?
+.El
 .Sh SEE ALSO
 .Xr mount_fusefs 8
 .Sh HISTORY
@@ -119,7 +110,7 @@ The
 driver was written as the part of the
 .Fx
 implementation of the FUSE userspace file system framework (see
-.Xr https://github.com/libfuse/libfuse )
+.Lk https://github.com/libfuse/libfuse )
 and first appeared in the
 .Pa sysutils/fusefs-kmod
 port, supporting

Modified: head/sys/fs/fuse/fuse.h
==============================================================================
--- head/sys/fs/fuse/fuse.h	Tue Aug  6 23:22:25 2019	(r350664)
+++ head/sys/fs/fuse/fuse.h	Wed Aug  7 00:38:26 2019	(r350665)
@@ -32,6 +32,11 @@
  * 
  * Copyright (C) 2005 Csaba Henk.
  * All rights reserved.
+ *
+ * Copyright (c) 2019 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by BFF Storage Systems, LLC under
+ * sponsorship from the FreeBSD Foundation.
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -63,87 +68,10 @@
 #define FUSE_MIN_DAEMON_TIMEOUT                    0      /* s */
 #define FUSE_MAX_DAEMON_TIMEOUT                    600    /* s */
 
-#ifndef FUSE_FREEBSD_VERSION
-#define	FUSE_FREEBSD_VERSION	"0.4.4"
-#endif
-
-/* Mapping versions to features */
-
-#define FUSE_KERNELABI_GEQ(maj, min)	\
-(FUSE_KERNEL_VERSION > (maj) || (FUSE_KERNEL_VERSION == (maj) && FUSE_KERNEL_MINOR_VERSION >= (min)))
-
-/*
- * Appearance of new FUSE operations is not always in par with version
- * numbering... At least, 7.3 is a sufficient condition for having
- * FUSE_{ACCESS,CREATE}.
- */
-#if FUSE_KERNELABI_GEQ(7, 3)
-#ifndef FUSE_HAS_ACCESS
-#define FUSE_HAS_ACCESS 1
-#endif
-#ifndef FUSE_HAS_CREATE
-#define FUSE_HAS_CREATE 1
-#endif
-#else /* FUSE_KERNELABI_GEQ(7, 3) */
-#ifndef FUSE_HAS_ACCESS
-#define FUSE_HAS_ACCESS 0
-#endif
-#ifndef FUSE_HAS_CREATE
-#define FUSE_HAS_CREATE 0
-#endif
-#endif
-
-#if FUSE_KERNELABI_GEQ(7, 7)
-#ifndef FUSE_HAS_GETLK
-#define FUSE_HAS_GETLK 1
-#endif
-#ifndef FUSE_HAS_SETLK
-#define FUSE_HAS_SETLK 1
-#endif
-#ifndef FUSE_HAS_SETLKW
-#define FUSE_HAS_SETLKW 1
-#endif
-#ifndef FUSE_HAS_INTERRUPT
-#define FUSE_HAS_INTERRUPT 1
-#endif
-#else /* FUSE_KERNELABI_GEQ(7, 7) */
-#ifndef FUSE_HAS_GETLK
-#define FUSE_HAS_GETLK 0
-#endif
-#ifndef FUSE_HAS_SETLK
-#define FUSE_HAS_SETLK 0
-#endif
-#ifndef FUSE_HAS_SETLKW
-#define FUSE_HAS_SETLKW 0
-#endif
-#ifndef FUSE_HAS_INTERRUPT
-#define FUSE_HAS_INTERRUPT 0
-#endif
-#endif
-
-#if FUSE_KERNELABI_GEQ(7, 8)
-#ifndef FUSE_HAS_FLUSH_RELEASE
-#define FUSE_HAS_FLUSH_RELEASE 1
-/*
- * "DESTROY" came in the middle of the 7.8 era,
- * so this is not completely exact...
- */
-#ifndef FUSE_HAS_DESTROY
-#define FUSE_HAS_DESTROY 1
-#endif
-#endif
-#else /* FUSE_KERNELABI_GEQ(7, 8) */
-#ifndef FUSE_HAS_FLUSH_RELEASE
-#define FUSE_HAS_FLUSH_RELEASE 0
-#ifndef FUSE_HAS_DESTROY
-#define FUSE_HAS_DESTROY 0
-#endif
-#endif
-#endif
-
 /* misc */
 
 SYSCTL_DECL(_vfs_fusefs);
+SYSCTL_DECL(_vfs_fusefs_stats);
 
 /* Fuse locking */
 

Modified: head/sys/fs/fuse/fuse_device.c
==============================================================================
--- head/sys/fs/fuse/fuse_device.c	Tue Aug  6 23:22:25 2019	(r350664)
+++ head/sys/fs/fuse/fuse_device.c	Wed Aug  7 00:38:26 2019	(r350665)
@@ -33,6 +33,11 @@
  * Copyright (C) 2005 Csaba Henk.
  * All rights reserved.
  *
+ * Copyright (c) 2019 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by BFF Storage Systems, LLC under
+ * sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -81,27 +86,28 @@ __FBSDID("$FreeBSD$");
 #include <sys/selinfo.h>
 
 #include "fuse.h"
+#include "fuse_internal.h"
 #include "fuse_ipc.h"
 
-SDT_PROVIDER_DECLARE(fuse);
+SDT_PROVIDER_DECLARE(fusefs);
 /* 
  * Fuse trace probe:
  * arg0: verbosity.  Higher numbers give more verbose messages
  * arg1: Textual message
  */
-SDT_PROBE_DEFINE2(fuse, , device, trace, "int", "char*");
+SDT_PROBE_DEFINE2(fusefs, , device, trace, "int", "char*");
 
 static struct cdev *fuse_dev;
 
+static d_kqfilter_t fuse_device_filter;
 static d_open_t fuse_device_open;
-static d_close_t fuse_device_close;
 static d_poll_t fuse_device_poll;
 static d_read_t fuse_device_read;
 static d_write_t fuse_device_write;
 
 static struct cdevsw fuse_device_cdevsw = {
+	.d_kqfilter = fuse_device_filter,
 	.d_open = fuse_device_open,
-	.d_close = fuse_device_close,
 	.d_name = "fuse",
 	.d_poll = fuse_device_poll,
 	.d_read = fuse_device_read,
@@ -109,6 +115,15 @@ static struct cdevsw fuse_device_cdevsw = {
 	.d_version = D_VERSION,
 };
 
+static int fuse_device_filt_read(struct knote *kn, long hint);
+static void fuse_device_filt_detach(struct knote *kn);
+
+struct filterops fuse_device_rfiltops = {
+	.f_isfd = 1,
+	.f_detach = fuse_device_filt_detach,
+	.f_event = fuse_device_filt_read,
+};
+
 /****************************
  *
  * >>> Fuse device op defs
@@ -119,11 +134,100 @@ static void
 fdata_dtor(void *arg)
 {
 	struct fuse_data *fdata;
+	struct fuse_ticket *tick;
 
 	fdata = arg;
+	if (fdata == NULL)
+		return;
+
+	fdata_set_dead(fdata);
+
+	FUSE_LOCK();
+	fuse_lck_mtx_lock(fdata->aw_mtx);
+	/* wakup poll()ers */
+	selwakeuppri(&fdata->ks_rsel, PZERO + 1);
+	/* Don't let syscall handlers wait in vain */
+	while ((tick = fuse_aw_pop(fdata))) {
+		fuse_lck_mtx_lock(tick->tk_aw_mtx);
+		fticket_set_answered(tick);
+		tick->tk_aw_errno = ENOTCONN;
+		wakeup(tick);
+		fuse_lck_mtx_unlock(tick->tk_aw_mtx);
+		FUSE_ASSERT_AW_DONE(tick);
+		fuse_ticket_drop(tick);
+	}
+	fuse_lck_mtx_unlock(fdata->aw_mtx);
+
+	/* Cleanup unsent operations */
+	fuse_lck_mtx_lock(fdata->ms_mtx);
+	while ((tick = fuse_ms_pop(fdata))) {
+		fuse_ticket_drop(tick);
+	}
+	fuse_lck_mtx_unlock(fdata->ms_mtx);
+	FUSE_UNLOCK();
+
 	fdata_trydestroy(fdata);
 }
 
+static int
+fuse_device_filter(struct cdev *dev, struct knote *kn)
+{
+	struct fuse_data *data;
+	int error;
+
+	error = devfs_get_cdevpriv((void **)&data);
+
+	/* EVFILT_WRITE is not supported; the device is always ready to write */
+	if (error == 0 && kn->kn_filter == EVFILT_READ) {
+		kn->kn_fop = &fuse_device_rfiltops;
+		kn->kn_hook = data;
+		knlist_add(&data->ks_rsel.si_note, kn, 0);
+		error = 0;
+	} else if (error == 0) {
+		error = EINVAL;
+		kn->kn_data = error;
+	}
+
+	return (error);
+}
+
+static void
+fuse_device_filt_detach(struct knote *kn)
+{
+	struct fuse_data *data;
+
+	data = (struct fuse_data*)kn->kn_hook;
+	MPASS(data != NULL);
+	knlist_remove(&data->ks_rsel.si_note, kn, 0);
+	kn->kn_hook = NULL;
+}
+
+static int
+fuse_device_filt_read(struct knote *kn, long hint)
+{
+	struct fuse_data *data;
+	int ready;
+
+	data = (struct fuse_data*)kn->kn_hook;
+	MPASS(data != NULL);
+
+	mtx_assert(&data->ms_mtx, MA_OWNED);
+	if (fdata_get_dead(data)) {
+		kn->kn_flags |= EV_EOF;
+		kn->kn_fflags = ENODEV;
+		kn->kn_data = 1;
+		ready = 1;
+	} else if (STAILQ_FIRST(&data->ms_head)) {
+		MPASS(data->ms_count >= 1);
+		kn->kn_data = data->ms_count;
+		ready = 1;
+	} else {
+		ready = 0;
+	}
+
+	return (ready);
+}
+
 /*
  * Resources are set up on a per-open basis
  */
@@ -133,52 +237,17 @@ fuse_device_open(struct cdev *dev, int oflags, int dev
 	struct fuse_data *fdata;
 	int error;
 
-	SDT_PROBE2(fuse, , device, trace, 1, "device open");
+	SDT_PROBE2(fusefs, , device, trace, 1, "device open");
 
 	fdata = fdata_alloc(dev, td->td_ucred);
 	error = devfs_set_cdevpriv(fdata, fdata_dtor);
 	if (error != 0)
 		fdata_trydestroy(fdata);
 	else
-		SDT_PROBE2(fuse, , device, trace, 1, "device open success");
+		SDT_PROBE2(fusefs, , device, trace, 1, "device open success");
 	return (error);
 }
 
-static int
-fuse_device_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
-{
-	struct fuse_data *data;
-	struct fuse_ticket *tick;
-	int error;
-
-	error = devfs_get_cdevpriv((void **)&data);
-	if (error != 0)
-		return (error);
-	if (!data)
-		panic("no fuse data upon fuse device close");
-	fdata_set_dead(data);
-
-	FUSE_LOCK();
-	fuse_lck_mtx_lock(data->aw_mtx);
-	/* wakup poll()ers */
-	selwakeuppri(&data->ks_rsel, PZERO + 1);
-	/* Don't let syscall handlers wait in vain */
-	while ((tick = fuse_aw_pop(data))) {
-		fuse_lck_mtx_lock(tick->tk_aw_mtx);
-		fticket_set_answered(tick);
-		tick->tk_aw_errno = ENOTCONN;
-		wakeup(tick);
-		fuse_lck_mtx_unlock(tick->tk_aw_mtx);
-		FUSE_ASSERT_AW_DONE(tick);
-		fuse_ticket_drop(tick);
-	}
-	fuse_lck_mtx_unlock(data->aw_mtx);
-	FUSE_UNLOCK();
-
-	SDT_PROBE2(fuse, , device, trace, 1, "device close");
-	return (0);
-}
-
 int
 fuse_device_poll(struct cdev *dev, int events, struct thread *td)
 {
@@ -219,7 +288,7 @@ fuse_device_read(struct cdev *dev, struct uio *uio, in
 	int buflen[3];
 	int i;
 
-	SDT_PROBE2(fuse, , device, trace, 1, "fuse device read");
+	SDT_PROBE2(fusefs, , device, trace, 1, "fuse device read");
 
 	err = devfs_get_cdevpriv((void **)&data);
 	if (err != 0)
@@ -228,7 +297,7 @@ fuse_device_read(struct cdev *dev, struct uio *uio, in
 	fuse_lck_mtx_lock(data->ms_mtx);
 again:
 	if (fdata_get_dead(data)) {
-		SDT_PROBE2(fuse, , device, trace, 2,
+		SDT_PROBE2(fusefs, , device, trace, 2,
 			"we know early on that reader should be kicked so we "
 			"don't wait for news");
 		fuse_lck_mtx_unlock(data->ms_mtx);
@@ -256,7 +325,7 @@ again:
 		 * -- and some other cases, too, tho not totally clear, when
 		 * (cv_signal/wakeup_one signals the whole process ?)
 		 */
-		SDT_PROBE2(fuse, , device, trace, 1, "no message on thread");
+		SDT_PROBE2(fusefs, , device, trace, 1, "no message on thread");
 		goto again;
 	}
 	fuse_lck_mtx_unlock(data->ms_mtx);
@@ -266,9 +335,10 @@ again:
 		 * somebody somewhere -- eg., umount routine --
 		 * wants this liaison finished off
 		 */
-		SDT_PROBE2(fuse, , device, trace, 2, "reader is to be sacked");
+		SDT_PROBE2(fusefs, , device, trace, 2,
+			"reader is to be sacked");
 		if (tick) {
-			SDT_PROBE2(fuse, , device, trace, 2, "weird -- "
+			SDT_PROBE2(fusefs, , device, trace, 2, "weird -- "
 				"\"kick\" is set tho there is message");
 			FUSE_ASSERT_MS_DONE(tick);
 			fuse_ticket_drop(tick);
@@ -276,7 +346,7 @@ again:
 		return (ENODEV);	/* This should make the daemon get off
 					 * of us */
 	}
-	SDT_PROBE2(fuse, , device, trace, 1,
+	SDT_PROBE2(fusefs, , device, trace, 1,
 		"fuse device read message successfully");
 
 	KASSERT(tick->tk_ms_bufdata || tick->tk_ms_bufsize == 0,
@@ -311,7 +381,7 @@ again:
 		 */
 		if (uio->uio_resid < buflen[i]) {
 			fdata_set_dead(data);
-			SDT_PROBE2(fuse, , device, trace, 2,
+			SDT_PROBE2(fusefs, , device, trace, 2,
 			    "daemon is stupid, kick it off...");
 			err = ENODEV;
 			break;
@@ -331,23 +401,26 @@ static inline int
 fuse_ohead_audit(struct fuse_out_header *ohead, struct uio *uio)
 {
 	if (uio->uio_resid + sizeof(struct fuse_out_header) != ohead->len) {
-		SDT_PROBE2(fuse, , device, trace, 1, "Format error: body size "
+		SDT_PROBE2(fusefs, , device, trace, 1,
+			"Format error: body size "
 			"differs from size claimed by header");
 		return (EINVAL);
 	}
-	if (uio->uio_resid && ohead->error) {
-		SDT_PROBE2(fuse, , device, trace, 1, 
+	if (uio->uio_resid && ohead->unique != 0 && ohead->error) {
+		SDT_PROBE2(fusefs, , device, trace, 1, 
 			"Format error: non zero error but message had a body");
 		return (EINVAL);
 	}
-	/* Sanitize the linuxism of negative errnos */
-	ohead->error = -(ohead->error);
 
 	return (0);
 }
 
-SDT_PROBE_DEFINE1(fuse, , device, fuse_device_write_bumped_into_callback,
-		"uint64_t");
+SDT_PROBE_DEFINE1(fusefs, , device, fuse_device_write_notify,
+	"struct fuse_out_header*");
+SDT_PROBE_DEFINE1(fusefs, , device, fuse_device_write_missing_ticket,
+	"uint64_t");
+SDT_PROBE_DEFINE1(fusefs, , device, fuse_device_write_found,
+	"struct fuse_ticket*");
 /*
  * fuse_device_write first reads the header sent by the daemon.
  * If that's OK, looks up ticket/callback node by the unique id seen in header.
@@ -360,15 +433,17 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i
 	struct fuse_out_header ohead;
 	int err = 0;
 	struct fuse_data *data;
-	struct fuse_ticket *tick, *x_tick;
+	struct mount *mp;
+	struct fuse_ticket *tick, *itick, *x_tick;
 	int found = 0;
 
 	err = devfs_get_cdevpriv((void **)&data);
 	if (err != 0)
 		return (err);
+	mp = data->mp;
 
 	if (uio->uio_resid < sizeof(struct fuse_out_header)) {
-		SDT_PROBE2(fuse, , device, trace, 1,
+		SDT_PROBE2(fusefs, , device, trace, 1,
 			"fuse_device_write got less than a header!");
 		fdata_set_dead(data);
 		return (EINVAL);
@@ -393,15 +468,29 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i
 	fuse_lck_mtx_lock(data->aw_mtx);
 	TAILQ_FOREACH_SAFE(tick, &data->aw_head, tk_aw_link,
 	    x_tick) {
-		SDT_PROBE1(fuse, , device,
-			fuse_device_write_bumped_into_callback,
-			tick->tk_unique);
 		if (tick->tk_unique == ohead.unique) {
+			SDT_PROBE1(fusefs, , device, fuse_device_write_found,
+				tick);
 			found = 1;
 			fuse_aw_remove(tick);
 			break;
 		}
 	}
+	if (found && tick->irq_unique > 0) {
+		/* 
+		 * Discard the FUSE_INTERRUPT ticket that tried to interrupt
+		 * this operation
+		 */
+		TAILQ_FOREACH_SAFE(itick, &data->aw_head, tk_aw_link,
+		    x_tick) {
+			if (itick->tk_unique == tick->irq_unique) {
+				fuse_aw_remove(itick);
+				fuse_ticket_drop(itick);
+				break;
+			}
+		}
+		tick->irq_unique = 0;
+	}
 	fuse_lck_mtx_unlock(data->aw_mtx);
 
 	if (found) {
@@ -414,13 +503,15 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i
 			 * via ticket_drop(), so no manual mucking
 			 * around...)
 			 */
-			SDT_PROBE2(fuse, , device, trace, 1,
+			SDT_PROBE2(fusefs, , device, trace, 1,
 				"pass ticket to a callback");
+			/* Sanitize the linuxism of negative errnos */
+			ohead.error *= -1;
 			memcpy(&tick->tk_aw_ohead, &ohead, sizeof(ohead));
 			err = tick->tk_aw_handler(tick, uio);
 		} else {
 			/* pretender doesn't wanna do anything with answer */
-			SDT_PROBE2(fuse, , device, trace, 1,
+			SDT_PROBE2(fusefs, , device, trace, 1,
 				"stuff devalidated, so we drop it");
 		}
 
@@ -430,11 +521,51 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i
 		 * because fuse_ticket_drop() will deal with refcount anyway.
 		 */
 		fuse_ticket_drop(tick);
+	} else if (ohead.unique == 0){
+		/* unique == 0 means asynchronous notification */
+		SDT_PROBE1(fusefs, , device, fuse_device_write_notify, &ohead);
+		switch (ohead.error) {
+		case FUSE_NOTIFY_INVAL_ENTRY:
+			err = fuse_internal_invalidate_entry(mp, uio);
+			break;
+		case FUSE_NOTIFY_INVAL_INODE:
+			err = fuse_internal_invalidate_inode(mp, uio);
+			break;
+		case FUSE_NOTIFY_RETRIEVE:
+		case FUSE_NOTIFY_STORE:
+			/*
+			 * Unimplemented.  I don't know of any file systems
+			 * that use them, and the protocol isn't sound anyway,
+			 * since the notification messages don't include the
+			 * inode's generation number.  Without that, it's
+			 * possible to manipulate the cache of the wrong vnode.
+			 * Finally, it's not defined what this message should
+			 * do for a file with dirty cache.
+			 */
+		case FUSE_NOTIFY_POLL:
+			/* Unimplemented.  See comments in fuse_vnops */
+		default:
+			/* Not implemented */
+			err = ENOSYS;
+		}
 	} else {
 		/* no callback at all! */
-		SDT_PROBE2(fuse, , device, trace, 1,
-			"erhm, no handler for this response");
-		err = EINVAL;
+		SDT_PROBE1(fusefs, , device, fuse_device_write_missing_ticket, 
+			ohead.unique);
+		if (ohead.error == -EAGAIN) {
+			/* 
+			 * This was probably a response to a FUSE_INTERRUPT
+			 * operation whose original operation is already
+			 * complete.  We can't store FUSE_INTERRUPT tickets
+			 * indefinitely because their responses are optional.
+			 * So we delete them when the original operation
+			 * completes.  And sadly the fuse_header_out doesn't
+			 * identify the opcode, so we have to guess.
+			 */
+			err = 0;
+		} else {
+			err = EINVAL;
+		}
 	}
 
 	return (err);
@@ -445,7 +576,7 @@ fuse_device_init(void)
 {
 
 	fuse_dev = make_dev(&fuse_device_cdevsw, 0, UID_ROOT, GID_OPERATOR,
-	    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, "fuse");
+	    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, "fuse");
 	if (fuse_dev == NULL)
 		return (ENOMEM);
 	return (0);

Modified: head/sys/fs/fuse/fuse_file.c
==============================================================================
--- head/sys/fs/fuse/fuse_file.c	Tue Aug  6 23:22:25 2019	(r350664)
+++ head/sys/fs/fuse/fuse_file.c	Wed Aug  7 00:38:26 2019	(r350665)
@@ -33,6 +33,11 @@
  * Copyright (C) 2005 Csaba Henk.
  * All rights reserved.
  *
+ * Copyright (c) 2019 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by BFF Storage Systems, LLC under
+ * sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -59,8 +64,9 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
-#include <sys/module.h>
 #include <sys/systm.h>
+#include <sys/counter.h>
+#include <sys/module.h>
 #include <sys/errno.h>
 #include <sys/kernel.h>
 #include <sys/conf.h>
@@ -79,52 +85,61 @@ __FBSDID("$FreeBSD$");
 #include "fuse.h"
 #include "fuse_file.h"
 #include "fuse_internal.h"

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



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