* [PATCH 0/4] libfuse: Avoid mount API code dup between mount-service and libfuse
@ 2026-09-30 13:44 Bernd Schubert via B4 Relay
2026-09-30 13:44 ` [PATCH 1/4] mount_fsmount: split superblock creation and move_mount into a helper Bernd Schubert via B4 Relay
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Bernd Schubert via B4 Relay @ 2026-09-30 13:44 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: neal, fuse-devel, Bernd Schubert
fuse service mount was written in parallel to libfuse additions of
the new mount API. Service mounts support the new mount API as well,
which results in code dup. In the mean time libfuse also supports
the new mount API through syscalls without glibc wrappers, as some
distros have a sufficiently recent kernel, but a too old glibc.
Those wrappers were mssing for service mounts so far.
Easiest fix is to avoid the code and to redirect service mounts
to what libfuse already has.
To: Darrick J. Wong <djwong@kernel.org>
Cc: neal@gompa.dev
Cc: fuse-devel@lists.linux.dev
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
---
Bernd Schubert (4):
mount_fsmount: split superblock creation and move_mount into a helper
mount_service: mount via the shared fsmount helper
mount_util: share the mtab flag-option builder
mount/fuse_service: share the service socket helpers
include/fuse_service_priv.h | 59 ++++++++++++++++++++++++
lib/fuse_service.c | 72 ++++++-----------------------
lib/mount.c | 21 +--------
lib/mount_fsmount.c | 98 ++++++++++++++++++++++------------------
lib/mount_i_linux.h | 18 ++++++++
lib/mount_util.c | 33 ++++++++++++++
lib/mount_util.h | 20 ++++++++
util/fusermount.c | 33 ++------------
util/mount_service.c | 108 +++++++++-----------------------------------
9 files changed, 223 insertions(+), 239 deletions(-)
---
base-commit: 5f8a64b0835620ab88afd8a59a713d5b6a9e99f4
change-id: 20260930-mount-service-use-mount-fsmount-bd6ea048a3da
Best regards,
--
Bernd Schubert <bernd@bsbernd.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/4] mount_fsmount: split superblock creation and move_mount into a helper
2026-09-30 13:44 [PATCH 0/4] libfuse: Avoid mount API code dup between mount-service and libfuse Bernd Schubert via B4 Relay
@ 2026-09-30 13:44 ` Bernd Schubert via B4 Relay
2026-09-30 15:13 ` Darrick J. Wong
2026-09-30 13:44 ` [PATCH 2/4] mount_service: mount via the shared fsmount helper Bernd Schubert via B4 Relay
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Bernd Schubert via B4 Relay @ 2026-09-30 13:44 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: neal, fuse-devel, Bernd Schubert
From: Bernd Schubert <bernd@bsbernd.com>
This is a preparation patch. fuse_kern_fsmount() ran fsconfig
CREATE, fsmount() and move_mount() inline. A later commit will make
mount_service.c call the same three calls after it has run FSOPEN,
SOURCE and MNTOPTS itself, so this moves them into
fuse_fsmount_create_and_move(). The fsopen fd stays owned by the
caller, because mount_service.c will close mo->fsopenfd itself
later.
fuse_kern_fsmount() now converts MS_* flags before calling the
helper, so unsupported flags are caught before the superblock is
created, not after.
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
---
lib/mount_fsmount.c | 86 +++++++++++++++++++++++++++++++----------------------
lib/mount_i_linux.h | 18 +++++++++++
2 files changed, 69 insertions(+), 35 deletions(-)
diff --git a/lib/mount_fsmount.c b/lib/mount_fsmount.c
index b2d0453e5c93..0b1fd4300d2d 100644
--- a/lib/mount_fsmount.c
+++ b/lib/mount_fsmount.c
@@ -489,6 +489,53 @@ void fuse_kern_umount_mountfd(int mountfd)
}
}
+int fuse_fsmount_create_and_move(int fsfd, unsigned int mount_attrs,
+ int dest_mnt_fd, const char *dest_path,
+ int *mountfd_out)
+{
+ int mountfd;
+ int res;
+
+ res = fuse_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
+ if (res == -1) {
+ int save_errno = errno;
+
+ log_fsconfig_kmsg(fsfd);
+ fuse_log(FUSE_LOG_ERR, "fuse: fsconfig CREATE failed: %s\n",
+ strerror(save_errno));
+ return -save_errno;
+ }
+
+ mountfd = fuse_fsmount(fsfd, FSMOUNT_CLOEXEC, mount_attrs);
+ if (mountfd == -1) {
+ int save_errno = errno;
+
+ log_fsconfig_kmsg(fsfd);
+ fuse_log(FUSE_LOG_ERR, "fuse: fsmount failed: %s\n",
+ strerror(save_errno));
+ return -save_errno;
+ }
+
+ if (dest_mnt_fd >= 0)
+ res = fuse_move_mount(mountfd, "", dest_mnt_fd, "",
+ MOVE_MOUNT_F_EMPTY_PATH |
+ MOVE_MOUNT_T_EMPTY_PATH);
+ else
+ res = fuse_move_mount(mountfd, "", AT_FDCWD, dest_path,
+ MOVE_MOUNT_F_EMPTY_PATH);
+ if (res == -1) {
+ int save_errno = errno;
+
+ fuse_log(FUSE_LOG_ERR, "fuse: move_mount failed: %s\n",
+ strerror(save_errno));
+ close(mountfd);
+ return -save_errno;
+ }
+
+ *mountfd_out = mountfd;
+ return 0;
+}
+
int fuse_kern_fsmount(const char *mnt, int dest_mnt_fd, unsigned long flags,
int blkdev, const char *fsname, const char *subtype,
const char *source_dev, const char *kernel_opts,
@@ -584,16 +631,6 @@ int fuse_kern_fsmount(const char *mnt, int dest_mnt_fd, unsigned long flags,
goto out_free;
}
- /* Create the filesystem instance */
- res = fuse_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
- if (res == -1) {
- err = -errno;
- log_fsconfig_kmsg(fsfd);
- fuse_log(FUSE_LOG_ERR, "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) {
@@ -602,33 +639,14 @@ int fuse_kern_fsmount(const char *mnt, int dest_mnt_fd, unsigned long flags,
goto out_free;
}
- /* Create mount object with mount attributes */
- mountfd = fuse_fsmount(fsfd, FSMOUNT_CLOEXEC, mount_attrs);
- if (mountfd == -1) {
- err = -errno;
- log_fsconfig_kmsg(fsfd);
- fuse_log(FUSE_LOG_ERR, "fuse: fsmount failed: %s\n",
- strerror(errno));
+ err = fuse_fsmount_create_and_move(fsfd, mount_attrs, dest_mnt_fd, mnt,
+ &mountfd);
+ if (err)
goto out_free;
- }
close(fsfd);
fsfd = -1;
- if (dest_mnt_fd >= 0)
- res = fuse_move_mount(mountfd, "", dest_mnt_fd, "",
- MOVE_MOUNT_F_EMPTY_PATH |
- MOVE_MOUNT_T_EMPTY_PATH);
- else
- res = fuse_move_mount(mountfd, "", AT_FDCWD, mnt,
- MOVE_MOUNT_F_EMPTY_PATH);
- if (res == -1) {
- err = -errno;
- fuse_log(FUSE_LOG_ERR, "fuse: move_mount failed: %s\n",
- strerror(errno));
- goto out_close_mntfd;
- }
-
res = fuse_mnt_add_mount_helper(mnt, source, type, mtab_opts);
if (res == -1) {
err = -EIO;
@@ -645,9 +663,7 @@ int fuse_kern_fsmount(const char *mnt, int dest_mnt_fd, unsigned long flags,
out_umount:
fuse_kern_umount_mountfd(mountfd);
-out_close_mntfd:
- if (mountfd != -1)
- close(mountfd);
+ close(mountfd);
out_free:
free(source);
free(type);
diff --git a/lib/mount_i_linux.h b/lib/mount_i_linux.h
index 8cf7ff4532c6..35bb54c82236 100644
--- a/lib/mount_i_linux.h
+++ b/lib/mount_i_linux.h
@@ -86,6 +86,24 @@ int fuse_kern_fsmount(const char *mnt, int mnt_fd, unsigned long flags,
int fuse_kern_fsmount_mo(const char *mnt, const struct mount_opts *mo,
const char *mtab_opts, int *mountfd_out);
+/**
+ * Create the superblock and attach the resulting mount to a destination.
+ *
+ * The fsopen fd stays owned by the caller - a caller that keeps it in
+ * long-lived state must not be left with a descriptor closed behind its back.
+ *
+ * @fsfd fsopen fd, fully configured
+ * @mount_attrs MOUNT_ATTR_* flags, from ms_flags_to_mount_attrs()
+ * @dest_mnt_fd pre-resolved destination fd, or -1 to use @dest_path
+ * @dest_path destination path, used only when @dest_mnt_fd is -1
+ * @mountfd_out on success receives the fsmount() fd, to be closed by the
+ * caller and usable for fuse_kern_umount_mountfd()
+ * @return 0 on success, negative error code on failure
+ */
+int fuse_fsmount_create_and_move(int fsfd, unsigned int mount_attrs,
+ int dest_mnt_fd, const char *dest_path,
+ int *mountfd_out);
+
/**
* Unmount (lazily) the mount @mountfd was created for, without a path lookup.
*
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/4] mount_service: mount via the shared fsmount helper
2026-09-30 13:44 [PATCH 0/4] libfuse: Avoid mount API code dup between mount-service and libfuse Bernd Schubert via B4 Relay
2026-09-30 13:44 ` [PATCH 1/4] mount_fsmount: split superblock creation and move_mount into a helper Bernd Schubert via B4 Relay
@ 2026-09-30 13:44 ` Bernd Schubert via B4 Relay
2026-09-30 15:16 ` Darrick J. Wong
2026-09-30 13:44 ` [PATCH 3/4] mount_util: share the mtab flag-option builder Bernd Schubert via B4 Relay
2026-09-30 13:44 ` [PATCH 4/4] mount/fuse_service: share the service socket helpers Bernd Schubert via B4 Relay
3 siblings, 1 reply; 9+ messages in thread
From: Bernd Schubert via B4 Relay @ 2026-09-30 13:44 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: neal, fuse-devel, Bernd Schubert
From: Bernd Schubert <bernd@bsbernd.com>
util/mount_service.c issued FSCONFIG_CMD_CREATE, fsmount() and
move_mount() itself, with the same FSMOUNT_CLOEXEC and
MOVE_MOUNT_*_EMPTY_PATH flags as lib/mount_fsmount.c. Both mount the
same filesystem, so a flag changed in one copy silently diverges.
mount_service.c also called the libc names fsconfig(), fsmount() and
move_mount() directly. HAVE_NEW_MOUNT_API only checks that the headers
declare these functions, not that libc exports them. On a system where
NEED_NEW_MOUNT_API_SYSCALL_WRAPPERS is also set (glibc older than
2.36), lib/mount_fsmount.c works around the missing symbols through
its fuse_-prefixed static inline wrappers, which mount_service.c had
no access to; calling the bare libc names left it with a declaration
to compile against but no symbol to link against.
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
---
util/mount_service.c | 49 ++++++++++++-------------------------------------
1 file changed, 12 insertions(+), 37 deletions(-)
diff --git a/util/mount_service.c b/util/mount_service.c
index 0b3266309a8a..dcdc26df1db4 100644
--- a/util/mount_service.c
+++ b/util/mount_service.c
@@ -28,11 +28,6 @@
#include <sys/ioctl.h>
#include <linux/fs.h>
-#ifdef HAVE_NEW_MOUNT_API
-#include <sys/mount.h>
-#include <linux/mount.h>
-#endif
-
#include "mount_util.h"
#include "util.h"
#include "fuse_i.h"
@@ -1439,63 +1434,45 @@ static int mount_service_fsopen_mount(struct mount_service *mo,
return FUSE_MOUNT_FALLBACK_NEEDED;
error = -ret;
- goto fail_fsconfig;
+ goto fail_mount;
}
snprintf(tmp, sizeof(tmp), "%i", mo->fusedevfd);
ret = apply_fsconfig_opt_fd(mo->fsopenfd, tmp);
if (ret < 0) {
error = -ret;
- goto fail_fsconfig;
+ goto fail_mount;
}
snprintf(tmp, sizeof(tmp), "%o", stbuf->st_mode & S_IFMT);
ret = apply_fsconfig_opt_string(mo->fsopenfd, "rootmode", tmp);
if (ret < 0) {
error = -ret;
- goto fail_fsconfig;
+ goto fail_mount;
}
snprintf(tmp, sizeof(tmp), "%u", getuid());
ret = apply_fsconfig_opt_string(mo->fsopenfd, "user_id", tmp);
if (ret < 0) {
error = -ret;
- goto fail_fsconfig;
+ goto fail_mount;
}
snprintf(tmp, sizeof(tmp), "%u", getgid());
ret = apply_fsconfig_opt_string(mo->fsopenfd, "group_id", tmp);
if (ret < 0) {
error = -ret;
- goto fail_fsconfig;
- }
-
- ret = fsconfig(mo->fsopenfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
- if (ret) {
- error = errno;
- fprintf(stderr, "%s: creating filesystem: %s\n",
- mo->msgtag, strerror(error));
- goto fail_fsconfig;
- }
-
- mfd = fsmount(mo->fsopenfd, FSMOUNT_CLOEXEC, attr_flags);
- if (mfd < 0) {
- error = errno;
- fprintf(stderr, "%s: fsmount: %s\n",
- mo->msgtag, strerror(error));
- goto fail_fsconfig;
- }
-
- ret = move_mount(mfd, "", mo->mountfd, "",
- MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH);
- close(mfd);
- if (ret) {
- error = errno;
- fprintf(stderr, "%s: move_mount: %s\n",
- mo->msgtag, strerror(error));
goto fail_mount;
}
+ ret = fuse_fsmount_create_and_move(mo->fsopenfd, attr_flags,
+ mo->mountfd, NULL, &mfd);
+ if (ret < 0) {
+ error = -ret;
+ goto fail_mount;
+ }
+ close(mfd);
+
/*
* The mount succeeded, so we send a positive reply even if the mtab
* update fails.
@@ -1515,8 +1492,6 @@ static int mount_service_fsopen_mount(struct mount_service *mo,
mo->mounted = true;
return mount_service_send_reply(mo, 0);
-fail_fsconfig:
- log_fsconfig_kmsg(mo->fsopenfd);
fail_mount:
return mount_service_send_reply(mo, error);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/4] mount_util: share the mtab flag-option builder
2026-09-30 13:44 [PATCH 0/4] libfuse: Avoid mount API code dup between mount-service and libfuse Bernd Schubert via B4 Relay
2026-09-30 13:44 ` [PATCH 1/4] mount_fsmount: split superblock creation and move_mount into a helper Bernd Schubert via B4 Relay
2026-09-30 13:44 ` [PATCH 2/4] mount_service: mount via the shared fsmount helper Bernd Schubert via B4 Relay
@ 2026-09-30 13:44 ` Bernd Schubert via B4 Relay
2026-09-30 15:20 ` Darrick J. Wong
2026-09-30 13:44 ` [PATCH 4/4] mount/fuse_service: share the service socket helpers Bernd Schubert via B4 Relay
3 siblings, 1 reply; 9+ messages in thread
From: Bernd Schubert via B4 Relay @ 2026-09-30 13:44 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: neal, fuse-devel, Bernd Schubert
From: Bernd Schubert <bernd@bsbernd.com>
The loop over mount_flags[] that builds the rw/nosuid/nodev mirrors of
an mtab record existed twice, in lib/mount.c and util/fusermount.c;
both feed the same record, so a change to one silently diverges.
fusermount3 does not link libfuse and cannot call fuse_opt_add_opt(),
so fuse_mnt_add_opt() moves to lib/mount_util.c next to mount_flags[].
fuse_mnt_add_opt() now has one realloc and one snprintf, because
realloc(NULL) is the malloc. The empty-list path reserves expand as
well, which strdup could not do. No caller pairs an empty list with a
non-zero expand, so nothing changes today.
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
---
lib/mount.c | 21 +--------------------
lib/mount_fsmount.c | 12 ++----------
lib/mount_util.c | 33 +++++++++++++++++++++++++++++++++
lib/mount_util.h | 20 ++++++++++++++++++++
util/fusermount.c | 33 +++------------------------------
5 files changed, 59 insertions(+), 60 deletions(-)
diff --git a/lib/mount.c b/lib/mount.c
index a6dd5013ea80..4d03ef4b848f 100644
--- a/lib/mount.c
+++ b/lib/mount.c
@@ -995,25 +995,6 @@ static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
return fd;
}
-/*
- * Append the flag-mirror prefix (rw/nosuid/nodev/...) of the mtab record
- * to @mtab_optsp, derived from the MS_* bitmask in @flags.
- */
-static int get_mtab_flag_opts(char **mtab_optsp, int flags)
-{
- int i;
-
- if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mtab_optsp, "rw") == -1)
- return -1;
-
- for (i = 0; mount_flags[i].opt != NULL; i++) {
- if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
- fuse_opt_add_opt(mtab_optsp, mount_flags[i].opt) == -1)
- return -1;
- }
- return 0;
-}
-
struct mount_opts *parse_mount_opts(struct fuse_args *args)
{
struct mount_opts *mo;
@@ -1057,7 +1038,7 @@ void destroy_mount_opts(struct mount_opts *mo)
int fuse_kern_mount_get_base_mtab_opts(const struct mount_opts *mo,
char **mtab_optsp)
{
- if (get_mtab_flag_opts(mtab_optsp, mo->flags) == -1)
+ if (fuse_mnt_get_mtab_flag_opts(mtab_optsp, mo->flags) == -1)
return -1;
if (mo->kernel_opts && fuse_opt_add_opt(mtab_optsp, mo->kernel_opts) == -1)
return -1;
diff --git a/lib/mount_fsmount.c b/lib/mount_fsmount.c
index 0b1fd4300d2d..730071206fc7 100644
--- a/lib/mount_fsmount.c
+++ b/lib/mount_fsmount.c
@@ -446,16 +446,8 @@ int apply_fsconfig_mount_opts(int fsfd, const char *opts)
continue;
/*
* Skip mount attributes, they're handled by fsmount()
- * not fsconfig().
- *
- * These string options (nosuid, nodev, etc.) are reconstructed
- * from MS_* flags by get_mtab_flag_opts() in lib/mount.c and
- * get_mtab_opts() in util/fusermount.c. Both the library path
- * (via fuse_kern_mount_get_base_mtab_opts) and fusermount3 path
- * rebuild these strings from the flags bitmask and pass them in
- * mtab_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).
+ * not fsconfig(). Callers rebuild them as strings from the
+ * MS_* bitmask for the mtab record, so they do show up here.
*
* Also skip mtab-only options - they're for /run/mount/utab, not kernel
*/
diff --git a/lib/mount_util.c b/lib/mount_util.c
index 2f763fe1218e..72ed17c93f47 100644
--- a/lib/mount_util.c
+++ b/lib/mount_util.c
@@ -140,6 +140,39 @@ const struct mount_flags mount_flags[] = {
{NULL, 0, 0, 0, 0, 0}
};
+int fuse_mnt_add_opt(char **optsp, const char *opt, unsigned int expand)
+{
+ /* an empty list gets no separator, and realloc(NULL) is the malloc */
+ const char *sep = *optsp ? "," : "";
+ size_t oldsize = *optsp ? strlen(*optsp) : 0;
+ size_t newsize = oldsize + strlen(sep) + strlen(opt) + expand + 1;
+ char *newopts = (char *) realloc(*optsp, newsize);
+
+ if (newopts == NULL) {
+ fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate memory\n");
+ return -1;
+ }
+
+ snprintf(newopts + oldsize, newsize - oldsize, "%s%s", sep, opt);
+ *optsp = newopts;
+ return 0;
+}
+
+int fuse_mnt_get_mtab_flag_opts(char **mtab_optsp, int flags)
+{
+ int i;
+
+ if (!(flags & MS_RDONLY) && fuse_mnt_add_opt(mtab_optsp, "rw", 0) == -1)
+ return -1;
+
+ for (i = 0; mount_flags[i].opt != NULL; i++) {
+ if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
+ fuse_mnt_add_opt(mtab_optsp, mount_flags[i].opt, 0) == -1)
+ return -1;
+ }
+ return 0;
+}
+
#ifdef IGNORE_MTAB
#define mtab_needs_update(mnt) 0
#else
diff --git a/lib/mount_util.h b/lib/mount_util.h
index b20a428d99c7..4485d8a29f93 100644
--- a/lib/mount_util.h
+++ b/lib/mount_util.h
@@ -24,6 +24,26 @@ struct mount_flags {
};
extern const struct mount_flags mount_flags[];
+/**
+ * @brief Append @opt to the comma-separated option list @optsp.
+ *
+ * @param[in,out] optsp list to extend, NULL for an empty list.
+ * @param[in] opt option to append.
+ * @param[in] expand extra bytes to reserve for a value the caller
+ * appends itself.
+ * @return 0 on success, -1 on failure.
+ */
+int fuse_mnt_add_opt(char **optsp, const char *opt, unsigned int expand);
+
+/**
+ * @brief Append the flag-mirror part of an mtab record (rw/nosuid/nodev/...).
+ *
+ * @param[in,out] mtab_optsp option list to extend.
+ * @param[in] flags MS_* bitmask the mirrors are derived from.
+ * @return 0 on success, -1 on failure.
+ */
+int fuse_mnt_get_mtab_flag_opts(char **mtab_optsp, int flags);
+
int fuse_mnt_add_mount(const char *progname, const char *fsname,
const char *mnt, const char *type, const char *opts);
int fuse_mnt_remove_mount(const char *progname, const char *mnt);
diff --git a/util/fusermount.c b/util/fusermount.c
index 3031b282a7a6..c7de86f4b12e 100644
--- a/util/fusermount.c
+++ b/util/fusermount.c
@@ -556,26 +556,6 @@ static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
return 0;
}
-static int add_option(char **optsp, const char *opt, unsigned expand)
-{
- char *newopts;
- if (*optsp == NULL)
- newopts = strdup(opt);
- else {
- unsigned oldsize = strlen(*optsp);
- unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
- newopts = (char *) realloc(*optsp, newsize);
- if (newopts)
- sprintf(newopts + oldsize, ",%s", opt);
- }
- if (newopts == NULL) {
- fprintf(stderr, "%s: failed to allocate memory\n", progname);
- return -1;
- }
- *optsp = newopts;
- return 0;
-}
-
/*
* Build the mtab/utab record string for this mount: flag-mirrors of MS_*
* (rw/nosuid/nodev/...) + the kernel-bound -o options + "user=<n>" when
@@ -585,19 +565,12 @@ static int add_option(char **optsp, const char *opt, unsigned expand)
*/
static int get_mtab_opts(int flags, const char *opts, char **mtab_optsp)
{
- int i;
int l;
- if (!(flags & MS_RDONLY) && add_option(mtab_optsp, "rw", 0) == -1)
+ if (fuse_mnt_get_mtab_flag_opts(mtab_optsp, flags) == -1)
return -1;
- for (i = 0; mount_flags[i].opt != NULL; i++) {
- if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
- add_option(mtab_optsp, mount_flags[i].opt, 0) == -1)
- return -1;
- }
-
- if (add_option(mtab_optsp, opts, 0) == -1)
+ if (fuse_mnt_add_opt(mtab_optsp, opts, 0) == -1)
return -1;
/* remove comma from end of opts*/
l = strlen(*mtab_optsp);
@@ -608,7 +581,7 @@ static int get_mtab_opts(int flags, const char *opts, char **mtab_optsp)
if (user == NULL)
return -1;
- if (add_option(mtab_optsp, "user=", strlen(user)) == -1)
+ if (fuse_mnt_add_opt(mtab_optsp, "user=", strlen(user)) == -1)
return -1;
strcat(*mtab_optsp, user);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/4] mount/fuse_service: share the service socket helpers
2026-09-30 13:44 [PATCH 0/4] libfuse: Avoid mount API code dup between mount-service and libfuse Bernd Schubert via B4 Relay
` (2 preceding siblings ...)
2026-09-30 13:44 ` [PATCH 3/4] mount_util: share the mtab flag-option builder Bernd Schubert via B4 Relay
@ 2026-09-30 13:44 ` Bernd Schubert via B4 Relay
2026-09-30 15:23 ` Darrick J. Wong
3 siblings, 1 reply; 9+ messages in thread
From: Bernd Schubert via B4 Relay @ 2026-09-30 13:44 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: neal, fuse-devel, Bernd Schubert
From: Bernd Schubert <bernd@bsbernd.com>
lib/fuse_service.c and util/mount_service.c each had their own sendmsg()
and recvmsg() for the same packets, repeating MSG_EOR|MSG_NOSIGNAL and
MSG_TRUNC, plus their own SO_SNDBUF check. Every change to how a packet
travels had to be made twice.
fuse_service_send_packet(), fuse_service_recv_packet() and
fuse_service_sendbuf_too_small() move to include/fuse_service_priv.h,
which both files already include for the packet layout. The error
messages differ per file and stay in the callers.
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
---
include/fuse_service_priv.h | 59 +++++++++++++++++++++++++++++++++++++
lib/fuse_service.c | 72 ++++++++++-----------------------------------
util/mount_service.c | 59 ++++++-------------------------------
3 files changed, 83 insertions(+), 107 deletions(-)
diff --git a/include/fuse_service_priv.h b/include/fuse_service_priv.h
index 988f7c9251c8..951694faaaba 100644
--- a/include/fuse_service_priv.h
+++ b/include/fuse_service_priv.h
@@ -9,6 +9,9 @@
#ifndef FUSE_SERVICE_PRIV_H_
#define FUSE_SERVICE_PRIV_H_
+#include <sys/socket.h>
+#include <limits.h>
+
/* All numeric fields are network order (big-endian) when going across the socket */
struct fuse_service_memfd_arg {
@@ -48,6 +51,36 @@ struct fuse_service_packet {
uint32_t magic; /* FUSE_SERVICE_*_{CMD,REPLY} */
};
+static inline ssize_t fuse_service_send_packet(int sockfd, void *ptr,
+ size_t len)
+{
+ struct iovec iov = {
+ .iov_base = ptr,
+ .iov_len = len,
+ };
+ struct msghdr msg = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+
+ return sendmsg(sockfd, &msg, MSG_EOR | MSG_NOSIGNAL);
+}
+
+static inline ssize_t fuse_service_recv_packet(int sockfd, void *ptr,
+ size_t len)
+{
+ struct iovec iov = {
+ .iov_base = ptr,
+ .iov_len = len,
+ };
+ struct msghdr msg = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+
+ return recvmsg(sockfd, &msg, MSG_TRUNC);
+}
+
#define FUSE_SERVICE_PROTO (1)
#define FUSE_SERVICE_MIN_PROTO (1)
#define FUSE_SERVICE_MAX_PROTO (1)
@@ -117,6 +150,32 @@ static inline size_t sizeof_fuse_service_open_command(size_t pathlen)
return sizeof(struct fuse_service_open_command) + pathlen + 1;
}
+/*
+ * A send buffer that cannot hold the largest open command makes the sendmsg
+ * fail later on; report the size so the caller can say so in its own words.
+ * A buffer we cannot query is not an error - most likely we won't be sending
+ * huge open commands, and if we do, the sendmsg will fail there too.
+ *
+ * @sendbuf_sizep set to the offending size when the buffer is too small
+ * @return true if the send buffer is too small
+ */
+static inline bool fuse_service_sendbuf_too_small(int sockfd,
+ int *sendbuf_sizep)
+{
+ int sendbuf_size = -1;
+ socklen_t optlen = sizeof(sendbuf_size);
+
+ if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuf_size, &optlen) ||
+ sendbuf_size < 0)
+ return false;
+
+ if ((size_t)sendbuf_size >= sizeof_fuse_service_open_command(PATH_MAX))
+ return false;
+
+ *sendbuf_sizep = sendbuf_size;
+ return true;
+}
+
struct fuse_service_string_command {
struct fuse_service_packet p;
char value[];
diff --git a/lib/fuse_service.c b/lib/fuse_service.c
index 0a05b3fbc1f2..1f3fc1be0888 100644
--- a/lib/fuse_service.c
+++ b/lib/fuse_service.c
@@ -135,36 +135,6 @@ static int __recv_fd(const struct fuse_service *sf,
return 0;
}
-static ssize_t __send_packet(const struct fuse_service *sf, void *ptr,
- size_t len)
-{
- struct iovec iov = {
- .iov_base = ptr,
- .iov_len = len,
- };
- struct msghdr msg = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- };
-
- return sendmsg(sf->sockfd, &msg, MSG_EOR | MSG_NOSIGNAL);
-}
-
-static ssize_t __recv_packet(const struct fuse_service *sf, void *ptr,
- size_t len)
-{
- struct iovec iov = {
- .iov_base = ptr,
- .iov_len = len,
- };
- struct msghdr msg = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- };
-
- return recvmsg(sf->sockfd, &msg, MSG_TRUNC);
-}
-
int fuse_service_receive_file(const struct fuse_service *sf, const char *path,
int *fdp)
{
@@ -266,7 +236,7 @@ static int fuse_service_request_path(const struct fuse_service *sf,
cmd->request_flags = htonl(rqflags);
memcpy(cmd->path, path, pathlen + 1);
- size = __send_packet(sf, cmd, cmdsz);
+ size = fuse_service_send_packet(sf->sockfd, cmd, cmdsz);
if (size < 0) {
int error = errno;
@@ -313,7 +283,7 @@ int fuse_service_send_goodbye(struct fuse_service *sf, int exitcode)
if (sf->sockfd < 0)
return 0;
- size = __send_packet(sf, &c, sizeof(c));
+ size = fuse_service_send_packet(sf->sockfd, &c, sizeof(c));
if (size < 0) {
int error = errno;
@@ -367,25 +337,13 @@ static int count_listen_fds(void)
static int check_sendbuf_size(int sockfd)
{
- const size_t min_size = sizeof_fuse_service_open_command(PATH_MAX);
- int sendbuf_size = -1;
- socklen_t optlen = sizeof(sendbuf_size);
- int ret;
+ int sendbuf_size;
- /*
- * If we can't query the maximum send buffer length, just keep going.
- * Most likely we won't be sending huge open commands, and if we do,
- * the sendmsg will fail there too.
- */
- ret = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuf_size, &optlen);
- if (ret || sendbuf_size < 0)
- return 0;
-
- if (sendbuf_size >= min_size)
+ if (!fuse_service_sendbuf_too_small(sockfd, &sendbuf_size))
return 0;
fuse_log(FUSE_LOG_ERR, "max socket send buffer is %d, need at least %zu.\n",
- sendbuf_size, min_size);
+ sendbuf_size, sizeof_fuse_service_open_command(PATH_MAX));
return -ENOBUFS;
}
@@ -456,7 +414,7 @@ static int negotiate_hello(struct fuse_service *sf)
uint32_t flags;
ssize_t size;
- size = __recv_packet(sf, &hello, sizeof(hello));
+ size = fuse_service_recv_packet(sf->sockfd, &hello, sizeof(hello));
if (size < 0) {
int error = errno;
@@ -511,7 +469,7 @@ static int negotiate_hello(struct fuse_service *sf)
if (flags & FUSE_SERVICE_FLAG_FUSEBLK)
sf->can_fuseblk = true;
- size = __send_packet(sf, &reply, sizeof(reply));
+ size = fuse_service_send_packet(sf->sockfd, &reply, sizeof(reply));
if (size < 0) {
int error = errno;
@@ -821,7 +779,7 @@ static int send_fsopen(const struct fuse_service *sf, const char *fstype,
if (!strncmp(fstype, "fuseblk", 7))
c.fsopen_flags |= htonl(FUSE_SERVICE_FSOPEN_FUSEBLK);
- size = __send_packet(sf, &c, sizeof(c));
+ size = fuse_service_send_packet(sf->sockfd, &c, sizeof(c));
if (size < 0) {
int error = errno;
@@ -830,7 +788,7 @@ static int send_fsopen(const struct fuse_service *sf, const char *fstype,
return -error;
}
- size = __recv_packet(sf, &reply, sizeof(reply));
+ size = fuse_service_recv_packet(sf->sockfd, &reply, sizeof(reply));
if (size < 0) {
int error = errno;
@@ -873,7 +831,7 @@ static int send_string(const struct fuse_service *sf, uint32_t command,
cmd->p.magic = htonl(command);
memcpy(cmd->value, value, valuelen + 1);
- size = __send_packet(sf, cmd, cmdsz);
+ size = fuse_service_send_packet(sf->sockfd, cmd, cmdsz);
if (size < 0) {
err = -errno;
fuse_log(FUSE_LOG_ERR, "fuse: send service string: %s\n",
@@ -881,7 +839,7 @@ static int send_string(const struct fuse_service *sf, uint32_t command,
goto out;
}
- size = __recv_packet(sf, &reply, sizeof(reply));
+ size = fuse_service_recv_packet(sf->sockfd, &reply, sizeof(reply));
if (size < 0) {
err = -errno;
fuse_log(FUSE_LOG_ERR, "fuse: service string reply: %s\n",
@@ -929,7 +887,7 @@ static int send_mountpoint(const struct fuse_service *sf, mode_t expected_fmt,
cmd->expected_fmt = htons(expected_fmt);
memcpy(cmd->value, value, valuelen + 1);
- size = __send_packet(sf, cmd, cmdsz);
+ size = fuse_service_send_packet(sf->sockfd, cmd, cmdsz);
if (size < 0) {
err = -errno;
fuse_log(FUSE_LOG_ERR, "fuse: send service mountpoint: %s\n",
@@ -937,7 +895,7 @@ static int send_mountpoint(const struct fuse_service *sf, mode_t expected_fmt,
goto out;
}
- size = __recv_packet(sf, &reply, sizeof(reply));
+ size = fuse_service_recv_packet(sf->sockfd, &reply, sizeof(reply));
if (size < 0) {
err = -errno;
fuse_log(FUSE_LOG_ERR, "fuse: service mountpoint reply: %s\n",
@@ -975,7 +933,7 @@ static int send_mount(const struct fuse_service *sf, unsigned int ms_flags,
};
ssize_t size;
- size = __send_packet(sf, &c, sizeof(c));
+ size = fuse_service_send_packet(sf->sockfd, &c, sizeof(c));
if (size < 0) {
int error = errno;
@@ -984,7 +942,7 @@ static int send_mount(const struct fuse_service *sf, unsigned int ms_flags,
return -error;
}
- size = __recv_packet(sf, &reply, sizeof(reply));
+ size = fuse_service_recv_packet(sf->sockfd, &reply, sizeof(reply));
if (size < 0) {
int error = errno;
diff --git a/util/mount_service.c b/util/mount_service.c
index dcdc26df1db4..47cc2d43d2a0 100644
--- a/util/mount_service.c
+++ b/util/mount_service.c
@@ -139,21 +139,6 @@ static ssize_t __send_fd(const struct mount_service *mo,
return sendmsg(mo->sockfd, &msg, MSG_EOR | MSG_NOSIGNAL);
}
-static ssize_t __send_packet(const struct mount_service *mo, void *ptr,
- size_t len)
-{
- struct iovec iov = {
- .iov_base = ptr,
- .iov_len = len,
- };
- struct msghdr msg = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- };
-
- return sendmsg(mo->sockfd, &msg, MSG_EOR | MSG_NOSIGNAL);
-}
-
static ssize_t __recv_packet_size(const struct mount_service *mo)
{
struct iovec iov = { };
@@ -164,21 +149,6 @@ static ssize_t __recv_packet_size(const struct mount_service *mo)
return recvmsg(mo->sockfd, &msg, MSG_PEEK | MSG_TRUNC);
}
-static ssize_t __recv_packet(const struct mount_service *mo, void *ptr,
- size_t len)
-{
- struct iovec iov = {
- .iov_base = ptr,
- .iov_len = len,
- };
- struct msghdr msg = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- };
-
- return recvmsg(mo->sockfd, &msg, MSG_TRUNC);
-}
-
/*
* Filter out the subtype of the filesystem (e.g. fuse.Y[.Z] -> Y[.Z]). The
* fuse server determines if it's appropriate to set the "blockdev" mount
@@ -271,25 +241,14 @@ static int try_drop_passrights(const struct mount_service *mo, int sockfd)
static int check_sendbuf_size(const struct mount_service *mo, int sockfd)
{
- const size_t min_size = sizeof_fuse_service_open_command(PATH_MAX);
- int sendbuf_size = -1;
- socklen_t optlen = sizeof(sendbuf_size);
- int ret;
+ int sendbuf_size;
- /*
- * If we can't query the maximum send buffer length, just keep going.
- * Most likely we won't be sending huge open commands, and if we do,
- * the sendmsg will fail there too.
- */
- ret = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuf_size, &optlen);
- if (ret || sendbuf_size < 0)
- return 0;
-
- if (sendbuf_size >= min_size)
+ if (!fuse_service_sendbuf_too_small(sockfd, &sendbuf_size))
return 0;
fprintf(stderr, "%s: max socket send buffer is %d, need at least %zu.\n",
- mo->msgtag, sendbuf_size, min_size);
+ mo->msgtag, sendbuf_size,
+ sizeof_fuse_service_open_command(PATH_MAX));
return MOUNT_SERVICE_FALLBACK_NEEDED;
}
@@ -369,14 +328,14 @@ static int mount_service_send_hello(const struct mount_service *mo)
else if (user_allow_other)
hello.flags |= htonl(FUSE_SERVICE_FLAG_ALLOW_OTHER);
- size = __send_packet(mo, &hello, sizeof(hello));
+ size = fuse_service_send_packet(mo->sockfd, &hello, sizeof(hello));
if (size < 0) {
fprintf(stderr, "%s: send hello: %s\n",
mo->msgtag, strerror(errno));
return -1;
}
- size = __recv_packet(mo, &reply, sizeof(reply));
+ size = fuse_service_recv_packet(mo->sockfd, &reply, sizeof(reply));
if (size < 0) {
fprintf(stderr, "%s: hello reply: %s\n",
mo->msgtag, strerror(errno));
@@ -581,7 +540,7 @@ static int mount_service_send_file_error(const struct mount_service *mo,
req->error = htonl(error);
memcpy(req->path, path, path_len + 1);
- written = __send_packet(mo, req, req_sz);
+ written = fuse_service_send_packet(mo->sockfd, req, req_sz);
if (written < 0) {
fprintf(stderr, "%s: send file error: %s\n",
mo->msgtag, strerror(errno));
@@ -671,7 +630,7 @@ static int mount_service_receive_command(const struct mount_service *mo,
return -1;
}
- size = __recv_packet(mo, command, alleged_size);
+ size = fuse_service_recv_packet(mo->sockfd, command, alleged_size);
if (size < 0) {
fprintf(stderr, "%s: receive service command: %s\n",
mo->msgtag, strerror(errno));
@@ -698,7 +657,7 @@ static int mount_service_send_reply(const struct mount_service *mo, int error)
};
ssize_t size;
- size = __send_packet(mo, &reply, sizeof(reply));
+ size = fuse_service_send_packet(mo->sockfd, &reply, sizeof(reply));
if (size < 0) {
fprintf(stderr, "%s: send service reply: %s\n",
mo->msgtag, strerror(errno));
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 1/4] mount_fsmount: split superblock creation and move_mount into a helper
2026-09-30 13:44 ` [PATCH 1/4] mount_fsmount: split superblock creation and move_mount into a helper Bernd Schubert via B4 Relay
@ 2026-09-30 15:13 ` Darrick J. Wong
0 siblings, 0 replies; 9+ messages in thread
From: Darrick J. Wong @ 2026-09-30 15:13 UTC (permalink / raw)
To: bernd; +Cc: neal, fuse-devel
On Wed, Sep 30, 2026 at 03:44:33PM +0200, Bernd Schubert via B4 Relay wrote:
> From: Bernd Schubert <bernd@bsbernd.com>
>
> This is a preparation patch. fuse_kern_fsmount() ran fsconfig
> CREATE, fsmount() and move_mount() inline. A later commit will make
> mount_service.c call the same three calls after it has run FSOPEN,
> SOURCE and MNTOPTS itself, so this moves them into
> fuse_fsmount_create_and_move(). The fsopen fd stays owned by the
> caller, because mount_service.c will close mo->fsopenfd itself
> later.
>
> fuse_kern_fsmount() now converts MS_* flags before calling the
> helper, so unsupported flags are caught before the superblock is
> created, not after.
>
> Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
This is a simple hoist, so
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
--D
> ---
> lib/mount_fsmount.c | 86 +++++++++++++++++++++++++++++++----------------------
> lib/mount_i_linux.h | 18 +++++++++++
> 2 files changed, 69 insertions(+), 35 deletions(-)
>
> diff --git a/lib/mount_fsmount.c b/lib/mount_fsmount.c
> index b2d0453e5c93..0b1fd4300d2d 100644
> --- a/lib/mount_fsmount.c
> +++ b/lib/mount_fsmount.c
> @@ -489,6 +489,53 @@ void fuse_kern_umount_mountfd(int mountfd)
> }
> }
>
> +int fuse_fsmount_create_and_move(int fsfd, unsigned int mount_attrs,
> + int dest_mnt_fd, const char *dest_path,
> + int *mountfd_out)
> +{
> + int mountfd;
> + int res;
> +
> + res = fuse_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
> + if (res == -1) {
> + int save_errno = errno;
> +
> + log_fsconfig_kmsg(fsfd);
> + fuse_log(FUSE_LOG_ERR, "fuse: fsconfig CREATE failed: %s\n",
> + strerror(save_errno));
> + return -save_errno;
> + }
> +
> + mountfd = fuse_fsmount(fsfd, FSMOUNT_CLOEXEC, mount_attrs);
> + if (mountfd == -1) {
> + int save_errno = errno;
> +
> + log_fsconfig_kmsg(fsfd);
> + fuse_log(FUSE_LOG_ERR, "fuse: fsmount failed: %s\n",
> + strerror(save_errno));
> + return -save_errno;
> + }
> +
> + if (dest_mnt_fd >= 0)
> + res = fuse_move_mount(mountfd, "", dest_mnt_fd, "",
> + MOVE_MOUNT_F_EMPTY_PATH |
> + MOVE_MOUNT_T_EMPTY_PATH);
> + else
> + res = fuse_move_mount(mountfd, "", AT_FDCWD, dest_path,
> + MOVE_MOUNT_F_EMPTY_PATH);
> + if (res == -1) {
> + int save_errno = errno;
> +
> + fuse_log(FUSE_LOG_ERR, "fuse: move_mount failed: %s\n",
> + strerror(save_errno));
> + close(mountfd);
> + return -save_errno;
> + }
> +
> + *mountfd_out = mountfd;
> + return 0;
> +}
> +
> int fuse_kern_fsmount(const char *mnt, int dest_mnt_fd, unsigned long flags,
> int blkdev, const char *fsname, const char *subtype,
> const char *source_dev, const char *kernel_opts,
> @@ -584,16 +631,6 @@ int fuse_kern_fsmount(const char *mnt, int dest_mnt_fd, unsigned long flags,
> goto out_free;
> }
>
> - /* Create the filesystem instance */
> - res = fuse_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
> - if (res == -1) {
> - err = -errno;
> - log_fsconfig_kmsg(fsfd);
> - fuse_log(FUSE_LOG_ERR, "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) {
> @@ -602,33 +639,14 @@ int fuse_kern_fsmount(const char *mnt, int dest_mnt_fd, unsigned long flags,
> goto out_free;
> }
>
> - /* Create mount object with mount attributes */
> - mountfd = fuse_fsmount(fsfd, FSMOUNT_CLOEXEC, mount_attrs);
> - if (mountfd == -1) {
> - err = -errno;
> - log_fsconfig_kmsg(fsfd);
> - fuse_log(FUSE_LOG_ERR, "fuse: fsmount failed: %s\n",
> - strerror(errno));
> + err = fuse_fsmount_create_and_move(fsfd, mount_attrs, dest_mnt_fd, mnt,
> + &mountfd);
> + if (err)
> goto out_free;
> - }
>
> close(fsfd);
> fsfd = -1;
>
> - if (dest_mnt_fd >= 0)
> - res = fuse_move_mount(mountfd, "", dest_mnt_fd, "",
> - MOVE_MOUNT_F_EMPTY_PATH |
> - MOVE_MOUNT_T_EMPTY_PATH);
> - else
> - res = fuse_move_mount(mountfd, "", AT_FDCWD, mnt,
> - MOVE_MOUNT_F_EMPTY_PATH);
> - if (res == -1) {
> - err = -errno;
> - fuse_log(FUSE_LOG_ERR, "fuse: move_mount failed: %s\n",
> - strerror(errno));
> - goto out_close_mntfd;
> - }
> -
> res = fuse_mnt_add_mount_helper(mnt, source, type, mtab_opts);
> if (res == -1) {
> err = -EIO;
> @@ -645,9 +663,7 @@ int fuse_kern_fsmount(const char *mnt, int dest_mnt_fd, unsigned long flags,
>
> out_umount:
> fuse_kern_umount_mountfd(mountfd);
> -out_close_mntfd:
> - if (mountfd != -1)
> - close(mountfd);
> + close(mountfd);
> out_free:
> free(source);
> free(type);
> diff --git a/lib/mount_i_linux.h b/lib/mount_i_linux.h
> index 8cf7ff4532c6..35bb54c82236 100644
> --- a/lib/mount_i_linux.h
> +++ b/lib/mount_i_linux.h
> @@ -86,6 +86,24 @@ int fuse_kern_fsmount(const char *mnt, int mnt_fd, unsigned long flags,
> int fuse_kern_fsmount_mo(const char *mnt, const struct mount_opts *mo,
> const char *mtab_opts, int *mountfd_out);
>
> +/**
> + * Create the superblock and attach the resulting mount to a destination.
> + *
> + * The fsopen fd stays owned by the caller - a caller that keeps it in
> + * long-lived state must not be left with a descriptor closed behind its back.
> + *
> + * @fsfd fsopen fd, fully configured
> + * @mount_attrs MOUNT_ATTR_* flags, from ms_flags_to_mount_attrs()
> + * @dest_mnt_fd pre-resolved destination fd, or -1 to use @dest_path
> + * @dest_path destination path, used only when @dest_mnt_fd is -1
> + * @mountfd_out on success receives the fsmount() fd, to be closed by the
> + * caller and usable for fuse_kern_umount_mountfd()
> + * @return 0 on success, negative error code on failure
> + */
> +int fuse_fsmount_create_and_move(int fsfd, unsigned int mount_attrs,
> + int dest_mnt_fd, const char *dest_path,
> + int *mountfd_out);
> +
> /**
> * Unmount (lazily) the mount @mountfd was created for, without a path lookup.
> *
>
> --
> 2.53.0
>
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2/4] mount_service: mount via the shared fsmount helper
2026-09-30 13:44 ` [PATCH 2/4] mount_service: mount via the shared fsmount helper Bernd Schubert via B4 Relay
@ 2026-09-30 15:16 ` Darrick J. Wong
0 siblings, 0 replies; 9+ messages in thread
From: Darrick J. Wong @ 2026-09-30 15:16 UTC (permalink / raw)
To: bernd; +Cc: neal, fuse-devel
On Wed, Sep 30, 2026 at 03:44:34PM +0200, Bernd Schubert via B4 Relay wrote:
> From: Bernd Schubert <bernd@bsbernd.com>
>
> util/mount_service.c issued FSCONFIG_CMD_CREATE, fsmount() and
> move_mount() itself, with the same FSMOUNT_CLOEXEC and
> MOVE_MOUNT_*_EMPTY_PATH flags as lib/mount_fsmount.c. Both mount the
> same filesystem, so a flag changed in one copy silently diverges.
>
> mount_service.c also called the libc names fsconfig(), fsmount() and
> move_mount() directly. HAVE_NEW_MOUNT_API only checks that the headers
> declare these functions, not that libc exports them. On a system where
> NEED_NEW_MOUNT_API_SYSCALL_WRAPPERS is also set (glibc older than
> 2.36), lib/mount_fsmount.c works around the missing symbols through
> its fuse_-prefixed static inline wrappers, which mount_service.c had
> no access to; calling the bare libc names left it with a declaration
> to compile against but no symbol to link against.
>
> Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
> ---
> util/mount_service.c | 49 ++++++++++++-------------------------------------
> 1 file changed, 12 insertions(+), 37 deletions(-)
>
> diff --git a/util/mount_service.c b/util/mount_service.c
> index 0b3266309a8a..dcdc26df1db4 100644
> --- a/util/mount_service.c
> +++ b/util/mount_service.c
> @@ -28,11 +28,6 @@
> #include <sys/ioctl.h>
> #include <linux/fs.h>
>
> -#ifdef HAVE_NEW_MOUNT_API
> -#include <sys/mount.h>
> -#include <linux/mount.h>
> -#endif
> -
> #include "mount_util.h"
> #include "util.h"
> #include "fuse_i.h"
> @@ -1439,63 +1434,45 @@ static int mount_service_fsopen_mount(struct mount_service *mo,
> return FUSE_MOUNT_FALLBACK_NEEDED;
>
> error = -ret;
> - goto fail_fsconfig;
> + goto fail_mount;
> }
>
> snprintf(tmp, sizeof(tmp), "%i", mo->fusedevfd);
> ret = apply_fsconfig_opt_fd(mo->fsopenfd, tmp);
> if (ret < 0) {
> error = -ret;
> - goto fail_fsconfig;
> + goto fail_mount;
> }
>
> snprintf(tmp, sizeof(tmp), "%o", stbuf->st_mode & S_IFMT);
> ret = apply_fsconfig_opt_string(mo->fsopenfd, "rootmode", tmp);
> if (ret < 0) {
> error = -ret;
> - goto fail_fsconfig;
> + goto fail_mount;
> }
>
> snprintf(tmp, sizeof(tmp), "%u", getuid());
> ret = apply_fsconfig_opt_string(mo->fsopenfd, "user_id", tmp);
> if (ret < 0) {
> error = -ret;
> - goto fail_fsconfig;
> + goto fail_mount;
> }
>
> snprintf(tmp, sizeof(tmp), "%u", getgid());
> ret = apply_fsconfig_opt_string(mo->fsopenfd, "group_id", tmp);
> if (ret < 0) {
> error = -ret;
> - goto fail_fsconfig;
> - }
> -
> - ret = fsconfig(mo->fsopenfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
> - if (ret) {
> - error = errno;
> - fprintf(stderr, "%s: creating filesystem: %s\n",
> - mo->msgtag, strerror(error));
> - goto fail_fsconfig;
> - }
> -
> - mfd = fsmount(mo->fsopenfd, FSMOUNT_CLOEXEC, attr_flags);
> - if (mfd < 0) {
> - error = errno;
> - fprintf(stderr, "%s: fsmount: %s\n",
> - mo->msgtag, strerror(error));
> - goto fail_fsconfig;
> - }
> -
> - ret = move_mount(mfd, "", mo->mountfd, "",
> - MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH);
> - close(mfd);
> - if (ret) {
> - error = errno;
> - fprintf(stderr, "%s: move_mount: %s\n",
> - mo->msgtag, strerror(error));
> goto fail_mount;
> }
>
> + ret = fuse_fsmount_create_and_move(mo->fsopenfd, attr_flags,
> + mo->mountfd, NULL, &mfd);
> + if (ret < 0) {
> + error = -ret;
> + goto fail_mount;
> + }
> + close(mfd);
Slick :)
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
--D
> +
> /*
> * The mount succeeded, so we send a positive reply even if the mtab
> * update fails.
> @@ -1515,8 +1492,6 @@ static int mount_service_fsopen_mount(struct mount_service *mo,
> mo->mounted = true;
> return mount_service_send_reply(mo, 0);
>
> -fail_fsconfig:
> - log_fsconfig_kmsg(mo->fsopenfd);
> fail_mount:
> return mount_service_send_reply(mo, error);
> }
>
> --
> 2.53.0
>
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/4] mount_util: share the mtab flag-option builder
2026-09-30 13:44 ` [PATCH 3/4] mount_util: share the mtab flag-option builder Bernd Schubert via B4 Relay
@ 2026-09-30 15:20 ` Darrick J. Wong
0 siblings, 0 replies; 9+ messages in thread
From: Darrick J. Wong @ 2026-09-30 15:20 UTC (permalink / raw)
To: bernd; +Cc: neal, fuse-devel
On Wed, Sep 30, 2026 at 03:44:35PM +0200, Bernd Schubert via B4 Relay wrote:
> From: Bernd Schubert <bernd@bsbernd.com>
>
> The loop over mount_flags[] that builds the rw/nosuid/nodev mirrors of
> an mtab record existed twice, in lib/mount.c and util/fusermount.c;
> both feed the same record, so a change to one silently diverges.
> fusermount3 does not link libfuse and cannot call fuse_opt_add_opt(),
> so fuse_mnt_add_opt() moves to lib/mount_util.c next to mount_flags[].
>
> fuse_mnt_add_opt() now has one realloc and one snprintf, because
> realloc(NULL) is the malloc. The empty-list path reserves expand as
> well, which strdup could not do. No caller pairs an empty list with a
> non-zero expand, so nothing changes today.
>
> Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
This looks like a pretty simple refactoring to hoist common code so
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
--D
> ---
> lib/mount.c | 21 +--------------------
> lib/mount_fsmount.c | 12 ++----------
> lib/mount_util.c | 33 +++++++++++++++++++++++++++++++++
> lib/mount_util.h | 20 ++++++++++++++++++++
> util/fusermount.c | 33 +++------------------------------
> 5 files changed, 59 insertions(+), 60 deletions(-)
>
> diff --git a/lib/mount.c b/lib/mount.c
> index a6dd5013ea80..4d03ef4b848f 100644
> --- a/lib/mount.c
> +++ b/lib/mount.c
> @@ -995,25 +995,6 @@ static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
> return fd;
> }
>
> -/*
> - * Append the flag-mirror prefix (rw/nosuid/nodev/...) of the mtab record
> - * to @mtab_optsp, derived from the MS_* bitmask in @flags.
> - */
> -static int get_mtab_flag_opts(char **mtab_optsp, int flags)
> -{
> - int i;
> -
> - if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mtab_optsp, "rw") == -1)
> - return -1;
> -
> - for (i = 0; mount_flags[i].opt != NULL; i++) {
> - if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
> - fuse_opt_add_opt(mtab_optsp, mount_flags[i].opt) == -1)
> - return -1;
> - }
> - return 0;
> -}
> -
> struct mount_opts *parse_mount_opts(struct fuse_args *args)
> {
> struct mount_opts *mo;
> @@ -1057,7 +1038,7 @@ void destroy_mount_opts(struct mount_opts *mo)
> int fuse_kern_mount_get_base_mtab_opts(const struct mount_opts *mo,
> char **mtab_optsp)
> {
> - if (get_mtab_flag_opts(mtab_optsp, mo->flags) == -1)
> + if (fuse_mnt_get_mtab_flag_opts(mtab_optsp, mo->flags) == -1)
> return -1;
> if (mo->kernel_opts && fuse_opt_add_opt(mtab_optsp, mo->kernel_opts) == -1)
> return -1;
> diff --git a/lib/mount_fsmount.c b/lib/mount_fsmount.c
> index 0b1fd4300d2d..730071206fc7 100644
> --- a/lib/mount_fsmount.c
> +++ b/lib/mount_fsmount.c
> @@ -446,16 +446,8 @@ int apply_fsconfig_mount_opts(int fsfd, const char *opts)
> continue;
> /*
> * Skip mount attributes, they're handled by fsmount()
> - * not fsconfig().
> - *
> - * These string options (nosuid, nodev, etc.) are reconstructed
> - * from MS_* flags by get_mtab_flag_opts() in lib/mount.c and
> - * get_mtab_opts() in util/fusermount.c. Both the library path
> - * (via fuse_kern_mount_get_base_mtab_opts) and fusermount3 path
> - * rebuild these strings from the flags bitmask and pass them in
> - * mtab_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).
> + * not fsconfig(). Callers rebuild them as strings from the
> + * MS_* bitmask for the mtab record, so they do show up here.
> *
> * Also skip mtab-only options - they're for /run/mount/utab, not kernel
> */
> diff --git a/lib/mount_util.c b/lib/mount_util.c
> index 2f763fe1218e..72ed17c93f47 100644
> --- a/lib/mount_util.c
> +++ b/lib/mount_util.c
> @@ -140,6 +140,39 @@ const struct mount_flags mount_flags[] = {
> {NULL, 0, 0, 0, 0, 0}
> };
>
> +int fuse_mnt_add_opt(char **optsp, const char *opt, unsigned int expand)
> +{
> + /* an empty list gets no separator, and realloc(NULL) is the malloc */
> + const char *sep = *optsp ? "," : "";
> + size_t oldsize = *optsp ? strlen(*optsp) : 0;
> + size_t newsize = oldsize + strlen(sep) + strlen(opt) + expand + 1;
> + char *newopts = (char *) realloc(*optsp, newsize);
> +
> + if (newopts == NULL) {
> + fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate memory\n");
> + return -1;
> + }
> +
> + snprintf(newopts + oldsize, newsize - oldsize, "%s%s", sep, opt);
> + *optsp = newopts;
> + return 0;
> +}
> +
> +int fuse_mnt_get_mtab_flag_opts(char **mtab_optsp, int flags)
> +{
> + int i;
> +
> + if (!(flags & MS_RDONLY) && fuse_mnt_add_opt(mtab_optsp, "rw", 0) == -1)
> + return -1;
> +
> + for (i = 0; mount_flags[i].opt != NULL; i++) {
> + if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
> + fuse_mnt_add_opt(mtab_optsp, mount_flags[i].opt, 0) == -1)
> + return -1;
> + }
> + return 0;
> +}
> +
> #ifdef IGNORE_MTAB
> #define mtab_needs_update(mnt) 0
> #else
> diff --git a/lib/mount_util.h b/lib/mount_util.h
> index b20a428d99c7..4485d8a29f93 100644
> --- a/lib/mount_util.h
> +++ b/lib/mount_util.h
> @@ -24,6 +24,26 @@ struct mount_flags {
> };
> extern const struct mount_flags mount_flags[];
>
> +/**
> + * @brief Append @opt to the comma-separated option list @optsp.
> + *
> + * @param[in,out] optsp list to extend, NULL for an empty list.
> + * @param[in] opt option to append.
> + * @param[in] expand extra bytes to reserve for a value the caller
> + * appends itself.
> + * @return 0 on success, -1 on failure.
> + */
> +int fuse_mnt_add_opt(char **optsp, const char *opt, unsigned int expand);
> +
> +/**
> + * @brief Append the flag-mirror part of an mtab record (rw/nosuid/nodev/...).
> + *
> + * @param[in,out] mtab_optsp option list to extend.
> + * @param[in] flags MS_* bitmask the mirrors are derived from.
> + * @return 0 on success, -1 on failure.
> + */
> +int fuse_mnt_get_mtab_flag_opts(char **mtab_optsp, int flags);
> +
> int fuse_mnt_add_mount(const char *progname, const char *fsname,
> const char *mnt, const char *type, const char *opts);
> int fuse_mnt_remove_mount(const char *progname, const char *mnt);
> diff --git a/util/fusermount.c b/util/fusermount.c
> index 3031b282a7a6..c7de86f4b12e 100644
> --- a/util/fusermount.c
> +++ b/util/fusermount.c
> @@ -556,26 +556,6 @@ static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
> return 0;
> }
>
> -static int add_option(char **optsp, const char *opt, unsigned expand)
> -{
> - char *newopts;
> - if (*optsp == NULL)
> - newopts = strdup(opt);
> - else {
> - unsigned oldsize = strlen(*optsp);
> - unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
> - newopts = (char *) realloc(*optsp, newsize);
> - if (newopts)
> - sprintf(newopts + oldsize, ",%s", opt);
> - }
> - if (newopts == NULL) {
> - fprintf(stderr, "%s: failed to allocate memory\n", progname);
> - return -1;
> - }
> - *optsp = newopts;
> - return 0;
> -}
> -
> /*
> * Build the mtab/utab record string for this mount: flag-mirrors of MS_*
> * (rw/nosuid/nodev/...) + the kernel-bound -o options + "user=<n>" when
> @@ -585,19 +565,12 @@ static int add_option(char **optsp, const char *opt, unsigned expand)
> */
> static int get_mtab_opts(int flags, const char *opts, char **mtab_optsp)
> {
> - int i;
> int l;
>
> - if (!(flags & MS_RDONLY) && add_option(mtab_optsp, "rw", 0) == -1)
> + if (fuse_mnt_get_mtab_flag_opts(mtab_optsp, flags) == -1)
> return -1;
>
> - for (i = 0; mount_flags[i].opt != NULL; i++) {
> - if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
> - add_option(mtab_optsp, mount_flags[i].opt, 0) == -1)
> - return -1;
> - }
> -
> - if (add_option(mtab_optsp, opts, 0) == -1)
> + if (fuse_mnt_add_opt(mtab_optsp, opts, 0) == -1)
> return -1;
> /* remove comma from end of opts*/
> l = strlen(*mtab_optsp);
> @@ -608,7 +581,7 @@ static int get_mtab_opts(int flags, const char *opts, char **mtab_optsp)
> if (user == NULL)
> return -1;
>
> - if (add_option(mtab_optsp, "user=", strlen(user)) == -1)
> + if (fuse_mnt_add_opt(mtab_optsp, "user=", strlen(user)) == -1)
> return -1;
> strcat(*mtab_optsp, user);
> }
>
> --
> 2.53.0
>
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 4/4] mount/fuse_service: share the service socket helpers
2026-09-30 13:44 ` [PATCH 4/4] mount/fuse_service: share the service socket helpers Bernd Schubert via B4 Relay
@ 2026-09-30 15:23 ` Darrick J. Wong
0 siblings, 0 replies; 9+ messages in thread
From: Darrick J. Wong @ 2026-09-30 15:23 UTC (permalink / raw)
To: bernd; +Cc: neal, fuse-devel
On Wed, Sep 30, 2026 at 03:44:36PM +0200, Bernd Schubert via B4 Relay wrote:
> From: Bernd Schubert <bernd@bsbernd.com>
>
> lib/fuse_service.c and util/mount_service.c each had their own sendmsg()
> and recvmsg() for the same packets, repeating MSG_EOR|MSG_NOSIGNAL and
> MSG_TRUNC, plus their own SO_SNDBUF check. Every change to how a packet
> travels had to be made twice.
>
> fuse_service_send_packet(), fuse_service_recv_packet() and
> fuse_service_sendbuf_too_small() move to include/fuse_service_priv.h,
> which both files already include for the packet layout. The error
> messages differ per file and stay in the callers.
>
> Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
Looks good,
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
--D
> ---
> include/fuse_service_priv.h | 59 +++++++++++++++++++++++++++++++++++++
> lib/fuse_service.c | 72 ++++++++++-----------------------------------
> util/mount_service.c | 59 ++++++-------------------------------
> 3 files changed, 83 insertions(+), 107 deletions(-)
>
> diff --git a/include/fuse_service_priv.h b/include/fuse_service_priv.h
> index 988f7c9251c8..951694faaaba 100644
> --- a/include/fuse_service_priv.h
> +++ b/include/fuse_service_priv.h
> @@ -9,6 +9,9 @@
> #ifndef FUSE_SERVICE_PRIV_H_
> #define FUSE_SERVICE_PRIV_H_
>
> +#include <sys/socket.h>
> +#include <limits.h>
> +
> /* All numeric fields are network order (big-endian) when going across the socket */
>
> struct fuse_service_memfd_arg {
> @@ -48,6 +51,36 @@ struct fuse_service_packet {
> uint32_t magic; /* FUSE_SERVICE_*_{CMD,REPLY} */
> };
>
> +static inline ssize_t fuse_service_send_packet(int sockfd, void *ptr,
> + size_t len)
> +{
> + struct iovec iov = {
> + .iov_base = ptr,
> + .iov_len = len,
> + };
> + struct msghdr msg = {
> + .msg_iov = &iov,
> + .msg_iovlen = 1,
> + };
> +
> + return sendmsg(sockfd, &msg, MSG_EOR | MSG_NOSIGNAL);
> +}
> +
> +static inline ssize_t fuse_service_recv_packet(int sockfd, void *ptr,
> + size_t len)
> +{
> + struct iovec iov = {
> + .iov_base = ptr,
> + .iov_len = len,
> + };
> + struct msghdr msg = {
> + .msg_iov = &iov,
> + .msg_iovlen = 1,
> + };
> +
> + return recvmsg(sockfd, &msg, MSG_TRUNC);
> +}
> +
> #define FUSE_SERVICE_PROTO (1)
> #define FUSE_SERVICE_MIN_PROTO (1)
> #define FUSE_SERVICE_MAX_PROTO (1)
> @@ -117,6 +150,32 @@ static inline size_t sizeof_fuse_service_open_command(size_t pathlen)
> return sizeof(struct fuse_service_open_command) + pathlen + 1;
> }
>
> +/*
> + * A send buffer that cannot hold the largest open command makes the sendmsg
> + * fail later on; report the size so the caller can say so in its own words.
> + * A buffer we cannot query is not an error - most likely we won't be sending
> + * huge open commands, and if we do, the sendmsg will fail there too.
> + *
> + * @sendbuf_sizep set to the offending size when the buffer is too small
> + * @return true if the send buffer is too small
> + */
> +static inline bool fuse_service_sendbuf_too_small(int sockfd,
> + int *sendbuf_sizep)
> +{
> + int sendbuf_size = -1;
> + socklen_t optlen = sizeof(sendbuf_size);
> +
> + if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuf_size, &optlen) ||
> + sendbuf_size < 0)
> + return false;
> +
> + if ((size_t)sendbuf_size >= sizeof_fuse_service_open_command(PATH_MAX))
> + return false;
> +
> + *sendbuf_sizep = sendbuf_size;
> + return true;
> +}
> +
> struct fuse_service_string_command {
> struct fuse_service_packet p;
> char value[];
> diff --git a/lib/fuse_service.c b/lib/fuse_service.c
> index 0a05b3fbc1f2..1f3fc1be0888 100644
> --- a/lib/fuse_service.c
> +++ b/lib/fuse_service.c
> @@ -135,36 +135,6 @@ static int __recv_fd(const struct fuse_service *sf,
> return 0;
> }
>
> -static ssize_t __send_packet(const struct fuse_service *sf, void *ptr,
> - size_t len)
> -{
> - struct iovec iov = {
> - .iov_base = ptr,
> - .iov_len = len,
> - };
> - struct msghdr msg = {
> - .msg_iov = &iov,
> - .msg_iovlen = 1,
> - };
> -
> - return sendmsg(sf->sockfd, &msg, MSG_EOR | MSG_NOSIGNAL);
> -}
> -
> -static ssize_t __recv_packet(const struct fuse_service *sf, void *ptr,
> - size_t len)
> -{
> - struct iovec iov = {
> - .iov_base = ptr,
> - .iov_len = len,
> - };
> - struct msghdr msg = {
> - .msg_iov = &iov,
> - .msg_iovlen = 1,
> - };
> -
> - return recvmsg(sf->sockfd, &msg, MSG_TRUNC);
> -}
> -
> int fuse_service_receive_file(const struct fuse_service *sf, const char *path,
> int *fdp)
> {
> @@ -266,7 +236,7 @@ static int fuse_service_request_path(const struct fuse_service *sf,
> cmd->request_flags = htonl(rqflags);
> memcpy(cmd->path, path, pathlen + 1);
>
> - size = __send_packet(sf, cmd, cmdsz);
> + size = fuse_service_send_packet(sf->sockfd, cmd, cmdsz);
> if (size < 0) {
> int error = errno;
>
> @@ -313,7 +283,7 @@ int fuse_service_send_goodbye(struct fuse_service *sf, int exitcode)
> if (sf->sockfd < 0)
> return 0;
>
> - size = __send_packet(sf, &c, sizeof(c));
> + size = fuse_service_send_packet(sf->sockfd, &c, sizeof(c));
> if (size < 0) {
> int error = errno;
>
> @@ -367,25 +337,13 @@ static int count_listen_fds(void)
>
> static int check_sendbuf_size(int sockfd)
> {
> - const size_t min_size = sizeof_fuse_service_open_command(PATH_MAX);
> - int sendbuf_size = -1;
> - socklen_t optlen = sizeof(sendbuf_size);
> - int ret;
> + int sendbuf_size;
>
> - /*
> - * If we can't query the maximum send buffer length, just keep going.
> - * Most likely we won't be sending huge open commands, and if we do,
> - * the sendmsg will fail there too.
> - */
> - ret = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuf_size, &optlen);
> - if (ret || sendbuf_size < 0)
> - return 0;
> -
> - if (sendbuf_size >= min_size)
> + if (!fuse_service_sendbuf_too_small(sockfd, &sendbuf_size))
> return 0;
>
> fuse_log(FUSE_LOG_ERR, "max socket send buffer is %d, need at least %zu.\n",
> - sendbuf_size, min_size);
> + sendbuf_size, sizeof_fuse_service_open_command(PATH_MAX));
> return -ENOBUFS;
> }
>
> @@ -456,7 +414,7 @@ static int negotiate_hello(struct fuse_service *sf)
> uint32_t flags;
> ssize_t size;
>
> - size = __recv_packet(sf, &hello, sizeof(hello));
> + size = fuse_service_recv_packet(sf->sockfd, &hello, sizeof(hello));
> if (size < 0) {
> int error = errno;
>
> @@ -511,7 +469,7 @@ static int negotiate_hello(struct fuse_service *sf)
> if (flags & FUSE_SERVICE_FLAG_FUSEBLK)
> sf->can_fuseblk = true;
>
> - size = __send_packet(sf, &reply, sizeof(reply));
> + size = fuse_service_send_packet(sf->sockfd, &reply, sizeof(reply));
> if (size < 0) {
> int error = errno;
>
> @@ -821,7 +779,7 @@ static int send_fsopen(const struct fuse_service *sf, const char *fstype,
> if (!strncmp(fstype, "fuseblk", 7))
> c.fsopen_flags |= htonl(FUSE_SERVICE_FSOPEN_FUSEBLK);
>
> - size = __send_packet(sf, &c, sizeof(c));
> + size = fuse_service_send_packet(sf->sockfd, &c, sizeof(c));
> if (size < 0) {
> int error = errno;
>
> @@ -830,7 +788,7 @@ static int send_fsopen(const struct fuse_service *sf, const char *fstype,
> return -error;
> }
>
> - size = __recv_packet(sf, &reply, sizeof(reply));
> + size = fuse_service_recv_packet(sf->sockfd, &reply, sizeof(reply));
> if (size < 0) {
> int error = errno;
>
> @@ -873,7 +831,7 @@ static int send_string(const struct fuse_service *sf, uint32_t command,
> cmd->p.magic = htonl(command);
> memcpy(cmd->value, value, valuelen + 1);
>
> - size = __send_packet(sf, cmd, cmdsz);
> + size = fuse_service_send_packet(sf->sockfd, cmd, cmdsz);
> if (size < 0) {
> err = -errno;
> fuse_log(FUSE_LOG_ERR, "fuse: send service string: %s\n",
> @@ -881,7 +839,7 @@ static int send_string(const struct fuse_service *sf, uint32_t command,
> goto out;
> }
>
> - size = __recv_packet(sf, &reply, sizeof(reply));
> + size = fuse_service_recv_packet(sf->sockfd, &reply, sizeof(reply));
> if (size < 0) {
> err = -errno;
> fuse_log(FUSE_LOG_ERR, "fuse: service string reply: %s\n",
> @@ -929,7 +887,7 @@ static int send_mountpoint(const struct fuse_service *sf, mode_t expected_fmt,
> cmd->expected_fmt = htons(expected_fmt);
> memcpy(cmd->value, value, valuelen + 1);
>
> - size = __send_packet(sf, cmd, cmdsz);
> + size = fuse_service_send_packet(sf->sockfd, cmd, cmdsz);
> if (size < 0) {
> err = -errno;
> fuse_log(FUSE_LOG_ERR, "fuse: send service mountpoint: %s\n",
> @@ -937,7 +895,7 @@ static int send_mountpoint(const struct fuse_service *sf, mode_t expected_fmt,
> goto out;
> }
>
> - size = __recv_packet(sf, &reply, sizeof(reply));
> + size = fuse_service_recv_packet(sf->sockfd, &reply, sizeof(reply));
> if (size < 0) {
> err = -errno;
> fuse_log(FUSE_LOG_ERR, "fuse: service mountpoint reply: %s\n",
> @@ -975,7 +933,7 @@ static int send_mount(const struct fuse_service *sf, unsigned int ms_flags,
> };
> ssize_t size;
>
> - size = __send_packet(sf, &c, sizeof(c));
> + size = fuse_service_send_packet(sf->sockfd, &c, sizeof(c));
> if (size < 0) {
> int error = errno;
>
> @@ -984,7 +942,7 @@ static int send_mount(const struct fuse_service *sf, unsigned int ms_flags,
> return -error;
> }
>
> - size = __recv_packet(sf, &reply, sizeof(reply));
> + size = fuse_service_recv_packet(sf->sockfd, &reply, sizeof(reply));
> if (size < 0) {
> int error = errno;
>
> diff --git a/util/mount_service.c b/util/mount_service.c
> index dcdc26df1db4..47cc2d43d2a0 100644
> --- a/util/mount_service.c
> +++ b/util/mount_service.c
> @@ -139,21 +139,6 @@ static ssize_t __send_fd(const struct mount_service *mo,
> return sendmsg(mo->sockfd, &msg, MSG_EOR | MSG_NOSIGNAL);
> }
>
> -static ssize_t __send_packet(const struct mount_service *mo, void *ptr,
> - size_t len)
> -{
> - struct iovec iov = {
> - .iov_base = ptr,
> - .iov_len = len,
> - };
> - struct msghdr msg = {
> - .msg_iov = &iov,
> - .msg_iovlen = 1,
> - };
> -
> - return sendmsg(mo->sockfd, &msg, MSG_EOR | MSG_NOSIGNAL);
> -}
> -
> static ssize_t __recv_packet_size(const struct mount_service *mo)
> {
> struct iovec iov = { };
> @@ -164,21 +149,6 @@ static ssize_t __recv_packet_size(const struct mount_service *mo)
> return recvmsg(mo->sockfd, &msg, MSG_PEEK | MSG_TRUNC);
> }
>
> -static ssize_t __recv_packet(const struct mount_service *mo, void *ptr,
> - size_t len)
> -{
> - struct iovec iov = {
> - .iov_base = ptr,
> - .iov_len = len,
> - };
> - struct msghdr msg = {
> - .msg_iov = &iov,
> - .msg_iovlen = 1,
> - };
> -
> - return recvmsg(mo->sockfd, &msg, MSG_TRUNC);
> -}
> -
> /*
> * Filter out the subtype of the filesystem (e.g. fuse.Y[.Z] -> Y[.Z]). The
> * fuse server determines if it's appropriate to set the "blockdev" mount
> @@ -271,25 +241,14 @@ static int try_drop_passrights(const struct mount_service *mo, int sockfd)
>
> static int check_sendbuf_size(const struct mount_service *mo, int sockfd)
> {
> - const size_t min_size = sizeof_fuse_service_open_command(PATH_MAX);
> - int sendbuf_size = -1;
> - socklen_t optlen = sizeof(sendbuf_size);
> - int ret;
> + int sendbuf_size;
>
> - /*
> - * If we can't query the maximum send buffer length, just keep going.
> - * Most likely we won't be sending huge open commands, and if we do,
> - * the sendmsg will fail there too.
> - */
> - ret = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuf_size, &optlen);
> - if (ret || sendbuf_size < 0)
> - return 0;
> -
> - if (sendbuf_size >= min_size)
> + if (!fuse_service_sendbuf_too_small(sockfd, &sendbuf_size))
> return 0;
>
> fprintf(stderr, "%s: max socket send buffer is %d, need at least %zu.\n",
> - mo->msgtag, sendbuf_size, min_size);
> + mo->msgtag, sendbuf_size,
> + sizeof_fuse_service_open_command(PATH_MAX));
> return MOUNT_SERVICE_FALLBACK_NEEDED;
> }
>
> @@ -369,14 +328,14 @@ static int mount_service_send_hello(const struct mount_service *mo)
> else if (user_allow_other)
> hello.flags |= htonl(FUSE_SERVICE_FLAG_ALLOW_OTHER);
>
> - size = __send_packet(mo, &hello, sizeof(hello));
> + size = fuse_service_send_packet(mo->sockfd, &hello, sizeof(hello));
> if (size < 0) {
> fprintf(stderr, "%s: send hello: %s\n",
> mo->msgtag, strerror(errno));
> return -1;
> }
>
> - size = __recv_packet(mo, &reply, sizeof(reply));
> + size = fuse_service_recv_packet(mo->sockfd, &reply, sizeof(reply));
> if (size < 0) {
> fprintf(stderr, "%s: hello reply: %s\n",
> mo->msgtag, strerror(errno));
> @@ -581,7 +540,7 @@ static int mount_service_send_file_error(const struct mount_service *mo,
> req->error = htonl(error);
> memcpy(req->path, path, path_len + 1);
>
> - written = __send_packet(mo, req, req_sz);
> + written = fuse_service_send_packet(mo->sockfd, req, req_sz);
> if (written < 0) {
> fprintf(stderr, "%s: send file error: %s\n",
> mo->msgtag, strerror(errno));
> @@ -671,7 +630,7 @@ static int mount_service_receive_command(const struct mount_service *mo,
> return -1;
> }
>
> - size = __recv_packet(mo, command, alleged_size);
> + size = fuse_service_recv_packet(mo->sockfd, command, alleged_size);
> if (size < 0) {
> fprintf(stderr, "%s: receive service command: %s\n",
> mo->msgtag, strerror(errno));
> @@ -698,7 +657,7 @@ static int mount_service_send_reply(const struct mount_service *mo, int error)
> };
> ssize_t size;
>
> - size = __send_packet(mo, &reply, sizeof(reply));
> + size = fuse_service_send_packet(mo->sockfd, &reply, sizeof(reply));
> if (size < 0) {
> fprintf(stderr, "%s: send service reply: %s\n",
> mo->msgtag, strerror(errno));
>
> --
> 2.53.0
>
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-09-30 15:23 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-30 13:44 [PATCH 0/4] libfuse: Avoid mount API code dup between mount-service and libfuse Bernd Schubert via B4 Relay
2026-09-30 13:44 ` [PATCH 1/4] mount_fsmount: split superblock creation and move_mount into a helper Bernd Schubert via B4 Relay
2026-09-30 15:13 ` Darrick J. Wong
2026-09-30 13:44 ` [PATCH 2/4] mount_service: mount via the shared fsmount helper Bernd Schubert via B4 Relay
2026-09-30 15:16 ` Darrick J. Wong
2026-09-30 13:44 ` [PATCH 3/4] mount_util: share the mtab flag-option builder Bernd Schubert via B4 Relay
2026-09-30 15:20 ` Darrick J. Wong
2026-09-30 13:44 ` [PATCH 4/4] mount/fuse_service: share the service socket helpers Bernd Schubert via B4 Relay
2026-09-30 15:23 ` Darrick J. Wong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox