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
This commit is contained in:
Edward Tomasz Napierala 2020-11-09 08:53:15 +00:00
parent 8b8af16875
commit e3b1c847a4
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=367517
4 changed files with 53 additions and 8 deletions

View File

@ -1181,13 +1181,15 @@ linux_pwritev(struct thread *td, struct linux_pwritev_args *uap)
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 *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 *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);
}

View File

@ -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:
@ -451,6 +454,15 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int ioflag)
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
* with what we see. If we see some inconsistency we discard the

View File

@ -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;

View File

@ -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();