From: "Darrick J. Wong" <djwong@kernel.org>
To: djwong@kernel.org, bschubert@ddn.com
Cc: linux-fsdevel@vger.kernel.org, bernd@bsbernd.com,
miklos@szeredi.hu, neal@gompa.dev, joannelkoong@gmail.com
Subject: [PATCH 04/17] mount_service: use the new mount api for the mount service
Date: Thu, 26 Mar 2026 18:25:49 -0700 [thread overview]
Message-ID: <177457463189.1008428.16697718096512582220.stgit@frogsfrogsfrogs> (raw)
In-Reply-To: <177457463048.1008428.11432672970504238251.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
Use the new fsopen/fsmount system calls to mount the filesystem so that
we get somewhat better diagnostics if something gets screwed up.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
meson.build | 15 +++
util/mount_service.c | 299 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 314 insertions(+)
diff --git a/meson.build b/meson.build
index d6ba8740effd5c..b0988548bf806a 100644
--- a/meson.build
+++ b/meson.build
@@ -130,6 +130,21 @@ special_funcs = {
int main(int argc, char *argv[]) {
return SD_LISTEN_FDS_START;
}
+ ''',
+ '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;
+ }
'''
}
diff --git a/util/mount_service.c b/util/mount_service.c
index ae078e537dc560..4a2c1111b66b91 100644
--- a/util/mount_service.c
+++ b/util/mount_service.c
@@ -65,6 +65,9 @@ struct mount_service {
/* O_PATH fd for mount point */
int mountfd;
+
+ /* fd for fsopen */
+ int fsopenfd;
};
/* Filter out the subtype of the filesystem (e.g. fuse.Y -> Y) */
@@ -87,6 +90,7 @@ static int mount_service_init(struct mount_service *mo, int argc, char *argv[])
mo->argvfd = -1;
mo->fusedevfd = -1;
mo->mountfd = -1;
+ mo->fsopenfd = -1;
for (i = 0; i < argc; i++) {
if (!strcmp(argv[i], "-t") && i + 1 < argc) {
@@ -690,9 +694,50 @@ static int mount_service_handle_fsopen_cmd(struct mount_service *mo,
return mount_service_send_reply(mo, error);
}
+#ifdef HAVE_NEW_MOUNT_API
+ /* If this fails we fall back on mount() */
+ mo->fsopenfd = fsopen(oc->value, FSOPEN_CLOEXEC);
+#endif
+
return mount_service_send_reply(mo, 0);
}
+#ifdef HAVE_NEW_MOUNT_API
+/* callers must preserve errno */
+static void emit_fsconfig_messages(const struct mount_service *mo)
+{
+ uint8_t buf[BUFSIZ];
+ ssize_t sz;
+
+ while ((sz = read(mo->fsopenfd, 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;
+ }
+ }
+}
+#endif
+
static int mount_service_handle_source_cmd(struct mount_service *mo,
const struct fuse_service_packet *p)
{
@@ -714,6 +759,21 @@ static int mount_service_handle_source_cmd(struct mount_service *mo,
return mount_service_send_reply(mo, error);
}
+#ifdef HAVE_NEW_MOUNT_API
+ if (mo->fsopenfd >= 0) {
+ int ret = fsconfig(mo->fsopenfd, FSCONFIG_SET_STRING, "source",
+ oc->value, 0);
+ if (ret) {
+ int error = errno;
+
+ fprintf(stderr, "%s: fsconfig source: %s\n",
+ mo->msgtag, strerror(error));
+ emit_fsconfig_messages(mo);
+ return mount_service_send_reply(mo, error);
+ }
+ }
+#endif
+
return mount_service_send_reply(mo, 0);
}
@@ -722,6 +782,8 @@ static int mount_service_handle_mntopts_cmd(struct mount_service *mo,
{
struct fuse_service_string_command *oc =
container_of(p, struct fuse_service_string_command, p);
+ char *tokstr = oc->value;
+ char *tok, *savetok;
if (mo->mntopts) {
fprintf(stderr, "%s: mount options respecified!\n",
@@ -738,6 +800,45 @@ static int mount_service_handle_mntopts_cmd(struct mount_service *mo,
return mount_service_send_reply(mo, error);
}
+ /* strtok_r mutates tokstr aka oc->value */
+ while ((tok = strtok_r(tokstr, ",", &savetok)) != NULL) {
+ char *equals = strchr(tok, '=');
+ char oldchar = 0;
+
+ if (equals) {
+ oldchar = *equals;
+ *equals = 0;
+ }
+
+#ifdef HAVE_NEW_MOUNT_API
+ if (mo->fsopenfd >= 0) {
+ int ret;
+
+ if (equals)
+ ret = fsconfig(mo->fsopenfd,
+ FSCONFIG_SET_STRING, tok,
+ equals + 1, 0);
+ else
+ ret = fsconfig(mo->fsopenfd,
+ FSCONFIG_SET_FLAG, tok,
+ NULL, 0);
+ if (ret) {
+ int error = errno;
+
+ fprintf(stderr, "%s: set mount option: %s\n",
+ mo->msgtag, strerror(error));
+ emit_fsconfig_messages(mo);
+ return mount_service_send_reply(mo, error);
+ }
+ }
+#endif
+
+ if (equals)
+ *equals = oldchar;
+
+ tokstr = NULL;
+ }
+
return mount_service_send_reply(mo, 0);
}
@@ -875,6 +976,196 @@ static int mount_service_regular_mount(struct mount_service *mo,
return mount_service_send_reply(mo, 0);
}
+#ifdef HAVE_NEW_MOUNT_API
+struct ms_to_mount_map {
+ unsigned long ms_flag;
+ unsigned int mount_attr_flag;
+};
+
+static const struct ms_to_mount_map attrs[] = {
+ { MS_RDONLY, MOUNT_ATTR_RDONLY },
+ { MS_NOSUID, MOUNT_ATTR_NOSUID },
+ { MS_NODEV, MOUNT_ATTR_NODEV },
+ { MS_NOEXEC, MOUNT_ATTR_NOEXEC },
+ { MS_RELATIME, MOUNT_ATTR_RELATIME },
+ { MS_NOATIME, MOUNT_ATTR_NOATIME },
+ { MS_STRICTATIME, MOUNT_ATTR_STRICTATIME },
+ { MS_NODIRATIME, MOUNT_ATTR_NODIRATIME },
+#ifdef MOUNT_ATTR_NOSYMFOLLOW
+ { MS_NOSYMFOLLOW, MOUNT_ATTR_NOSYMFOLLOW },
+#endif
+ { 0, 0 },
+};
+
+static void get_mount_attr_flags(const struct fuse_service_mount_command *oc,
+ unsigned int *attr_flags,
+ unsigned long *leftover_ms_flags)
+{
+ const struct ms_to_mount_map *i;
+ unsigned int ms_flags = ntohl(oc->ms_flags);
+ unsigned int mount_attr_flags = 0;
+
+ for (i = attrs; i->ms_flag != 0; i++) {
+ if (ms_flags & i->ms_flag)
+ mount_attr_flags |= i->mount_attr_flag;
+ ms_flags &= ~i->ms_flag;
+ }
+
+ *leftover_ms_flags = ms_flags;
+ *attr_flags = mount_attr_flags;
+}
+
+struct ms_to_str_map {
+ unsigned long ms_flag;
+ const char *string;
+};
+
+static const struct ms_to_str_map strflags[] = {
+ { MS_SYNCHRONOUS, "sync" },
+ { MS_DIRSYNC, "dirsync" },
+ { MS_LAZYTIME, "lazytime" },
+ { 0, 0 },
+};
+
+static int set_ms_flags(struct mount_service *mo, unsigned long ms_flags)
+{
+ const struct ms_to_str_map *i;
+ int ret;
+
+ for (i = strflags; i->ms_flag != 0; i++) {
+ if (!(ms_flags & i->ms_flag))
+ continue;
+
+ ret = fsconfig(mo->fsopenfd, FSCONFIG_SET_FLAG, i->string,
+ NULL, 0);
+ if (ret) {
+ int error = errno;
+
+ fprintf(stderr, "%s: set %s option: %s\n",
+ mo->msgtag, i->string, strerror(error));
+ emit_fsconfig_messages(mo);
+
+ errno = error;
+ return -1;
+ }
+ ms_flags &= ~i->ms_flag;
+ }
+
+ /*
+ * We can't translate all the supplied MS_ flags into MOUNT_ATTR_ flags
+ * or string flags! Return a magic code so the caller will fall back
+ * to regular mount(2).
+ */
+ return ms_flags ? -2 : 0;
+}
+
+static int mount_service_fsopen_mount(struct mount_service *mo,
+ struct fuse_service_mount_command *oc,
+ struct stat *stbuf)
+{
+ char tmp[64];
+ char *dot;
+ unsigned long ms_flags;
+ unsigned int attr_flags;
+ int mfd;
+ int error;
+ int ret;
+
+ get_mount_attr_flags(oc, &attr_flags, &ms_flags);
+
+ ret = set_ms_flags(mo, ms_flags);
+ if (ret == -2)
+ return ret;
+ if (ret) {
+ error = errno;
+ goto fail_mount;
+ }
+
+ snprintf(tmp, sizeof(tmp), "%i", mo->fusedevfd);
+ ret = fsconfig(mo->fsopenfd, FSCONFIG_SET_STRING, "fd", tmp, 0);
+ if (ret) {
+ error = errno;
+ fprintf(stderr, "%s: set fd option: %s\n",
+ mo->msgtag, strerror(error));
+ goto fail_fsconfig;
+ }
+
+ snprintf(tmp, sizeof(tmp), "%o", stbuf->st_mode & S_IFMT);
+ ret = fsconfig(mo->fsopenfd, FSCONFIG_SET_STRING, "rootmode", tmp, 0);
+ if (ret) {
+ error = errno;
+ fprintf(stderr, "%s: set rootmode option: %s\n",
+ mo->msgtag, strerror(error));
+ goto fail_fsconfig;
+ }
+
+ snprintf(tmp, sizeof(tmp), "%u", getuid());
+ ret = fsconfig(mo->fsopenfd, FSCONFIG_SET_STRING, "user_id", tmp, 0);
+ if (ret) {
+ error = errno;
+ fprintf(stderr, "%s: set user_id option: %s\n",
+ mo->msgtag, strerror(error));
+ goto fail_fsconfig;
+ }
+
+ snprintf(tmp, sizeof(tmp), "%u", getgid());
+ ret = fsconfig(mo->fsopenfd, FSCONFIG_SET_STRING, "group_id", tmp, 0);
+ if (ret) {
+ error = errno;
+ fprintf(stderr, "%s: set group_id option: %s\n",
+ mo->msgtag, strerror(error));
+ goto fail_fsconfig;
+ }
+
+ dot = strchr(mo->fstype, '.');
+ if (dot) {
+ ret = fsconfig(mo->fsopenfd, FSCONFIG_SET_STRING, "subtype",
+ dot + 1, 0);
+ if (ret) {
+ error = errno;
+ fprintf(stderr, "%s: set subtype option: %s\n",
+ mo->msgtag, strerror(error));
+ 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;
+ }
+
+ return mount_service_send_reply(mo, 0);
+
+fail_fsconfig:
+ emit_fsconfig_messages(mo);
+fail_mount:
+ return mount_service_send_reply(mo, error);
+}
+#else
+# define mount_service_fsopen_mount(...) (-2)
+#endif
+
static int mount_service_handle_mount_cmd(struct mount_service *mo,
struct fuse_service_packet *p)
{
@@ -949,6 +1240,12 @@ static int mount_service_handle_mount_cmd(struct mount_service *mo,
return mount_service_send_reply(mo, EINVAL);
}
+ if (mo->fsopenfd >= 0) {
+ ret = mount_service_fsopen_mount(mo, oc, &stbuf);
+ if (ret != -2)
+ return ret;
+ }
+
return mount_service_regular_mount(mo, oc, &stbuf);
}
@@ -971,6 +1268,7 @@ static void mount_service_destroy(struct mount_service *mo)
close(mo->mountfd);
close(mo->fusedevfd);
close(mo->argvfd);
+ close(mo->fsopenfd);
shutdown(mo->sockfd, SHUT_RDWR);
close(mo->sockfd);
@@ -984,6 +1282,7 @@ static void mount_service_destroy(struct mount_service *mo)
mo->argvfd = -1;
mo->fusedevfd = -1;
mo->mountfd = -1;
+ mo->fsopenfd = -1;
}
int mount_service_main(int argc, char *argv[])
next prev parent reply other threads:[~2026-03-27 1:25 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-27 1:24 [PATCHSET v3] libfuse: run fuse servers as a contained service Darrick J. Wong
2026-03-27 1:25 ` [PATCH 01/17] Refactor mount code / move common functions to mount_util.c Darrick J. Wong
2026-03-27 1:25 ` [PATCH 02/17] mount_service: add systemd/inetd socket service mounting helper Darrick J. Wong
2026-03-30 20:44 ` Bernd Schubert
2026-03-30 21:37 ` Darrick J. Wong
2026-04-07 23:39 ` Darrick J. Wong
2026-03-27 1:25 ` [PATCH 03/17] mount_service: create high level fuse helpers Darrick J. Wong
2026-03-30 19:37 ` Bernd Schubert
2026-03-30 20:30 ` Darrick J. Wong
2026-03-30 20:51 ` Bernd Schubert
2026-03-30 21:09 ` Darrick J. Wong
2026-03-27 1:25 ` Darrick J. Wong [this message]
2026-03-30 21:06 ` [PATCH 04/17] mount_service: use the new mount api for the mount service Bernd Schubert
2026-03-30 21:18 ` Darrick J. Wong
2026-03-30 21:40 ` Bernd Schubert
2026-03-30 21:47 ` Darrick J. Wong
2026-03-27 1:26 ` [PATCH 05/17] mount_service: update mtab after a successful mount Darrick J. Wong
2026-04-07 23:42 ` Darrick J. Wong
2026-03-27 1:26 ` [PATCH 06/17] util: hoist the fuse.conf parsing code Darrick J. Wong
2026-04-07 23:40 ` Darrick J. Wong
2026-03-27 1:26 ` [PATCH 07/17] util: fix checkpatch complaints in fuser_conf.[ch] Darrick J. Wong
2026-03-27 1:26 ` [PATCH 08/17] mount_service: read fuse.conf to enable allow_other for unprivileged mounts Darrick J. Wong
2026-03-27 1:27 ` [PATCH 09/17] util: hoist the other non-root user limits Darrick J. Wong
2026-03-27 1:27 ` [PATCH 10/17] util: fix more checkpatch complaints in fuser_conf.[ch] Darrick J. Wong
2026-03-27 1:27 ` [PATCH 11/17] mount_service: use over the other non-root user checks Darrick J. Wong
2026-04-07 23:47 ` Darrick J. Wong
2026-03-27 1:27 ` [PATCH 12/17] mount.fuse3: integrate systemd service startup Darrick J. Wong
2026-04-07 23:56 ` Darrick J. Wong
2026-03-27 1:28 ` [PATCH 13/17] mount_service: allow installation as a setuid program Darrick J. Wong
2026-03-27 1:28 ` [PATCH 14/17] example/service_ll: create a sample systemd service fuse server Darrick J. Wong
2026-04-08 0:09 ` Darrick J. Wong
2026-03-27 1:28 ` [PATCH 15/17] example/service: create a sample systemd service for a high-level " Darrick J. Wong
2026-03-27 1:28 ` [PATCH 16/17] example/hello_ll: port to single-file common code Darrick J. Wong
2026-03-27 1:29 ` [PATCH 17/17] nullfs: support fuse systemd service mode Darrick J. Wong
2026-04-08 0:11 ` Darrick J. Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=177457463189.1008428.16697718096512582220.stgit@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=bernd@bsbernd.com \
--cc=bschubert@ddn.com \
--cc=joannelkoong@gmail.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=miklos@szeredi.hu \
--cc=neal@gompa.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.