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