Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2227005/?format=api
{ "id": 2227005, "url": "http://patchwork.ozlabs.org/api/patches/2227005/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-ext4/patch/20260422233045.GH7739@frogsfrogsfrogs/", "project": { "id": 8, "url": "http://patchwork.ozlabs.org/api/projects/8/?format=api", "name": "Linux ext4 filesystem development", "link_name": "linux-ext4", "list_id": "linux-ext4.vger.kernel.org", "list_email": "linux-ext4@vger.kernel.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260422233045.GH7739@frogsfrogsfrogs>", "list_archive_url": null, "date": "2026-04-22T23:30:45", "name": "[RFC,2/4] exfat: enable fuse systemd service mode", "commit_ref": null, "pull_url": null, "state": "not-applicable", "archived": false, "hash": "f4cae9988af06c972b9acbaa7b7f4cbc8c4bc258", "submitter": { "id": 77032, "url": "http://patchwork.ozlabs.org/api/people/77032/?format=api", "name": "Darrick J. Wong", "email": "djwong@kernel.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-ext4/patch/20260422233045.GH7739@frogsfrogsfrogs/mbox/", "series": [ { "id": 501128, "url": "http://patchwork.ozlabs.org/api/series/501128/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-ext4/list/?series=501128", "date": "2026-04-22T23:29:50", "name": "[RFC,1/4] fusefatfs: enable fuse systemd service mode", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/501128/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2227005/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2227005/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "\n <SRS0=X71Y=CV=vger.kernel.org=linux-ext4+bounces-16029-patchwork-incoming=ozlabs.org@ozlabs.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "linux-ext4@vger.kernel.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "patchwork-incoming@ozlabs.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=TWMx9UDI;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=ozlabs.org\n (client-ip=150.107.74.76; helo=mail.ozlabs.org;\n envelope-from=srs0=x71y=cv=vger.kernel.org=linux-ext4+bounces-16029-patchwork-incoming=ozlabs.org@ozlabs.org;\n receiver=patchwork.ozlabs.org)", "gandalf.ozlabs.org;\n arc=pass smtp.remote-ip=\"2600:3c0a:e001:db::12fc:5321\"\n arc.chain=subspace.kernel.org", "gandalf.ozlabs.org;\n dmarc=pass (p=quarantine dis=none) header.from=kernel.org", "gandalf.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=TWMx9UDI;\n\tdkim-atps=neutral", "gandalf.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c0a:e001:db::12fc:5321; helo=sea.lore.kernel.org;\n envelope-from=linux-ext4+bounces-16029-patchwork-incoming=ozlabs.org@vger.kernel.org;\n receiver=ozlabs.org)", "smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=\"TWMx9UDI\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=10.30.226.201" ], "Received": [ "from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g1Fvf2zV6z1y2d\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 23 Apr 2026 09:35:26 +1000 (AEST)", "from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3])\n\tby gandalf.ozlabs.org (Postfix) with ESMTP id 4g1Fvf2WQWz4wKP\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 23 Apr 2026 09:35:26 +1000 (AEST)", "by gandalf.ozlabs.org (Postfix)\n\tid 4g1Fvf2Rbbz4wKB; Thu, 23 Apr 2026 09:35:26 +1000 (AEST)", "from sea.lore.kernel.org (sea.lore.kernel.org\n [IPv6:2600:3c0a:e001:db::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby gandalf.ozlabs.org (Postfix) with ESMTPS id 4g1FvZ1Pvpz4wKP\n\tfor <patchwork-incoming@ozlabs.org>; Thu, 23 Apr 2026 09:35:22 +1000 (AEST)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id 577333137D7D\n\tfor <patchwork-incoming@ozlabs.org>; Wed, 22 Apr 2026 23:30:47 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 745073A451E;\n\tWed, 22 Apr 2026 23:30:46 +0000 (UTC)", "from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org\n [10.30.226.201])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 3249132C924;\n\tWed, 22 Apr 2026 23:30:46 +0000 (UTC)", "by smtp.kernel.org (Postfix) with ESMTPSA id 03476C2BCB6;\n\tWed, 22 Apr 2026 23:30:45 +0000 (UTC)" ], "ARC-Seal": [ "i=2; a=rsa-sha256; d=ozlabs.org; s=201707; t=1776900926; cv=pass;\n\tb=EVTktDawq+yhf6MJ3on/nF52D6GfJAgHA+xwKkWz1ZrdpVjTa3QBvEZQ/LvPAQPDosrSxq8reEH9m0LX7S5/yGWJXRqo/Rqx4SogVDkARI8oygadUAccOpjXObBbNuSRmXNKk7cmH3maq+RbjzMj09Ami4HD9LCcxY9V2Yv9LxsyL+3mQBKoFRIWU38KudxQyp5P/HVgjm+1AEfW+oDDVPYMA40mU4j4MskaO77bu6zlSBIXDnE4Kj+owJ4yaeV7WPZ1R21vjaVmAokVN9hbUfCgsrRBUEiSF2L4jXpROo5jqE3jic0YQCw8PJ61mDno0rjQHivVil/aHL6By8k+3g==", "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1776900646; cv=none;\n b=T8TvcwsWy20Ut3NydeVhADIptPL2CMA2Dch6oP8TglZPbUGv2ufl/E/vOILz5iDhhxKGyukmBCrrfpaTML5tAVilZXymwY9DuNbBbMGF7GqTu/sxywPJgNyUJJvh7eW1tgDxtVKRPfHjgi8wzqVWexzx7pwZPs9asfAaqzB9+a4=" ], "ARC-Message-Signature": [ "i=2; a=rsa-sha256; d=ozlabs.org; s=201707;\n\tt=1776900926; c=relaxed/relaxed;\n\tbh=YFBXwqWgv6Hrf2L4/FvcIkLEpX1OGRJwfvDh0oAOgR8=;\n\th=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version:\n\t Content-Type:Content-Disposition:In-Reply-To;\n b=UieE4g0IU70gtr4rXU9SYg4tSmvwU+4xQWdr1aAXrVRIG4gjO+lJx/qM/Q29bR22WYhEPC1KFo/OsOjV54aHQ7j7KKdmBsV9Vw8puJliVdPz8R9kLt+HCcl3mLybmUunT10VMB9yf3Q1iU/5W8fggHfv7kuXE8VZNNyZmoGBgztXp4ehA+wyC7i/Xh9fKC5BDH90kAMjL4bNB7wmgDrGTta03sod3dDw1qFfJWn2h8BhbNg20evH3hRn7izD/dSwZuHtuofvQIaxOqR9xKvSWFvihYeAnFn4evtTK+mZvdo8r18VgWLuHm1i9qP7IENu2sEcrJ9vz76yFpYwH3QUtg==", "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1776900646; c=relaxed/simple;\n\tbh=9L1HZddCQvHV5SFhUNt3RFhZ1S7dl1qZFSJrU3Edfvg=;\n\th=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version:\n\t Content-Type:Content-Disposition:In-Reply-To;\n b=YXBOumcxJfr8KG1R6ESntX/846VdxvWRwVrelgX6BX1rNi3C5s2KAGM/o3k2/hijYLmDd0rcIKfp0zocgqoRuZgxCWgj7dXh6ObPF12ztmBa4FoCoc2Sxw8FjnSo8MKsXIb8XYxHrWTwgTzzqQH8xOewW4J4jXmkg6uiK1ZMoe8=" ], "ARC-Authentication-Results": [ "i=2; gandalf.ozlabs.org;\n dmarc=pass (p=quarantine dis=none) header.from=kernel.org;\n dkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=TWMx9UDI; dkim-atps=neutral;\n spf=pass (client-ip=2600:3c0a:e001:db::12fc:5321; helo=sea.lore.kernel.org;\n envelope-from=linux-ext4+bounces-16029-patchwork-incoming=ozlabs.org@vger.kernel.org;\n receiver=ozlabs.org) smtp.mailfrom=vger.kernel.org", "i=1; smtp.subspace.kernel.org;\n dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=TWMx9UDI; arc=none smtp.client-ip=10.30.226.201" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1776900646;\n\tbh=9L1HZddCQvHV5SFhUNt3RFhZ1S7dl1qZFSJrU3Edfvg=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=TWMx9UDI//YRmBNyNzbg+CW/rv9jJgSkkrDZIcjoSklP2R/NSyYiJ4800MaPKFPR6\n\t euVQzuPrhNfDaAo279Wfgoq8+X9v+AWmU6aE3dR8ou2j7hu8hAxNa9mj6Sy6oM1fqA\n\t a5L8pw8wExA1me+TTmOaWfuf0N9HgjICir4nScd7NAM28rb4DgTlR2NSoG4OfwGbpy\n\t GPm1BWY1eDgyPvCZCUbjChYLz2cYP7Io3ZxLwQwRF3lOgsn2sbwip3wAqEm8AvrfxX\n\t jmXf/e6xA0+0zA9leA2owpjJePDmwZOzpy8OL4VlwB7dsie4tj3Drk56aDb9tOuJBo\n\t BAIQaYVus5C1g==", "Date": "Wed, 22 Apr 2026 16:30:45 -0700", "From": "\"Darrick J. Wong\" <djwong@kernel.org>", "To": "linux-fsdevel <linux-fsdevel@vger.kernel.org>,\n\tlinux-ext4 <linux-ext4@vger.kernel.org>,\n\tfuse-devel <fuse-devel@lists.linux.dev>", "Cc": "Miklos Szeredi <miklos@szeredi.hu>, Bernd Schubert <bernd@bsbernd.com>,\n\tJoanne Koong <joannelkoong@gmail.com>,\n\tTheodore Ts'o <tytso@mit.edu>, Neal Gompa <neal@gompa.dev>,\n\tAmir Goldstein <amir73il@gmail.com>,\n\tChristian Brauner <brauner@kernel.org>, demiobenour@gmail.com", "Subject": "[RFC PATCH 2/4] exfat: enable fuse systemd service mode", "Message-ID": "<20260422233045.GH7739@frogsfrogsfrogs>", "References": "<20260422231518.GA7717@frogsfrogsfrogs>", "Precedence": "bulk", "X-Mailing-List": "linux-ext4@vger.kernel.org", "List-Id": "<linux-ext4.vger.kernel.org>", "List-Subscribe": "<mailto:linux-ext4+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:linux-ext4+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=us-ascii", "Content-Disposition": "inline", "In-Reply-To": "<20260422231518.GA7717@frogsfrogsfrogs>", "X-Spam-Status": "No, score=-1.2 required=5.0 tests=ARC_SIGNED,ARC_VALID,\n\tDKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DMARC_PASS,\n\tMAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=disabled\n\tversion=4.0.1", "X-Spam-Checker-Version": "SpamAssassin 4.0.1 (2024-03-25) on gandalf.ozlabs.org" }, "content": "From: Darrick J. Wong <djwong@kernel.org>\n\nEnable use of exfat as a contained systemd service.\n\nSigned-off-by: \"Darrick J. Wong\" <djwong@kernel.org>\n---\n libexfat/exfat.h | 3 +\n configure.ac | 150 ++++++++++++++++++++++++++++++++++++++++++++++++\n fuse/Makefile.am | 16 +++++\n fuse/exfat.socket.in | 15 +++++\n fuse/exfat@.service.in | 102 +++++++++++++++++++++++++++++++++\n fuse/main.c | 131 ++++++++++++++++++++++++++++++++++++++++--\n libexfat/io.c | 21 ++++++-\n libexfat/mount.c | 19 +++++-\n 8 files changed, 447 insertions(+), 10 deletions(-)\n create mode 100644 fuse/exfat.socket.in\n create mode 100644 fuse/exfat@.service.in", "diff": "diff --git a/libexfat/exfat.h b/libexfat/exfat.h\nindex 9b9a682844c093..3023ecd53acd5b 100644\n--- a/libexfat/exfat.h\n+++ b/libexfat/exfat.h\n@@ -147,6 +147,7 @@ void exfat_warn(const char* format, ...) PRINTF;\n void exfat_debug(const char* format, ...) PRINTF;\n \n struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode);\n+struct exfat_dev* exfat_fdopen(int fd, const char* spec, enum exfat_mode mode);\n int exfat_close(struct exfat_dev* dev);\n int exfat_fsync(struct exfat_dev* dev);\n enum exfat_mode exfat_get_mode(const struct exfat_dev* dev);\n@@ -225,6 +226,8 @@ int exfat_set_label(struct exfat* ef, const char* label);\n \n int exfat_soil_super_block(const struct exfat* ef);\n int exfat_mount(struct exfat* ef, const char* spec, const char* options);\n+int exfat_mount_from(struct exfat* ef, int fd, const char* spec,\n+\t\t const char* options);\n void exfat_unmount(struct exfat* ef);\n \n time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec,\ndiff --git a/configure.ac b/configure.ac\nindex ee62b88931b738..63e7327f7ee651 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -32,7 +32,7 @@ AM_PROG_AR\n AC_SYS_LARGEFILE\n AC_CANONICAL_HOST\n PKG_CHECK_MODULES([FUSE3], [fuse3],\n- [AC_DEFINE([FUSE_USE_VERSION], [30], [Required FUSE API version.])],\n+ [have_fuse3_pkg=yes ; AC_DEFINE([FUSE_USE_VERSION], [319], [Required FUSE API version.])],\n [PKG_CHECK_MODULES([FUSE2], [fuse >= 2.6],\n [AC_DEFINE([FUSE_USE_VERSION], [26], [Required FUSE API version.])])])\n AC_MSG_CHECKING([whether host-specific configuration is needed for $host_os])\n@@ -55,6 +55,154 @@ case \"$host_os\" in\n AC_MSG_RESULT([no])\n \t;;\n esac\n+\n+\n+dnl\n+dnl Check if the FUSE library tells us where to put fs service sockets\n+dnl\n+have_fuse_service=\n+fuse_service_socket_dir=\n+if test -n \"$have_fuse3_pkg\"\n+then\n+\tAC_ARG_WITH([fuse_service_socket_dir],\n+\t [AS_HELP_STRING([--with-fuse-service-socket-dir@<:@=DIR@:>@],\n+\t\t [Create fuse3 filesystem service sockets in DIR.])],\n+\t [],\n+\t [with_fuse_service_socket_dir=yes])\n+\tAS_IF([test \"x${with_fuse_service_socket_dir}\" != \"xno\"],\n+\t [\n+\t\tAS_IF([test \"x${with_fuse_service_socket_dir}\" = \"xyes\"],\n+\t\t [\n+\t\t\tAS_IF([test \"x$have_fuse3_pkg\" = \"xyes\" ],\n+\t\t\t [\n+\t\t\t\twith_fuse_service_socket_dir=\"$($PKG_CONFIG --variable=service_socket_dir fuse3)\"\n+\t\t\t ], [\n+\t\t\t\twith_fuse_service_socket_dir=\"\"\n+\t\t\t ])\n+\t\t ])\n+\t\tAC_MSG_CHECKING([for fuse3 service socket dir])\n+\t\tfuse_service_socket_dir=\"${with_fuse_service_socket_dir}\"\n+\t\tAS_IF([test -n \"${fuse_service_socket_dir}\"],\n+\t\t [\n+\t\t\tAC_MSG_RESULT(${fuse_service_socket_dir})\n+\t\t ],\n+\t\t [\n+\t\t\tAC_MSG_RESULT(no)\n+\t\t ])\n+\t ],\n+\t [])\n+\tAC_ARG_WITH([fuse_service_socket_perms],\n+\t [AS_HELP_STRING([--with-fuse-service-socket-perms@<:@=MODE@:>@],\n+\t\t [Create fuse3 filesystem service socket with these permissions.])],\n+\t [],\n+\t [with_fuse_service_socket_perms=yes])\n+\tAS_IF([test \"x${with_fuse_service_socket_perms}\" != \"xno\"],\n+\t [\n+\t\tAS_IF([test \"x${with_fuse_service_socket_perms}\" = \"xyes\"],\n+\t\t [\n+\t\t\tAS_IF([test \"x$have_fuse3_pkg\" = \"xyes\" ],\n+\t\t\t [\n+\t\t\t\twith_fuse_service_socket_perms=\"$($PKG_CONFIG --variable=service_socket_perms fuse3)\"\n+\t\t\t ], [\n+\t\t\t\twith_fuse_service_socket_perms=\"\"\n+\t\t\t ])\n+\t\t ])\n+\t\tfuse_service_socket_perms=\"${with_fuse_service_socket_perms}\"\n+\t ],\n+\t [])\n+\n+\tAC_MSG_CHECKING([for fuse_service_accept in libfuse])\n+\told_cflags=\"$CFLAGS\"\n+\tCFLAGS=\"$CFLAGS $FUSE3_CFLAGS\"\n+\tAC_LINK_IFELSE(\n+\t[\tAC_LANG_PROGRAM([[\n+\t#define _GNU_SOURCE\n+\t#define _FILE_OFFSET_BITS\t64\n+\t#define FUSE_USE_VERSION\t319\n+\t#include <fuse_lowlevel.h>\n+\t#include <fuse_service.h>\n+\t\t]], [[\n+\tstruct fuse_service *moo;\n+\tfuse_service_accepted(moo);\n+\t\t]])\n+\t], have_fuse_service_accept=yes\n+\t AC_MSG_RESULT(yes),\n+\t AC_MSG_RESULT(no))\n+\tCFLAGS=\"$old_cflags\"\n+\n+\tAC_MSG_CHECKING([for fuse3 service support])\n+\tAS_IF([test -n \"${fuse_service_socket_dir}\" && test \"${have_fuse_service_accept}\" = \"yes\"],\n+\t [\n+\t\tAC_MSG_RESULT(yes)\n+\t\thave_fuse_service=\"yes\"\n+\t ],\n+\t [\n+\t\tAC_MSG_RESULT(no)\n+\t ])\n+fi\n+AC_SUBST(have_fuse_service)\n+AC_SUBST(fuse_service_socket_dir)\n+AC_SUBST(fuse_service_socket_perms)\n+if test \"$have_fuse_service\" = yes\n+then\n+\tAC_DEFINE(HAVE_FUSE_SERVICE, 1, [Define to 1 if fuse supports service])\n+fi\n+\n+dnl\n+dnl Where do systemd services go?\n+dnl\n+AC_ARG_WITH([systemd_unit_dir],\n+ [AS_HELP_STRING([--with-systemd-unit-dir@<:@=DIR@:>@],\n+\t[Install systemd system units into DIR.])],\n+ [],\n+ [with_systemd_unit_dir=yes])\n+AS_IF([test \"x${with_systemd_unit_dir}\" != \"xno\"],\n+ [\n+\tAS_IF([test \"x${with_systemd_unit_dir}\" = \"xyes\"],\n+\t [\n+\t\tPKG_CHECK_MODULES([systemd], [systemd],\n+\t\t [\n+\t\t\twith_systemd_unit_dir=\"$($PKG_CONFIG --variable=systemdsystemunitdir systemd)\"\n+\t\t ], [\n+\t\t\twith_systemd_unit_dir=\"\"\n+\t\t ])\n+\t\tm4_pattern_allow([^PKG_(MAJOR|MINOR|BUILD|REVISION)$])\n+\t ])\n+\tAC_MSG_CHECKING([for systemd system unit dir])\n+\tsystemd_system_unit_dir=\"${with_systemd_unit_dir}\"\n+\tAS_IF([test -n \"${systemd_system_unit_dir}\"],\n+\t [\n+\t\tAC_MSG_RESULT(${systemd_system_unit_dir})\n+\t\thave_systemd=\"yes\"\n+\t ],\n+\t [\n+\t\tAC_MSG_RESULT(no)\n+\t\thave_systemd=\"no\"\n+\t ])\n+ ],\n+ [\n+\thave_systemd=\"disabled\"\n+ ])\n+AC_SUBST(have_systemd)\n+AC_SUBST(systemd_system_unit_dir)\n+\n+AC_MSG_CHECKING([for exfat-fuse service support and systemd])\n+AS_IF([test \"${FUSE4FS_CMT}${have_fuse_service}${have_systemd}\" = \"yesyes\"],\n+ [\n+ AC_MSG_RESULT(yes)\n+ AC_DEFINE(HAVE_EXFAT_FUSE_SERVICE, 1,\n+ [Define to 1 if exfat should be built with fuse service support])\n+ have_exfat_service=yes\n+ AM_CONDITIONAL(HAVE_EXFAT_FUSE_SERVICE, [true])\n+ ],\n+ [\n+ AC_MSG_RESULT(no)\n+ AM_CONDITIONAL(HAVE_EXFAT_FUSE_SERVICE, [false])\n+ have_exfat_service=no\n+ ]\n+)\n+AC_SUBST(have_exfat_service)\n+\n AC_CONFIG_HEADERS([libexfat/config.h])\n AC_CONFIG_FILES([\n \tlibexfat/Makefile\ndiff --git a/fuse/Makefile.am b/fuse/Makefile.am\nindex 09c8cac9f5d0ec..660b23ce1965fc 100644\n--- a/fuse/Makefile.am\n+++ b/fuse/Makefile.am\n@@ -27,6 +27,22 @@ mount_exfat_fuse_CPPFLAGS = -imacros $(top_srcdir)/libexfat/config.h\n mount_exfat_fuse_CFLAGS = $(FUSE2_CFLAGS) $(FUSE3_CFLAGS) $(UBLIO_CFLAGS)\n mount_exfat_fuse_LDADD = $(top_srcdir)/libexfat/libexfat.a $(FUSE2_LIBS) $(FUSE3_LIBS) $(UBLIO_LIBS)\n \n+if HAVE_EXFAT_FUSE_SERVICE\n+bin_SCRIPTS = exfat.socket exfat@.service\n+endif\n+\n+exfat.socket: exfat.socket.in\n+\tsed \\\n+\t\t-e \"s|@FUSE3_SERVICE_SOCKET_DIR@|$(fuse_service_socket_dir)|g\" \\\n+\t\t-e \"s|@FUSE3_SERVICE_SOCKET_PERMS@|$(fuse_service_socket_perms)|g\" \\\n+\t\t< $< > $@\n+\n+exfat@.service: exfat@.service.in\n+\tsed -e \"s|@SBINDIR@|$(sbindir)|g\" \\\n+\t\t < $< > $@\n+\n+EXTRA_PROGRAMS=$(SERVICE_FILES)\n+\n install-exec-hook:\n \tln -sf $(sbin_PROGRAMS) $(DESTDIR)$(sbindir)/mount.exfat\n \ndiff --git a/fuse/exfat.socket.in b/fuse/exfat.socket.in\nnew file mode 100644\nindex 00000000000000..8a957ad700fc16\n--- /dev/null\n+++ b/fuse/exfat.socket.in\n@@ -0,0 +1,15 @@\n+# SPDX-License-Identifier: GPL-2.0-or-later\n+#\n+# Copyright (C) 2026 Oracle. All Rights Reserved.\n+# Author: Darrick J. Wong <djwong@kernel.org>\n+[Unit]\n+Description=Socket for exfat Service\n+\n+[Socket]\n+ListenSequentialPacket=@FUSE3_SERVICE_SOCKET_DIR@/exfat\n+Accept=yes\n+SocketMode=@FUSE3_SERVICE_SOCKET_PERMS@\n+RemoveOnStop=yes\n+\n+[Install]\n+WantedBy=sockets.target\ndiff --git a/fuse/exfat@.service.in b/fuse/exfat@.service.in\nnew file mode 100644\nindex 00000000000000..9b7855fe524de6\n--- /dev/null\n+++ b/fuse/exfat@.service.in\n@@ -0,0 +1,102 @@\n+# SPDX-License-Identifier: GPL-2.0-or-later\n+#\n+# Copyright (C) 2026 Oracle. All Rights Reserved.\n+# Author: Darrick J. Wong <djwong@kernel.org>\n+[Unit]\n+Description=exfat Service\n+\n+# Don't leave failed units behind, systemd does not clean them up!\n+CollectMode=inactive-or-failed\n+\n+[Service]\n+Type=exec\n+ExecStart=/@SBINDIR@/mount.exfat-fuse\n+\n+# Try to capture core dumps\n+LimitCORE=infinity\n+\n+SyslogIdentifier=%N\n+\n+# No realtime CPU scheduling\n+RestrictRealtime=true\n+\n+# Don't let us see anything in the regular system, and don't run as root\n+DynamicUser=true\n+ProtectSystem=strict\n+ProtectHome=true\n+PrivateTmp=true\n+PrivateDevices=true\n+PrivateUsers=true\n+\n+# No network access\n+PrivateNetwork=true\n+ProtectHostname=true\n+RestrictAddressFamilies=none\n+IPAddressDeny=any\n+\n+# Don't let the program mess with the kernel configuration at all\n+ProtectKernelLogs=true\n+ProtectKernelModules=true\n+ProtectKernelTunables=true\n+ProtectControlGroups=true\n+ProtectProc=invisible\n+RestrictNamespaces=true\n+RestrictFileSystems=\n+\n+# Hide everything in /proc, even /proc/mounts\n+ProcSubset=pid\n+\n+# Only allow the default personality Linux\n+LockPersonality=true\n+\n+# No writable memory pages\n+MemoryDenyWriteExecute=true\n+\n+# Don't let our mounts leak out to the host\n+PrivateMounts=true\n+\n+# Restrict system calls to the native arch and only enough to get things going\n+SystemCallArchitectures=native\n+SystemCallFilter=@system-service\n+SystemCallFilter=~@privileged\n+SystemCallFilter=~@resources\n+\n+SystemCallFilter=~@clock\n+SystemCallFilter=~@cpu-emulation\n+SystemCallFilter=~@debug\n+SystemCallFilter=~@module\n+SystemCallFilter=~@reboot\n+SystemCallFilter=~@swap\n+\n+SystemCallFilter=~@mount\n+\n+# libfuse io_uring wants to pin cores and memory\n+SystemCallFilter=mbind\n+SystemCallFilter=sched_setaffinity\n+\n+# Leave a breadcrumb if we get whacked by the system call filter\n+SystemCallErrorNumber=EL3RST\n+\n+# Log to the kernel dmesg, just like an in-kernel ext4 driver\n+StandardOutput=append:/dev/ttyprintk\n+StandardError=append:/dev/ttyprintk\n+\n+# Run with no capabilities at all\n+CapabilityBoundingSet=\n+AmbientCapabilities=\n+NoNewPrivileges=true\n+\n+# fuse4fs doesn't create files\n+UMask=7777\n+\n+# No access to hardware /dev files at all\n+ProtectClock=true\n+DevicePolicy=closed\n+\n+# Don't mess with set[ug]id anything.\n+RestrictSUIDSGID=true\n+\n+# Don't let OOM kills of processes in this containment group kill the whole\n+# service, because we don't want filesystem drivers to go down.\n+OOMPolicy=continue\n+OOMScoreAdjust=-1000\ndiff --git a/fuse/main.c b/fuse/main.c\nindex cf1033a543f038..d7aa8d21db62e3 100644\n--- a/fuse/main.c\n+++ b/fuse/main.c\n@@ -34,6 +34,10 @@\n #include <sys/types.h>\n #include <pwd.h>\n #include <unistd.h>\n+#ifdef HAVE_EXFAT_FUSE_SERVICE\n+# include <sys/mount.h>\n+# include <fuse_service.h>\n+#endif\n \n #ifndef DEBUG\n \t#define exfat_debug(format, ...) do {} while (0)\n@@ -45,6 +49,102 @@\n \n struct exfat ef;\n \n+#ifdef HAVE_EXFAT_FUSE_SERVICE\n+static struct fuse_service *service;\n+static int bdev_fd = -1;\n+\n+static inline bool fuse_exfat_is_service(void)\n+{\n+\treturn fuse_service_accepted(service);\n+}\n+\n+static int fuse_exfat_service_connect(struct fuse_args *args)\n+{\n+\tint ret;\n+\n+\tret = fuse_service_accept(&service);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (fuse_service_accepted(service))\n+\t\treturn fuse_service_append_args(service, args);\n+\n+\treturn 0;\n+}\n+\n+static int fuse_exfat_service_get_config(const char *device, bool ro)\n+{\n+\tint open_flags = 0; /* fuseblk server means we can't open exclusive */\n+\tint fd;\n+\tint ret;\n+\n+\tif (ro)\n+\t\topen_flags |= O_RDONLY;\n+\telse\n+\t\topen_flags |= O_SYNC | O_RDWR;\n+\n+\tret = fuse_service_request_file(service, device, open_flags, 0, 0);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = fuse_service_receive_file(service, device, &fd);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (fd < 0) {\n+\t\tfprintf(stderr, \"%s opening device: %s.\\n\", device,\n+\t\t\t strerror(-fd));\n+\t\treturn -1;\n+\t}\n+\tbdev_fd = fd;\n+\n+\treturn fuse_service_finish_file_requests(service);\n+}\n+\n+static int fuse_exfat_service_mount(struct exfat *ef, const char *spec,\n+\t\t\t\t const char *exfat_options)\n+{\n+\tconst int is_ro = exfat_match_option(exfat_options, \"ro\");\n+\tint rc;\n+\n+\trc = fuse_exfat_service_get_config(spec, is_ro);\n+\tif (rc)\n+\t\treturn EXIT_FAILURE;\n+\n+\treturn exfat_mount_from(ef, bdev_fd, spec, exfat_options);\n+}\n+\n+static int fuse_exfat_service_main(char **argv,\n+\t\t\t\t const struct fuse_operations *ops)\n+{\n+\tstruct fuse_args args = FUSE_ARGS_INIT(0, argv);\n+\tchar **p = argv;\n+\n+\twhile (*(p++) != NULL)\n+\t\targs.argc++;\n+\n+\tfuse_service_expect_mount_format(service, S_IFDIR);\n+\treturn fuse_service_main(service, &args, ops, NULL);\n+}\n+\n+static int fuse_exfat_service_finish(int exitcode)\n+{\n+\tif (!fuse_exfat_is_service())\n+\t\treturn exitcode;\n+\n+\tfuse_service_send_goodbye(service, exitcode);\n+\tfuse_service_destroy(&service);\n+\n+\treturn fuse_service_exit(exitcode);\n+}\n+#else\n+# define fuse_exfat_is_service(...)\t\t(false)\n+# define fuse_exfat_service_connect(...)\t(0)\n+# define fuse_exfat_service_mount(...)\t\t(1)\n+# define fuse_exfat_service_main(...)\t\t(1)\n+# define fuse_exfat_service_finish(ret)\t\t(ret)\n+#endif /* HAVE_EXFAT_FUSE_SERVICE */\n+\n static struct exfat_node* get_node(const struct fuse_file_info* fi)\n {\n \treturn (struct exfat_node*) (size_t) fi->fh;\n@@ -529,6 +629,12 @@ static char* add_user_option(char* options)\n \n \tif (getuid() == 0)\n \t\treturn options;\n+\tif (fuse_exfat_is_service()) {\n+\t\toptions = add_option(options, \"uid\", \"0\");\n+\t\tif (!options)\n+\t\t\treturn NULL;\n+\t\treturn add_option(options, \"gid\", \"0\");\n+\t}\n \n \tpw = getpwuid(getuid());\n \tif (pw == NULL || pw->pw_name == NULL)\n@@ -601,12 +707,17 @@ static char* add_passthrough_fuse_options(char* fuse_options,\n static int fuse_exfat_main(char* mount_options, char* mount_point)\n {\n \tchar* argv[] = {\"exfat\", \"-s\", \"-o\", mount_options, mount_point, NULL};\n+\n+\tif (fuse_exfat_is_service())\n+\t\treturn fuse_exfat_service_main(argv, &fuse_exfat_ops);\n+\n \treturn fuse_main(sizeof(argv) / sizeof(argv[0]) - 1, argv,\n \t\t\t&fuse_exfat_ops, NULL);\n }\n \n int main(int argc, char* argv[])\n {\n+\tstruct fuse_args args = FUSE_ARGS_INIT(argc, argv);\n \tconst char* spec = NULL;\n \tchar* mount_point = NULL;\n \tchar* fuse_options;\n@@ -633,7 +744,11 @@ int main(int argc, char* argv[])\n \t\treturn 1;\n \t}\n \n-\twhile ((opt = getopt(argc, argv, \"dno:Vv\")) != -1)\n+\trc = fuse_exfat_service_connect(&args);\n+\tif (rc)\n+\t\texit(EXIT_FAILURE);\n+\n+\twhile ((opt = getopt(args.argc, args.argv, \"dno:Vv\")) != -1)\n \t{\n \t\tswitch (opt)\n \t\t{\n@@ -675,16 +790,20 @@ int main(int argc, char* argv[])\n \t\t\tbreak;\n \t\t}\n \t}\n-\tif (argc - optind != 2)\n+\tif (args.argc - optind != 2)\n \t{\n \t\tfree(exfat_options);\n \t\tfree(fuse_options);\n \t\tusage(argv[0]);\n \t}\n-\tspec = argv[optind];\n-\tmount_point = argv[optind + 1];\n+\tspec = args.argv[optind];\n+\tmount_point = args.argv[optind + 1];\n \n-\tif (exfat_mount(&ef, spec, exfat_options) != 0)\n+\tif (fuse_exfat_is_service())\n+\t\trc = fuse_exfat_service_mount(&ef, spec, exfat_options);\n+\telse\n+\t\trc = exfat_mount(&ef, spec, exfat_options);\n+\tif (rc != 0)\n \t{\n \t\tfree(exfat_options);\n \t\tfree(fuse_options);\n@@ -704,5 +823,5 @@ int main(int argc, char* argv[])\n \trc = fuse_exfat_main(fuse_options, mount_point);\n \n \tfree(fuse_options);\n-\treturn rc;\n+\treturn fuse_exfat_service_finish(rc);\n }\ndiff --git a/libexfat/io.c b/libexfat/io.c\nindex 7af5316da70b4b..2a4c823979a9a8 100644\n--- a/libexfat/io.c\n+++ b/libexfat/io.c\n@@ -86,7 +86,8 @@ static int open_rw(const char* spec)\n \treturn fd;\n }\n \n-struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)\n+static struct exfat_dev* __exfat_open(int fd, const char* spec,\n+\t\t\t\t enum exfat_mode mode)\n {\n \tstruct exfat_dev* dev;\n \tstruct stat stbuf;\n@@ -119,6 +120,10 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)\n \t\treturn NULL;\n \t}\n \n+\tdev->fd = fd;\n+\tif (dev->fd >= 0)\n+\t\tgoto opened;\n+\n \tswitch (mode)\n \t{\n \tcase EXFAT_MODE_RO:\n@@ -162,6 +167,7 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)\n \t\treturn NULL;\n \t}\n \n+opened:\n \tif (fstat(dev->fd, &stbuf) != 0)\n \t{\n \t\tclose(dev->fd);\n@@ -284,6 +290,19 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)\n \treturn dev;\n }\n \n+struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)\n+{\n+\treturn __exfat_open(-1, spec, mode);\n+}\n+\n+struct exfat_dev* exfat_fdopen(int fd, const char* spec, enum exfat_mode mode)\n+{\n+\tif (fd < 0)\n+\t\treturn NULL;\n+\n+\treturn __exfat_open(fd, spec, mode);\n+}\n+\n int exfat_close(struct exfat_dev* dev)\n {\n \tint rc = 0;\ndiff --git a/libexfat/mount.c b/libexfat/mount.c\nindex 86fb84db2445f5..dd6cf707d2ebbc 100644\n--- a/libexfat/mount.c\n+++ b/libexfat/mount.c\n@@ -180,7 +180,8 @@ static void exfat_free(struct exfat* ef)\n \tef->sb = NULL;\n }\n \n-int exfat_mount(struct exfat* ef, const char* spec, const char* options)\n+static int __exfat_mount(struct exfat* ef, int fd, const char* spec,\n+\t\t\t const char* options)\n {\n \tint rc;\n \tenum exfat_mode mode;\n@@ -196,7 +197,10 @@ int exfat_mount(struct exfat* ef, const char* spec, const char* options)\n \t\tmode = EXFAT_MODE_ANY;\n \telse\n \t\tmode = EXFAT_MODE_RW;\n-\tef->dev = exfat_open(spec, mode);\n+\tif (fd >= 0)\n+\t\tef->dev = exfat_fdopen(fd, spec, mode);\n+\telse\n+\t\tef->dev = exfat_open(spec, mode);\n \tif (ef->dev == NULL)\n \t\treturn -ENODEV;\n \tif (exfat_get_mode(ef->dev) == EXFAT_MODE_RO)\n@@ -340,6 +344,17 @@ int exfat_mount(struct exfat* ef, const char* spec, const char* options)\n \treturn -EIO;\n }\n \n+int exfat_mount_from(struct exfat* ef, int fd, const char* spec,\n+\t\t const char* options)\n+{\n+\treturn __exfat_mount(ef, fd, spec, options);\n+}\n+\n+int exfat_mount(struct exfat* ef, const char* spec, const char* options)\n+{\n+\treturn __exfat_mount(ef, -1, spec, options);\n+}\n+\n static void finalize_super_block(struct exfat* ef)\n {\n \tif (ef->ro)\n", "prefixes": [ "RFC", "2/4" ] }