Skip to content

Commit c4331e1

Browse files
Darrick J. WongMiklos Szeredi
authored andcommitted
fuse: move the backing file idr and code into a new source file
iomap support for fuse is also going to want the ability to attach backing files to a fuse filesystem. Move the fuse_backing code into a separate file so that both can use it. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
1 parent d3906d8 commit c4331e1

4 files changed

Lines changed: 208 additions & 183 deletions

File tree

fs/fuse/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ obj-$(CONFIG_VIRTIO_FS) += virtiofs.o
1313
fuse-y := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o ioctl.o
1414
fuse-y += iomode.o
1515
fuse-$(CONFIG_FUSE_DAX) += dax.o
16-
fuse-$(CONFIG_FUSE_PASSTHROUGH) += passthrough.o
16+
fuse-$(CONFIG_FUSE_PASSTHROUGH) += passthrough.o backing.o
1717
fuse-$(CONFIG_SYSCTL) += sysctl.o
1818
fuse-$(CONFIG_FUSE_IO_URING) += dev_uring.o
1919

fs/fuse/backing.c

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* FUSE passthrough to backing file.
4+
*
5+
* Copyright (c) 2023 CTERA Networks.
6+
*/
7+
8+
#include "fuse_i.h"
9+
10+
#include <linux/file.h>
11+
12+
struct fuse_backing *fuse_backing_get(struct fuse_backing *fb)
13+
{
14+
if (fb && refcount_inc_not_zero(&fb->count))
15+
return fb;
16+
return NULL;
17+
}
18+
19+
static void fuse_backing_free(struct fuse_backing *fb)
20+
{
21+
pr_debug("%s: fb=0x%p\n", __func__, fb);
22+
23+
if (fb->file)
24+
fput(fb->file);
25+
put_cred(fb->cred);
26+
kfree_rcu(fb, rcu);
27+
}
28+
29+
void fuse_backing_put(struct fuse_backing *fb)
30+
{
31+
if (fb && refcount_dec_and_test(&fb->count))
32+
fuse_backing_free(fb);
33+
}
34+
35+
void fuse_backing_files_init(struct fuse_conn *fc)
36+
{
37+
idr_init(&fc->backing_files_map);
38+
}
39+
40+
static int fuse_backing_id_alloc(struct fuse_conn *fc, struct fuse_backing *fb)
41+
{
42+
int id;
43+
44+
idr_preload(GFP_KERNEL);
45+
spin_lock(&fc->lock);
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);
49+
idr_preload_end();
50+
51+
WARN_ON_ONCE(id == 0);
52+
return id;
53+
}
54+
55+
static struct fuse_backing *fuse_backing_id_remove(struct fuse_conn *fc,
56+
int id)
57+
{
58+
struct fuse_backing *fb;
59+
60+
spin_lock(&fc->lock);
61+
fb = idr_remove(&fc->backing_files_map, id);
62+
spin_unlock(&fc->lock);
63+
64+
return fb;
65+
}
66+
67+
static int fuse_backing_id_free(int id, void *p, void *data)
68+
{
69+
struct fuse_backing *fb = p;
70+
71+
WARN_ON_ONCE(refcount_read(&fb->count) != 1);
72+
fuse_backing_free(fb);
73+
return 0;
74+
}
75+
76+
void fuse_backing_files_free(struct fuse_conn *fc)
77+
{
78+
idr_for_each(&fc->backing_files_map, fuse_backing_id_free, NULL);
79+
idr_destroy(&fc->backing_files_map);
80+
}
81+
82+
int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map)
83+
{
84+
struct file *file;
85+
struct super_block *backing_sb;
86+
struct fuse_backing *fb = NULL;
87+
int res;
88+
89+
pr_debug("%s: fd=%d flags=0x%x\n", __func__, map->fd, map->flags);
90+
91+
/* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
92+
res = -EPERM;
93+
if (!fc->passthrough || !capable(CAP_SYS_ADMIN))
94+
goto out;
95+
96+
res = -EINVAL;
97+
if (map->flags || map->padding)
98+
goto out;
99+
100+
file = fget_raw(map->fd);
101+
res = -EBADF;
102+
if (!file)
103+
goto out;
104+
105+
/* read/write/splice/mmap passthrough only relevant for regular files */
106+
res = d_is_dir(file->f_path.dentry) ? -EISDIR : -EINVAL;
107+
if (!d_is_reg(file->f_path.dentry))
108+
goto out_fput;
109+
110+
backing_sb = file_inode(file)->i_sb;
111+
res = -ELOOP;
112+
if (backing_sb->s_stack_depth >= fc->max_stack_depth)
113+
goto out_fput;
114+
115+
fb = kmalloc(sizeof(struct fuse_backing), GFP_KERNEL);
116+
res = -ENOMEM;
117+
if (!fb)
118+
goto out_fput;
119+
120+
fb->file = file;
121+
fb->cred = prepare_creds();
122+
refcount_set(&fb->count, 1);
123+
124+
res = fuse_backing_id_alloc(fc, fb);
125+
if (res < 0) {
126+
fuse_backing_free(fb);
127+
fb = NULL;
128+
}
129+
130+
out:
131+
pr_debug("%s: fb=0x%p, ret=%i\n", __func__, fb, res);
132+
133+
return res;
134+
135+
out_fput:
136+
fput(file);
137+
goto out;
138+
}
139+
140+
int fuse_backing_close(struct fuse_conn *fc, int backing_id)
141+
{
142+
struct fuse_backing *fb = NULL;
143+
int err;
144+
145+
pr_debug("%s: backing_id=%d\n", __func__, backing_id);
146+
147+
/* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
148+
err = -EPERM;
149+
if (!fc->passthrough || !capable(CAP_SYS_ADMIN))
150+
goto out;
151+
152+
err = -EINVAL;
153+
if (backing_id <= 0)
154+
goto out;
155+
156+
err = -ENOENT;
157+
fb = fuse_backing_id_remove(fc, backing_id);
158+
if (!fb)
159+
goto out;
160+
161+
fuse_backing_put(fb);
162+
err = 0;
163+
out:
164+
pr_debug("%s: fb=0x%p, err=%i\n", __func__, fb, err);
165+
166+
return err;
167+
}
168+
169+
struct fuse_backing *fuse_backing_lookup(struct fuse_conn *fc, int backing_id)
170+
{
171+
struct fuse_backing *fb;
172+
173+
rcu_read_lock();
174+
fb = idr_find(&fc->backing_files_map, backing_id);
175+
fb = fuse_backing_get(fb);
176+
rcu_read_unlock();
177+
178+
return fb;
179+
}

fs/fuse/fuse_i.h

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,29 +1529,11 @@ struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid,
15291529
void fuse_file_release(struct inode *inode, struct fuse_file *ff,
15301530
unsigned int open_flags, fl_owner_t id, bool isdir);
15311531

1532-
/* passthrough.c */
1533-
static inline struct fuse_backing *fuse_inode_backing(struct fuse_inode *fi)
1534-
{
1535-
#ifdef CONFIG_FUSE_PASSTHROUGH
1536-
return READ_ONCE(fi->fb);
1537-
#else
1538-
return NULL;
1539-
#endif
1540-
}
1541-
1542-
static inline struct fuse_backing *fuse_inode_backing_set(struct fuse_inode *fi,
1543-
struct fuse_backing *fb)
1544-
{
1545-
#ifdef CONFIG_FUSE_PASSTHROUGH
1546-
return xchg(&fi->fb, fb);
1547-
#else
1548-
return NULL;
1549-
#endif
1550-
}
1551-
1532+
/* backing.c */
15521533
#ifdef CONFIG_FUSE_PASSTHROUGH
15531534
struct fuse_backing *fuse_backing_get(struct fuse_backing *fb);
15541535
void fuse_backing_put(struct fuse_backing *fb);
1536+
struct fuse_backing *fuse_backing_lookup(struct fuse_conn *fc, int backing_id);
15551537
#else
15561538

15571539
static inline struct fuse_backing *fuse_backing_get(struct fuse_backing *fb)
@@ -1562,13 +1544,38 @@ static inline struct fuse_backing *fuse_backing_get(struct fuse_backing *fb)
15621544
static inline void fuse_backing_put(struct fuse_backing *fb)
15631545
{
15641546
}
1547+
static inline struct fuse_backing *fuse_backing_lookup(struct fuse_conn *fc,
1548+
int backing_id)
1549+
{
1550+
return NULL;
1551+
}
15651552
#endif
15661553

15671554
void fuse_backing_files_init(struct fuse_conn *fc);
15681555
void fuse_backing_files_free(struct fuse_conn *fc);
15691556
int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map);
15701557
int fuse_backing_close(struct fuse_conn *fc, int backing_id);
15711558

1559+
/* passthrough.c */
1560+
static inline struct fuse_backing *fuse_inode_backing(struct fuse_inode *fi)
1561+
{
1562+
#ifdef CONFIG_FUSE_PASSTHROUGH
1563+
return READ_ONCE(fi->fb);
1564+
#else
1565+
return NULL;
1566+
#endif
1567+
}
1568+
1569+
static inline struct fuse_backing *fuse_inode_backing_set(struct fuse_inode *fi,
1570+
struct fuse_backing *fb)
1571+
{
1572+
#ifdef CONFIG_FUSE_PASSTHROUGH
1573+
return xchg(&fi->fb, fb);
1574+
#else
1575+
return NULL;
1576+
#endif
1577+
}
1578+
15721579
struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id);
15731580
void fuse_passthrough_release(struct fuse_file *ff, struct fuse_backing *fb);
15741581

0 commit comments

Comments
 (0)