1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * fs/sharefs/file.c 4 * 5 * Copyright (c) 1998-2022 Erez Zadok 6 * Copyright (c) 2009 Shrikar Archak 7 * Copyright (c) 2003-2022 Stony Brook University 8 * Copyright (c) 2003-2022 The Research Foundation of SUNY 9 * Copyright (c) 2023 Huawei Device Co., Ltd. 10 */ 11 12#include "sharefs.h" 13 14static int sharefs_readdir(struct file *file, struct dir_context *ctx) 15{ 16 int err; 17 struct file *lower_file = NULL; 18 struct dentry *dentry = file->f_path.dentry; 19 20 lower_file = sharefs_lower_file(file); 21 err = iterate_dir(lower_file, ctx); 22 file->f_pos = lower_file->f_pos; 23 if (err >= 0) /* copy the atime */ 24 fsstack_copy_attr_atime(d_inode(dentry), 25 file_inode(lower_file)); 26 return err; 27} 28 29static int sharefs_open(struct inode *inode, struct file *file) 30{ 31 int err = 0; 32 struct file *lower_file = NULL; 33 struct path lower_path; 34 35 /* don't open unhashed/deleted files */ 36 if (d_unhashed(file->f_path.dentry)) { 37 err = -ENOENT; 38 goto out_err; 39 } 40 41 file->private_data = 42 kzalloc(sizeof(struct sharefs_file_info), GFP_KERNEL); 43 if (!SHAREFS_F(file)) { 44 err = -ENOMEM; 45 goto out_err; 46 } 47 48 /* open lower object and link sharefs's file struct to lower's */ 49 sharefs_get_lower_path(file->f_path.dentry, &lower_path); 50 lower_file = dentry_open(&lower_path, file->f_flags, current_cred()); 51 path_put(&lower_path); 52 if (IS_ERR(lower_file)) { 53 err = PTR_ERR(lower_file); 54 lower_file = sharefs_lower_file(file); 55 if (lower_file) { 56 sharefs_set_lower_file(file, NULL); 57 fput(lower_file); /* fput calls dput for lower_dentry */ 58 } 59 } else { 60 sharefs_set_lower_file(file, lower_file); 61 } 62 63 if (err) { 64 kfree(SHAREFS_F(file)); 65 } else { 66 kuid_t uid = inode->i_uid; 67 kgid_t gid = inode->i_gid; 68 mode_t mode = inode->i_mode; 69 fsstack_copy_attr_all(inode, sharefs_lower_inode(inode)); 70 inode->i_uid = uid; 71 inode->i_gid = gid; 72 inode->i_mode = mode; 73 } 74out_err: 75 return err; 76} 77 78static int sharefs_flush(struct file *file, fl_owner_t id) 79{ 80 int err = 0; 81 struct file *lower_file = NULL; 82 83 lower_file = sharefs_lower_file(file); 84 if (lower_file && lower_file->f_op && lower_file->f_op->flush) { 85 filemap_write_and_wait(file->f_mapping); 86 err = lower_file->f_op->flush(lower_file, id); 87 } 88 89 return err; 90} 91 92/* release all lower object references & free the file info structure */ 93static int sharefs_file_release(struct inode *inode, struct file *file) 94{ 95 struct file *lower_file; 96 97 lower_file = sharefs_lower_file(file); 98 if (lower_file) { 99 sharefs_set_lower_file(file, NULL); 100 fput(lower_file); 101 } 102 103 kfree(SHAREFS_F(file)); 104 return 0; 105} 106 107static int sharefs_fsync(struct file *file, loff_t start, loff_t end, 108 int datasync) 109{ 110 int err; 111 struct file *lower_file; 112 struct path lower_path; 113 struct dentry *dentry = file->f_path.dentry; 114 115 err = __generic_file_fsync(file, start, end, datasync); 116 if (err) 117 goto out; 118 lower_file = sharefs_lower_file(file); 119 sharefs_get_lower_path(dentry, &lower_path); 120 err = vfs_fsync_range(lower_file, start, end, datasync); 121 sharefs_put_lower_path(dentry, &lower_path); 122out: 123 return err; 124} 125 126static int sharefs_fasync(int fd, struct file *file, int flag) 127{ 128 int err = 0; 129 struct file *lower_file = NULL; 130 131 lower_file = sharefs_lower_file(file); 132 if (lower_file->f_op && lower_file->f_op->fasync) 133 err = lower_file->f_op->fasync(fd, lower_file, flag); 134 135 return err; 136} 137 138/* 139 * Sharefs cannot use generic_file_llseek as ->llseek, because it would 140 * only set the offset of the upper file. So we have to implement our 141 * own method to set both the upper and lower file offsets 142 * consistently. 143 */ 144static loff_t sharefs_file_llseek(struct file *file, loff_t offset, int whence) 145{ 146 loff_t err; 147 struct file *lower_file; 148 149 lower_file = sharefs_lower_file(file); 150 lower_file->f_pos = file->f_pos; 151 err = generic_file_llseek(lower_file, offset, whence); 152 file->f_pos = lower_file->f_pos; 153 154 return err; 155} 156 157/* 158 * Sharefs read_iter, redirect modified iocb to lower read_iter 159 */ 160ssize_t sharefs_read_iter(struct kiocb *iocb, struct iov_iter *iter) 161{ 162 int err; 163 struct file *file = iocb->ki_filp; 164 struct file *lower_file; 165 166 lower_file = sharefs_lower_file(file); 167 if (!lower_file->f_op->read_iter) { 168 err = -EINVAL; 169 goto out; 170 } 171 172 /* prevent lower_file from being released */ 173 get_file(lower_file); 174 iocb->ki_filp = lower_file; 175 err = lower_file->f_op->read_iter(iocb, iter); 176 iocb->ki_filp = file; 177 fput(lower_file); 178 179 /* update upper inode atime as needed */ 180 if (err >= 0 || err == -EIOCBQUEUED) 181 fsstack_copy_attr_atime(d_inode(file->f_path.dentry), 182 file_inode(lower_file)); 183out: 184 return err; 185} 186 187/* 188 * Sharefs write_iter, redirect modified iocb to lower write_iter 189 */ 190ssize_t sharefs_write_iter(struct kiocb *iocb, struct iov_iter *iter) 191{ 192 int err; 193 struct file *file = iocb->ki_filp; 194 struct file *lower_file; 195 196 lower_file = sharefs_lower_file(file); 197 if (!lower_file->f_op->write_iter) { 198 err = -EINVAL; 199 goto out; 200 } 201 202 get_file(lower_file); /* prevent lower_file from being released */ 203 iocb->ki_filp = lower_file; 204 err = lower_file->f_op->write_iter(iocb, iter); 205 iocb->ki_filp = file; 206 fput(lower_file); 207 /* update upper inode times/sizes as needed */ 208 if (err >= 0 || err == -EIOCBQUEUED) { 209 fsstack_copy_inode_size(d_inode(file->f_path.dentry), 210 file_inode(lower_file)); 211 fsstack_copy_attr_times(d_inode(file->f_path.dentry), 212 file_inode(lower_file)); 213 } 214out: 215 return err; 216} 217 218int sharefs_file_mmap(struct file *file, struct vm_area_struct *vma) 219{ 220 int err = 0; 221 struct file *lower_file; 222 223 lower_file = sharefs_lower_file(file); 224 if (!lower_file) 225 return -EINVAL; 226 227 if (!lower_file->f_op->mmap) 228 return -ENODEV; 229 230 if (WARN_ON(file != vma->vm_file)) 231 return -EIO; 232 233 vma->vm_file = get_file(lower_file); 234 err = call_mmap(vma->vm_file, vma); 235 if (err) 236 fput(lower_file); 237 else 238 fput(file); 239 240 file_accessed(file); 241 242 return err; 243} 244 245const struct file_operations sharefs_main_fops = { 246 .llseek = sharefs_file_llseek, 247 .open = sharefs_open, 248 .flush = sharefs_flush, 249 .release = sharefs_file_release, 250 .fsync = sharefs_fsync, 251 .fasync = sharefs_fasync, 252 .read_iter = sharefs_read_iter, 253 .write_iter = sharefs_write_iter, 254 .mmap = sharefs_file_mmap, 255 .splice_read = generic_file_splice_read, 256 .splice_write = iter_file_splice_write, 257}; 258 259/* trimmed directory options */ 260const struct file_operations sharefs_dir_fops = { 261 .llseek = sharefs_file_llseek, 262 .read = generic_read_dir, 263 .iterate = sharefs_readdir, 264 .open = sharefs_open, 265 .release = sharefs_file_release, 266 .flush = sharefs_flush, 267 .fsync = sharefs_fsync, 268 .fasync = sharefs_fasync, 269}; 270