linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Amir Goldstein <amir73il@gmail.com>
To: Miklos Szeredi <miklos@szeredi.hu>
Cc: Daniel Rosenberg <drosen@google.com>,
	Paul Lawrence <paullawrence@google.com>,
	Alessio Balsini <balsini@android.com>,
	fuse-devel@lists.sourceforge.net, linux-fsdevel@vger.kernel.org
Subject: [PATCH v13 10/10] fuse: setup a passthrough fd without a permanent backing id
Date: Fri, 19 May 2023 15:57:05 +0300	[thread overview]
Message-ID: <20230519125705.598234-11-amir73il@gmail.com> (raw)
In-Reply-To: <20230519125705.598234-1-amir73il@gmail.com>

WIP

Add an ioctl to associate a FUSE server open fd with a request.
A later response to this request get use the FOPEN_PASSTHROUGH flag
to request passthrough to the associated backing file.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---

Miklos,

After implementing refcounted backing files, I started to think how
to limit the server from mapping too many files.

I wanted to limit the backing files mappings to the number of open fuse
files to simplify backing files accounting (i.e. open files are
effectively accounted to clients).

It occured to me that creatig a 1-to-1 mapping between fuse files and
backing file ids is quite futile if there is no need to manage 1-to-many
backing file mappings.

If only 1-to-1 mapping is desired, the proposed ioctl associates a
backing file with a pending request.  The backing file will be kept
open for as long the request lives, or until its refcount is handed
over to the client, which can then use it to setup passthough to the
backing file without the intermediate idr array.

I have not implemented the full hand over yet, because I wanted to
hear your feedback first.

Thanks,
Amir.


 fs/fuse/dev.c             | 45 ++++++++++++++++++++++++++++++++++++++-
 fs/fuse/fuse_i.h          | 16 +++++++++-----
 fs/fuse/passthrough.c     | 12 ++++++++++-
 include/uapi/linux/fuse.h |  8 +++++++
 4 files changed, 74 insertions(+), 7 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index cb00234e7843..01fb9c5411d2 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -61,6 +61,8 @@ static struct fuse_req *fuse_request_alloc(struct fuse_mount *fm, gfp_t flags)
 
 static void fuse_request_free(struct fuse_req *req)
 {
+	if (test_bit(FR_PASSTHROUGH, &req->flags))
+		fuse_passthrough_put(req->fpt);
 	kmem_cache_free(fuse_req_cachep, req);
 }
 
@@ -2251,6 +2253,43 @@ static int fuse_device_clone(struct fuse_conn *fc, struct file *new)
 	return 0;
 }
 
+// Associate an passthrough fd to a fuse request
+static int fuse_handle_ioc_passthrough_setup(struct fuse_dev *fud,
+				struct fuse_passthrough_setup_in __user *arg)
+{
+	struct fuse_pqueue *fpq = &fud->pq;
+	struct fuse_req *req;
+	struct fuse_passthrough_setup_in fpts;
+	struct fuse_passthrough *fpt;
+	int err;
+
+	if (copy_from_user(&fpts, arg, sizeof(fpts)))
+		return -EFAULT;
+
+	if (fpts.padding)
+		return -EINVAL;
+
+	err = fuse_passthrough_open(fud->fc, fpts.fd, &fpt);
+	if (err)
+		return err;
+
+	spin_lock(&fpq->lock);
+	req = NULL;
+	if (fpq->connected)
+		req = request_find(fpq, fpts.unique);
+	if (req) {
+		__set_bit(FR_PASSTHROUGH, &req->flags);
+		req->fpt = fpt;
+	}
+	spin_unlock(&fpq->lock);
+	if (!req) {
+		fuse_passthrough_put(fpt);
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
 static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
 			   unsigned long arg)
 {
@@ -2291,7 +2330,7 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
 		if (!f.file)
 			return -EINVAL;
 
-		res = fuse_passthrough_open(fud->fc, fd);
+		res = fuse_passthrough_open(fud->fc, fd, NULL);
 		fdput(f);
 		break;
 	case FUSE_DEV_IOC_PASSTHROUGH_CLOSE:
@@ -2300,6 +2339,10 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
 
 		res = fuse_passthrough_close(fud->fc, id);
 		break;
+	case FUSE_DEV_IOC_PASSTHROUGH_SETUP:
+		res = fuse_handle_ioc_passthrough_setup(fud,
+			   (struct fuse_passthrough_setup_in __user *)arg);
+		break;
 	default:
 		res = -ENOTTY;
 		break;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 238a43349298..085d7607ba6e 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -332,6 +332,7 @@ struct fuse_io_priv {
  * FR_FINISHED:		request is finished
  * FR_PRIVATE:		request is on private list
  * FR_ASYNC:		request is asynchronous
+ * FR_PASSTHROUGH:	request is associated with passthrough file
  */
 enum fuse_req_flag {
 	FR_ISREPLY,
@@ -346,6 +347,7 @@ enum fuse_req_flag {
 	FR_FINISHED,
 	FR_PRIVATE,
 	FR_ASYNC,
+	FR_PASSTHROUGH,
 };
 
 /**
@@ -385,10 +387,13 @@ struct fuse_req {
 	/** Used to wake up the task waiting for completion of request*/
 	wait_queue_head_t waitq;
 
-#if IS_ENABLED(CONFIG_VIRTIO_FS)
-	/** virtio-fs's physically contiguous buffer for in and out args */
-	void *argbuf;
-#endif
+	union {
+		/** virtio-fs's physically contiguous buffer for in/out args */
+		void *argbuf;
+
+		/** passthrough file associated with request */
+		struct fuse_passthrough *fpt;
+	};
 
 	/** fuse_mount this request belongs to */
 	struct fuse_mount *fm;
@@ -1347,7 +1352,8 @@ void fuse_file_release(struct inode *inode, struct fuse_file *ff,
 		       unsigned int open_flags, fl_owner_t id, bool isdir);
 
 /* passthrough.c */
-int fuse_passthrough_open(struct fuse_conn *fc, int backing_fd);
+int fuse_passthrough_open(struct fuse_conn *fc, int backing_fd,
+			  struct fuse_passthrough **pfpt);
 int fuse_passthrough_close(struct fuse_conn *fc, int passthrough_fh);
 int fuse_passthrough_setup(struct fuse_conn *fc, struct fuse_file *ff,
 			   struct fuse_open_out *openarg);
diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
index 2b745b6b2364..85a1d72b1666 100644
--- a/fs/fuse/passthrough.c
+++ b/fs/fuse/passthrough.c
@@ -216,8 +216,12 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
 /*
  * Returns passthrough_fh id that can be passed with FOPEN_PASSTHROUGH
  * open response and needs to be released with fuse_passthrough_close().
+ *
+ * When @pfpt is non-NULL, an anonynous passthrough handle is returned
+ * via *pfpt on success and the return value is 0.
  */
-int fuse_passthrough_open(struct fuse_conn *fc, int backing_fd)
+int fuse_passthrough_open(struct fuse_conn *fc, int backing_fd,
+			  struct fuse_passthrough **pfpt)
 {
 	struct file *passthrough_filp;
 	struct inode *passthrough_inode;
@@ -252,6 +256,12 @@ int fuse_passthrough_open(struct fuse_conn *fc, int backing_fd)
 	passthrough->cred = prepare_creds();
 	refcount_set(&passthrough->count, 1);
 
+	if (pfpt) {
+		/* Return an anonynous passthrough handle */
+		*pfpt = passthrough;
+		return 0;
+	}
+
 	idr_preload(GFP_KERNEL);
 	spin_lock(&fc->lock);
 	res = idr_alloc_cyclic(&fc->passthrough_files_map, passthrough, 1, 0,
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index 3da1f59007cf..028a65fe3fa2 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -993,11 +993,19 @@ struct fuse_notify_retrieve_in {
 	uint64_t	dummy4;
 };
 
+struct fuse_passthrough_setup_in {
+	uint64_t	unique;
+	uint32_t        fd;
+	uint32_t        padding;
+};
+
 /* Device ioctls: */
 #define FUSE_DEV_IOC_MAGIC		229
 #define FUSE_DEV_IOC_CLONE		_IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t)
 #define FUSE_DEV_IOC_PASSTHROUGH_OPEN	_IOW(FUSE_DEV_IOC_MAGIC, 1, uint32_t)
 #define FUSE_DEV_IOC_PASSTHROUGH_CLOSE	_IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t)
+#define FUSE_DEV_IOC_PASSTHROUGH_SETUP	_IOW(FUSE_DEV_IOC_MAGIC, 3, \
+					     struct fuse_passthrough_setup_in)
 
 struct fuse_lseek_in {
 	uint64_t	fh;
-- 
2.34.1


  parent reply	other threads:[~2023-05-19 12:58 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-19 12:56 [PATCH v13 00/10] fuse: Add support for passthrough read/write Amir Goldstein
2023-05-19 12:56 ` [PATCH v13 01/10] fs: Generic function to convert iocb to rw flags Amir Goldstein
2023-05-19 12:56 ` [PATCH v13 02/10] fuse: Definitions and ioctl for passthrough Amir Goldstein
2023-05-19 15:12   ` Miklos Szeredi
2023-05-20 10:20     ` Amir Goldstein
2023-05-22 14:50       ` Miklos Szeredi
2023-05-24 10:00         ` Amir Goldstein
2023-05-19 12:56 ` [PATCH v13 03/10] fuse: Passthrough initialization and release Amir Goldstein
2023-05-19 12:56 ` [PATCH v13 04/10] fuse: Introduce synchronous read and write for passthrough Amir Goldstein
2023-05-19 12:57 ` [PATCH v13 05/10] fuse: Handle asynchronous read and write in passthrough Amir Goldstein
2023-05-22 15:20   ` Miklos Szeredi
2023-05-24 10:03     ` Amir Goldstein
2023-08-21 15:27       ` Amir Goldstein
2023-08-22 10:18         ` Amir Goldstein
2023-08-22 11:03           ` Miklos Szeredi
2023-08-22 13:22             ` Amir Goldstein
2023-08-22 14:06               ` Miklos Szeredi
2023-08-24 12:11             ` Amir Goldstein
2023-08-29 12:42               ` Miklos Szeredi
2023-05-19 12:57 ` [PATCH v13 06/10] fuse: Use daemon creds in passthrough mode Amir Goldstein
2023-05-19 12:57 ` [PATCH v13 07/10] fuse: Introduce passthrough for mmap Amir Goldstein
2023-05-19 12:57 ` [PATCH v13 08/10] fuse: update inode size/mtime after passthrough write Amir Goldstein
2023-09-25  6:41   ` [External] " Zhang Tianci
2023-09-25 10:43     ` Amir Goldstein
2023-09-26 15:31       ` Jens Axboe
2023-09-26 15:48         ` Amir Goldstein
2023-09-26 16:19           ` Jens Axboe
2023-09-26 16:56             ` Amir Goldstein
2023-05-19 12:57 ` [PATCH v13 09/10] fuse: invalidate atime after passthrough read/mmap Amir Goldstein
2023-05-19 12:57 ` Amir Goldstein [this message]
2023-06-06 10:22   ` Fwd: [PATCH v13 10/10] fuse: setup a passthrough fd without a permanent backing id Miklos Szeredi
2023-06-06 11:00     ` [fuse-devel] " Amir Goldstein
2023-06-06 12:46       ` Miklos Szeredi
2023-05-20 10:28 ` [PATCH v13 00/10] fuse: Add support for passthrough read/write Amir Goldstein
2023-06-06  9:13 ` Amir Goldstein
2023-06-06  9:49   ` Miklos Szeredi
2023-06-06 11:19     ` Amir Goldstein
2023-06-06 13:06       ` Miklos Szeredi
2023-08-29 18:14         ` Amir Goldstein
2023-09-20 13:56           ` Amir Goldstein
2023-09-20 18:15             ` Miklos Szeredi
2023-09-21  7:33               ` Amir Goldstein
2023-09-21  8:21                 ` Miklos Szeredi
2023-09-21  9:17                   ` Amir Goldstein
2023-09-21  9:30                     ` Miklos Szeredi
2023-09-21 10:31                       ` Amir Goldstein
2023-09-21 11:50                         ` Miklos Szeredi
2023-09-22 12:45                           ` Amir Goldstein
2023-10-08 17:53                             ` Amir Goldstein
2023-10-10 14:31                               ` Miklos Szeredi
2023-10-10 15:14                                 ` Amir Goldstein
2023-10-14 16:01                                   ` Amir Goldstein
2023-10-16 10:30                                 ` Amir Goldstein
2023-10-16 13:21                                   ` Miklos Szeredi
2023-10-16 19:16                                   ` Bernd Schubert

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=20230519125705.598234-11-amir73il@gmail.com \
    --to=amir73il@gmail.com \
    --cc=balsini@android.com \
    --cc=drosen@google.com \
    --cc=fuse-devel@lists.sourceforge.net \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    --cc=paullawrence@google.com \
    /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;
as well as URLs for NNTP newsgroup(s).