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 14 static void fuse_file_accessed(struct file *file) 15 { 16 struct inode *inode = file_inode(file); 17 18 fuse_invalidate_atime(inode); 19 } 20 21 static 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 28 ssize_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 53 ssize_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 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) 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 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) 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 132 ssize_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 */ 152 struct 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); 181 out: 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 188 void 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 } 198