svn commit: r367517 - in head/sys: compat/linux fs/fuse

Edward Tomasz Napierala trasz at FreeBSD.org
Mon Nov 9 08:53:16 UTC 2020


Author: trasz
Date: Mon Nov  9 08:53:15 2020
New Revision: 367517
URL: https://svnweb.freebsd.org/changeset/base/367517

Log:
  Make it possible to mount a fuse filesystem, such as squashfuse,
  from a Linux binary.  Should come handy for AppImages.
  
  Reviewed by:	asomers
  MFC after:	2 weeks
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D26959

Modified:
  head/sys/compat/linux/linux_file.c
  head/sys/fs/fuse/fuse_device.c
  head/sys/fs/fuse/fuse_ipc.h
  head/sys/fs/fuse/fuse_vfsops.c

Modified: head/sys/compat/linux/linux_file.c
==============================================================================
--- head/sys/compat/linux/linux_file.c	Mon Nov  9 05:20:02 2020	(r367516)
+++ head/sys/compat/linux/linux_file.c	Mon Nov  9 08:53:15 2020	(r367517)
@@ -1181,13 +1181,15 @@ linux_pwritev(struct thread *td, struct linux_pwritev_
 int
 linux_mount(struct thread *td, struct linux_mount_args *args)
 {
-	char fstypename[MFSNAMELEN];
-	char *mntonname, *mntfromname;
+	struct mntarg *ma = NULL;
+	char *fstypename, *mntonname, *mntfromname, *data;
 	int error, fsflags;
 
+	fstypename = malloc(MNAMELEN, M_TEMP, M_WAITOK);
 	mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
 	mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
-	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
+	data = NULL;
+	error = copyinstr(args->filesystemtype, fstypename, MNAMELEN - 1,
 	    NULL);
 	if (error != 0)
 		goto out;
@@ -1208,6 +1210,31 @@ linux_mount(struct thread *td, struct linux_mount_args
 		strcpy(fstypename, "linprocfs");
 	} else if (strcmp(fstypename, "vfat") == 0) {
 		strcpy(fstypename, "msdosfs");
+	} else if (strcmp(fstypename, "fuse") == 0) {
+		char *fuse_options, *fuse_option, *fuse_name;
+
+		if (strcmp(mntfromname, "fuse") == 0)
+			strcpy(mntfromname, "/dev/fuse");
+
+		strcpy(fstypename, "fusefs");
+		data = malloc(MNAMELEN, M_TEMP, M_WAITOK);
+		error = copyinstr(args->data, data, MNAMELEN - 1, NULL);
+		if (error != 0)
+			goto out;
+
+		fuse_options = data;
+		while ((fuse_option = strsep(&fuse_options, ",")) != NULL) {
+			fuse_name = strsep(&fuse_option, "=");
+			if (fuse_name == NULL || fuse_option == NULL)
+				goto out;
+			ma = mount_arg(ma, fuse_name, fuse_option, -1);
+		}
+
+		/*
+		 * The FUSE server uses Linux errno values instead of FreeBSD
+		 * ones; add a flag to tell fuse(4) to do errno translation.
+		 */
+		ma = mount_arg(ma, "linux_errnos", "1", -1);
 	}
 
 	fsflags = 0;
@@ -1225,14 +1252,15 @@ linux_mount(struct thread *td, struct linux_mount_args
 	if (args->rwflag & LINUX_MS_REMOUNT)
 		fsflags |= MNT_UPDATE;
 
-	error = kernel_vmount(fsflags,
-	    "fstype", fstypename,
-	    "fspath", mntonname,
-	    "from", mntfromname,
-	    NULL);
+	ma = mount_arg(ma, "fstype", fstypename, -1);
+	ma = mount_arg(ma, "fspath", mntonname, -1);
+	ma = mount_arg(ma, "from", mntfromname, -1);
+	error = kernel_mount(ma, fsflags);
 out:
+	free(fstypename, M_TEMP);
 	free(mntonname, M_TEMP);
 	free(mntfromname, M_TEMP);
+	free(data, M_TEMP);
 	return (error);
 }
 

Modified: head/sys/fs/fuse/fuse_device.c
==============================================================================
--- head/sys/fs/fuse/fuse_device.c	Mon Nov  9 05:20:02 2020	(r367516)
+++ head/sys/fs/fuse/fuse_device.c	Mon Nov  9 08:53:15 2020	(r367517)
@@ -89,6 +89,9 @@ __FBSDID("$FreeBSD$");
 #include "fuse_internal.h"
 #include "fuse_ipc.h"
 
+#include <compat/linux/linux_errno.h>
+#include <compat/linux/linux_errno.inc>
+
 SDT_PROVIDER_DECLARE(fusefs);
 /* 
  * Fuse trace probe:
@@ -450,6 +453,15 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i
 	}
 	if ((err = uiomove(&ohead, sizeof(struct fuse_out_header), uio)) != 0)
 		return (err);
+
+	if (data->linux_errnos != 0 && ohead.error != 0) {
+		err = -ohead.error;
+		if (err < 0 || err >= nitems(linux_to_bsd_errtbl))
+			return (EINVAL);
+
+		/* '-', because it will get flipped again below */
+		ohead.error = -linux_to_bsd_errtbl[err];
+	}
 
 	/*
 	 * We check header information (which is redundant) and compare it

Modified: head/sys/fs/fuse/fuse_ipc.h
==============================================================================
--- head/sys/fs/fuse/fuse_ipc.h	Mon Nov  9 05:20:02 2020	(r367516)
+++ head/sys/fs/fuse/fuse_ipc.h	Mon Nov  9 08:53:15 2020	(r367517)
@@ -217,6 +217,7 @@ struct fuse_data {
 	struct selinfo			ks_rsel;
 
 	int				daemon_timeout;
+	int				linux_errnos;
 	unsigned			time_gran;
 	uint64_t			notimpl;
 	uint64_t			mnt_flag;

Modified: head/sys/fs/fuse/fuse_vfsops.c
==============================================================================
--- head/sys/fs/fuse/fuse_vfsops.c	Mon Nov  9 05:20:02 2020	(r367516)
+++ head/sys/fs/fuse/fuse_vfsops.c	Mon Nov  9 08:53:15 2020	(r367517)
@@ -300,6 +300,7 @@ fuse_vfsop_mount(struct mount *mp)
 
 	uint64_t mntopts, __mntopts;
 	uint32_t max_read;
+	int linux_errnos;
 	int daemon_timeout;
 	int fd;
 
@@ -312,6 +313,7 @@ fuse_vfsop_mount(struct mount *mp)
 
 	subtype = NULL;
 	max_read = ~0;
+	linux_errnos = 0;
 	err = 0;
 	mntopts = 0;
 	__mntopts = 0;
@@ -337,6 +339,7 @@ fuse_vfsop_mount(struct mount *mp)
 	FUSE_FLAGOPT(intr, FSESS_INTR);
 
 	(void)vfs_scanopt(opts, "max_read=", "%u", &max_read);
+	(void)vfs_scanopt(opts, "linux_errnos", "%d", &linux_errnos);
 	if (vfs_scanopt(opts, "timeout=", "%u", &daemon_timeout) == 1) {
 		if (daemon_timeout < FUSE_MIN_DAEMON_TIMEOUT)
 			daemon_timeout = FUSE_MIN_DAEMON_TIMEOUT;
@@ -411,6 +414,7 @@ fuse_vfsop_mount(struct mount *mp)
 	data->dataflags |= mntopts;
 	data->max_read = max_read;
 	data->daemon_timeout = daemon_timeout;
+	data->linux_errnos = linux_errnos;
 	data->mnt_flag = mp->mnt_flag & MNT_UPDATEMASK;
 	FUSE_UNLOCK();
 


More information about the svn-src-all mailing list