mirror of
https://github.com/libfuse/libfuse.git
synced 2026-07-07 14:47:41 +08:00
Add support for the new linux mount API
So far only supported for fuse_session_mount(), which is called from high and low level API, but not yet supported for fuse_open_channel(), which used for privilege drop through mount.fuse. Main goal for the new API is support for synchronous FUSE_INIT and I don't think that is going to work with fuse_open_channel(). At least not with io-uring support as long as it is started from FUSE_INIT. Signed-off-by: Bernd Schubert <bschubert@ddn.com>
This commit is contained in:
committed by
Bernd Schubert
parent
4f70e5f3ab
commit
14cb7b93bb
+70
-2
@@ -20,6 +20,9 @@
|
||||
#include "util.h"
|
||||
#include "fuse_uring_i.h"
|
||||
#include "fuse_daemonize_i.h"
|
||||
#if defined(__linux__)
|
||||
#include "mount_i_linux.h"
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdatomic.h>
|
||||
@@ -4404,6 +4407,63 @@ int fuse_session_custom_io_30(struct fuse_session *se,
|
||||
offsetof(struct fuse_custom_io, clone_fd), fd);
|
||||
}
|
||||
|
||||
#if defined(HAVE_NEW_MOUNT_API)
|
||||
static int fuse_session_mount_new_api(struct fuse_session *se,
|
||||
const char *mountpoint)
|
||||
{
|
||||
int fd = -1;
|
||||
int res, err;
|
||||
char *mnt_opts = NULL;
|
||||
char *mnt_opts_with_fd = NULL;
|
||||
char fd_opt[32];
|
||||
|
||||
res = fuse_kern_mount_get_base_mnt_opts(se->mo, &mnt_opts);
|
||||
err = -EIO;
|
||||
if (res == -1) {
|
||||
fuse_log(FUSE_LOG_ERR,
|
||||
"fuse: failed to get base mount options\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
fd = fuse_kern_mount_prepare(mountpoint, se->mo);
|
||||
if (fd == -1) {
|
||||
fuse_log(FUSE_LOG_ERR, "Mount preparation failed.\n");
|
||||
err = -EIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
snprintf(fd_opt, sizeof(fd_opt), "fd=%i", fd);
|
||||
if (fuse_opt_add_opt(&mnt_opts_with_fd, mnt_opts) == -1 ||
|
||||
fuse_opt_add_opt(&mnt_opts_with_fd, fd_opt) == -1) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
err = fuse_kern_fsmount_mo(mountpoint, se->mo, mnt_opts_with_fd);
|
||||
err:
|
||||
if (err) {
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
fd = -1;
|
||||
se->fd = -1;
|
||||
se->error = -errno;
|
||||
}
|
||||
|
||||
free(mnt_opts);
|
||||
free(mnt_opts_with_fd);
|
||||
return fd;
|
||||
}
|
||||
#else
|
||||
static int fuse_session_mount_new_api(struct fuse_session *se,
|
||||
const char *mountpoint)
|
||||
{
|
||||
(void)se;
|
||||
(void)mountpoint;
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int fuse_session_mount(struct fuse_session *se, const char *_mountpoint)
|
||||
{
|
||||
int fd;
|
||||
@@ -4431,6 +4491,8 @@ int fuse_session_mount(struct fuse_session *se, const char *_mountpoint)
|
||||
close(fd);
|
||||
} while (fd >= 0 && fd <= 2);
|
||||
|
||||
/* Open channel */
|
||||
|
||||
/*
|
||||
* To allow FUSE daemons to run without privileges, the caller may open
|
||||
* /dev/fuse before launching the file system and pass on the file
|
||||
@@ -4448,9 +4510,15 @@ int fuse_session_mount(struct fuse_session *se, const char *_mountpoint)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Open channel */
|
||||
/* new linux mount api */
|
||||
fd = fuse_session_mount_new_api(se, mountpoint);
|
||||
if (fd >= 0)
|
||||
goto out;
|
||||
|
||||
/* fall back to old API */
|
||||
se->error = 0; /* reset error of new api */
|
||||
fd = fuse_kern_mount(mountpoint, se->mo);
|
||||
if (fd == -1)
|
||||
if (fd < 0)
|
||||
goto error_out;
|
||||
|
||||
out:
|
||||
|
||||
@@ -7,6 +7,9 @@ libfuse_sources = ['fuse.c', 'fuse_i.h', 'fuse_loop.c', 'fuse_loop_mt.c',
|
||||
|
||||
if host_machine.system().startswith('linux')
|
||||
libfuse_sources += [ 'mount.c' ]
|
||||
if private_cfg.get('HAVE_NEW_MOUNT_API', false)
|
||||
libfuse_sources += [ 'mount_fsmount.c' ]
|
||||
endif
|
||||
else
|
||||
libfuse_sources += [ 'mount_bsd.c' ]
|
||||
endif
|
||||
|
||||
+22
-3
@@ -442,7 +442,7 @@ static int fuse_mount_fusermount(const char *mountpoint, const struct mount_opts
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
static int fuse_kern_mount_prepare(const char *mnt,
|
||||
int fuse_kern_mount_prepare(const char *mnt,
|
||||
struct mount_opts *mo)
|
||||
{
|
||||
char tmp[128];
|
||||
@@ -493,6 +493,26 @@ out_close:
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(HAVE_NEW_MOUNT_API)
|
||||
/**
|
||||
* Wrapper for fuse_kern_fsmount that accepts struct mount_opts
|
||||
* @mnt: mountpoint
|
||||
* @mo: mount options
|
||||
* @mnt_opts: mount options to pass to the kernel
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure with errno set
|
||||
*/
|
||||
int fuse_kern_fsmount_mo(const char *mnt, const struct mount_opts *mo,
|
||||
const char *mnt_opts)
|
||||
{
|
||||
const char *devname = fuse_mnt_get_devname();
|
||||
|
||||
return fuse_kern_fsmount(mnt, mo->flags, mo->blkdev, mo->fsname,
|
||||
mo->subtype, devname, mo->kernel_opts,
|
||||
mnt_opts);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Complete the mount operation with an already-opened fd
|
||||
* @mnt: mountpoint
|
||||
@@ -636,8 +656,7 @@ void destroy_mount_opts(struct mount_opts *mo)
|
||||
free(mo);
|
||||
}
|
||||
|
||||
static int fuse_kern_mount_get_base_mnt_opts(const struct mount_opts *mo,
|
||||
char **mnt_optsp)
|
||||
int fuse_kern_mount_get_base_mnt_opts(const struct mount_opts *mo, char **mnt_optsp)
|
||||
{
|
||||
if (get_mnt_flag_opts(mnt_optsp, mo->flags) == -1)
|
||||
return -1;
|
||||
|
||||
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
* FUSE: Filesystem in Userspace
|
||||
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
* 2026 Bernd Schubert <bernd@bsbernd.com>
|
||||
*
|
||||
* New Linux mount API (fsopen/fsconfig/fsmount/move_mount) support.
|
||||
*
|
||||
* This program can be distributed under the terms of the GNU LGPLv2.
|
||||
* See the file LGPL2.txt.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "fuse_config.h"
|
||||
#include "fuse_misc.h"
|
||||
#include "mount_util.h"
|
||||
#include "mount_i_linux.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
/*
|
||||
* Mount attribute flags for fsmount() - from linux/mount.h
|
||||
* This file is only compiled conditionally when support for the new
|
||||
* mount API is detected - only flags that were not in the initial linux
|
||||
* commit introducing that API are defined here.
|
||||
*/
|
||||
#ifndef MOUNT_ATTR_NOSYMFOLLOW
|
||||
#define MOUNT_ATTR_NOSYMFOLLOW 0x00200000
|
||||
#endif
|
||||
|
||||
struct ms_to_str_map {
|
||||
unsigned long ms_flag;
|
||||
const char *string;
|
||||
};
|
||||
|
||||
static const struct ms_to_str_map flag_to_str_map[] = {
|
||||
{ MS_SYNCHRONOUS, "sync" },
|
||||
{ MS_DIRSYNC, "dirsync" },
|
||||
{ MS_LAZYTIME, "lazytime" },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
struct ms_to_mount_attr_map {
|
||||
unsigned long ms_flag;
|
||||
unsigned long mount_attr;
|
||||
};
|
||||
|
||||
static const struct ms_to_mount_attr_map ms_to_attr_map[] = {
|
||||
{ MS_NOSUID, MOUNT_ATTR_NOSUID },
|
||||
{ MS_NODEV, MOUNT_ATTR_NODEV },
|
||||
{ MS_NOEXEC, MOUNT_ATTR_NOEXEC },
|
||||
{ MS_NOATIME, MOUNT_ATTR_NOATIME },
|
||||
{ MS_RELATIME, MOUNT_ATTR_RELATIME },
|
||||
{ MS_STRICTATIME, MOUNT_ATTR_STRICTATIME },
|
||||
{ MS_NODIRATIME, MOUNT_ATTR_NODIRATIME },
|
||||
{ MS_NOSYMFOLLOW, MOUNT_ATTR_NOSYMFOLLOW },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
/*
|
||||
* Convert MS_* mount flags to MOUNT_ATTR_* mount attributes.
|
||||
* These flags are passed to fsmount(), not fsconfig().
|
||||
* Mount attributes control mount-point level behavior.
|
||||
*
|
||||
* @attrs MOUNT_ATTR flags, built from MS_ flags
|
||||
* @return remaining flags
|
||||
*/
|
||||
static int ms_flags_to_mount_attrs(unsigned long flags,
|
||||
unsigned long *attrs)
|
||||
{
|
||||
const struct ms_to_mount_attr_map *map;
|
||||
|
||||
*attrs = 0;
|
||||
|
||||
for (map = ms_to_attr_map; map->ms_flag; map++) {
|
||||
if (flags & map->ms_flag) {
|
||||
*attrs |= map->mount_attr;
|
||||
flags &= ~map->ms_flag;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and print kernel error messages from fsopen fd.
|
||||
* The kernel can provide detailed error/warning/info messages via the
|
||||
* filesystem context fd that are more informative than strerror(errno).
|
||||
*/
|
||||
static void log_fsconfig_kmsg(int fd)
|
||||
{
|
||||
char buf[4096];
|
||||
int err, sz = 0;
|
||||
|
||||
err = errno;
|
||||
|
||||
while ((sz = read(fd, buf, sizeof(buf) - 1)) != -1) {
|
||||
if (sz <= 0)
|
||||
continue;
|
||||
if (buf[sz - 1] == '\n')
|
||||
buf[--sz] = '\0';
|
||||
else
|
||||
buf[sz] = '\0';
|
||||
|
||||
if (!*buf)
|
||||
continue;
|
||||
|
||||
switch (buf[0]) {
|
||||
case 'e':
|
||||
fprintf(stderr, " Error: %s\n", buf + 2);
|
||||
break;
|
||||
case 'w':
|
||||
fprintf(stderr, " Warning: %s\n", buf + 2);
|
||||
break;
|
||||
case 'i':
|
||||
fprintf(stderr, " Info: %s\n", buf + 2);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, " %s\n", buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
errno = err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply VFS superblock (fsconfig) flags to the filesystem context.
|
||||
* Only handles flags that are filesystem parameters (ro, sync, dirsync).
|
||||
* Mount attributes (nosuid, nodev, etc.) are handled separately via fsmount().
|
||||
*
|
||||
* @ms_flags flags to set, outvalue are the remaining flags
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
static int set_ms_flags(int fsfd, unsigned long *ms_flags)
|
||||
{
|
||||
const struct ms_to_str_map *fme; /* flag map entry */
|
||||
int ret, flags = *ms_flags;
|
||||
|
||||
for (fme = flag_to_str_map; flags != 0 && fme->ms_flag != 0; fme++) {
|
||||
if (!(flags & fme->ms_flag))
|
||||
continue;
|
||||
|
||||
ret = fsconfig(fsfd, FSCONFIG_SET_FLAG, fme->string, NULL, 0);
|
||||
if (ret) {
|
||||
int save_errno = errno;
|
||||
|
||||
fprintf(stderr, "fuse: set fsconfig %s option failed: %s\n",
|
||||
fme->string, strerror(save_errno));
|
||||
log_fsconfig_kmsg(fsfd);
|
||||
|
||||
return -save_errno;
|
||||
}
|
||||
flags &= ~fme->ms_flag;
|
||||
}
|
||||
|
||||
*ms_flags = flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply the "fd" parameter via fsconfig
|
||||
*
|
||||
* Special handler for the "fd" mount option. Note that despite the name,
|
||||
* the fd parameter is passed as a u32 string value, not as a file descriptor
|
||||
* to pass to the kernel. Uses FSCONFIG_SET_STRING rather than FSCONFIG_SET_FD.
|
||||
*
|
||||
* Returns 0 on success, negative error code on failure.
|
||||
*/
|
||||
static int apply_opt_fd(int fsfd, const char *value)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* The fd parameter is a u32 value, not a file descriptor to pass */
|
||||
res = fsconfig(fsfd, FSCONFIG_SET_STRING, "fd", value, 0);
|
||||
if (res == -1) {
|
||||
int save_errno = errno;
|
||||
|
||||
fprintf(stderr, "fuse: fsconfig SET_STRING fd=%s failed:",
|
||||
value);
|
||||
log_fsconfig_kmsg(fsfd);
|
||||
return -save_errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply a key=value string option via fsconfig
|
||||
*
|
||||
* Applies a mount option that consists of a key-value pair (e.g., "rootmode=40000").
|
||||
* Uses FSCONFIG_SET_STRING to pass the key and value to the filesystem configuration.
|
||||
*
|
||||
* Returns 0 on success, negative error code on failure.
|
||||
*/
|
||||
static int apply_opt_string(int fsfd, const char *key, const char *value)
|
||||
{
|
||||
int res, save_errno;
|
||||
|
||||
res = fsconfig(fsfd, FSCONFIG_SET_STRING, key, value, 0);
|
||||
save_errno = errno;
|
||||
if (res == -1) {
|
||||
fprintf(stderr, "fuse: fsconfig SET_STRING %s=%s failed: ",
|
||||
key, value);
|
||||
log_fsconfig_kmsg(fsfd);
|
||||
return -save_errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply a boolean flag option via fsconfig
|
||||
*
|
||||
* Applies a mount option that is a simple flag without a value (e.g., "rw").
|
||||
* Uses FSCONFIG_SET_FLAG to set the flag in the filesystem configuration.
|
||||
*
|
||||
* Returns 0 on success, negative error code on failure.
|
||||
*/
|
||||
static int apply_opt_flag(int fsfd, const char *opt)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = fsconfig(fsfd, FSCONFIG_SET_FLAG, opt, NULL, 0);
|
||||
if (res == -1) {
|
||||
int save_errno = errno;
|
||||
|
||||
fprintf(stderr, "fuse: fsconfig SET_FLAG %s failed:", opt);
|
||||
log_fsconfig_kmsg(fsfd);
|
||||
return -save_errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse and apply a single mount option via fsconfig
|
||||
*
|
||||
* Parses a mount option which can be either:
|
||||
* - A key=value pair (e.g., "rootmode=40000")
|
||||
* - A flag without a value (e.g., "rw")
|
||||
*
|
||||
* Special handling for the "fd" parameter which is treated as a string
|
||||
* value rather than a file descriptor to pass.
|
||||
*
|
||||
* Returns 0 on success, negative error code on failure.
|
||||
*/
|
||||
static int apply_opt_key_value(int fsfd, char *opt)
|
||||
{
|
||||
char *eq;
|
||||
const char *key;
|
||||
const char *value;
|
||||
|
||||
eq = strchr(opt, '=');
|
||||
if (!eq)
|
||||
return apply_opt_flag(fsfd, opt);
|
||||
|
||||
*eq = '\0';
|
||||
key = opt;
|
||||
value = eq + 1;
|
||||
|
||||
if (strcmp(key, "fd") == 0)
|
||||
return apply_opt_fd(fsfd, value);
|
||||
|
||||
return apply_opt_string(fsfd, key, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if an option is a mount attribute (handled by fsmount, not fsconfig)
|
||||
* Uses the mount_flags table to determine if an option is a mount attribute.
|
||||
*/
|
||||
static int is_mount_attr_opt(const char *opt)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; mount_flags[i].opt != NULL; i++) {
|
||||
if (strcmp(mount_flags[i].opt, opt) == 0)
|
||||
return mount_flags[i].is_mount_attr;
|
||||
}
|
||||
|
||||
/* Unknown option, assume it's not a mount attribute */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse kernel options string and apply via fsconfig
|
||||
* Options are comma-separated key=value pairs
|
||||
*/
|
||||
static int apply_mount_opts(int fsfd, const char *opts)
|
||||
{
|
||||
char *opts_copy;
|
||||
char *opt;
|
||||
char *saveptr;
|
||||
int res;
|
||||
|
||||
if (!opts || !*opts)
|
||||
return 0;
|
||||
|
||||
opts_copy = strdup(opts);
|
||||
if (!opts_copy) {
|
||||
fprintf(stderr, "fuse: failed to allocate memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
opt = strtok_r(opts_copy, ",", &saveptr);
|
||||
while (opt) {
|
||||
/*
|
||||
* Skip mount attributes, they're handled by fsmount()
|
||||
* not fsconfig().
|
||||
*
|
||||
* These string options (nosuid, nodev, etc.) are reconstructed
|
||||
* from MS_* flags by get_mnt_flag_opts() in lib/mount.c and
|
||||
* get_mnt_opts() in util/fusermount.c. Both the library path
|
||||
* (via fuse_kern_mount_get_base_mnt_opts) and fusermount3 path
|
||||
* rebuild these strings from the flags bitmask and pass them in
|
||||
* mnt_opts. They must be filtered here because they are mount
|
||||
* attributes (passed to fsmount via MOUNT_ATTR_*), not
|
||||
* filesystem parameters (which would be passed to fsconfig).
|
||||
*/
|
||||
if (!is_mount_attr_opt(opt)) {
|
||||
res = apply_opt_key_value(fsfd, opt);
|
||||
if (res < 0) {
|
||||
free(opts_copy);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
opt = strtok_r(NULL, ",", &saveptr);
|
||||
}
|
||||
|
||||
free(opts_copy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int fuse_kern_fsmount(const char *mnt, unsigned long flags, int blkdev,
|
||||
const char *fsname, const char *subtype,
|
||||
const char *source_dev, const char *kernel_opts,
|
||||
const char *mnt_opts)
|
||||
{
|
||||
const char *type;
|
||||
char *source = NULL;
|
||||
int fsfd = -1;
|
||||
int mntfd = -1;
|
||||
int err, res;
|
||||
unsigned long mount_attrs;
|
||||
|
||||
/* Determine filesystem type */
|
||||
type = blkdev ? "fuseblk" : "fuse";
|
||||
|
||||
/* Try to open filesystem context */
|
||||
fsfd = fsopen(type, FSOPEN_CLOEXEC);
|
||||
if (fsfd == -1) {
|
||||
if (errno != EPERM)
|
||||
fprintf(stderr, "fuse: fsopen(%s) failed: %s\n", type,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Build source string */
|
||||
source = malloc((fsname ? strlen(fsname) : 0) +
|
||||
(subtype ? strlen(subtype) : 0) +
|
||||
strlen(source_dev) + 32);
|
||||
err = -ENOMEM;
|
||||
if (!source) {
|
||||
fprintf(stderr, "fuse: failed to allocate memory\n");
|
||||
goto out_close_fsfd;
|
||||
}
|
||||
|
||||
strcpy(source, fsname ? fsname : (subtype ? subtype : source_dev));
|
||||
|
||||
/* Configure source */
|
||||
res = fsconfig(fsfd, FSCONFIG_SET_STRING, "source", source, 0);
|
||||
if (res == -1) {
|
||||
err = -errno;
|
||||
log_fsconfig_kmsg(fsfd);
|
||||
fprintf(stderr, "fuse: fsconfig source failed: %s\n",
|
||||
strerror(errno));
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* Apply VFS superblock (fsconfig) flags (ro, sync, dirsync) */
|
||||
res = set_ms_flags(fsfd, &flags);
|
||||
if (res != 0)
|
||||
goto out_free;
|
||||
|
||||
/* Apply kernel options */
|
||||
err = apply_mount_opts(fsfd, kernel_opts);
|
||||
if (err < 0) {
|
||||
log_fsconfig_kmsg(fsfd);
|
||||
fprintf(stderr,
|
||||
"fuse: failed to apply kernel options '%s'\n",
|
||||
kernel_opts);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* Apply additional mount options */
|
||||
err = apply_mount_opts(fsfd, mnt_opts);
|
||||
if (err < 0) {
|
||||
log_fsconfig_kmsg(fsfd);
|
||||
fprintf(stderr,
|
||||
"fuse: failed to apply additional mount options '%s'\n",
|
||||
mnt_opts);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* Create the filesystem instance */
|
||||
res = fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
|
||||
if (res == -1) {
|
||||
err = -errno;
|
||||
log_fsconfig_kmsg(fsfd);
|
||||
fprintf(stderr, "fuse: fsconfig CREATE failed: %s\n",
|
||||
strerror(errno));
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* Convert MS_* flags to MOUNT_ATTR_* for fsmount() */
|
||||
flags = ms_flags_to_mount_attrs(flags, &mount_attrs);
|
||||
if (flags != 0) {
|
||||
/* unsupported flags found, either fsconfig or mount attr flags */
|
||||
//fuse_log(FUSE_LOG_ERR, "Unsupported mount flags found: %d", flags);
|
||||
errno = -ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create mount object with mount attributes */
|
||||
mntfd = fsmount(fsfd, FSMOUNT_CLOEXEC, mount_attrs);
|
||||
if (mntfd == -1) {
|
||||
err = -errno;
|
||||
log_fsconfig_kmsg(fsfd);
|
||||
fprintf(stderr, "fuse: fsmount failed: %s\n",
|
||||
strerror(errno));
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
close(fsfd);
|
||||
fsfd = -1;
|
||||
|
||||
/* Attach to mount point */
|
||||
if (move_mount(mntfd, "", AT_FDCWD, mnt, MOVE_MOUNT_F_EMPTY_PATH) ==
|
||||
-1) {
|
||||
err = -errno;
|
||||
fprintf(stderr, "fuse: move_mount failed: %s\n",
|
||||
strerror(errno));
|
||||
goto out_close_mntfd;
|
||||
}
|
||||
|
||||
err = fuse_mnt_add_mount_helper(mnt, source, type, mnt_opts);
|
||||
if (err == -1)
|
||||
goto out_umount;
|
||||
|
||||
close(mntfd);
|
||||
free(source);
|
||||
return 0;
|
||||
|
||||
out_umount:
|
||||
{
|
||||
/* race free umount */
|
||||
char fd_path[64];
|
||||
|
||||
snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%d", mntfd);
|
||||
if (umount2(fd_path, MNT_DETACH) == -1 && errno != EINVAL) {
|
||||
fprintf(stderr,
|
||||
"fuse: cleanup umount failed: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
out_close_mntfd:
|
||||
if (mntfd != -1)
|
||||
close(mntfd);
|
||||
out_free:
|
||||
free(source);
|
||||
out_close_fsfd:
|
||||
if (fsfd != -1)
|
||||
close(fsfd);
|
||||
errno = -err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -29,4 +29,28 @@ struct mount_opts {
|
||||
unsigned int max_read;
|
||||
};
|
||||
|
||||
int fuse_kern_mount_prepare(const char *mnt, struct mount_opts *mo);
|
||||
|
||||
int fuse_kern_mount_get_base_mnt_opts(const struct mount_opts *mo, char **mnt_optsp);
|
||||
|
||||
/**
|
||||
* Mount using the new Linux mount API (fsopen/fsconfig/fsmount/move_mount)
|
||||
* @mnt: mountpoint
|
||||
* @flags: mount flags (MS_NOSUID, MS_NODEV, etc.)
|
||||
* @blkdev: 1 for fuseblk, 0 for fuse
|
||||
* @fsname: filesystem name (or NULL)
|
||||
* @subtype: filesystem subtype (or NULL)
|
||||
* @source_dev: device name for building source string
|
||||
* @kernel_opts: kernel mount options string
|
||||
* @mnt_opts: additional mount options to pass to the kernel
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure with errno set
|
||||
*/
|
||||
int fuse_kern_fsmount(const char *mnt, unsigned long flags, int blkdev,
|
||||
const char *fsname, const char *subtype,
|
||||
const char *source_dev, const char *kernel_opts,
|
||||
const char *mnt_opts);
|
||||
|
||||
int fuse_kern_fsmount_mo(const char *mnt, const struct mount_opts *mo,
|
||||
const char *mnt_opts);
|
||||
#endif /* FUSE_MOUNT_I_LINUX_H_ */
|
||||
|
||||
+15
@@ -118,6 +118,21 @@ special_funcs = {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
''',
|
||||
'new_mount_api': '''
|
||||
#define _GNU_SOURCE
|
||||
#include <sys/mount.h>
|
||||
#include <linux/mount.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
int main(void) {
|
||||
int fsfd = fsopen("fuse", FSOPEN_CLOEXEC);
|
||||
int res = fsconfig(fsfd, FSCONFIG_SET_STRING, "source", "test", 0);
|
||||
int mntfd = fsmount(fsfd, FSMOUNT_CLOEXEC, 0);
|
||||
res = move_mount(mntfd, "", AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH);
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user