]>
git.ipfire.org Git - thirdparty/kernel/linux.git/blob - fs/fuse/passthrough.c
1 // SPDX-License-Identifier: GPL-2.0
3 * FUSE passthrough to backing file.
5 * Copyright (c) 2023 CTERA Networks.
10 #include <linux/file.h>
12 struct fuse_backing
*fuse_backing_get(struct fuse_backing
*fb
)
14 if (fb
&& refcount_inc_not_zero(&fb
->count
))
19 static void fuse_backing_free(struct fuse_backing
*fb
)
21 pr_debug("%s: fb=0x%p\n", __func__
, fb
);
29 void fuse_backing_put(struct fuse_backing
*fb
)
31 if (fb
&& refcount_dec_and_test(&fb
->count
))
32 fuse_backing_free(fb
);
35 void fuse_backing_files_init(struct fuse_conn
*fc
)
37 idr_init(&fc
->backing_files_map
);
40 static int fuse_backing_id_alloc(struct fuse_conn
*fc
, struct fuse_backing
*fb
)
44 idr_preload(GFP_KERNEL
);
46 /* FIXME: xarray might be space inefficient */
47 id
= idr_alloc_cyclic(&fc
->backing_files_map
, fb
, 1, 0, GFP_ATOMIC
);
48 spin_unlock(&fc
->lock
);
51 WARN_ON_ONCE(id
== 0);
55 static struct fuse_backing
*fuse_backing_id_remove(struct fuse_conn
*fc
,
58 struct fuse_backing
*fb
;
61 fb
= idr_remove(&fc
->backing_files_map
, id
);
62 spin_unlock(&fc
->lock
);
67 static int fuse_backing_id_free(int id
, void *p
, void *data
)
69 struct fuse_backing
*fb
= p
;
71 WARN_ON_ONCE(refcount_read(&fb
->count
) != 1);
72 fuse_backing_free(fb
);
76 void fuse_backing_files_free(struct fuse_conn
*fc
)
78 idr_for_each(&fc
->backing_files_map
, fuse_backing_id_free
, NULL
);
79 idr_destroy(&fc
->backing_files_map
);
82 int fuse_backing_open(struct fuse_conn
*fc
, struct fuse_backing_map
*map
)
85 struct super_block
*backing_sb
;
86 struct fuse_backing
*fb
= NULL
;
89 pr_debug("%s: fd=%d flags=0x%x\n", __func__
, map
->fd
, map
->flags
);
91 /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
93 if (!fc
->passthrough
|| !capable(CAP_SYS_ADMIN
))
100 file
= fget(map
->fd
);
106 if (!file
->f_op
->read_iter
|| !file
->f_op
->write_iter
)
109 backing_sb
= file_inode(file
)->i_sb
;
111 if (backing_sb
->s_stack_depth
>= fc
->max_stack_depth
)
114 fb
= kmalloc(sizeof(struct fuse_backing
), GFP_KERNEL
);
120 fb
->cred
= prepare_creds();
121 refcount_set(&fb
->count
, 1);
123 res
= fuse_backing_id_alloc(fc
, fb
);
125 fuse_backing_free(fb
);
130 pr_debug("%s: fb=0x%p, ret=%i\n", __func__
, fb
, res
);
139 int fuse_backing_close(struct fuse_conn
*fc
, int backing_id
)
141 struct fuse_backing
*fb
= NULL
;
144 pr_debug("%s: backing_id=%d\n", __func__
, backing_id
);
146 /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
148 if (!fc
->passthrough
|| !capable(CAP_SYS_ADMIN
))
156 fb
= fuse_backing_id_remove(fc
, backing_id
);
160 fuse_backing_put(fb
);
163 pr_debug("%s: fb=0x%p, err=%i\n", __func__
, fb
, err
);