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_readdir(struct file * file,struct dir_context * ctx)14 static 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
sharefs_open(struct inode * inode,struct file * file)29 static 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 }
74 out_err:
75 return err;
76 }
77
sharefs_flush(struct file * file,fl_owner_t id)78 static 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 */
sharefs_file_release(struct inode * inode,struct file * file)93 static 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
sharefs_fsync(struct file * file,loff_t start,loff_t end,int datasync)107 static 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);
122 out:
123 return err;
124 }
125
sharefs_fasync(int fd,struct file * file,int flag)126 static 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 */
sharefs_file_llseek(struct file * file,loff_t offset,int whence)144 static 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 */
sharefs_read_iter(struct kiocb * iocb,struct iov_iter * iter)160 ssize_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));
183 out:
184 return err;
185 }
186
187 /*
188 * Sharefs write_iter, redirect modified iocb to lower write_iter
189 */
sharefs_write_iter(struct kiocb * iocb,struct iov_iter * iter)190 ssize_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 }
214 out:
215 return err;
216 }
217
sharefs_file_mmap(struct file * file,struct vm_area_struct * vma)218 int 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
245 const 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 */
260 const 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