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();
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to