Thread (56 messages) 56 messages, 8 authors, 2023-05-15

Re: [PATCH RESEND V12 4/8] fuse: Passthrough initialization and release

From: Amir Goldstein <amir73il@gmail.com>
Date: 2021-05-05 12:21:42
Also in: lkml

On Wed, Feb 17, 2021 at 3:52 PM Miklos Szeredi [off-list ref] wrote:
On Mon, Jan 25, 2021 at 4:31 PM Alessio Balsini [off-list ref] wrote:
quoted
Implement the FUSE passthrough ioctl that associates the lower
(passthrough) file system file with the fuse_file.

The file descriptor passed to the ioctl by the FUSE daemon is used to
access the relative file pointer, that will be copied to the fuse_file
data structure to consolidate the link between the FUSE and lower file
system.

To enable the passthrough mode, user space triggers the
FUSE_DEV_IOC_PASSTHROUGH_OPEN ioctl and, if the call succeeds, receives
back an identifier that will be used at open/create response time in the
fuse_open_out field to associate the FUSE file to the lower file system
file.
The value returned by the ioctl to user space can be:
- > 0: success, the identifier can be used as part of an open/create
reply.
- <= 0: an error occurred.
The value 0 represents an error to preserve backward compatibility: the
fuse_open_out field that is used to pass the passthrough_fh back to the
kernel uses the same bits that were previously as struct padding, and is
commonly zero-initialized (e.g., in the libfuse implementation).
Removing 0 from the correct values fixes the ambiguity between the case
in which 0 corresponds to a real passthrough_fh, a missing
implementation of FUSE passthrough or a request for a normal FUSE file,
simplifying the user space implementation.

For the passthrough mode to be successfully activated, the lower file
system file must implement both read_iter and write_iter file
operations. This extra check avoids special pseudo files to be targeted
for this feature.
Passthrough comes with another limitation: no further file system
stacking is allowed for those FUSE file systems using passthrough.

Signed-off-by: Alessio Balsini <redacted>
---
 fs/fuse/inode.c       |  5 +++
 fs/fuse/passthrough.c | 87 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 90 insertions(+), 2 deletions(-)
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index a1104d5abb70..7ebc398fbacb 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1133,6 +1133,11 @@ EXPORT_SYMBOL_GPL(fuse_send_init);

 static int free_fuse_passthrough(int id, void *p, void *data)
 {
+       struct fuse_passthrough *passthrough = (struct fuse_passthrough *)p;
+
+       fuse_passthrough_release(passthrough);
+       kfree(p);
+
        return 0;
 }
diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
index 594060c654f8..cf993e83803e 100644
--- a/fs/fuse/passthrough.c
+++ b/fs/fuse/passthrough.c
@@ -3,19 +3,102 @@
 #include "fuse_i.h"

 #include <linux/fuse.h>
+#include <linux/idr.h>

 int fuse_passthrough_open(struct fuse_dev *fud,
                          struct fuse_passthrough_out *pto)
 {
-       return -EINVAL;
+       int res;
+       struct file *passthrough_filp;
+       struct fuse_conn *fc = fud->fc;
+       struct inode *passthrough_inode;
+       struct super_block *passthrough_sb;
+       struct fuse_passthrough *passthrough;
+
+       if (!fc->passthrough)
+               return -EPERM;
+
+       /* This field is reserved for future implementation */
+       if (pto->len != 0)
+               return -EINVAL;
+
+       passthrough_filp = fget(pto->fd);
+       if (!passthrough_filp) {
+               pr_err("FUSE: invalid file descriptor for passthrough.\n");
+               return -EBADF;
+       }
+
+       if (!passthrough_filp->f_op->read_iter ||
+           !passthrough_filp->f_op->write_iter) {
+               pr_err("FUSE: passthrough file misses file operations.\n");
+               res = -EBADF;
+               goto err_free_file;
+       }
+
+       passthrough_inode = file_inode(passthrough_filp);
+       passthrough_sb = passthrough_inode->i_sb;
+       if (passthrough_sb->s_stack_depth >= FILESYSTEM_MAX_STACK_DEPTH) {
+               pr_err("FUSE: fs stacking depth exceeded for passthrough\n");
No need to print an error to the logs, this can be a perfectly normal
occurrence.  However I'd try to find a more unique error value than
EINVAL so that the fuse server can interpret this as "not your fault,
but can't support passthrough on this file".  E.g. EOPNOTSUPP.
Sorry for the fashionably late response...
Same comment for !{read,write}_iter case above.
EBAFD is really not appropriate there.
May I suggest ELOOP for s_stack_depth and EOPNOTSUPP
for no rw iter ops.

Are you planning to post another version of the patches soon?

Thanks,
Amir.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help