1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * fs/hmdfs/file_local.c
4 *
5 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
6 */
7
8 #include <linux/file.h>
9 #include <linux/fs.h>
10 #include <linux/namei.h>
11 #include <linux/page-flags.h>
12 #include <linux/pagemap.h>
13 #include <linux/sched/signal.h>
14 #include <linux/slab.h>
15
16 #include "hmdfs_client.h"
17 #include "hmdfs_dentryfile.h"
18 #include "hmdfs_device_view.h"
19 #include "hmdfs_merge_view.h"
20 #include "hmdfs_share.h"
21 #include "hmdfs_trace.h"
22
update_upper_file(struct file * upper_file,struct file * lower_file)23 static inline void update_upper_file(struct file *upper_file, struct file *lower_file)
24 {
25 loff_t upper_size = i_size_read(upper_file->f_inode);
26 loff_t lower_size = i_size_read(lower_file->f_inode);
27
28 if (upper_file->f_inode->i_mapping && upper_size != lower_size) {
29 i_size_write(upper_file->f_inode, lower_size);
30 truncate_inode_pages(upper_file->f_inode->i_mapping, 0);
31 }
32 }
33
hmdfs_file_open_local(struct inode * inode,struct file * file)34 int hmdfs_file_open_local(struct inode *inode, struct file *file)
35 {
36 int err = 0;
37 struct file *lower_file = NULL;
38 struct path lower_path;
39 struct super_block *sb = inode->i_sb;
40 const struct cred *cred = hmdfs_sb(sb)->cred;
41 struct hmdfs_file_info *gfi = kzalloc(sizeof(*gfi), GFP_KERNEL);
42 struct hmdfs_inode_info *info = hmdfs_i(inode);
43
44 if (!gfi) {
45 err = -ENOMEM;
46 goto out_err;
47 }
48
49 hmdfs_get_lower_path(file->f_path.dentry, &lower_path);
50 if (inode->i_mapping != NULL &&
51 inode->i_mapping->a_ops == &hmdfs_aops_cloud)
52 lower_file = dentry_open(&lower_path, file->f_flags | O_DIRECT,
53 cred);
54 else
55 lower_file = dentry_open(&lower_path, file->f_flags, cred);
56 hmdfs_put_lower_path(&lower_path);
57 if (IS_ERR(lower_file)) {
58 err = PTR_ERR(lower_file);
59 kfree(gfi);
60 } else {
61 gfi->lower_file = lower_file;
62 file->private_data = gfi;
63 update_upper_file(file, lower_file);
64 if (file->f_flags & (O_RDWR | O_WRONLY))
65 atomic_inc(&info->write_opened);
66 }
67 out_err:
68 return err;
69 }
70
hmdfs_file_release_local(struct inode * inode,struct file * file)71 int hmdfs_file_release_local(struct inode *inode, struct file *file)
72 {
73 struct hmdfs_file_info *gfi = hmdfs_f(file);
74 struct hmdfs_inode_info *info = hmdfs_i(inode);
75
76 if (file->f_flags & (O_RDWR | O_WRONLY))
77 atomic_dec(&info->write_opened);
78 file->private_data = NULL;
79 fput(gfi->lower_file);
80 kfree(gfi);
81 return 0;
82 }
83
hmdfs_file_accessed(struct file * file)84 static void hmdfs_file_accessed(struct file *file)
85 {
86 struct file *lower_file = hmdfs_f(file)->lower_file;
87 struct inode *inode = file_inode(file);
88 struct inode *lower_inode = file_inode(lower_file);
89
90 if (file->f_flags & O_NOATIME)
91 return;
92
93 inode->i_atime = lower_inode->i_atime;
94 }
95
hmdfs_do_read_iter(struct file * file,struct iov_iter * iter,loff_t * ppos)96 ssize_t hmdfs_do_read_iter(struct file *file, struct iov_iter *iter,
97 loff_t *ppos)
98 {
99 ssize_t ret;
100 struct file *lower_file = hmdfs_f(file)->lower_file;
101 struct kiocb *iocb;
102
103 if (!iov_iter_count(iter))
104 return 0;
105
106 if (file->f_inode->i_mapping != NULL &&
107 file->f_inode->i_mapping->a_ops == &hmdfs_aops_cloud) {
108 iocb = container_of(ppos, struct kiocb, ki_pos);
109 ret = generic_file_read_iter(iocb, iter);
110 } else {
111 ret = vfs_iter_read(lower_file, iter, ppos, 0);
112 }
113 hmdfs_file_accessed(file);
114
115 return ret;
116 }
117
hmdfs_local_read_iter(struct kiocb * iocb,struct iov_iter * iter)118 static ssize_t hmdfs_local_read_iter(struct kiocb *iocb, struct iov_iter *iter)
119 {
120 return hmdfs_do_read_iter(iocb->ki_filp, iter, &iocb->ki_pos);
121 }
122
hmdfs_file_modified(struct file * file)123 static void hmdfs_file_modified(struct file *file)
124 {
125 struct inode *inode = file_inode(file);
126 struct dentry *dentry = file_dentry(file);
127 struct file *lower_file = hmdfs_f(file)->lower_file;
128 struct inode *lower_inode = file_inode(lower_file);
129
130 inode->i_atime = lower_inode->i_atime;
131 inode->i_ctime = lower_inode->i_ctime;
132 inode->i_mtime = lower_inode->i_mtime;
133 i_size_write(inode, i_size_read(lower_inode));
134
135 if (!hmdfs_i_merge(hmdfs_i(inode)))
136 update_inode_to_dentry(dentry, inode);
137 }
138
hmdfs_do_write_iter(struct file * file,struct iov_iter * iter,loff_t * ppos)139 ssize_t hmdfs_do_write_iter(struct file *file, struct iov_iter *iter,
140 loff_t *ppos)
141 {
142 ssize_t ret;
143 struct file *lower_file = hmdfs_f(file)->lower_file;
144 struct inode *inode = file_inode(file);
145
146 if (!iov_iter_count(iter))
147 return 0;
148
149 inode_lock(inode);
150
151 ret = file_remove_privs(file);
152 if (ret)
153 goto out_unlock;
154
155 file_start_write(lower_file);
156 ret = vfs_iter_write(lower_file, iter, ppos, 0);
157 file_end_write(lower_file);
158
159 hmdfs_file_modified(file);
160
161 out_unlock:
162 inode_unlock(inode);
163 return ret;
164 }
165
hmdfs_local_write_iter(struct kiocb * iocb,struct iov_iter * iter)166 ssize_t hmdfs_local_write_iter(struct kiocb *iocb, struct iov_iter *iter)
167 {
168 return hmdfs_do_write_iter(iocb->ki_filp, iter, &iocb->ki_pos);
169 }
170
hmdfs_fsync_local(struct file * file,loff_t start,loff_t end,int datasync)171 int hmdfs_fsync_local(struct file *file, loff_t start, loff_t end, int datasync)
172 {
173 int err;
174 struct file *lower_file = hmdfs_f(file)->lower_file;
175
176 err = __generic_file_fsync(file, start, end, datasync);
177 if (err)
178 goto out;
179
180 err = vfs_fsync_range(lower_file, start, end, datasync);
181 out:
182 return err;
183 }
184
hmdfs_file_llseek_local(struct file * file,loff_t offset,int whence)185 loff_t hmdfs_file_llseek_local(struct file *file, loff_t offset, int whence)
186 {
187 loff_t ret;
188 struct file *lower_file;
189
190 lower_file = hmdfs_f(file)->lower_file;
191 lower_file->f_pos = file->f_pos;
192 ret = vfs_llseek(lower_file, offset, whence);
193 file->f_pos = lower_file->f_pos;
194
195 return ret;
196 }
197
hmdfs_file_mmap_local(struct file * file,struct vm_area_struct * vma)198 int hmdfs_file_mmap_local(struct file *file, struct vm_area_struct *vma)
199 {
200 struct hmdfs_file_info *private_data = file->private_data;
201 struct file *realfile = NULL;
202 int ret;
203
204 if (!private_data)
205 return -EINVAL;
206
207 realfile = private_data->lower_file;
208 if (!realfile)
209 return -EINVAL;
210
211 if (!realfile->f_op->mmap)
212 return -ENODEV;
213
214 if (WARN_ON(file != vma->vm_file))
215 return -EIO;
216
217 vma->vm_file = get_file(realfile);
218 ret = call_mmap(vma->vm_file, vma);
219 if (ret)
220 fput(realfile);
221 else
222 fput(file);
223
224 file_accessed(file);
225
226 return ret;
227 }
228
229 const struct file_operations hmdfs_file_fops_local = {
230 .owner = THIS_MODULE,
231 .llseek = hmdfs_file_llseek_local,
232 .read_iter = hmdfs_local_read_iter,
233 .write_iter = hmdfs_local_write_iter,
234 .mmap = hmdfs_file_mmap_local,
235 .open = hmdfs_file_open_local,
236 .release = hmdfs_file_release_local,
237 .fsync = hmdfs_fsync_local,
238 .splice_read = generic_file_splice_read,
239 .splice_write = iter_file_splice_write,
240 };
241
hmdfs_iterate_local(struct file * file,struct dir_context * ctx)242 static int hmdfs_iterate_local(struct file *file, struct dir_context *ctx)
243 {
244 int err = 0;
245 loff_t start_pos = ctx->pos;
246 struct file *lower_file = hmdfs_f(file)->lower_file;
247
248 if (ctx->pos == -1)
249 return 0;
250
251 lower_file->f_pos = file->f_pos;
252 err = iterate_dir(lower_file, ctx);
253 file->f_pos = lower_file->f_pos;
254
255 if (err < 0)
256 ctx->pos = -1;
257
258 trace_hmdfs_iterate_local(file->f_path.dentry, start_pos, ctx->pos,
259 err);
260 return err;
261 }
262
hmdfs_dir_open_local(struct inode * inode,struct file * file)263 int hmdfs_dir_open_local(struct inode *inode, struct file *file)
264 {
265 int err = 0;
266 struct file *lower_file = NULL;
267 struct dentry *dentry = file->f_path.dentry;
268 struct path lower_path;
269 struct super_block *sb = inode->i_sb;
270 const struct cred *cred = hmdfs_sb(sb)->cred;
271 struct hmdfs_file_info *gfi = kzalloc(sizeof(*gfi), GFP_KERNEL);
272
273 if (!gfi)
274 return -ENOMEM;
275
276 if (IS_ERR_OR_NULL(cred)) {
277 err = -EPERM;
278 goto out_err;
279 }
280 hmdfs_get_lower_path(dentry, &lower_path);
281 lower_file = dentry_open(&lower_path, file->f_flags, cred);
282 hmdfs_put_lower_path(&lower_path);
283 if (IS_ERR(lower_file)) {
284 err = PTR_ERR(lower_file);
285 goto out_err;
286 } else {
287 gfi->lower_file = lower_file;
288 file->private_data = gfi;
289 }
290 return err;
291
292 out_err:
293 kfree(gfi);
294 return err;
295 }
296
hmdfs_dir_release_local(struct inode * inode,struct file * file)297 static int hmdfs_dir_release_local(struct inode *inode, struct file *file)
298 {
299 struct hmdfs_file_info *gfi = hmdfs_f(file);
300
301 file->private_data = NULL;
302 fput(gfi->lower_file);
303 kfree(gfi);
304 return 0;
305 }
306
307 const struct file_operations hmdfs_dir_ops_local = {
308 .owner = THIS_MODULE,
309 .iterate = hmdfs_iterate_local,
310 .open = hmdfs_dir_open_local,
311 .release = hmdfs_dir_release_local,
312 .fsync = hmdfs_fsync_local,
313 };
314
__hmdfs_ioc_set_share_path(struct file * file,struct hmdfs_share_control * sc)315 static int __hmdfs_ioc_set_share_path(struct file *file,
316 struct hmdfs_share_control *sc)
317 {
318 struct super_block *sb = file->f_inode->i_sb;
319 struct hmdfs_sb_info *sbi = hmdfs_sb(sb);
320 struct hmdfs_share_table *st = &sbi->share_table;
321 struct hmdfs_share_item *item;
322 struct dentry *dentry;
323 const char *dir_path, *full_path;
324 struct qstr relative_path;
325 struct fd src;
326 int err = 0;
327
328 src = fdget(sc->src_fd);
329 if (!src.file)
330 return -EBADF;
331
332 /* only reg file can be shared */
333 if (!S_ISREG(src.file->f_inode->i_mode)) {
334 err = -EPERM;
335 goto err_out;
336 }
337
338 /* share file is not allowed to be shared */
339 if (hmdfs_is_share_file(src.file)) {
340 err = -EPERM;
341 goto err_out;
342 }
343
344 dentry = src.file->f_path.dentry;
345 if (dentry->d_name.len > NAME_MAX) {
346 err = -ENAMETOOLONG;
347 goto err_out;
348 }
349
350 dir_path = hmdfs_get_dentry_relative_path(file->f_path.dentry);
351 if (unlikely(!dir_path)) {
352 err = -ENOMEM;
353 goto err_out;
354 }
355
356 full_path = hmdfs_connect_path(dir_path, dentry->d_name.name);
357 if (unlikely(!full_path)) {
358 err = -ENOMEM;
359 goto free_dir;
360 }
361 relative_path.name = full_path;
362 relative_path.len = strlen(full_path);
363
364 spin_lock(&sbi->share_table.item_list_lock);
365 item = hmdfs_lookup_share_item(st, &relative_path);
366 if (!item) {
367 err = insert_share_item(st, &relative_path, src.file, sc->cid);
368 goto unlock;
369 }
370
371 if (item->opened)
372 err = -EEXIST;
373 else
374 update_share_item(item, src.file, sc->cid);
375
376 unlock:
377 spin_unlock(&sbi->share_table.item_list_lock);
378 kfree(full_path);
379 free_dir:
380 kfree(dir_path);
381 err_out:
382 fdput(src);
383 return err;
384 }
385
hmdfs_ioc_set_share_path(struct file * file,unsigned long arg)386 static int hmdfs_ioc_set_share_path(struct file *file, unsigned long arg)
387 {
388 struct hmdfs_share_control sc;
389
390 if (copy_from_user(&sc, (struct hmdfs_share_control __user *)arg,
391 sizeof(sc)))
392 return -EFAULT;
393
394 return __hmdfs_ioc_set_share_path(file, &sc);
395 }
396
hmdfs_dir_ioctl_local(struct file * file,unsigned int cmd,unsigned long arg)397 static long hmdfs_dir_ioctl_local(struct file *file, unsigned int cmd,
398 unsigned long arg)
399 {
400 switch (cmd) {
401 case HMDFS_IOC_SET_SHARE_PATH:
402 return hmdfs_ioc_set_share_path(file, arg);
403 default:
404 return -ENOTTY;
405 }
406 }
407
408 const struct file_operations hmdfs_dir_ops_share = {
409 .owner = THIS_MODULE,
410 .iterate = hmdfs_iterate_local,
411 .open = hmdfs_dir_open_local,
412 .release = hmdfs_dir_release_local,
413 .fsync = hmdfs_fsync_local,
414 .unlocked_ioctl = hmdfs_dir_ioctl_local,
415 .compat_ioctl = hmdfs_dir_ioctl_local,
416 };
417