Skip to content
This repository was archived by the owner on Dec 25, 2023. It is now read-only.

Commit 8e51964

Browse files
balsiniKujouYuko
authored andcommittedNov 29, 2021
FROMLIST: fuse: Definitions and ioctl for passthrough
Expose the FUSE_PASSTHROUGH interface to user space and declare all the basic data structures and functions as the skeleton on top of which the FUSE passthrough functionality will be built. As part of this, introduce the new FUSE passthrough ioctl, which allows the FUSE daemon to specify a direct connection between a FUSE file and a lower file system file. Such ioctl requires user space to pass the file descriptor of one of its opened files through the fuse_passthrough_out data structure introduced in this patch. This structure includes extra fields for possible future extensions. Also, add the passthrough functions for the set-up and tear-down of the data structures and locks that will be used both when fuse_conns and fuse_files are created/deleted. Bug: 179164095 Link: https://lore.kernel.org/lkml/[email protected]/ Signed-off-by: Alessio Balsini <[email protected]> Change-Id: I732532581348adadda5b5048a9346c2b0868d539 Signed-off-by: Alessio Balsini <[email protected]> (cherry picked from commit d02368d67989781a3484cd8dd71e0079d0d1bda2) Signed-off-by: alk3pInjection <[email protected]>
1 parent a45be6a commit 8e51964

File tree

8 files changed

+93
-3
lines changed

8 files changed

+93
-3
lines changed
 

‎fs/fuse/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ obj-$(CONFIG_FUSE_FS) += fuse.o
66
obj-$(CONFIG_CUSE) += cuse.o
77

88
fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o acl.o
9+
fuse-objs += passthrough.o

‎fs/fuse/dev.c

+12
Original file line numberDiff line numberDiff line change
@@ -2251,6 +2251,7 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
22512251
int res;
22522252
int oldfd;
22532253
struct fuse_dev *fud = NULL;
2254+
struct fuse_passthrough_out pto;
22542255

22552256
if (_IOC_TYPE(cmd) != FUSE_DEV_IOC_MAGIC)
22562257
return -EINVAL;
@@ -2281,6 +2282,17 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
22812282
}
22822283
}
22832284
break;
2285+
case _IOC_NR(FUSE_DEV_IOC_PASSTHROUGH_OPEN):
2286+
res = -EFAULT;
2287+
if (!copy_from_user(&pto,
2288+
(struct fuse_passthrough_out __user *)arg,
2289+
sizeof(pto))) {
2290+
res = -EINVAL;
2291+
fud = fuse_get_dev(file);
2292+
if (fud)
2293+
res = fuse_passthrough_open(fud, &pto);
2294+
}
2295+
break;
22842296
default:
22852297
res = -ENOTTY;
22862298
break;

‎fs/fuse/dir.c

+1
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
511511
ff->fh = outopen.fh;
512512
ff->nodeid = outentry.nodeid;
513513
ff->open_flags = outopen.open_flags;
514+
fuse_passthrough_setup(fc, ff, &outopen);
514515
inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
515516
&outentry.attr, entry_attr_timeout(&outentry), 0);
516517
if (!inode) {

‎fs/fuse/file.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
135135
if (!err) {
136136
ff->fh = outarg.fh;
137137
ff->open_flags = outarg.open_flags;
138-
138+
fuse_passthrough_setup(fc, ff, &outarg);
139139
} else if (err != -ENOSYS || isdir) {
140140
fuse_file_free(ff);
141141
return err;
@@ -257,6 +257,8 @@ void fuse_release_common(struct file *file, bool isdir)
257257
struct fuse_req *req = ff->reserved_req;
258258
int opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE;
259259

260+
fuse_passthrough_release(&ff->passthrough);
261+
260262
fuse_prepare_release(ff, file->f_flags, opcode);
261263

262264
if (ff->flock) {

‎fs/fuse/fuse_i.h

+27
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,14 @@ enum {
122122

123123
struct fuse_conn;
124124

125+
/**
126+
* Reference to lower filesystem file for read/write operations handled in
127+
* passthrough mode
128+
*/
129+
struct fuse_passthrough {
130+
struct file *filp;
131+
};
132+
125133
/** FUSE specific file data */
126134
struct fuse_file {
127135
/** Fuse connection for this file */
@@ -148,6 +156,9 @@ struct fuse_file {
148156
/** Entry on inode's write_files list */
149157
struct list_head write_entry;
150158

159+
/** Container for data related to the passthrough functionality */
160+
struct fuse_passthrough passthrough;
161+
151162
/** RB node to be linked on fuse_conn->polled_files */
152163
struct rb_node polled_node;
153164

@@ -640,6 +651,9 @@ struct fuse_conn {
640651
/** Allow other than the mounter user to access the filesystem ? */
641652
unsigned allow_other:1;
642653

654+
/** Passthrough mode for read/write IO */
655+
unsigned int passthrough:1;
656+
643657
/** The number of requests waiting for completion */
644658
atomic_t num_waiting;
645659

@@ -678,6 +692,12 @@ struct fuse_conn {
678692

679693
/** List of device instances belonging to this connection */
680694
struct list_head devices;
695+
696+
/** IDR for passthrough requests */
697+
struct idr passthrough_req;
698+
699+
/** Protects passthrough_req */
700+
spinlock_t passthrough_req_lock;
681701
};
682702

683703
static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
@@ -996,4 +1016,11 @@ struct posix_acl;
9961016
struct posix_acl *fuse_get_acl(struct inode *inode, int type);
9971017
int fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type);
9981018

1019+
/* passthrough.c */
1020+
int fuse_passthrough_open(struct fuse_dev *fud,
1021+
struct fuse_passthrough_out *pto);
1022+
int fuse_passthrough_setup(struct fuse_conn *fc, struct fuse_file *ff,
1023+
struct fuse_open_out *openarg);
1024+
void fuse_passthrough_release(struct fuse_passthrough *passthrough);
1025+
9991026
#endif /* _FS_FUSE_I_H */

‎fs/fuse/inode.c

+16-1
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns)
605605
{
606606
memset(fc, 0, sizeof(*fc));
607607
spin_lock_init(&fc->lock);
608+
spin_lock_init(&fc->passthrough_req_lock);
608609
init_rwsem(&fc->killsb);
609610
refcount_set(&fc->count, 1);
610611
atomic_set(&fc->dev_count, 1);
@@ -614,6 +615,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns)
614615
INIT_LIST_HEAD(&fc->bg_queue);
615616
INIT_LIST_HEAD(&fc->entry);
616617
INIT_LIST_HEAD(&fc->devices);
618+
idr_init(&fc->passthrough_req);
617619
atomic_set(&fc->num_waiting, 0);
618620
fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND;
619621
fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD;
@@ -926,6 +928,12 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
926928
}
927929
if (arg->flags & FUSE_ABORT_ERROR)
928930
fc->abort_err = 1;
931+
if (arg->flags & FUSE_PASSTHROUGH) {
932+
fc->passthrough = 1;
933+
/* Prevent further stacking */
934+
fc->sb->s_stack_depth =
935+
FILESYSTEM_MAX_STACK_DEPTH;
936+
}
929937
} else {
930938
ra_pages = fc->max_read / PAGE_SIZE;
931939
fc->no_lock = 1;
@@ -957,7 +965,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
957965
FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO |
958966
FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT |
959967
FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL |
960-
FUSE_ABORT_ERROR;
968+
FUSE_ABORT_ERROR | FUSE_PASSTHROUGH;
961969
req->in.h.opcode = FUSE_INIT;
962970
req->in.numargs = 1;
963971
req->in.args[0].size = sizeof(*arg);
@@ -973,9 +981,16 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
973981
fuse_request_send_background(fc, req);
974982
}
975983

984+
static int free_fuse_passthrough(int id, void *p, void *data)
985+
{
986+
return 0;
987+
}
988+
976989
static void fuse_free_conn(struct fuse_conn *fc)
977990
{
978991
WARN_ON(!list_empty(&fc->devices));
992+
idr_for_each(&fc->passthrough_req, free_fuse_passthrough, NULL);
993+
idr_destroy(&fc->passthrough_req);
979994
kfree_rcu(fc, rcu);
980995
}
981996

‎fs/fuse/passthrough.c

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include "fuse_i.h"
4+
5+
#include <linux/fuse.h>
6+
7+
int fuse_passthrough_open(struct fuse_dev *fud,
8+
struct fuse_passthrough_out *pto)
9+
{
10+
return -EINVAL;
11+
}
12+
13+
int fuse_passthrough_setup(struct fuse_conn *fc, struct fuse_file *ff,
14+
struct fuse_open_out *openarg)
15+
{
16+
return -EINVAL;
17+
}
18+
19+
void fuse_passthrough_release(struct fuse_passthrough *passthrough)
20+
{
21+
}

‎include/uapi/linux/fuse.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ struct fuse_file_lock {
274274
#define FUSE_HANDLE_KILLPRIV (1 << 19)
275275
#define FUSE_POSIX_ACL (1 << 20)
276276
#define FUSE_ABORT_ERROR (1 << 21)
277+
#define FUSE_PASSTHROUGH (1 << 31)
277278

278279
/**
279280
* CUSE INIT request/reply flags
@@ -506,7 +507,7 @@ struct fuse_create_in {
506507
struct fuse_open_out {
507508
uint64_t fh;
508509
uint32_t open_flags;
509-
uint32_t padding;
510+
uint32_t passthrough_fh;
510511
};
511512

512513
struct fuse_release_in {
@@ -707,6 +708,14 @@ struct fuse_in_header {
707708
uint32_t padding;
708709
};
709710

711+
/* fuse_passthrough_out for passthrough V1 */
712+
struct fuse_passthrough_out {
713+
uint32_t fd;
714+
/* For future implementation */
715+
uint32_t len;
716+
void *vec;
717+
};
718+
710719
struct fuse_out_header {
711720
uint32_t len;
712721
int32_t error;
@@ -784,6 +793,8 @@ struct fuse_notify_retrieve_in {
784793
/* Device ioctls: */
785794
#define FUSE_DEV_IOC_MAGIC 229
786795
#define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t)
796+
/* 127 is reserved for the V1 interface implementation in Android */
797+
#define FUSE_DEV_IOC_PASSTHROUGH_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 127, struct fuse_passthrough_out)
787798

788799
struct fuse_lseek_in {
789800
uint64_t fh;

0 commit comments

Comments
 (0)
This repository has been archived.