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_passthrough_end_write(struct kiocb
*iocb
, ssize_t ret
)
23 struct inode
*inode
= file_inode(iocb
->ki_filp
);
25 fuse_write_update_attr(inode
, iocb
->ki_pos
, ret
);
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
= {
37 .accessed
= fuse_file_accessed
,
41 pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu\n", __func__
,
42 backing_file
, iocb
->ki_pos
, count
);
47 ret
= backing_file_read_iter(backing_file
, iter
, iocb
, iocb
->ki_flags
,
53 ssize_t
fuse_passthrough_write_iter(struct kiocb
*iocb
,
54 struct iov_iter
*iter
)
56 struct file
*file
= iocb
->ki_filp
;
57 struct inode
*inode
= file_inode(file
);
58 struct fuse_file
*ff
= file
->private_data
;
59 struct file
*backing_file
= fuse_file_passthrough(ff
);
60 size_t count
= iov_iter_count(iter
);
62 struct backing_file_ctx ctx
= {
64 .end_write
= fuse_passthrough_end_write
,
67 pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu\n", __func__
,
68 backing_file
, iocb
->ki_pos
, count
);
74 ret
= backing_file_write_iter(backing_file
, iter
, iocb
, iocb
->ki_flags
,
81 ssize_t
fuse_passthrough_splice_read(struct file
*in
, loff_t
*ppos
,
82 struct pipe_inode_info
*pipe
,
83 size_t len
, unsigned int flags
)
85 struct fuse_file
*ff
= in
->private_data
;
86 struct file
*backing_file
= fuse_file_passthrough(ff
);
87 struct backing_file_ctx ctx
= {
89 .accessed
= fuse_file_accessed
,
94 pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__
,
95 backing_file
, *ppos
, len
, flags
);
97 init_sync_kiocb(&iocb
, in
);
99 ret
= backing_file_splice_read(backing_file
, &iocb
, pipe
, len
, flags
, &ctx
);
105 ssize_t
fuse_passthrough_splice_write(struct pipe_inode_info
*pipe
,
106 struct file
*out
, loff_t
*ppos
,
107 size_t len
, unsigned int flags
)
109 struct fuse_file
*ff
= out
->private_data
;
110 struct file
*backing_file
= fuse_file_passthrough(ff
);
111 struct inode
*inode
= file_inode(out
);
113 struct backing_file_ctx ctx
= {
115 .end_write
= fuse_passthrough_end_write
,
119 pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__
,
120 backing_file
, *ppos
, len
, flags
);
123 init_sync_kiocb(&iocb
, out
);
125 ret
= backing_file_splice_write(pipe
, backing_file
, &iocb
, len
, flags
, &ctx
);
132 ssize_t
fuse_passthrough_mmap(struct file
*file
, struct vm_area_struct
*vma
)
134 struct fuse_file
*ff
= file
->private_data
;
135 struct file
*backing_file
= fuse_file_passthrough(ff
);
136 struct backing_file_ctx ctx
= {
138 .accessed
= fuse_file_accessed
,
141 pr_debug("%s: backing_file=0x%p, start=%lu, end=%lu\n", __func__
,
142 backing_file
, vma
->vm_start
, vma
->vm_end
);
144 return backing_file_mmap(backing_file
, vma
, &ctx
);
147 struct fuse_backing
*fuse_backing_get(struct fuse_backing
*fb
)
149 if (fb
&& refcount_inc_not_zero(&fb
->count
))
154 static void fuse_backing_free(struct fuse_backing
*fb
)
156 pr_debug("%s: fb=0x%p\n", __func__
, fb
);
164 void fuse_backing_put(struct fuse_backing
*fb
)
166 if (fb
&& refcount_dec_and_test(&fb
->count
))
167 fuse_backing_free(fb
);
170 void fuse_backing_files_init(struct fuse_conn
*fc
)
172 idr_init(&fc
->backing_files_map
);
175 static int fuse_backing_id_alloc(struct fuse_conn
*fc
, struct fuse_backing
*fb
)
179 idr_preload(GFP_KERNEL
);
180 spin_lock(&fc
->lock
);
181 /* FIXME: xarray might be space inefficient */
182 id
= idr_alloc_cyclic(&fc
->backing_files_map
, fb
, 1, 0, GFP_ATOMIC
);
183 spin_unlock(&fc
->lock
);
186 WARN_ON_ONCE(id
== 0);
190 static struct fuse_backing
*fuse_backing_id_remove(struct fuse_conn
*fc
,
193 struct fuse_backing
*fb
;
195 spin_lock(&fc
->lock
);
196 fb
= idr_remove(&fc
->backing_files_map
, id
);
197 spin_unlock(&fc
->lock
);
202 static int fuse_backing_id_free(int id
, void *p
, void *data
)
204 struct fuse_backing
*fb
= p
;
206 WARN_ON_ONCE(refcount_read(&fb
->count
) != 1);
207 fuse_backing_free(fb
);
211 void fuse_backing_files_free(struct fuse_conn
*fc
)
213 idr_for_each(&fc
->backing_files_map
, fuse_backing_id_free
, NULL
);
214 idr_destroy(&fc
->backing_files_map
);
217 int fuse_backing_open(struct fuse_conn
*fc
, struct fuse_backing_map
*map
)
220 struct super_block
*backing_sb
;
221 struct fuse_backing
*fb
= NULL
;
224 pr_debug("%s: fd=%d flags=0x%x\n", __func__
, map
->fd
, map
->flags
);
226 /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
228 if (!fc
->passthrough
|| !capable(CAP_SYS_ADMIN
))
232 if (map
->flags
|| map
->padding
)
235 file
= fget_raw(map
->fd
);
240 backing_sb
= file_inode(file
)->i_sb
;
242 if (backing_sb
->s_stack_depth
>= fc
->max_stack_depth
)
245 fb
= kmalloc(sizeof(struct fuse_backing
), GFP_KERNEL
);
251 fb
->cred
= prepare_creds();
252 refcount_set(&fb
->count
, 1);
254 res
= fuse_backing_id_alloc(fc
, fb
);
256 fuse_backing_free(fb
);
261 pr_debug("%s: fb=0x%p, ret=%i\n", __func__
, fb
, res
);
270 int fuse_backing_close(struct fuse_conn
*fc
, int backing_id
)
272 struct fuse_backing
*fb
= NULL
;
275 pr_debug("%s: backing_id=%d\n", __func__
, backing_id
);
277 /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
279 if (!fc
->passthrough
|| !capable(CAP_SYS_ADMIN
))
287 fb
= fuse_backing_id_remove(fc
, backing_id
);
291 fuse_backing_put(fb
);
294 pr_debug("%s: fb=0x%p, err=%i\n", __func__
, fb
, err
);
300 * Setup passthrough to a backing file.
302 * Returns an fb object with elevated refcount to be stored in fuse inode.
304 struct fuse_backing
*fuse_passthrough_open(struct file
*file
,
308 struct fuse_file
*ff
= file
->private_data
;
309 struct fuse_conn
*fc
= ff
->fm
->fc
;
310 struct fuse_backing
*fb
= NULL
;
311 struct file
*backing_file
;
319 fb
= idr_find(&fc
->backing_files_map
, backing_id
);
320 fb
= fuse_backing_get(fb
);
327 /* Allocate backing file per fuse file to store fuse path */
328 backing_file
= backing_file_open(&file
->f_path
, file
->f_flags
,
329 &fb
->file
->f_path
, fb
->cred
);
330 err
= PTR_ERR(backing_file
);
331 if (IS_ERR(backing_file
)) {
332 fuse_backing_put(fb
);
337 ff
->passthrough
= backing_file
;
338 ff
->cred
= get_cred(fb
->cred
);
340 pr_debug("%s: backing_id=%d, fb=0x%p, backing_file=0x%p, err=%i\n", __func__
,
341 backing_id
, fb
, ff
->passthrough
, err
);
343 return err
? ERR_PTR(err
) : fb
;
346 void fuse_passthrough_release(struct fuse_file
*ff
, struct fuse_backing
*fb
)
348 pr_debug("%s: fb=0x%p, backing_file=0x%p\n", __func__
,
349 fb
, ff
->passthrough
);
351 fput(ff
->passthrough
);
352 ff
->passthrough
= NULL
;