]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
fuse: abort on fatal signal during sync init
authorMiklos Szeredi <mszeredi@redhat.com>
Mon, 16 Mar 2026 13:10:00 +0000 (14:10 +0100)
committerMiklos Szeredi <mszeredi@redhat.com>
Tue, 24 Mar 2026 14:26:32 +0000 (15:26 +0100)
When sync init is used and the server exits for some reason (error, crash)
while processing FUSE_INIT, the filesystem creation will hang.  The reason
is that while all other threads will exit, the mounting thread (or process)
will keep the device fd open, which will prevent an abort from happening.

This is a regression from the async mount case, where the mount was done
first, and the FUSE_INIT processing afterwards, in which case there's no
such recursive syscall keeping the fd open.

Fixes: dfb84c330794 ("fuse: allow synchronous FUSE_INIT")
Cc: stable@vger.kernel.org # v6.18
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
Reviewed-by: Bernd Schubert <bernd@bsbernd.com>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/dev.c
fs/fuse/fuse_i.h
fs/fuse/inode.c

index 2c16b94357d5155ec491ce960f5823a64dc349d9..b212565a78cf4760f7df0e14e04a210d27d81bf9 100644 (file)
@@ -570,6 +570,11 @@ static void request_wait_answer(struct fuse_req *req)
                if (!err)
                        return;
 
+               if (req->args->abort_on_kill) {
+                       fuse_abort_conn(fc);
+                       return;
+               }
+
                if (test_bit(FR_URING, &req->flags))
                        removed = fuse_uring_remove_pending_req(req);
                else
@@ -676,7 +681,8 @@ ssize_t __fuse_simple_request(struct mnt_idmap *idmap,
                        fuse_force_creds(req);
 
                __set_bit(FR_WAITING, &req->flags);
-               __set_bit(FR_FORCE, &req->flags);
+               if (!args->abort_on_kill)
+                       __set_bit(FR_FORCE, &req->flags);
        } else {
                WARN_ON(args->nocreds);
                req = fuse_get_req(idmap, fm, false);
index 7f16049387d15e869db4be23a93605098588eda9..23a241f18623a4e256ffb9805eaf40044db5bc0f 100644 (file)
@@ -345,6 +345,7 @@ struct fuse_args {
        bool is_ext:1;
        bool is_pinned:1;
        bool invalidate_vmap:1;
+       bool abort_on_kill:1;
        struct fuse_in_arg in_args[4];
        struct fuse_arg out_args[2];
        void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error);
index e57b8af06be93ecc29c58864a9c9e99c68e3283b..84f78fb89d35386abede7f5b99a10a3ef68c2c3c 100644 (file)
@@ -1551,6 +1551,7 @@ int fuse_send_init(struct fuse_mount *fm)
        int err;
 
        if (fm->fc->sync_init) {
+               ia->args.abort_on_kill = true;
                err = fuse_simple_request(fm, &ia->args);
                /* Ignore size of init reply */
                if (err > 0)