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