File Index
Files and directories
Sign in
FILE

passthrough.c

File preview with syntax highlighting.

linux-6.19.14/fs/fuse/passthrough.c C
  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#include <linux/backing-file.h>
 12#include <linux/splice.h>
 13
 14static void fuse_file_accessed(struct file *file)
 15{
 16	struct inode *inode = file_inode(file);
 17
 18	fuse_invalidate_atime(inode);
 19}
 20
 21static void fuse_passthrough_end_write(struct kiocb *iocb, ssize_t ret)
 22{
 23	struct inode *inode = file_inode(iocb->ki_filp);
 24
 25	fuse_write_update_attr(inode, iocb->ki_pos, ret);
 26}
 27
 28ssize_t fuse_passthrough_read_iter(struct kiocb *iocb, struct iov_iter *iter)
 29{
 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);
 34	ssize_t ret;
 35	struct backing_file_ctx ctx = {
 36		.cred = ff->cred,
 37		.accessed = fuse_file_accessed,
 38	};
 39
 40
 41	pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu\n", __func__,
 42		 backing_file, iocb->ki_pos, count);
 43
 44	if (!count)
 45		return 0;
 46
 47	ret = backing_file_read_iter(backing_file, iter, iocb, iocb->ki_flags,
 48				     &ctx);
 49
 50	return ret;
 51}
 52
 53ssize_t fuse_passthrough_write_iter(struct kiocb *iocb,
 54				    struct iov_iter *iter)
 55{
 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);
 61	ssize_t ret;
 62	struct backing_file_ctx ctx = {
 63		.cred = ff->cred,
 64		.end_write = fuse_passthrough_end_write,
 65	};
 66
 67	pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu\n", __func__,
 68		 backing_file, iocb->ki_pos, count);
 69
 70	if (!count)
 71		return 0;
 72
 73	inode_lock(inode);
 74	ret = backing_file_write_iter(backing_file, iter, iocb, iocb->ki_flags,
 75				      &ctx);
 76	inode_unlock(inode);
 77
 78	return ret;
 79}
 80
 81ssize_t fuse_passthrough_splice_read(struct file *in, loff_t *ppos,
 82				     struct pipe_inode_info *pipe,
 83				     size_t len, unsigned int flags)
 84{
 85	struct fuse_file *ff = in->private_data;
 86	struct file *backing_file = fuse_file_passthrough(ff);
 87	struct backing_file_ctx ctx = {
 88		.cred = ff->cred,
 89		.accessed = fuse_file_accessed,
 90	};
 91	struct kiocb iocb;
 92	ssize_t ret;
 93
 94	pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__,
 95		 backing_file, *ppos, len, flags);
 96
 97	init_sync_kiocb(&iocb, in);
 98	iocb.ki_pos = *ppos;
 99	ret = backing_file_splice_read(backing_file, &iocb, pipe, len, flags, &ctx);
100	*ppos = iocb.ki_pos;
101
102	return ret;
103}
104
105ssize_t fuse_passthrough_splice_write(struct pipe_inode_info *pipe,
106				      struct file *out, loff_t *ppos,
107				      size_t len, unsigned int flags)
108{
109	struct fuse_file *ff = out->private_data;
110	struct file *backing_file = fuse_file_passthrough(ff);
111	struct inode *inode = file_inode(out);
112	ssize_t ret;
113	struct backing_file_ctx ctx = {
114		.cred = ff->cred,
115		.end_write = fuse_passthrough_end_write,
116	};
117	struct kiocb iocb;
118
119	pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__,
120		 backing_file, *ppos, len, flags);
121
122	inode_lock(inode);
123	init_sync_kiocb(&iocb, out);
124	iocb.ki_pos = *ppos;
125	ret = backing_file_splice_write(pipe, backing_file, &iocb, len, flags, &ctx);
126	*ppos = iocb.ki_pos;
127	inode_unlock(inode);
128
129	return ret;
130}
131
132ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
133{
134	struct fuse_file *ff = file->private_data;
135	struct file *backing_file = fuse_file_passthrough(ff);
136	struct backing_file_ctx ctx = {
137		.cred = ff->cred,
138		.accessed = fuse_file_accessed,
139	};
140
141	pr_debug("%s: backing_file=0x%p, start=%lu, end=%lu\n", __func__,
142		 backing_file, vma->vm_start, vma->vm_end);
143
144	return backing_file_mmap(backing_file, vma, &ctx);
145}
146
147/*
148 * Setup passthrough to a backing file.
149 *
150 * Returns an fb object with elevated refcount to be stored in fuse inode.
151 */
152struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
153{
154	struct fuse_file *ff = file->private_data;
155	struct fuse_conn *fc = ff->fm->fc;
156	struct fuse_backing *fb = NULL;
157	struct file *backing_file;
158	int err;
159
160	err = -EINVAL;
161	if (backing_id <= 0)
162		goto out;
163
164	err = -ENOENT;
165	fb = fuse_backing_lookup(fc, backing_id);
166	if (!fb)
167		goto out;
168
169	/* Allocate backing file per fuse file to store fuse path */
170	backing_file = backing_file_open(&file->f_path, file->f_flags,
171					 &fb->file->f_path, fb->cred);
172	err = PTR_ERR(backing_file);
173	if (IS_ERR(backing_file)) {
174		fuse_backing_put(fb);
175		goto out;
176	}
177
178	err = 0;
179	ff->passthrough = backing_file;
180	ff->cred = get_cred(fb->cred);
181out:
182	pr_debug("%s: backing_id=%d, fb=0x%p, backing_file=0x%p, err=%i\n", __func__,
183		 backing_id, fb, ff->passthrough, err);
184
185	return err ? ERR_PTR(err) : fb;
186}
187
188void fuse_passthrough_release(struct fuse_file *ff, struct fuse_backing *fb)
189{
190	pr_debug("%s: fb=0x%p, backing_file=0x%p\n", __func__,
191		 fb, ff->passthrough);
192
193	fput(ff->passthrough);
194	ff->passthrough = NULL;
195	put_cred(ff->cred);
196	ff->cred = NULL;
197}
~/ Read-only file preview.