]>
git.ipfire.org Git - thirdparty/kernel/linux.git/blob - fs/fuse/passthrough.c
2b119c592f028a5713b8e64f024d1168c45ffde8
1 // SPDX-License-Identifier: GPL-2.0
3 * FUSE passthrough to backing file.
5 * Copyright (c) 2023 CTERA Networks.
10 #include <linux/file.h>
11 #include <linux/backing-file.h>
12 #include <linux/splice.h>
14 static void fuse_file_accessed(struct file
*file
)
16 struct inode
*inode
= file_inode(file
);
18 fuse_invalidate_atime(inode
);
21 static void fuse_file_modified(struct file
*file
)
23 struct inode
*inode
= file_inode(file
);
25 fuse_invalidate_attr_mask(inode
, FUSE_STATX_MODSIZE
);
28 ssize_t
fuse_passthrough_read_iter(struct kiocb
*iocb
, struct iov_iter
*iter
)
30 struct file
*file
= iocb
->ki_filp
;
31 struct fuse_file
*ff
= file
->private_data
;
32 struct file
*backing_file
= fuse_file_passthrough(ff
);
33 size_t count
= iov_iter_count(iter
);
35 struct backing_file_ctx ctx
= {
38 .accessed
= fuse_file_accessed
,
42 pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu\n", __func__
,
43 backing_file
, iocb
->ki_pos
, count
);
48 ret
= backing_file_read_iter(backing_file
, iter
, iocb
, iocb
->ki_flags
,
54 ssize_t
fuse_passthrough_write_iter(struct kiocb
*iocb
,
55 struct iov_iter
*iter
)
57 struct file
*file
= iocb
->ki_filp
;
58 struct inode
*inode
= file_inode(file
);
59 struct fuse_file
*ff
= file
->private_data
;
60 struct file
*backing_file
= fuse_file_passthrough(ff
);
61 size_t count
= iov_iter_count(iter
);
63 struct backing_file_ctx ctx
= {
66 .end_write
= fuse_file_modified
,
69 pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu\n", __func__
,
70 backing_file
, iocb
->ki_pos
, count
);
76 ret
= backing_file_write_iter(backing_file
, iter
, iocb
, iocb
->ki_flags
,
83 ssize_t
fuse_passthrough_splice_read(struct file
*in
, loff_t
*ppos
,
84 struct pipe_inode_info
*pipe
,
85 size_t len
, unsigned int flags
)
87 struct fuse_file
*ff
= in
->private_data
;
88 struct file
*backing_file
= fuse_file_passthrough(ff
);
89 struct backing_file_ctx ctx
= {
92 .accessed
= fuse_file_accessed
,
95 pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__
,
96 backing_file
, ppos
? *ppos
: 0, len
, flags
);
98 return backing_file_splice_read(backing_file
, ppos
, pipe
, len
, flags
,
102 ssize_t
fuse_passthrough_splice_write(struct pipe_inode_info
*pipe
,
103 struct file
*out
, loff_t
*ppos
,
104 size_t len
, unsigned int flags
)
106 struct fuse_file
*ff
= out
->private_data
;
107 struct file
*backing_file
= fuse_file_passthrough(ff
);
108 struct inode
*inode
= file_inode(out
);
110 struct backing_file_ctx ctx
= {
113 .end_write
= fuse_file_modified
,
116 pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__
,
117 backing_file
, ppos
? *ppos
: 0, len
, flags
);
120 ret
= backing_file_splice_write(pipe
, backing_file
, ppos
, len
, flags
,
127 struct fuse_backing
*fuse_backing_get(struct fuse_backing
*fb
)
129 if (fb
&& refcount_inc_not_zero(&fb
->count
))
134 static void fuse_backing_free(struct fuse_backing
*fb
)
136 pr_debug("%s: fb=0x%p\n", __func__
, fb
);
144 void fuse_backing_put(struct fuse_backing
*fb
)
146 if (fb
&& refcount_dec_and_test(&fb
->count
))
147 fuse_backing_free(fb
);
150 void fuse_backing_files_init(struct fuse_conn
*fc
)
152 idr_init(&fc
->backing_files_map
);
155 static int fuse_backing_id_alloc(struct fuse_conn
*fc
, struct fuse_backing
*fb
)
159 idr_preload(GFP_KERNEL
);
160 spin_lock(&fc
->lock
);
161 /* FIXME: xarray might be space inefficient */
162 id
= idr_alloc_cyclic(&fc
->backing_files_map
, fb
, 1, 0, GFP_ATOMIC
);
163 spin_unlock(&fc
->lock
);
166 WARN_ON_ONCE(id
== 0);
170 static struct fuse_backing
*fuse_backing_id_remove(struct fuse_conn
*fc
,
173 struct fuse_backing
*fb
;
175 spin_lock(&fc
->lock
);
176 fb
= idr_remove(&fc
->backing_files_map
, id
);
177 spin_unlock(&fc
->lock
);
182 static int fuse_backing_id_free(int id
, void *p
, void *data
)
184 struct fuse_backing
*fb
= p
;
186 WARN_ON_ONCE(refcount_read(&fb
->count
) != 1);
187 fuse_backing_free(fb
);
191 void fuse_backing_files_free(struct fuse_conn
*fc
)
193 idr_for_each(&fc
->backing_files_map
, fuse_backing_id_free
, NULL
);
194 idr_destroy(&fc
->backing_files_map
);
197 int fuse_backing_open(struct fuse_conn
*fc
, struct fuse_backing_map
*map
)
200 struct super_block
*backing_sb
;
201 struct fuse_backing
*fb
= NULL
;
204 pr_debug("%s: fd=%d flags=0x%x\n", __func__
, map
->fd
, map
->flags
);
206 /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
208 if (!fc
->passthrough
|| !capable(CAP_SYS_ADMIN
))
215 file
= fget(map
->fd
);
221 if (!file
->f_op
->read_iter
|| !file
->f_op
->write_iter
)
224 backing_sb
= file_inode(file
)->i_sb
;
226 if (backing_sb
->s_stack_depth
>= fc
->max_stack_depth
)
229 fb
= kmalloc(sizeof(struct fuse_backing
), GFP_KERNEL
);
235 fb
->cred
= prepare_creds();
236 refcount_set(&fb
->count
, 1);
238 res
= fuse_backing_id_alloc(fc
, fb
);
240 fuse_backing_free(fb
);
245 pr_debug("%s: fb=0x%p, ret=%i\n", __func__
, fb
, res
);
254 int fuse_backing_close(struct fuse_conn
*fc
, int backing_id
)
256 struct fuse_backing
*fb
= NULL
;
259 pr_debug("%s: backing_id=%d\n", __func__
, backing_id
);
261 /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
263 if (!fc
->passthrough
|| !capable(CAP_SYS_ADMIN
))
271 fb
= fuse_backing_id_remove(fc
, backing_id
);
275 fuse_backing_put(fb
);
278 pr_debug("%s: fb=0x%p, err=%i\n", __func__
, fb
, err
);
284 * Setup passthrough to a backing file.
286 * Returns an fb object with elevated refcount to be stored in fuse inode.
288 struct fuse_backing
*fuse_passthrough_open(struct file
*file
,
292 struct fuse_file
*ff
= file
->private_data
;
293 struct fuse_conn
*fc
= ff
->fm
->fc
;
294 struct fuse_backing
*fb
= NULL
;
295 struct file
*backing_file
;
303 fb
= idr_find(&fc
->backing_files_map
, backing_id
);
304 fb
= fuse_backing_get(fb
);
311 /* Allocate backing file per fuse file to store fuse path */
312 backing_file
= backing_file_open(&file
->f_path
, file
->f_flags
,
313 &fb
->file
->f_path
, fb
->cred
);
314 err
= PTR_ERR(backing_file
);
315 if (IS_ERR(backing_file
)) {
316 fuse_backing_put(fb
);
321 ff
->passthrough
= backing_file
;
322 ff
->cred
= get_cred(fb
->cred
);
324 pr_debug("%s: backing_id=%d, fb=0x%p, backing_file=0x%p, err=%i\n", __func__
,
325 backing_id
, fb
, ff
->passthrough
, err
);
327 return err
? ERR_PTR(err
) : fb
;
330 void fuse_passthrough_release(struct fuse_file
*ff
, struct fuse_backing
*fb
)
332 pr_debug("%s: fb=0x%p, backing_file=0x%p\n", __func__
,
333 fb
, ff
->passthrough
);
335 fput(ff
->passthrough
);
336 ff
->passthrough
= NULL
;