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, *lower_file;
153
154 lower_file = sharefs_lower_file(file);
155 if (!lower_file->f_op->read_iter) {
156 err = -EINVAL;
157 goto out;
158 }
159
160 /* prevent lower_file from being released */
161 get_file(lower_file);
162 iocb->ki_filp = lower_file;
163 err = lower_file->f_op->read_iter(iocb, iter);
164 iocb->ki_filp = file;
165 fput(lower_file);
166
167 /* update upper inode atime as needed */
168 if (err >= 0 || err == -EIOCBQUEUED)
169 fsstack_copy_attr_atime(d_inode(file->f_path.dentry),
170 file_inode(lower_file));
171 out:
172 return err;
173 }
174
175 /*
176 * Sharefs write_iter, redirect modified iocb to lower write_iter
177 */
178 ssize_t
sharefs_write_iter(struct kiocb * iocb,struct iov_iter * iter)179 sharefs_write_iter(struct kiocb *iocb, struct iov_iter *iter)
180 {
181 int err;
182 struct file *file = iocb->ki_filp, *lower_file;
183
184 lower_file = sharefs_lower_file(file);
185 if (!lower_file->f_op->write_iter) {
186 err = -EINVAL;
187 goto out;
188 }
189
190 get_file(lower_file); /* prevent lower_file from being released */
191 iocb->ki_filp = lower_file;
192 err = lower_file->f_op->write_iter(iocb, iter);
193 iocb->ki_filp = file;
194 fput(lower_file);
195 /* update upper inode times/sizes as needed */
196 if (err >= 0 || err == -EIOCBQUEUED) {
197 fsstack_copy_inode_size(d_inode(file->f_path.dentry),
198 file_inode(lower_file));
199 fsstack_copy_attr_times(d_inode(file->f_path.dentry),
200 file_inode(lower_file));
201 }
202 out:
203 return err;
204 }
205
206 const struct file_operations sharefs_main_fops = {
207 .llseek = sharefs_file_llseek,
208 .open = sharefs_open,
209 .flush = sharefs_flush,
210 .release = sharefs_file_release,
211 .fsync = sharefs_fsync,
212 .fasync = sharefs_fasync,
213 .read_iter = sharefs_read_iter,
214 .write_iter = sharefs_write_iter,
215 };
216
217 /* trimmed directory options */
218 const struct file_operations sharefs_dir_fops = {
219 .llseek = sharefs_file_llseek,
220 .open = sharefs_open,
221 .release = sharefs_file_release,
222 .flush = sharefs_flush,
223 .fsync = sharefs_fsync,
224 .fasync = sharefs_fasync,
225 };
226