From: "Darrick J. Wong" <djwong@kernel.org>
To: Bernd Schubert <bernd@bsbernd.com>
Cc: linux-fsdevel@vger.kernel.org, Miklos Szeredi <miklos@szeredi.hu>,
Joanne Koong <joannelkoong@gmail.com>,
Bernd Schubert <bschubert@ddn.com>
Subject: Re: [PATCH 19/19] Add support for sync-init of unprivileged daemons
Date: Tue, 24 Mar 2026 13:21:25 -0700 [thread overview]
Message-ID: <20260324202125.GV6202@frogsfrogsfrogs> (raw)
In-Reply-To: <20260323-fuse-init-before-mount-v1-19-a52d3040af69@bsbernd.com>
On Mon, Mar 23, 2026 at 06:45:14PM +0100, Bernd Schubert wrote:
> From: Bernd Schubert <bschubert@ddn.com>
>
> This makes use of the bidirectional fusermount. Added is
> doc/README.mount, which explains the new bidirectional
> communication with fusermount.
>
> Signed-off-by: Bernd Schubert <bschubert@ddn.com>
All right, last patch before I go have some lunch and circle back to
your recent replies :)
> ---
> doc/README.mount | 86 ++++++++++++++++++++++++
> doc/README.sync-init | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++
These new readmes feel like they ought to go at the beginning (or at
least a separate patch) to argue for why synchronous init is needed
in libfuse? I do appreciate the flow diagrams though.
> lib/fuse_lowlevel.c | 115 ++++++++++++++++++++++++++------
> lib/mount.c | 126 ++++++++++++++++++++++++++++++++++-
> lib/mount_i_linux.h | 7 ++
> util/fusermount.c | 2 -
> 6 files changed, 494 insertions(+), 26 deletions(-)
>
> diff --git a/doc/README.mount b/doc/README.mount
> new file mode 100644
> index 0000000000000000000000000000000000000000..526382ad8a5f6b405a7cb1927b79bacd6c2c2c5c
> --- /dev/null
> +++ b/doc/README.mount
> @@ -0,0 +1,86 @@
> +FUSE Mount API Flowcharts
> +=========================
> +
> +Old Mount API
> +-------------
> +
> +fuse_kern_mount()
> + |
> + +-- fuse_mount_sys()
> + | +-- Try direct mount → mount() syscall
> + | +-- On EPERM: fuse_mount_fusermount()
> + | +-- socketpair()
> + | +-- spawn fusermount3 (no --sync-init)
> + | +-- fusermount3: open /dev/fuse, mount(), send fd
> + | +-- receive_fd() → return fd
> + |
> + +-- Worker threads started AFTER mount
> + └─> FUSE_INIT asynchronous (queued in kernel)
> +
> +
> +New Mount API - Privileged Mount
> +---------------------------------
> +
> +fuse_session_mount_new_api()
> + |
> + +-- fuse_kern_mount_prepare() → open /dev/fuse → fd
> + |
> + +-- session_start_sync_init(se, fd)
> + | +-- ioctl(fd, FUSE_DEV_IOC_SYNC_INIT)
> + | +-- pthread_create(worker) → ready to process FUSE_INIT
> + |
> + +-- fuse_kern_fsmount_mo()
> + | +-- fsopen/fsconfig/fsmount (BLOCKS until FUSE_INIT completes)
> + | +-- Worker processes FUSE_INIT during fsmount()
> + | +-- move_mount()
> + |
> + +-- session_wait_sync_init_completion(se) → pthread_join
> + └─> return fd
> +
> +
> +New Mount API - EPERM Fallback (fusermount3 with sync-init)
> +------------------------------------------------------------
> +
> +fuse_session_mount_new_api()
> + |
> + +-- fuse_kern_mount_prepare() → open /dev/fuse → fd1
> + |
> + +-- session_start_sync_init(se, fd1)
> + | +-- ioctl(fd1, FUSE_DEV_IOC_SYNC_INIT)
> + | +-- pthread_create(worker) → ready with fd1
> + |
> + +-- fuse_kern_fsmount_mo() → EPERM
> + |
> + +-- *** FALLBACK TO FUSERMOUNT3 WITH SYNC-INIT ***
> + |
> + +-- session_wait_sync_init_completion(se)
> + | +-- pthread_cancel/join → terminate worker with wrong fd1
> + |
> + +-- close(fd1)
> + |
> + +-- fuse_mount_fusermount_sync_init() [NEW]
> + | +-- socketpair()
> + | +-- spawn fusermount3 --sync-init
> + | +-- fusermount3: open /dev/fuse → fd2, send fd2
> + | +-- receive_fd() → fd2
> + | +-- fusermount3 waits for signal
> + | └─> return fd2, sock
> + |
> + +-- session_start_sync_init(se, fd2)
> + | +-- ioctl(fd2, FUSE_DEV_IOC_SYNC_INIT)
> + | +-- pthread_create(worker) → ready with fd2
> + |
> + +-- send_proceed_signal(sock) [NEW]
> + | +-- send(sock, "\0", 1) → signal fusermount3
> + |
> + +-- fusermount3: mount() (BLOCKS)
> + | +-- Kernel sends FUSE_INIT to fd2
> + | +-- Worker processes FUSE_INIT
> + | +-- mount() returns
> + |
> + +-- close(sock)
> + |
> + +-- session_wait_sync_init_completion(se) → pthread_join
> + |
> + └─> return fd2
> +
> diff --git a/doc/README.sync-init b/doc/README.sync-init
> new file mode 100644
> index 0000000000000000000000000000000000000000..44e47a2eef2c45026abaa19562537eef37f256b9
> --- /dev/null
> +++ b/doc/README.sync-init
> @@ -0,0 +1,184 @@
> +FUSE Synchronous vs Asynchronous FUSE_INIT
> +============================================
> +
> +This document explains the difference between asynchronous and synchronous
> +FUSE_INIT processing, and when each mode is used.
> +
> +
> +Overview
> +--------
> +
> +FUSE_INIT is the initial handshake between the kernel FUSE module and the
> +userspace filesystem daemon. During this handshake, the kernel and daemon
> +negotiate capabilities, protocol version, and various feature flags.
> +
> +Asynchronous FUSE_INIT (Traditional Behavior)
> +----------------------------------------------
> +
> +In the traditional asynchronous mode:
> +
> +1. mount() syscall completes and returns to caller
> +2. Filesystem appears mounted to the system
> +3. FUSE daemon starts worker threads
> +4. Worker threads process FUSE_INIT request
> +5. Filesystem becomes fully operational
> +
> +Timeline:
> + mount() -----> returns
> + |
> + v
> + FUSE_INIT sent
> + |
> + v
> + daemon processes FUSE_INIT
> + |
> + v
> + filesystem ready
> +
> +Limitations:
> +
> +1. **No early requests**: The kernel cannot send requests (like getxattr)
> + during the mount() syscall. This breaks SELinux, which needs to query
> + extended attributes on the root inode immediately upon mounting.
> +
> +2. **Daemonization timing**: With the old fuse_daemonize() API, the daemon
> + must call it AFTER mount, because there's no way to report mount failures
> + to the parent process if daemonization happens first.
> +
> +3. **No custom root inode**: The root inode ID is hardcoded to FUSE_ROOT_ID (1)
> + because FUSE_INIT hasn't been processed yet when the mount completes.
> +
> +4. **Thread startup after mount**: io_uring threads and other worker threads
> + can only start after mount() returns, not before.
Especially this part which explains why we care about sync init :)
> +
> +Synchronous FUSE_INIT (New Behavior)
> +-------------------------------------
> +
> +Kernel support: Linux kernel commit dfb84c330794 (v6.18+)
> +libfuse support: libfuse 3.19+
> +
> +In synchronous mode:
> +
> +1. FUSE daemon opens /dev/fuse
> +2. Daemon calls ioctl(fd, FUSE_DEV_IOC_SYNC_INIT)
> +3. Daemon starts worker thread
> +4. Daemon calls mount() syscall
> +5. Kernel sends FUSE_INIT during mount() - mount() blocks
> +6. Worker thread processes FUSE_INIT while mount() is blocked
> +7. Worker thread may process additional requests (getxattr, etc.)
> +8. mount() syscall completes and returns
> +9. Filesystem is fully operational
> +
> +Timeline:
> + open /dev/fuse
> + |
> + v
> + ioctl(FUSE_DEV_IOC_SYNC_INIT)
> + |
> + v
> + start worker thread
> + |
> + v
> + mount() -----> blocks
> + | |
> + | v
> + | FUSE_INIT sent
> + | |
> + | v
> + | worker processes FUSE_INIT
> + | |
> + | v
> + | (possible getxattr, etc.)
> + | |
> + +-------> returns
> + |
> + v
> + filesystem ready
> +
> +Advantages:
> +
> +1. **SELinux support**: The kernel can send getxattr requests during mount()
> + to query security labels on the root inode.
> +
> +2. **Early daemonization**: The daemon can fork BEFORE mount using the new
> + fuse_daemonize_start()/signal() API, and report mount failures to the
> + parent process.
> +
> +3. **Custom root inode**: The daemon can specify a custom root inode ID
> + during FUSE_INIT, before mount() completes.
> +
> +4. **Thread startup before mount**: io_uring threads and worker threads
> + start before mount(), ensuring they're ready to handle requests.
> +
> +5. **Better error reporting**: Mount failures and initialization errors
> + can be properly reported to the parent process when using the new
> + daemonization API.
> +
> +
> +When Synchronous FUSE_INIT is Used
> +-----------------------------------
> +
> +libfuse automatically enables synchronous FUSE_INIT when:
> +
> +1. The application calls fuse_session_want_sync_init(), OR
> +2. The new daemonization API is used (fuse_daemonize_start() was called)
> +
> +Synchronous FUSE_INIT requires:
> +- Kernel support (commit dfb84c330794 or later)
> +- Worker thread started before mount()
> +- ioctl(FUSE_DEV_IOC_SYNC_INIT) succeeds
> +
> +If the kernel doesn't support synchronous FUSE_INIT, libfuse automatically
> +falls back to asynchronous mode.
> +
> +
> +Implementation Details
> +----------------------
> +
> +The synchronous FUSE_INIT implementation uses a worker thread:
> +
> +- **session_sync_init_worker()**: Thread function that polls /dev/fuse
> + and processes FUSE_INIT and any subsequent requests until mount completes.
> +
> +- **session_start_sync_init()**: Creates the worker thread before mount().
> + Calls ioctl(FUSE_DEV_IOC_SYNC_INIT) to enable kernel support.
> +
> +- **session_wait_sync_init_completion()**: Waits for the worker thread
> + to complete after mount() returns. Checks for errors.
> +
> +The worker thread processes requests in a loop until se->terminate_mount_worker
> +is set, which happens after mount() completes successfully.
> +
> +
> +Compatibility
> +-------------
> +
> +Synchronous FUSE_INIT is fully backward compatible:
> +
> +- Old kernels: ioctl returns ENOTTY, libfuse falls back to async mode
> +- Old applications: Continue to work with async FUSE_INIT
> +- New applications on old kernels: Graceful fallback to async mode
> +- New applications on new kernels: Automatic sync mode when appropriate
> +
> +
> +Example: Enabling Synchronous FUSE_INIT
> +----------------------------------------
> +
> +Explicit request:
> + struct fuse_session *se = fuse_session_new(...);
> + fuse_session_want_sync_init(se);
> + fuse_session_mount(se, mountpoint);
> +
> +Automatic (with new daemonization API):
> + fuse_daemonize_start(0); // Triggers sync init automatically
> + fuse_session_mount(se, mountpoint);
> +
> +
> +See Also
> +--------
> +
> +- doc/README.daemonize - New daemonization API documentation
> +- doc/README.fusermount - Synchronous FUSE_INIT protocol with fusermount3
> +- doc/README.mount - Mount implementation details
> +
> diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
> index a7293a3898c37c3877eadf965d310ae2aa5cc2d1..da966217ed841744a20bee60de8ae615d1015b47 100644
> --- a/lib/fuse_lowlevel.c
> +++ b/lib/fuse_lowlevel.c
> @@ -41,6 +41,7 @@
> #include <assert.h>
> #include <sys/file.h>
> #include <sys/ioctl.h>
> +#include <sys/wait.h>
> #include <stdalign.h>
> #include <poll.h>
>
> @@ -4551,6 +4552,8 @@ static int session_wait_sync_init_completion(struct fuse_session *se)
> se->init_wakeup_fd = -1;
> }
>
> + se->init_thread = 0;
> +
> if (se->init_error != 0) {
> fuse_log(FUSE_LOG_ERR, "fuse: init worker failed: %d\n", se->init_error);
> return -1;
> @@ -4564,56 +4567,125 @@ static int session_wait_sync_init_completion(struct fuse_session *se)
> return 0;
> }
>
> -/* Only linux supports sync FUSE_INIT so far */
> +/*
> + * Mount using the new Linux mount API (fsopen/fsconfig/fsmount/move_mount)
> + * Sync-init is only supported with the new API, as the mount might hang
> + * in case of daemon crash during FUSE_INIT. That also means once the sync init
> + * ioctl succeed fallback is not allowed anymore.
> + * Returns: fd on success, -1 on failure
> + */
> static int fuse_session_mount_new_api(struct fuse_session *se,
> - const char *mountpoint)
> + const char *mountpoint, bool *fall_back)
> {
> int fd = -1;
> + int sock_fd = -1;
> + pid_t fusermount_pid = -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");
> - err = -EIO;
Odd churn in this function...
> 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;
> }
>
> - /*
> - * Enable synchronous FUSE_INIT and start worker thread, sync init
> - * failure is not an error
> - */
> + *fall_back = true;
> se->fd = fd;
> err = session_start_sync_init(se, fd);
> if (err) {
> /* ENOTTY means kernel doesn't support sync init - not an error */
> if (err != -ENOTTY)
> goto err;
> + } else {
> + *fall_back = false;
> }
> +
> +
> snprintf(fd_opt, sizeof(fd_opt), "fd=%i", fd);
> + err = -ENOMEM;
> 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;
> }
>
> + /* Try to mount directly */
> err = fuse_kern_fsmount_mo(mountpoint, se->mo, mnt_opts_with_fd);
> +
> + /* If mount failed with EPERM, fall back to fusermount3 with sync-init */
...since this is the new "actually use bidirectional fusermount3" code
mentioned in the commit message.
> + if (err < 0 && errno == EPERM) {
> + if (se->debug)
> + fuse_log(FUSE_LOG_DEBUG,
> + "fuse: privileged mount failed with EPERM, falling back to fusermount3\n");
> +
> + /* Terminate worker thread with wrong fd */
> + if (session_wait_sync_init_completion(se) < 0)
> + fuse_log(FUSE_LOG_ERR, "fuse: sync init completion failed\n");
> +
> + /* Close the privileged fd */
> + close(fd);
> + fd = -1;
> + se->fd = -1;
> +
> + /* Call fusermount3 with --sync-init */
> + err = -ENOTSUP;
> + fd = mount_fusermount_obtain_fd(mountpoint, se->mo, mnt_opts,
> + &sock_fd, &fusermount_pid);
> + if (fd < 0) {
> + fuse_log(
> + FUSE_LOG_ERR,
> + "fuse: fusermount3 sync-init failed\n");
> + goto err;
> + }
> +
> + /* Start worker thread with correct fd from fusermount3 */
> + se->fd = fd;
> + err = session_start_sync_init(se, fd);
> + if (err) {
> + if (err != -ENOTTY) {
> + fuse_log(
> + FUSE_LOG_ERR,
> + "fuse: failed to start sync init worker\n");
> + goto err_with_sock;
> + }
> + } else {
> + *fall_back = false;
We already set *fall_back to false above, didn't we? I'm slightly
confused -- should we set *fall_back=true any time this function returns
nonzero?
> + }
> +
> + /* Send proceed signal and wait for mount result */
> + err = fuse_fusermount_proceed_mnt(sock_fd);
> + if (err < 0) {
> + err = -EIO;
> + goto err_with_sock;
> + }
> + } else if (err < 0) {
> + /* Mount failed with non-EPERM error, bail out */
> + goto err;
> + }
> +
> +err_with_sock:
> + if (sock_fd >= 0) {
> + close(sock_fd);
> + /* Reap fusermount3 child process to prevent zombie */
> + if (fusermount_pid > 0)
> + waitpid(fusermount_pid, NULL, 0);
> + }
> err:
> if (err < 0) {
> + /* Close fd first to unblock worker thread */
> if (fd >= 0)
> close(fd);
> fd = -1;
> se->fd = -1;
> - se->error = -errno;
> + se->error = err;
> }
> /* Wait for synchronous FUSE_INIT to complete */
> if (session_wait_sync_init_completion(se) < 0)
> @@ -4625,10 +4697,11 @@ err:
> }
> #else
> static int fuse_session_mount_new_api(struct fuse_session *se,
> - const char *mountpoint)
> + const char *mountpoint, bool *fall_back)
> {
> (void) se;
> (void) mountpoint;
> + (void) fall_back;
>
> return -1;
> }
> @@ -4638,6 +4711,7 @@ int fuse_session_mount(struct fuse_session *se, const char *_mountpoint)
> {
> int fd;
> char *mountpoint;
> + bool fall_back;
>
> if (_mountpoint == NULL) {
> fuse_log(FUSE_LOG_ERR, "Invalid null-ptr mountpoint!\n");
> @@ -4681,21 +4755,18 @@ int fuse_session_mount(struct fuse_session *se, const char *_mountpoint)
> return 0;
> }
>
> - /* new linux mount api */
> - fd = fuse_session_mount_new_api(se, mountpoint);
> - if (fd >= 0)
> - goto out;
> + /* new linux mount api (and sync init) */
> + fd = fuse_session_mount_new_api(se, mountpoint, &fall_back);
>
> /* fall back to old API */
> - se->error = 0; /* reset error of new api */
> - fd = fuse_kern_mount(mountpoint, se->mo);
> - if (fd < 0)
> - goto error_out;
> + if (fall_back && fd < 0) {
> + se->error = 0; /* reset error of new api */
> + fd = fuse_kern_mount(mountpoint, se->mo);
> + if (fd < 0)
> + goto error_out;
> + }
>
> -out:
> se->fd = fd;
> -
> - /* Save mountpoint */
> se->mountpoint = mountpoint;
>
> return 0;
> diff --git a/lib/mount.c b/lib/mount.c
> index 263b05051c236458b830c40181bce7f494803800..985938ea0be3e1affad19adad527a31ac2ca6034 100644
> --- a/lib/mount.c
> +++ b/lib/mount.c
> @@ -41,6 +41,7 @@
> #define FUSERMOUNT_PROG "fusermount3"
> #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
> #define FUSE_COMMFD2_ENV "_FUSE_COMMFD2"
> +#define ARG_FD_ENTRY_SIZE 30
Thirty seems a bit much for an integer, especially one that can't go
above 1 million. Eh, it's just stack space. :)
> enum {
> KEY_KERN_FLAG,
> @@ -313,7 +314,7 @@ static int setup_auto_unmount(const char *mountpoint, int quiet)
> return -1;
> }
>
> - char arg_fd_entry[30];
> + char arg_fd_entry[ARG_FD_ENTRY_SIZE];
> snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[0]);
> setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
> /*
> @@ -386,7 +387,7 @@ static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
> return -1;
> }
>
> - char arg_fd_entry[30];
> + char arg_fd_entry[ARG_FD_ENTRY_SIZE];
> snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[0]);
> setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
> /*
> @@ -446,6 +447,127 @@ static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
> return fd;
> }
>
> +/*
> + * Mount using fusermount3 with --sync-init flag for bidirectional fd exchange
> + * Used by new mount API when privileged mount fails with EPERM
> + *
> + * Returns: fd on success, -1 on failure
> + * On success, *sock_fd_out contains the socket fd for signaling fusermount3
> + */
> +int mount_fusermount_obtain_fd(const char *mountpoint, struct mount_opts *mo,
> + const char *opts, int *sock_fd_out,
> + pid_t *pid_out)
> +{
> + int fds[2];
> + pid_t pid;
> + int res;
> + char arg_fd_entry[ARG_FD_ENTRY_SIZE];
> + posix_spawn_file_actions_t action;
> + int fd, status;
> +
> + (void)mo;
> +
> + if (!mountpoint) {
> + fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n");
> + return -1;
> + }
> +
> + res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
> + if (res == -1) {
> + fuse_log(FUSE_LOG_ERR, "Running %s: socketpair() failed: %s\n",
> + FUSERMOUNT_PROG, strerror(errno));
> + return -1;
> + }
> +
> + snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[0]);
> + setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
Oh! /me realizes that FUSE_COMMFD{,2}_ENV can convey different things!
If you're trying to get fusermount to *mount* a filesystem, then it's
the AF_UNIX socket that is used to pass the /dev/fuse fd to the fuse
server and then to trigger the mount.
If you pass --auto-unmount/-U then fusermount waits for the socket to
close and then unmounts the mount.
> + snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[1]);
> + setenv(FUSE_COMMFD2_ENV, arg_fd_entry, 1);
...and I guess you can pass the fds on the cli instead of goofy
environment variables? I wonder if you should be passing them via CLI
since you know fusermount supports it. OTOH I don't really care either
way ;)
> +
> + char const *const argv[] = {
> + FUSERMOUNT_PROG,
> + "--sync-init",
> + "-o", opts ? opts : "",
> + "--",
> + mountpoint,
> + NULL,
> + };
> +
> + posix_spawn_file_actions_init(&action);
> + posix_spawn_file_actions_addclose(&action, fds[1]);
> + status = fusermount_posix_spawn(&action, argv, &pid);
> + posix_spawn_file_actions_destroy(&action);
> +
> + if (status != 0) {
> + close(fds[0]);
> + close(fds[1]);
> + return -1;
> + }
> +
> + close(fds[0]);
> +
> + fd = receive_fd(fds[1]);
> + if (fd < 0) {
> + close(fds[1]);
> + waitpid(pid, NULL, 0);
> + return -1;
> + }
> +
> + fcntl(fd, F_SETFD, FD_CLOEXEC);
> +
> + /* Return socket fd for later signaling */
> + *sock_fd_out = fds[1];
> + *pid_out = pid;
> +
> + return fd;
> +}
> +
> +/*
> + * Send proceed signal to fusermount3 and wait for mount result
> + * Returns: 0 on success, -1 on failure
> + */
> +int fuse_fusermount_proceed_mnt(int sock_fd)
> +{
> + char buf = '\0';
> + ssize_t res;
> +
> + /* Send proceed signal */
> + do {
> + res = send(sock_fd, &buf, 1, 0);
> + } while (res == -1 && errno == EINTR);
I wonder if all the pipe/socket communications ought to have been turned
into a bunch of wrappers like what I did for
mount_service.c/fuse_service.c?
That said, it looks like most of the fusermount/sync-init communcations
are single ints so maybe it doesn't matter. The communications for the
fuse servers is much more complex and hence needs more structure.
--D
> +
> + if (res != 1) {
> + fuse_log(FUSE_LOG_ERR, "fuse: failed to send proceed signal: %s\n",
> + strerror(errno));
> + return -1;
> + }
> +
> + /* Wait for mount result from fusermount3 (4-byte error code) */
> + int32_t status;
> +
> + do {
> + res = recv(sock_fd, &status, sizeof(status), 0);
> + } while (res == -1 && errno == EINTR);
> +
> + if (res != sizeof(status)) {
> + if (res == 0)
> + fuse_log(FUSE_LOG_ERR, "fuse: fusermount3 closed connection\n");
> + else
> + fuse_log(FUSE_LOG_ERR, "fuse: failed to receive mount status: %s\n",
> + strerror(errno));
> + return -1;
> + }
> +
> + if (status != 0) {
> + if (status != -EPERM)
> + fuse_log(FUSE_LOG_ERR, "fuse: fusermount3 mount failed: %s\n",
> + strerror(-status));
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> #ifndef O_CLOEXEC
> #define O_CLOEXEC 0
> #endif
> diff --git a/lib/mount_i_linux.h b/lib/mount_i_linux.h
> index 867105019fa57576682091d1a650302f31e450b3..2a3386443afa73a508454124332527c35a184398 100644
> --- a/lib/mount_i_linux.h
> +++ b/lib/mount_i_linux.h
> @@ -76,5 +76,12 @@ int fuse_kern_fsmount_mo(const char *mnt, struct mount_opts *mo,
> const char *mnt_opts);
> char *fuse_mnt_build_source(const struct mount_opts *mo);
> char *fuse_mnt_build_type(const struct mount_opts *mo);
> +int mount_fusermount_obtain_fd(const char *mountpoint,
> + struct mount_opts *mo,
> + const char *opts, int *sock_fd_out,
> + pid_t *pid_out);
> +
> +int fuse_fusermount_proceed_mnt(int sock_fd);
> +
>
> #endif /* FUSE_MOUNT_I_H_ */
> diff --git a/util/fusermount.c b/util/fusermount.c
> index 808b4afd89ceb49273c944d43bffe5033e27549b..e6d973687bb4eef0d7e6626a1028cc32dd177e89 100644
> --- a/util/fusermount.c
> +++ b/util/fusermount.c
> @@ -1397,7 +1397,6 @@ struct mount_context {
> char *source;
> char *mnt_opts;
> char *x_opts;
> - const char *type;
> };
>
> /*
> @@ -1521,7 +1520,6 @@ static int mount_fuse_finish_fsmount(const char *mnt, const char *opts,
>
> /* Store results in context */
> ctx->source = mp.source;
> - ctx->type = mp.type;
> ctx->mnt_opts = final_mnt_opts;
> *type = mp.type;
>
>
> --
> 2.43.0
>
>
next prev parent reply other threads:[~2026-03-24 20:21 UTC|newest]
Thread overview: 59+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-23 17:44 [PATCH 00/19] libfuse: Add support for synchronous init Bernd Schubert
2026-03-23 17:44 ` [PATCH 01/19] ci-build: Add environment logging Bernd Schubert
2026-03-23 17:44 ` [PATCH 02/19] Add 'STRCPY' to the checkpatch ignore option Bernd Schubert
2026-03-23 21:03 ` Darrick J. Wong
2026-03-23 17:44 ` [PATCH 03/19] checkpatch.pl: Add _Atomic to $Attribute patttern Bernd Schubert
2026-03-23 21:09 ` Darrick J. Wong
2026-03-23 17:44 ` [PATCH 04/19] Add a new daemonize API Bernd Schubert
2026-03-23 22:28 ` Darrick J. Wong
2026-03-24 17:36 ` Bernd Schubert
2026-03-24 22:20 ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 05/19] Sync fuse_kernel.h with linux-6.18 Bernd Schubert
2026-03-23 21:16 ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 06/19] mount.c: Split fuse_mount_sys to prepare privileged sync FUSE_INIT Bernd Schubert
2026-03-23 22:34 ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 07/19] Add FUSE_MOUNT_FALLBACK_NEEDED define for -2 mount errors Bernd Schubert
2026-03-23 22:36 ` Darrick J. Wong
2026-03-24 18:03 ` Bernd Schubert
2026-03-23 17:45 ` [PATCH 08/19] Refactor mount code / move common functions to mount_util.c Bernd Schubert
2026-03-23 22:40 ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 09/19] Move mount flags to mount_i.h Bernd Schubert
2026-03-23 22:45 ` Darrick J. Wong
2026-03-24 18:40 ` Bernd Schubert
2026-03-23 17:45 ` [PATCH 10/19] conftest.py: Add more valgrind filter patterns Bernd Schubert
2026-03-23 17:45 ` [PATCH 11/19] Add support for the new linux mount API Bernd Schubert
2026-03-23 23:42 ` Darrick J. Wong
2026-03-24 20:16 ` Bernd Schubert
2026-03-24 22:46 ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 12/19] fuse mount: Support synchronous FUSE_INIT (privileged daemon) Bernd Schubert
2026-03-24 0:03 ` Darrick J. Wong
2026-03-24 20:42 ` Bernd Schubert
2026-03-24 22:50 ` Darrick J. Wong
2026-03-25 7:52 ` Bernd Schubert
2026-03-25 16:42 ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 13/19] Add fuse_session_set_debug() to enable debug output without foreground Bernd Schubert
2026-03-24 0:04 ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 14/19] Move more generic mount code to mount_util.{c,h} Bernd Schubert
2026-03-24 0:06 ` Darrick J. Wong
2026-03-24 20:57 ` Bernd Schubert
2026-03-23 17:45 ` [PATCH 15/19] Split the fusermount do_mount function Bernd Schubert
2026-03-24 0:14 ` Darrick J. Wong
2026-03-24 21:05 ` Bernd Schubert
2026-03-24 22:53 ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 16/19] fusermount: Refactor extract_x_options Bernd Schubert
2026-03-24 0:18 ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 17/19] Make fusermount work bidirectional for sync init Bernd Schubert
2026-03-24 19:35 ` Darrick J. Wong
2026-03-24 21:24 ` Bernd Schubert
2026-03-24 22:59 ` Darrick J. Wong
2026-03-25 19:48 ` Bernd Schubert
2026-03-25 22:03 ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 18/19] New mount API: Filter out "user=" Bernd Schubert
2026-03-24 19:51 ` Darrick J. Wong
2026-03-24 20:01 ` Bernd Schubert
2026-03-24 23:02 ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 19/19] Add support for sync-init of unprivileged daemons Bernd Schubert
2026-03-24 20:21 ` Darrick J. Wong [this message]
2026-03-24 21:53 ` Bernd Schubert
2026-03-24 23:13 ` Darrick J. Wong
2026-03-24 0:19 ` [PATCH 00/19] libfuse: Add support for synchronous init 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=20260324202125.GV6202@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 \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox