1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * fs/hmdfs/file_merge.c
4  *
5  * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
6  */
7 
8 #include "hmdfs_merge_view.h"
9 
10 #include <linux/file.h>
11 
12 #include "hmdfs.h"
13 #include "hmdfs_trace.h"
14 #include "authority/authentication.h"
15 
16 struct hmdfs_iterate_callback_merge {
17 	struct dir_context ctx;
18 	struct dir_context *caller;
19 	/*
20 	 * Record the return value of 'caller->actor':
21 	 *
22 	 * false, buffer is exhausted
23 	 * false, current task is pending
24 	 * false, something is wrong
25 	 * true, success and can do more
26 	 */
27 	bool result ;
28 	struct rb_root *root;
29 	uint64_t dev_id;
30 };
31 
32 struct hmdfs_cache_entry {
33 	struct rb_node rb_node;
34 	int name_len;
35 	char *name;
36 	int file_type;
37 };
38 
39 struct hmdfs_user_info {
40 	char *local_path;
41 	char *distributed_path;
42 	char *bundle_name;
43 };
44 
allocate_entry(const char *name, int namelen, int d_type)45 struct hmdfs_cache_entry *allocate_entry(const char *name, int namelen,
46 					 int d_type)
47 {
48 	struct hmdfs_cache_entry *data;
49 
50 	data = kmalloc(sizeof(*data), GFP_KERNEL);
51 	if (!data)
52 		return ERR_PTR(-ENOMEM);
53 
54 	data->name = kstrndup(name, namelen, GFP_KERNEL);
55 	if (!data->name) {
56 		kfree(data);
57 		return ERR_PTR(-ENOMEM);
58 	}
59 
60 	data->name_len = namelen;
61 	data->file_type = d_type;
62 
63 	return data;
64 }
65 
insert_filename(struct rb_root *root, struct hmdfs_cache_entry **new_entry)66 int insert_filename(struct rb_root *root, struct hmdfs_cache_entry **new_entry)
67 {
68 	struct rb_node *parent = NULL;
69 	struct rb_node **new_node = &(root->rb_node);
70 	int cmp_res = 0;
71 	struct hmdfs_cache_entry *data = *new_entry;
72 
73 	while (*new_node) {
74 		struct hmdfs_cache_entry *entry = container_of(
75 			*new_node, struct hmdfs_cache_entry, rb_node);
76 		parent = *new_node;
77 
78 		if (data->name_len < entry->name_len)
79 			cmp_res = -1;
80 		else if (data->name_len > entry->name_len)
81 			cmp_res = 1;
82 		else
83 			cmp_res = strncmp(data->name, entry->name,
84 					  data->name_len);
85 
86 		if (!cmp_res) {
87 			kfree(data->name);
88 			kfree(data);
89 			*new_entry = entry;
90 			return entry->file_type;
91 		}
92 
93 		if (cmp_res < 0)
94 			new_node = &((*new_node)->rb_left);
95 		else if (cmp_res > 0)
96 			new_node = &((*new_node)->rb_right);
97 	}
98 
99 	rb_link_node(&data->rb_node, parent, new_node);
100 	rb_insert_color(&data->rb_node, root);
101 
102 	return 0;
103 }
104 
recursive_delete(struct rb_node *node)105 static void recursive_delete(struct rb_node *node)
106 {
107 	struct hmdfs_cache_entry *entry = NULL;
108 
109 	if (!node)
110 		return;
111 
112 	recursive_delete(node->rb_left);
113 	recursive_delete(node->rb_right);
114 
115 	entry = container_of(node, struct hmdfs_cache_entry, rb_node);
116 	kfree(entry->name);
117 	kfree(entry);
118 }
119 
destroy_tree(struct rb_root *root)120 static void destroy_tree(struct rb_root *root)
121 {
122 	if (!root)
123 		return;
124 	recursive_delete(root->rb_node);
125 	root->rb_node = NULL;
126 }
127 
delete_filename(struct rb_root *root, struct hmdfs_cache_entry *data)128 static void delete_filename(struct rb_root *root,
129 			    struct hmdfs_cache_entry *data)
130 {
131 	struct rb_node **node = &(root->rb_node);
132 	struct hmdfs_cache_entry *entry = NULL;
133 	int cmp_res = 0;
134 
135 	while (*node) {
136 		entry = container_of(*node, struct hmdfs_cache_entry, rb_node);
137 		if (data->name_len < entry->name_len)
138 			cmp_res = -1;
139 		else if (data->name_len > entry->name_len)
140 			cmp_res = 1;
141 		else
142 			cmp_res = strncmp(data->name, entry->name,
143 					  data->name_len);
144 
145 		if (!cmp_res)
146 			goto found;
147 
148 		if (cmp_res < 0)
149 			node = &((*node)->rb_left);
150 		else if (cmp_res > 0)
151 			node = &((*node)->rb_right);
152 	}
153 	return;
154 
155 found:
156 	rb_erase(*node, root);
157 	kfree(entry->name);
158 	kfree(entry);
159 }
160 
rename_conflicting_file(char *dentry_name, int *len, unsigned int dev_id)161 static void rename_conflicting_file(char *dentry_name, int *len,
162 				    unsigned int dev_id)
163 {
164 	int i = *len - 1;
165 	int dot_pos = -1;
166 	char *buffer;
167 
168 	buffer = kzalloc(DENTRY_NAME_MAX_LEN, GFP_KERNEL);
169 	if (!buffer)
170 		return;
171 
172 	while (i >= 0) {
173 		if (dentry_name[i] == '/')
174 			break;
175 		if (dentry_name[i] == '.') {
176 			// TODO: 这个修改同步到 CT01
177 			dot_pos = i;
178 			break;
179 		}
180 		i--;
181 	}
182 
183 	if (dot_pos == -1) {
184 		snprintf(dentry_name + *len, DENTRY_NAME_MAX_LEN - *len,
185 			 CONFLICTING_FILE_SUFFIX, dev_id);
186 		goto done;
187 	}
188 
189 	for (i = 0; i < *len - dot_pos; i++)
190 		buffer[i] = dentry_name[i + dot_pos];
191 
192 	buffer[i] = '\0';
193 	snprintf(dentry_name + dot_pos, DENTRY_NAME_MAX_LEN - dot_pos,
194 		 CONFLICTING_FILE_SUFFIX, dev_id);
195 	strcat(dentry_name, buffer);
196 
197 done:
198 	*len = strlen(dentry_name);
199 	kfree(buffer);
200 }
201 
rename_conflicting_directory(char *dentry_name, int *len)202 static void rename_conflicting_directory(char *dentry_name, int *len)
203 {
204 	snprintf(dentry_name + *len, DENTRY_NAME_MAX_LEN - *len,
205 		 CONFLICTING_DIR_SUFFIX);
206 	*len += strlen(CONFLICTING_DIR_SUFFIX);
207 }
208 
hmdfs_actor_merge(struct dir_context *ctx, const char *name, int namelen, long long offset, unsigned long long ino, unsigned int d_type)209 static bool hmdfs_actor_merge(struct dir_context *ctx, const char *name,
210 			     int namelen, long long offset, unsigned long long ino,
211 			     unsigned int d_type)
212 {
213 	bool ret = true;
214 	int insert_res = 0;
215 	int max_devid_len = 2;
216 	char *dentry_name = NULL;
217 	int dentry_len = namelen;
218 	struct hmdfs_cache_entry *cache_entry = NULL;
219 	struct hmdfs_iterate_callback_merge *iterate_callback_merge = NULL;
220 	struct dir_context *org_ctx = NULL;
221 
222 	if (hmdfs_file_type(name) != HMDFS_TYPE_COMMON) {
223 		/*
224 		* return true here, so that the caller can continue to next
225 		* dentry even if failed on this dentry somehow.
226 		*/
227 		return true;
228 	}
229 
230 
231 	if (namelen > NAME_MAX)
232 		return false;
233 	dentry_name = kzalloc(NAME_MAX + 1, GFP_KERNEL);
234 	if (!dentry_name)
235 		return false;
236 
237 	strncpy(dentry_name, name, dentry_len);
238 
239 	cache_entry = allocate_entry(dentry_name, dentry_len, d_type);
240 	if (IS_ERR(cache_entry)) {
241 		ret = PTR_ERR(cache_entry);
242 		goto done;
243 	}
244 
245 	iterate_callback_merge =
246 		container_of(ctx, struct hmdfs_iterate_callback_merge, ctx);
247 	insert_res =
248 		insert_filename(iterate_callback_merge->root, &cache_entry);
249 	if (d_type == DT_DIR && insert_res == DT_DIR) {
250 		goto done;
251 	} else if (d_type == DT_DIR &&
252 		  (insert_res == DT_REG || insert_res == DT_LNK)) {
253 		if (strlen(CONFLICTING_DIR_SUFFIX) > NAME_MAX - dentry_len) {
254 			ret = false;
255 			goto delete;
256 		}
257 		rename_conflicting_directory(dentry_name, &dentry_len);
258 		cache_entry->file_type = DT_DIR;
259 	} else if ((d_type == DT_REG || d_type == DT_LNK) && insert_res > 0) {
260 		if (strlen(CONFLICTING_FILE_SUFFIX) + max_devid_len >
261 		    NAME_MAX - dentry_len) {
262 			ret = false;
263 			goto delete;
264 		}
265 		rename_conflicting_file(dentry_name, &dentry_len,
266 					iterate_callback_merge->dev_id);
267 	}
268 
269 	org_ctx = iterate_callback_merge->caller;
270 	ret = org_ctx->actor(org_ctx, dentry_name, dentry_len, org_ctx->pos,
271 			     ino, d_type);
272 	/*
273 	 * Record original return value, so that the caller can be aware of
274 	 * different situations.
275 	 */
276 	iterate_callback_merge->result = ret;
277 	if (!ret && d_type == DT_DIR && cache_entry->file_type == DT_DIR &&
278 	   (insert_res == DT_REG || insert_res == DT_LNK))
279 		cache_entry->file_type = DT_REG;
280 
281 delete:
282 	if (!ret && !insert_res)
283 		delete_filename(iterate_callback_merge->root, cache_entry);
284 done:
285 	kfree(dentry_name);
286 	return ret;
287 }
288 
289 struct hmdfs_file_info *
get_next_hmdfs_file_info(struct hmdfs_file_info *fi_head, int device_id)290 get_next_hmdfs_file_info(struct hmdfs_file_info *fi_head, int device_id)
291 {
292 	struct hmdfs_file_info *fi_iter = NULL;
293 	struct hmdfs_file_info *fi_result = NULL;
294 
295 	mutex_lock(&fi_head->comrade_list_lock);
296 	list_for_each_entry_safe(fi_iter, fi_result, &(fi_head->comrade_list),
297 				  comrade_list) {
298 		if (fi_iter->device_id == device_id)
299 			break;
300 	}
301 	mutex_unlock(&fi_head->comrade_list_lock);
302 
303 	return fi_result != fi_head ? fi_result : NULL;
304 }
305 
get_hmdfs_file_info(struct hmdfs_file_info *fi_head, int device_id)306 struct hmdfs_file_info *get_hmdfs_file_info(struct hmdfs_file_info *fi_head,
307 					    int device_id)
308 {
309 	struct hmdfs_file_info *fi_iter = NULL;
310 
311 	mutex_lock(&fi_head->comrade_list_lock);
312 	list_for_each_entry(fi_iter, &(fi_head->comrade_list), comrade_list) {
313 		if (fi_iter->device_id == device_id) {
314 			mutex_unlock(&fi_head->comrade_list_lock);
315 			return fi_iter;
316 		}
317 	}
318 	mutex_unlock(&fi_head->comrade_list_lock);
319 
320 	return NULL;
321 }
322 
hmdfs_iterate_merge(struct file *file, struct dir_context *ctx)323 int hmdfs_iterate_merge(struct file *file, struct dir_context *ctx)
324 {
325 	int err = 0;
326 	struct hmdfs_file_info *fi_head = hmdfs_f(file);
327 	struct hmdfs_file_info *fi_iter = NULL;
328 	struct file *lower_file_iter = NULL;
329 	loff_t start_pos = ctx->pos;
330 	unsigned long device_id = (unsigned long)((ctx->pos) << 1 >>
331 				  (POS_BIT_NUM - DEV_ID_BIT_NUM));
332 	struct hmdfs_iterate_callback_merge ctx_merge = {
333 		.ctx.actor = hmdfs_actor_merge,
334 		.caller = ctx,
335 		.root = &fi_head->root,
336 		.dev_id = device_id
337 	};
338 
339 	/* pos = -1 indicates that all devices have been traversed
340 	 * or an error has occurred.
341 	 */
342 	if (ctx->pos == -1)
343 		return 0;
344 
345 	fi_iter = get_hmdfs_file_info(fi_head, device_id);
346 	if (!fi_iter) {
347 		fi_iter = get_next_hmdfs_file_info(fi_head, device_id);
348 		// dev_id is changed, parameter is set 0 to get next file info
349 		if (fi_iter)
350 			ctx_merge.ctx.pos =
351 				hmdfs_set_pos(fi_iter->device_id, 0, 0);
352 	}
353 	while (fi_iter) {
354 		ctx_merge.dev_id = fi_iter->device_id;
355 		device_id = ctx_merge.dev_id;
356 		lower_file_iter = fi_iter->lower_file;
357 		lower_file_iter->f_pos = file->f_pos;
358 		err = iterate_dir(lower_file_iter, &ctx_merge.ctx);
359 		file->f_pos = lower_file_iter->f_pos;
360 		ctx->pos = file->f_pos;
361 
362 		if (err)
363 			goto done;
364 		/*
365 		 * ctx->actor return nonzero means buffer is exhausted or
366 		 * something is wrong, thus we should not continue.
367 		 */
368 		if (ctx_merge.result)
369 			goto done;
370 		fi_iter = get_next_hmdfs_file_info(fi_head, device_id);
371 		if (fi_iter) {
372 			file->f_pos = hmdfs_set_pos(fi_iter->device_id, 0, 0);
373 			ctx->pos = file->f_pos;
374 		}
375 	}
376 done:
377 	trace_hmdfs_iterate_merge(file->f_path.dentry, start_pos, ctx->pos,
378 				  err);
379 	return err;
380 }
381 
do_dir_open_merge(struct file *file, const struct cred *cred, struct hmdfs_file_info *fi_head)382 int do_dir_open_merge(struct file *file, const struct cred *cred,
383 		      struct hmdfs_file_info *fi_head)
384 {
385 	int ret = -EINVAL;
386 	struct hmdfs_dentry_info_merge *dim = hmdfs_dm(file->f_path.dentry);
387 	struct hmdfs_dentry_comrade *comrade = NULL;
388 	struct hmdfs_file_info *fi = NULL;
389 	struct path lo_p = { .mnt = file->f_path.mnt };
390 	struct file *lower_file = NULL;
391 
392 	if (IS_ERR_OR_NULL(cred))
393 		return ret;
394 
395 	wait_event(dim->wait_queue, !has_merge_lookup_work(dim));
396 
397 	mutex_lock(&dim->comrade_list_lock);
398 	list_for_each_entry(comrade, &(dim->comrade_list), list) {
399 		fi = kzalloc(sizeof(*fi), GFP_KERNEL);
400 		if (!fi) {
401 			ret = ret ? -ENOMEM : 0;
402 			continue; // allow some dir to fail to open
403 		}
404 		lo_p.dentry = comrade->lo_d;
405 		// make sure that dentry will not be dentry_kill before open
406 		dget(lo_p.dentry);
407 		if (unlikely(d_is_negative(lo_p.dentry))) {
408 			hmdfs_info("dentry is negative, try again");
409 			kfree(fi);
410 			dput(lo_p.dentry);
411 			continue;  // skip this device
412 		}
413 		lower_file = dentry_open(&lo_p, file->f_flags, cred);
414 		dput(lo_p.dentry);
415 		if (IS_ERR(lower_file)) {
416 			kfree(fi);
417 			continue;
418 		}
419 		ret = 0;
420 		fi->device_id = comrade->dev_id;
421 		fi->lower_file = lower_file;
422 		mutex_lock(&fi_head->comrade_list_lock);
423 		list_add_tail(&fi->comrade_list, &fi_head->comrade_list);
424 		mutex_unlock(&fi_head->comrade_list_lock);
425 	}
426 	mutex_unlock(&dim->comrade_list_lock);
427 	return ret;
428 }
429 
hmdfs_dir_open_merge(struct inode *inode, struct file *file)430 int hmdfs_dir_open_merge(struct inode *inode, struct file *file)
431 {
432 	int ret = 0;
433 	struct hmdfs_file_info *fi = NULL;
434 
435 	fi = kzalloc(sizeof(*fi), GFP_KERNEL);
436 	if (!fi)
437 		return -ENOMEM;
438 
439 	file->private_data = fi;
440 	fi->root = RB_ROOT;
441 	mutex_init(&fi->comrade_list_lock);
442 	INIT_LIST_HEAD(&fi->comrade_list);
443 
444 	ret = do_dir_open_merge(file, hmdfs_sb(inode->i_sb)->cred, fi);
445 	if (ret)
446 		kfree(fi);
447 
448 	return ret;
449 }
450 
hmdfs_dir_release_merge(struct inode *inode, struct file *file)451 int hmdfs_dir_release_merge(struct inode *inode, struct file *file)
452 {
453 	struct hmdfs_file_info *fi_head = hmdfs_f(file);
454 	struct hmdfs_file_info *fi_iter = NULL;
455 	struct hmdfs_file_info *fi_temp = NULL;
456 
457 	mutex_lock(&fi_head->comrade_list_lock);
458 	list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list),
459 				  comrade_list) {
460 		list_del_init(&(fi_iter->comrade_list));
461 		fput(fi_iter->lower_file);
462 		kfree(fi_iter);
463 	}
464 	mutex_unlock(&fi_head->comrade_list_lock);
465 	destroy_tree(&fi_head->root);
466 	file->private_data = NULL;
467 	kfree(fi_head);
468 
469 	return 0;
470 }
471 
472 static long hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg);
473 
hmdfs_dir_unlocked_ioctl_merge(struct file *file, unsigned int cmd, unsigned long arg)474 long hmdfs_dir_unlocked_ioctl_merge(struct file *file, unsigned int cmd,
475 							unsigned long arg)
476 {
477 	struct hmdfs_file_info *fi_head = hmdfs_f(file);
478 	struct hmdfs_file_info *fi_iter = NULL;
479 	struct hmdfs_file_info *fi_temp = NULL;
480 	struct file *lower_file = NULL;
481 	int error = -ENOTTY;
482 
483 	if (cmd == HMDFS_IOC_GET_DST_PATH)
484 		return hmdfs_ioc_get_dst_path(file, arg);
485 	mutex_lock(&fi_head->comrade_list_lock);
486 	list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list),
487 				  comrade_list) {
488 		if (fi_iter->device_id == 0) {
489 			lower_file = fi_iter->lower_file;
490 			if (lower_file->f_op->unlocked_ioctl)
491 				error = lower_file->f_op->unlocked_ioctl(
492 					lower_file, cmd, arg);
493 			break;
494 		}
495 	}
496 	mutex_unlock(&fi_head->comrade_list_lock);
497 	return error;
498 }
499 
hmdfs_dir_compat_ioctl_merge(struct file *file, unsigned int cmd, unsigned long arg)500 long hmdfs_dir_compat_ioctl_merge(struct file *file, unsigned int cmd,
501 							unsigned long arg)
502 {
503 	struct hmdfs_file_info *fi_head = hmdfs_f(file);
504 	struct hmdfs_file_info *fi_iter = NULL;
505 	struct hmdfs_file_info *fi_temp = NULL;
506 	struct file *lower_file = NULL;
507 	int error = -ENOTTY;
508 
509 	if (cmd == HMDFS_IOC_GET_DST_PATH)
510 		return hmdfs_ioc_get_dst_path(file, arg);
511 	mutex_lock(&fi_head->comrade_list_lock);
512 	list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list),
513 				  comrade_list) {
514 		if (fi_iter->device_id == 0) {
515 			lower_file = fi_iter->lower_file;
516 			if (lower_file->f_op->compat_ioctl)
517 				error = lower_file->f_op->compat_ioctl(
518 					lower_file, cmd, arg);
519 			break;
520 		}
521 	}
522 	mutex_unlock(&fi_head->comrade_list_lock);
523 	return error;
524 }
525 
526 const struct file_operations hmdfs_dir_fops_merge = {
527 	.owner = THIS_MODULE,
528 	.iterate_shared = hmdfs_iterate_merge,
529 	.open = hmdfs_dir_open_merge,
530 	.release = hmdfs_dir_release_merge,
531 	.unlocked_ioctl = hmdfs_dir_unlocked_ioctl_merge,
532 	.compat_ioctl = hmdfs_dir_compat_ioctl_merge,
533 };
534 
hmdfs_merge_read_iter(struct kiocb *iocb, struct iov_iter *iter)535 static ssize_t hmdfs_merge_read_iter(struct kiocb *iocb, struct iov_iter *iter)
536 {
537 	return hmdfs_do_read_iter(iocb->ki_filp, iter, &iocb->ki_pos);
538 }
539 
hmdfs_merge_write_iter(struct kiocb *iocb, struct iov_iter *iter)540 ssize_t hmdfs_merge_write_iter(struct kiocb *iocb, struct iov_iter *iter)
541 {
542 	return hmdfs_do_write_iter(iocb->ki_filp, iter, &iocb->ki_pos);
543 }
544 
hmdfs_file_open_merge(struct inode *inode, struct file *file)545 int hmdfs_file_open_merge(struct inode *inode, struct file *file)
546 {
547 	int err = 0;
548 	struct file *lower_file = NULL;
549 	struct path lo_p = { .mnt = file->f_path.mnt };
550 	struct super_block *sb = inode->i_sb;
551 	const struct cred *cred = hmdfs_sb(sb)->cred;
552 	struct hmdfs_file_info *gfi = NULL;
553 	struct dentry *parent = NULL;
554 
555 	lo_p.dentry = hmdfs_get_fst_lo_d(file->f_path.dentry);
556 	if (!lo_p.dentry) {
557 		err = -EINVAL;
558 		goto out_err;
559 	}
560 
561 	gfi = kzalloc(sizeof(*gfi), GFP_KERNEL);
562 	if (!gfi) {
563 		err = -ENOMEM;
564 		goto out_err;
565 	}
566 
567 	parent = dget_parent(file->f_path.dentry);
568 	lower_file = dentry_open(&lo_p, file->f_flags, cred);
569 	if (IS_ERR(lower_file)) {
570 		err = PTR_ERR(lower_file);
571 		kfree(gfi);
572 	} else {
573 		gfi->lower_file = lower_file;
574 		file->private_data = gfi;
575 		hmdfs_update_upper_file(file, lower_file);
576 	}
577 	dput(parent);
578 out_err:
579 	dput(lo_p.dentry);
580 	return err;
581 }
582 
hmdfs_file_flush_merge(struct file *file, fl_owner_t id)583 int hmdfs_file_flush_merge(struct file *file, fl_owner_t id)
584 {
585 	struct hmdfs_file_info *gfi = hmdfs_f(file);
586 	struct file *lower_file = gfi->lower_file;
587 
588 	if (lower_file->f_op->flush)
589 		return lower_file->f_op->flush(lower_file, id);
590 
591 	return 0;
592 }
593 
hmdfs_ioc_get_writeopen_cnt(struct file *filp, unsigned long arg)594 static long hmdfs_ioc_get_writeopen_cnt(struct file *filp, unsigned long arg)
595 {
596 	struct hmdfs_file_info *gfi = hmdfs_f(filp);
597 	struct file *lower_file = gfi->lower_file;
598 	struct inode *lower_inode = file_inode(lower_file);
599 
600 	u32 wo_cnt = atomic_read(&(hmdfs_i(lower_inode))->write_opened);
601 
602 	return put_user(wo_cnt, (int __user *)arg);
603 }
604 
copy_string_from_user(unsigned long pos, unsigned long len, char **data)605 static int copy_string_from_user(unsigned long pos, unsigned long len,
606 				char **data)
607 {
608 	char *tmp_data;
609 
610 	if (len >= PATH_MAX)
611 		return -EINVAL;
612 	if (!access_ok((char __user *)pos, len))
613 		return -EFAULT;
614 
615 	tmp_data = kzalloc(len + 1, GFP_KERNEL);
616 	if (!tmp_data)
617 		return -ENOMEM;
618 	*data = tmp_data;
619 
620 	if (copy_from_user(tmp_data, (char __user *)pos, len))
621 		return -EFAULT;
622 
623 	return 0;
624 }
625 
hmdfs_get_info_from_user(unsigned long pos, struct hmdfs_dst_info *hdi, struct hmdfs_user_info *data)626 static int hmdfs_get_info_from_user(unsigned long pos,
627 		struct hmdfs_dst_info *hdi, struct hmdfs_user_info *data)
628 {
629 	int ret = 0;
630 
631 	if (!access_ok((struct hmdfs_dst_info __user *)pos,
632 			sizeof(struct hmdfs_dst_info)))
633 		return -ENOMEM;
634 	if (copy_from_user(hdi, (struct hmdfs_dst_info __user *)pos,
635 			sizeof(struct hmdfs_dst_info)))
636 		return -EFAULT;
637 
638 	ret = copy_string_from_user(hdi->local_path_pos, hdi->local_path_len,
639 				    &data->local_path);
640 	if (ret != 0)
641 		return ret;
642 
643 	ret = copy_string_from_user(hdi->distributed_path_pos,
644 				    hdi->distributed_path_len,
645 				    &data->distributed_path);
646 	if (ret != 0)
647 		return ret;
648 
649 	ret = copy_string_from_user(hdi->bundle_name_pos, hdi->bundle_name_len,
650 				    &data->bundle_name);
651 	if (ret != 0)
652 		return ret;
653 
654 	return 0;
655 }
656 
change_cred(struct dentry *dentry, const char *bundle_name)657 static const struct cred *change_cred(struct dentry *dentry,
658 				      const char *bundle_name)
659 {
660 	int bid;
661 	struct cred *cred = NULL;
662 	const struct cred *old_cred = NULL;
663 
664 	cred = prepare_creds();
665 	if (!cred) {
666 		return NULL;
667 	}
668 	bid = get_bundle_uid(hmdfs_sb(dentry->d_sb), bundle_name);
669 	if (bid != 0) {
670 		cred->fsuid = KUIDT_INIT(bid);
671 		cred->fsgid = KGIDT_INIT(bid);
672 		old_cred = override_creds(cred);
673 	}
674 
675 	return old_cred;
676 }
677 
get_file_size(const char *path_value, uint64_t pos)678 static int get_file_size(const char *path_value, uint64_t pos)
679 {
680 	int ret;
681 	uint64_t size;
682 	struct path path;
683 	struct kstat buf;
684 
685 	ret = kern_path(path_value, 0, &path);
686 	if (ret)
687 		return ret;
688 	ret = vfs_getattr(&path, &buf, STATX_BASIC_STATS | STATX_BTIME, 0);
689 	path_put(&path);
690 	if (ret) {
691 		hmdfs_err("call vfs_getattr failed, err %d", ret);
692 		return ret;
693 	}
694 
695 	size = buf.size;
696 	ret = copy_to_user((uint64_t __user *)pos, &size, sizeof(uint64_t));
697 	return ret;
698 }
699 
create_link_file(struct hmdfs_user_info *data)700 static int create_link_file(struct hmdfs_user_info *data)
701 {
702 	int ret;
703 	struct dentry *dentry;
704 	struct path path;
705 
706 	ret = kern_path(data->distributed_path, 0, &path);
707 	if (ret == 0){
708 		path_put(&path);
709 		return ret;
710 	}
711 
712 	dentry = kern_path_create(AT_FDCWD, data->distributed_path, &path, 0);
713 	if (IS_ERR(dentry))
714 		return PTR_ERR(dentry);
715 	ret = vfs_symlink(&nop_mnt_idmap, path.dentry->d_inode, dentry, data->local_path);
716 	done_path_create(&path, dentry);
717 
718 	return ret;
719 }
720 
create_dir(const char *path_value, mode_t mode)721 static int create_dir(const char *path_value, mode_t mode)
722 {
723 	int err = 0;
724 	struct path path;
725 	struct dentry *dentry;
726 
727 	dentry = kern_path_create(AT_FDCWD, path_value, &path, LOOKUP_DIRECTORY);
728 	if(PTR_ERR(dentry) == -EEXIST)
729 		return 0;
730 	if (IS_ERR(dentry))
731 		return PTR_ERR(dentry);
732 
733 	err = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode);
734 	if (err && err != -EEXIST)
735 		hmdfs_err("vfs_mkdir failed, err = %d", err);
736 	done_path_create(&path, dentry);
737 
738 	return err;
739 }
740 
create_dir_recursive(const char *path_value, mode_t mode)741 static int create_dir_recursive(const char *path_value, mode_t mode)
742 {
743 	int err = 0;
744 	char *tmp_path = kstrdup(path_value, GFP_KERNEL);
745 	char *p = tmp_path;
746 
747 	if (!tmp_path)
748 		return -ENOMEM;
749 
750 	if (*p == '/')
751 		p++;
752 
753 	while (*p) {
754 		if (*p == '/') {
755 			*p = '\0';
756 			err = create_dir(tmp_path, mode);
757 			if (err != 0)
758 				break;
759 			*p = '/';
760 		}
761 		p++;
762 	}
763 
764 	kfree(tmp_path);
765 	return err;
766 }
767 
hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg)768 static long hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg)
769 {
770 	int ret = 0;
771 	const struct cred *old_cred;
772 	struct hmdfs_dst_info hdi;
773 	struct hmdfs_user_info *data;
774 
775 	data = kzalloc(sizeof(*data), GFP_KERNEL);
776 	if (!data) {
777 		ret = -ENOMEM;
778 		goto err_free_data;
779 	}
780 
781 	ret = hmdfs_get_info_from_user(arg, &hdi, data);
782 	if (ret != 0)
783 		goto err_free_all;
784 
785 	old_cred = change_cred(filp->f_path.dentry, data->bundle_name);
786 	if (!old_cred) {
787 		ret = -EACCES;
788 		goto err_free_all;
789 	}
790 
791 	ret = create_dir_recursive(data->distributed_path, DIR_MODE);
792 	if (ret != 0)
793 		goto err_revert;
794 
795 	ret = create_link_file(data);
796 	if (ret != 0 && ret != -EEXIST)
797 		goto err_revert;
798 
799 	ret = get_file_size(data->local_path, hdi.size);
800 
801 err_revert:
802 	revert_creds(old_cred);
803 err_free_all:
804 	kfree(data->local_path);
805 	kfree(data->distributed_path);
806 	kfree(data->bundle_name);
807 err_free_data:
808 	kfree(data);
809 	return ret;
810 }
811 
hmdfs_file_ioctl_merge(struct file *filp, unsigned int cmd, unsigned long arg)812 static long hmdfs_file_ioctl_merge(struct file *filp, unsigned int cmd, unsigned long arg)
813 {
814 	switch (cmd) {
815 	case HMDFS_IOC_GET_WRITEOPEN_CNT:
816 		return hmdfs_ioc_get_writeopen_cnt(filp, arg);
817 	case HMDFS_IOC_GET_DST_PATH:
818 		return hmdfs_ioc_get_dst_path(filp, arg);
819 	default:
820 		return -ENOTTY;
821 	}
822 }
823 
824 /* Transparent transmission of parameters to device_view level,
825  * so file operations are same as device_view local operations.
826  */
827 const struct file_operations hmdfs_file_fops_merge = {
828 	.owner = THIS_MODULE,
829 	.llseek = hmdfs_file_llseek_local,
830 	.read_iter = hmdfs_merge_read_iter,
831 	.write_iter = hmdfs_merge_write_iter,
832 	.mmap = hmdfs_file_mmap_local,
833 	.open = hmdfs_file_open_merge,
834 	.flush = hmdfs_file_flush_merge,
835 	.release = hmdfs_file_release_local,
836 	.fsync = hmdfs_fsync_local,
837 	.unlocked_ioctl	= hmdfs_file_ioctl_merge,
838 	.compat_ioctl = hmdfs_file_ioctl_merge,
839 	.splice_read = copy_splice_read,
840 	.splice_write = iter_file_splice_write,
841 };
842