• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_trace.h"
21 
hmdfs_file_open_local(struct inode * inode,struct file * file)22 int hmdfs_file_open_local(struct inode *inode, struct file *file)
23 {
24 	int err = 0;
25 	struct file *lower_file = NULL;
26 	struct path lower_path;
27 	struct super_block *sb = inode->i_sb;
28 	const struct cred *cred = hmdfs_sb(sb)->cred;
29 	struct hmdfs_file_info *gfi = kzalloc(sizeof(*gfi), GFP_KERNEL);
30 
31 	if (!gfi) {
32 		err = -ENOMEM;
33 		goto out_err;
34 	}
35 
36 	hmdfs_get_lower_path(file->f_path.dentry, &lower_path);
37 	lower_file = dentry_open(&lower_path, file->f_flags, cred);
38 	hmdfs_put_lower_path(&lower_path);
39 	if (IS_ERR(lower_file)) {
40 		err = PTR_ERR(lower_file);
41 		kfree(gfi);
42 	} else {
43 		gfi->lower_file = lower_file;
44 		file->private_data = gfi;
45 	}
46 out_err:
47 	return err;
48 }
49 
hmdfs_file_release_local(struct inode * inode,struct file * file)50 int hmdfs_file_release_local(struct inode *inode, struct file *file)
51 {
52 	struct hmdfs_file_info *gfi = hmdfs_f(file);
53 
54 	file->private_data = NULL;
55 	fput(gfi->lower_file);
56 	kfree(gfi);
57 	return 0;
58 }
59 
hmdfs_file_accessed(struct file * file)60 static void hmdfs_file_accessed(struct file *file)
61 {
62 	struct file *lower_file = hmdfs_f(file)->lower_file;
63 	struct inode *inode = file_inode(file);
64 	struct inode *lower_inode = file_inode(lower_file);
65 
66 	if (file->f_flags & O_NOATIME)
67 		return;
68 
69 	inode->i_atime = lower_inode->i_atime;
70 }
71 
hmdfs_do_read_iter(struct file * file,struct iov_iter * iter,loff_t * ppos)72 ssize_t hmdfs_do_read_iter(struct file *file, struct iov_iter *iter,
73 	loff_t *ppos)
74 {
75 	ssize_t ret;
76 	struct file *lower_file = hmdfs_f(file)->lower_file;
77 
78 	if (!iov_iter_count(iter))
79 		return 0;
80 
81 	ret = vfs_iter_read(lower_file, iter, ppos, 0);
82 	hmdfs_file_accessed(file);
83 
84 	return ret;
85 }
86 
hmdfs_local_read_iter(struct kiocb * iocb,struct iov_iter * iter)87 static ssize_t hmdfs_local_read_iter(struct kiocb *iocb, struct iov_iter *iter)
88 {
89 	return hmdfs_do_read_iter(iocb->ki_filp, iter, &iocb->ki_pos);
90 }
91 
hmdfs_file_modified(struct file * file)92 static void hmdfs_file_modified(struct file *file)
93 {
94 	struct inode *inode = file_inode(file);
95 	struct dentry *dentry = file_dentry(file);
96 	struct file *lower_file = hmdfs_f(file)->lower_file;
97 	struct inode *lower_inode = file_inode(lower_file);
98 
99 	inode->i_atime = lower_inode->i_atime;
100 	inode->i_ctime = lower_inode->i_ctime;
101 	inode->i_mtime = lower_inode->i_mtime;
102 	i_size_write(inode, i_size_read(lower_inode));
103 
104 	if (!hmdfs_i_merge(hmdfs_i(inode)))
105 		update_inode_to_dentry(dentry, inode);
106 }
107 
hmdfs_do_write_iter(struct file * file,struct iov_iter * iter,loff_t * ppos)108 ssize_t hmdfs_do_write_iter(struct file *file, struct iov_iter *iter,
109 	loff_t *ppos)
110 {
111 	ssize_t ret;
112 	struct file *lower_file = hmdfs_f(file)->lower_file;
113 	struct inode *inode = file_inode(file);
114 
115 	if (!iov_iter_count(iter))
116 		return 0;
117 
118 	inode_lock(inode);
119 
120 	ret = file_remove_privs(file);
121 	if (ret)
122 		goto out_unlock;
123 
124 	file_start_write(lower_file);
125 	ret = vfs_iter_write(lower_file, iter, ppos, 0);
126 	file_end_write(lower_file);
127 
128 	hmdfs_file_modified(file);
129 
130 out_unlock:
131 	inode_unlock(inode);
132 	return ret;
133 }
134 
hmdfs_local_write_iter(struct kiocb * iocb,struct iov_iter * iter)135 ssize_t hmdfs_local_write_iter(struct kiocb *iocb, struct iov_iter *iter)
136 {
137 	return hmdfs_do_write_iter(iocb->ki_filp, iter, &iocb->ki_pos);
138 }
139 
hmdfs_fsync_local(struct file * file,loff_t start,loff_t end,int datasync)140 int hmdfs_fsync_local(struct file *file, loff_t start, loff_t end, int datasync)
141 {
142 	int err;
143 	struct file *lower_file = hmdfs_f(file)->lower_file;
144 
145 	err = __generic_file_fsync(file, start, end, datasync);
146 	if (err)
147 		goto out;
148 
149 	err = vfs_fsync_range(lower_file, start, end, datasync);
150 out:
151 	return err;
152 }
153 
hmdfs_file_llseek_local(struct file * file,loff_t offset,int whence)154 loff_t hmdfs_file_llseek_local(struct file *file, loff_t offset, int whence)
155 {
156 	int err = 0;
157 	struct file *lower_file = NULL;
158 
159 	err = generic_file_llseek(file, offset, whence);
160 	if (err < 0)
161 		goto out;
162 	lower_file = hmdfs_f(file)->lower_file;
163 	err = generic_file_llseek(lower_file, offset, whence);
164 out:
165 	return err;
166 }
167 
hmdfs_file_mmap_local(struct file * file,struct vm_area_struct * vma)168 int hmdfs_file_mmap_local(struct file *file, struct vm_area_struct *vma)
169 {
170 	struct hmdfs_file_info *private_data = file->private_data;
171 	struct file *realfile = NULL;
172 	int ret;
173 
174 	if (!private_data)
175 		return -EINVAL;
176 
177 	realfile = private_data->lower_file;
178 	if (!realfile)
179 		return -EINVAL;
180 
181 	if (!realfile->f_op->mmap)
182 		return -ENODEV;
183 
184 	if (WARN_ON(file != vma->vm_file))
185 		return -EIO;
186 
187 	vma->vm_file = get_file(realfile);
188 	ret = call_mmap(vma->vm_file, vma);
189 	if (ret)
190 		fput(realfile);
191 	else
192 		fput(file);
193 
194 	file_accessed(file);
195 
196 	return ret;
197 }
198 
199 const struct file_operations hmdfs_file_fops_local = {
200 	.owner = THIS_MODULE,
201 	.llseek = hmdfs_file_llseek_local,
202 	.read_iter = hmdfs_local_read_iter,
203 	.write_iter = hmdfs_local_write_iter,
204 	.mmap = hmdfs_file_mmap_local,
205 	.open = hmdfs_file_open_local,
206 	.release = hmdfs_file_release_local,
207 	.fsync = hmdfs_fsync_local,
208 };
209 
hmdfs_iterate_local(struct file * file,struct dir_context * ctx)210 static int hmdfs_iterate_local(struct file *file, struct dir_context *ctx)
211 {
212 	int err = 0;
213 	loff_t start_pos = ctx->pos;
214 	struct file *lower_file = hmdfs_f(file)->lower_file;
215 
216 	if (ctx->pos == -1)
217 		return 0;
218 
219 	lower_file->f_pos = file->f_pos;
220 	err = iterate_dir(lower_file, ctx);
221 	file->f_pos = lower_file->f_pos;
222 
223 	if (err < 0)
224 		ctx->pos = -1;
225 
226 	trace_hmdfs_iterate_local(file->f_path.dentry, start_pos, ctx->pos,
227 				  err);
228 	return err;
229 }
230 
hmdfs_dir_open_local(struct inode * inode,struct file * file)231 int hmdfs_dir_open_local(struct inode *inode, struct file *file)
232 {
233 	int err = 0;
234 	struct file *lower_file = NULL;
235 	struct dentry *dentry = file->f_path.dentry;
236 	struct path lower_path;
237 	struct super_block *sb = inode->i_sb;
238 	const struct cred *cred = hmdfs_sb(sb)->cred;
239 	struct hmdfs_file_info *gfi = kzalloc(sizeof(*gfi), GFP_KERNEL);
240 
241 	if (!gfi)
242 		return -ENOMEM;
243 
244 	if (IS_ERR_OR_NULL(cred)) {
245 		err = -EPERM;
246 		goto out_err;
247 	}
248 	hmdfs_get_lower_path(dentry, &lower_path);
249 	lower_file = dentry_open(&lower_path, file->f_flags, cred);
250 	hmdfs_put_lower_path(&lower_path);
251 	if (IS_ERR(lower_file)) {
252 		err = PTR_ERR(lower_file);
253 		goto out_err;
254 	} else {
255 		gfi->lower_file = lower_file;
256 		file->private_data = gfi;
257 	}
258 	return err;
259 
260 out_err:
261 	kfree(gfi);
262 	return err;
263 }
264 
hmdfs_dir_release_local(struct inode * inode,struct file * file)265 static int hmdfs_dir_release_local(struct inode *inode, struct file *file)
266 {
267 	struct hmdfs_file_info *gfi = hmdfs_f(file);
268 
269 	file->private_data = NULL;
270 	fput(gfi->lower_file);
271 	kfree(gfi);
272 	return 0;
273 }
274 
hmdfs_is_dst_path(struct path * src,struct path * dst)275 static inline bool hmdfs_is_dst_path(struct path *src, struct path *dst)
276 {
277 	return (src->dentry == dst->dentry) && (src->mnt == dst->mnt);
278 }
279 
hmdfs_is_share_file(struct file * file)280 bool hmdfs_is_share_file(struct file *file)
281 {
282 	struct file *cur_file = file;
283 	struct hmdfs_dentry_info *gdi;
284 	struct hmdfs_file_info *gfi;
285 
286 	while (cur_file->f_inode->i_sb->s_magic == HMDFS_SUPER_MAGIC) {
287 		gdi = hmdfs_d(cur_file->f_path.dentry);
288 		gfi = hmdfs_f(cur_file);
289 		if (hm_isshare(gdi->file_type))
290 			return true;
291 		if (gfi->lower_file)
292 			cur_file = gfi->lower_file;
293 		else
294 			break;
295 	}
296 
297 	return false;
298 }
299 
hmdfs_is_share_item_still_valid(struct hmdfs_share_item * item)300 bool hmdfs_is_share_item_still_valid(struct hmdfs_share_item *item)
301 {
302 	if (kref_read(&item->ref) == 1 && time_after(jiffies, item->timeout))
303 		return false;
304 
305 	return true;
306 }
307 
release_share_item(struct hmdfs_share_item * item)308 inline void release_share_item(struct hmdfs_share_item *item)
309 {
310 	kfree(item->relative_path.name);
311 	fput(item->file);
312 	kfree(item);
313 }
314 
hmdfs_remove_share_item(struct kref * ref)315 void hmdfs_remove_share_item(struct kref *ref)
316 {
317 	struct hmdfs_share_item *item =
318 			container_of(ref, struct hmdfs_share_item, ref);
319 
320 	list_del(&item->list);
321 	release_share_item(item);
322 }
323 
hmdfs_lookup_share_item(struct hmdfs_share_table * st,struct qstr * cur_relative_path)324 struct hmdfs_share_item *hmdfs_lookup_share_item(struct hmdfs_share_table *st,
325 						struct qstr *cur_relative_path)
326 {
327 	struct hmdfs_share_item *item, *tmp;
328 
329 	list_for_each_entry_safe(item, tmp, &st->item_list_head, list) {
330 		if (hmdfs_is_share_item_still_valid(item)) {
331 			if (qstr_eq(&item->relative_path, cur_relative_path))
332 				return item;
333 		} else {
334 			kref_put(&item->ref, hmdfs_remove_share_item);
335 			st->item_cnt--;
336 		}
337 	}
338 
339 	return NULL;
340 }
341 
set_item_timeout(struct hmdfs_share_item * item)342 inline void set_item_timeout(struct hmdfs_share_item *item)
343 {
344 	item->timeout = jiffies + HZ * HMDFS_SHARE_ITEM_TIMEOUT_S;
345 }
346 
hmdfs_insert_share_item(struct hmdfs_share_table * st,struct qstr * relative_path,struct file * file,char * cid)347 static int hmdfs_insert_share_item(struct hmdfs_share_table *st,
348 		struct qstr *relative_path, struct file *file, char *cid)
349 {
350 	struct hmdfs_share_item *new_item = NULL;
351 	int ret = 0;
352 
353 	if (st->item_cnt >= st->max_cnt) {
354 		ret = -EMFILE;
355 		goto out;
356 	}
357 
358 	new_item = kmalloc(sizeof(*new_item), GFP_KERNEL);
359 	if (new_item) {
360 		new_item->file = file;
361 		get_file(file);
362 		new_item->relative_path = *relative_path;
363 		memcpy(new_item->cid, cid, HMDFS_CID_SIZE);
364 		kref_init(&new_item->ref);
365 		list_add_tail(&new_item->list, &st->item_list_head);
366 		set_item_timeout(new_item);
367 		st->item_cnt++;
368 	} else {
369 		ret = -ENOMEM;
370 	}
371 
372 out:
373 	return ret;
374 }
375 
hmdfs_update_share_item(struct hmdfs_share_item * item,struct file * file,char * cid)376 static int hmdfs_update_share_item(struct hmdfs_share_item *item,
377 					struct file *file, char *cid)
378 {
379 	/* if not the same file, we need to update struct file */
380 	if (!hmdfs_is_dst_path(&file->f_path, &item->file->f_path)) {
381 		fput(item->file);
382 		item->file = file;
383 		get_file(file);
384 	}
385 	memcpy(item->cid, cid, HMDFS_CID_SIZE);
386 	set_item_timeout(item);
387 
388 	return 0;
389 }
390 
hmdfs_add_to_share_table(struct file * file,struct hmdfs_sb_info * sbi,struct hmdfs_share_control * sc)391 static int hmdfs_add_to_share_table(struct file *file,
392 		struct hmdfs_sb_info *sbi, struct hmdfs_share_control *sc)
393 {
394 	struct fd src = fdget(sc->src_fd);
395 	struct hmdfs_share_table *st = &sbi->share_table;
396 	struct hmdfs_share_item *item;
397 	struct dentry *dentry;
398 	const char *dir_path, *cur_path;
399 	struct qstr relative_path;
400 	int err = 0;
401 
402 	if (!src.file)
403 		return -EBADF;
404 
405 	if (!S_ISREG(src.file->f_inode->i_mode)) {
406 		err = -EPERM;
407 		goto err_out;
408 	}
409 
410 	if (hmdfs_is_share_file(src.file)) {
411 		err = -EPERM;
412 		goto err_out;
413 	}
414 
415 	dir_path = hmdfs_get_dentry_relative_path(file->f_path.dentry);
416 	if (unlikely(!dir_path)) {
417 		err = -ENOMEM;
418 		goto err_out;
419 	}
420 
421 	dentry = src.file->f_path.dentry;
422 	if (dentry->d_name.len > NAME_MAX) {
423 		kfree(dir_path);
424 		err = -ENAMETOOLONG;
425 		goto err_out;
426 	}
427 
428 	cur_path = hmdfs_connect_path(dir_path, dentry->d_name.name);
429 	if (unlikely(!cur_path)) {
430 		kfree(dir_path);
431 		err = -ENOMEM;
432 		goto err_out;
433 	}
434 	relative_path.name = cur_path;
435 	relative_path.len = strlen(cur_path);
436 
437 	spin_lock(&sbi->share_table.item_list_lock);
438 	item = hmdfs_lookup_share_item(st, &relative_path);
439 	if (!item)
440 		err = hmdfs_insert_share_item(st, &relative_path,
441 							src.file, sc->cid);
442 	else {
443 		if (kref_read(&item->ref) != 1)
444 			err = -EEXIST;
445 		else
446 			hmdfs_update_share_item(item, src.file, sc->cid);
447 	}
448 	spin_unlock(&sbi->share_table.item_list_lock);
449 
450 	if (err < 0)
451 		kfree(cur_path);
452 	kfree(dir_path);
453 
454 err_out:
455 	fdput(src);
456 	return err;
457 }
458 
hmdfs_ioc_set_share_path(struct file * file,unsigned long arg)459 static int hmdfs_ioc_set_share_path(struct file *file, unsigned long arg)
460 {
461 	struct hmdfs_share_control sc;
462 	struct super_block *sb = file->f_inode->i_sb;
463 	struct hmdfs_sb_info *sbi = hmdfs_sb(sb);
464 	int error;
465 
466 	if (copy_from_user(&sc, (struct hmdfs_share_control __user *)arg,
467 							sizeof(sc)))
468 		return -EFAULT;
469 
470 	error = hmdfs_add_to_share_table(file, sbi, &sc);
471 
472 	return error;
473 }
474 
hmdfs_dir_ioctl_local(struct file * file,unsigned int cmd,unsigned long arg)475 static long hmdfs_dir_ioctl_local(struct file *file, unsigned int cmd,
476 						unsigned long arg)
477 {
478 	switch (cmd) {
479 	case HMDFS_IOC_SET_SHARE_PATH:
480 		return hmdfs_ioc_set_share_path(file, arg);
481 	default:
482 		return -ENOTTY;
483 	}
484 }
485 
486 const struct file_operations hmdfs_dir_ops_local = {
487 	.owner = THIS_MODULE,
488 	.iterate = hmdfs_iterate_local,
489 	.open = hmdfs_dir_open_local,
490 	.release = hmdfs_dir_release_local,
491 	.fsync = hmdfs_fsync_local,
492 };
493 
494 const struct file_operations hmdfs_dir_ops_share = {
495 	.owner = THIS_MODULE,
496 	.iterate = hmdfs_iterate_local,
497 	.open = hmdfs_dir_open_local,
498 	.release = hmdfs_dir_release_local,
499 	.fsync = hmdfs_fsync_local,
500 	.unlocked_ioctl = hmdfs_dir_ioctl_local,
501 	.compat_ioctl = hmdfs_dir_ioctl_local,
502 };
503