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

Pedro Giffuni pfg at FreeBSD.org
Wed Aug 7 15:49:14 UTC 2019


Awesome work.

Thanks!

On 06/08/2019 19:38, Alan Somers wrote:
> 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 at 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 at 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 ***
>


More information about the svn-src-head mailing list