[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <176169814940.1428772.13665592936257476002.stgit@frogsfrogsfrogs>
Date: Tue, 28 Oct 2025 18:08:25 -0700
From: "Darrick J. Wong" <djwong@...nel.org>
To: djwong@...nel.org, bschubert@....com
Cc: linux-ext4@...r.kernel.org, linux-fsdevel@...r.kernel.org,
 bernd@...ernd.com, miklos@...redi.hu, joannelkoong@...il.com, neal@...pa.dev
Subject: [PATCH 5/5] fuservicemount: create loop devices for regular files
From: Darrick J. Wong <djwong@...nel.org>
If a fuse server asks fuservicemount to open a regular file, try to
create an auto-clear loop device so that the fuse server can use iomap.
Signed-off-by: "Darrick J. Wong" <djwong@...nel.org>
---
 include/fuse_service.h      |    6 ++++++
 include/fuse_service_priv.h |    3 ++-
 lib/fuse_service.c          |    5 ++++-
 util/mount_service.c        |   34 ++++++++++++++++++++++++++++++++++
 4 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/include/fuse_service.h b/include/fuse_service.h
index 47080a75bc9ab6..906f36434d2243 100644
--- a/include/fuse_service.h
+++ b/include/fuse_service.h
@@ -95,6 +95,12 @@ int fuse_service_take_fusedev(struct fuse_service *sfp);
 int fuse_service_parse_cmdline_opts(struct fuse_args *args,
 				    struct fuse_cmdline_opts *opts);
 
+/**
+ * If the file opened is a regular file, try to create a loop device for it.
+ * If successful, the loop device is returned; if not, the regular file is.
+ */
+#define FUSE_SERVICE_REQUEST_FILE_TRYLOOP	(1U << 0)
+
 /**
  * Ask the mount.service helper to open a file on behalf of the fuse server.
  *
diff --git a/include/fuse_service_priv.h b/include/fuse_service_priv.h
index ce2e194ccf0be6..6fc7d59c363ea8 100644
--- a/include/fuse_service_priv.h
+++ b/include/fuse_service_priv.h
@@ -58,7 +58,8 @@ static inline size_t sizeof_fuse_service_requested_file(size_t pathlen)
 	return sizeof(struct fuse_service_requested_file) + pathlen + 1;
 }
 
-#define FUSE_SERVICE_OPEN_FLAGS		(0)
+#define FUSE_SERVICE_OPEN_TRYLOOP	(1U << 0)
+#define FUSE_SERVICE_OPEN_FLAGS		(FUSE_SERVICE_OPEN_TRYLOOP)
 
 struct fuse_service_open_command {
 	struct fuse_service_packet p;
diff --git a/lib/fuse_service.c b/lib/fuse_service.c
index 48633640c1c41b..af23ec06ac60a1 100644
--- a/lib/fuse_service.c
+++ b/lib/fuse_service.c
@@ -152,7 +152,7 @@ int fuse_service_receive_file(struct fuse_service *sf, const char *path,
 	return recv_requested_file(sf->sockfd, path, fdp);
 }
 
-#define FUSE_SERVICE_REQUEST_FILE_FLAGS	(0)
+#define FUSE_SERVICE_REQUEST_FILE_FLAGS	(FUSE_SERVICE_REQUEST_FILE_TRYLOOP)
 
 int fuse_service_request_file(struct fuse_service *sf, const char *path,
 			      int open_flags, mode_t create_mode,
@@ -177,6 +177,9 @@ int fuse_service_request_file(struct fuse_service *sf, const char *path,
 		return -1;
 	}
 
+	if (request_flags & FUSE_SERVICE_REQUEST_FILE_TRYLOOP)
+		rqflags |= FUSE_SERVICE_OPEN_TRYLOOP;
+
 	cmd = calloc(1, iov.iov_len);
 	if (!cmd) {
 		perror("fuse: alloc service file request");
diff --git a/util/mount_service.c b/util/mount_service.c
index e3410d524167a4..e62183800043e8 100644
--- a/util/mount_service.c
+++ b/util/mount_service.c
@@ -25,15 +25,20 @@
 #include <limits.h>
 #include <sys/stat.h>
 #include <arpa/inet.h>
+#ifdef HAVE_STRUCT_LOOP_CONFIG_INFO
+# include <linux/loop.h>
+#endif
 
 #include "mount_util.h"
 #include "util.h"
 #include "fuse_i.h"
 #include "fuse_service_priv.h"
+#include "fuse_loopdev.h"
 #include "mount_service.h"
 
 #define FUSE_KERN_DEVICE_ENV	"FUSE_KERN_DEVICE"
 #define FUSE_DEV		"/dev/fuse"
+#define LOOPCTL			"/dev/loop-control"
 
 struct mount_service {
 	/* alleged fuse subtype based on -t cli argument */
@@ -542,6 +547,35 @@ static int mount_service_handle_open_cmd(struct mount_service *mo,
 		return mount_service_send_file_error(mo, error, oc->path);
 	}
 
+	if (request_flags & FUSE_SERVICE_OPEN_TRYLOOP) {
+		int loop_fd = -1;
+
+		ret = fuse_loopdev_setup(fd, ntohl(oc->open_flags), oc->path,
+					 5, &loop_fd, NULL);
+		if (ret) {
+			/*
+			 * If the setup function returned EBUSY, there is
+			 * already a loop device backed by this file, so we
+			 * must return an error.  For any other type of error
+			 * we'll send back the first file we opened.
+			 */
+			if (errno == EBUSY) {
+				ret = mount_service_send_file_error(mo, errno,
+						oc->path);
+				close(fd);
+				return ret;
+			}
+		} else if (loop_fd >= 0) {
+			/*
+			 * Send back the loop device instead of the file.
+			 */
+			ret = mount_service_send_file(mo, oc->path, loop_fd);
+			close(loop_fd);
+			close(fd);
+			return ret;
+		}
+	}
+
 	ret = mount_service_send_file(mo, oc->path, fd);
 	close(fd);
 	return ret;
Powered by blists - more mailing lists
 
