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: 61+ 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-26 19:32 ` Bernd Schubert
2026-03-26 22:33 ` 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 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.