1// SPDX-License-Identifier: GPL-2.0
2/*
3 * fs/hmdfs/inode_cloud_merge.c
4 *
5 * Copyright (c) 2023-2023 Huawei Device Co., Ltd.
6 */
7
8#include "hmdfs_merge_view.h"
9#include <linux/atomic.h>
10#include <linux/fs.h>
11#include <linux/fs_stack.h>
12#include <linux/kernel.h>
13#include <linux/list.h>
14#include <linux/mount.h>
15#include <linux/namei.h>
16#include <linux/rwsem.h>
17#include <linux/slab.h>
18#include <linux/types.h>
19#include "authority/authentication.h"
20#include "hmdfs_trace.h"
21
22static struct inode *fill_inode_merge(struct super_block *sb,
23				      struct inode *parent_inode,
24				      struct dentry *child_dentry,
25				      struct dentry *lo_d_dentry)
26{
27	int ret = 0;
28	struct dentry *fst_lo_d = NULL;
29	struct hmdfs_inode_info *info = NULL;
30	struct inode *inode = NULL;
31	umode_t mode;
32
33	if (lo_d_dentry) {
34		fst_lo_d = lo_d_dentry;
35		dget(fst_lo_d);
36	} else {
37		fst_lo_d = hmdfs_get_fst_lo_d(child_dentry);
38	}
39	if (!fst_lo_d) {
40		inode = ERR_PTR(-EINVAL);
41		goto out;
42	}
43	if (hmdfs_i(parent_inode)->inode_type == HMDFS_LAYER_ZERO)
44		inode = hmdfs_iget_locked_root(sb, HMDFS_ROOT_MERGE_CLOUD, NULL,
45					       NULL);
46	else
47		inode = hmdfs_iget5_locked_cloud_merge(sb, fst_lo_d);
48	if (!inode) {
49		hmdfs_err("iget5_locked get inode NULL");
50		inode = ERR_PTR(-ENOMEM);
51		goto out;
52	}
53	if (!(inode->i_state & I_NEW))
54		goto out;
55	info = hmdfs_i(inode);
56	if (hmdfs_i(parent_inode)->inode_type == HMDFS_LAYER_ZERO)
57		info->inode_type = HMDFS_LAYER_FIRST_MERGE_CLOUD;
58	else
59		info->inode_type = HMDFS_LAYER_OTHER_MERGE_CLOUD;
60
61	inode->i_uid = USER_DATA_RW_UID;
62	inode->i_gid = USER_DATA_RW_GID;
63
64	update_inode_attr(inode, child_dentry);
65	mode = d_inode(fst_lo_d)->i_mode;
66
67	if (S_ISREG(mode)) {
68		inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
69		inode->i_op = &hmdfs_file_iops_cloud_merge;
70		inode->i_fop = &hmdfs_file_fops_merge;
71		set_nlink(inode, 1);
72	} else if (S_ISDIR(mode)) {
73		inode->i_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IXOTH;
74		inode->i_op = &hmdfs_dir_iops_cloud_merge;
75		inode->i_fop = &hmdfs_dir_fops_merge;
76		set_nlink(inode, get_num_comrades(child_dentry) + 2);
77	} else {
78		ret = -EIO;
79		goto bad_inode;
80	}
81
82	unlock_new_inode(inode);
83out:
84	dput(fst_lo_d);
85	return inode;
86bad_inode:
87	iget_failed(inode);
88	return ERR_PTR(ret);
89}
90
91static struct hmdfs_dentry_comrade *
92cloud_merge_lookup_comrade(struct hmdfs_sb_info *sbi,
93			   const char *name,
94			   int devid,
95			   unsigned int flags)
96{
97	int err;
98	struct path root, path;
99	struct hmdfs_dentry_comrade *comrade = NULL;
100
101	err = kern_path(sbi->real_dst, LOOKUP_DIRECTORY, &root);
102	if (err) {
103		comrade = ERR_PTR(err);
104		goto out;
105	}
106
107	err = vfs_path_lookup(root.dentry, root.mnt, name, flags, &path);
108	if (err) {
109		comrade = ERR_PTR(err);
110		goto root_put;
111	}
112
113	comrade = alloc_comrade(path.dentry, devid);
114
115	path_put(&path);
116root_put:
117	path_put(&root);
118out:
119	return comrade;
120}
121
122static void merge_lookup_sync(struct hmdfs_dentry_info_merge *mdi,
123			     struct hmdfs_sb_info *sbi,
124			     int devid,
125			     const char *name,
126			     unsigned int flags)
127{
128	struct hmdfs_dentry_comrade *comrade;
129
130	comrade = cloud_merge_lookup_comrade(sbi, name, devid, flags);
131	if (IS_ERR(comrade))
132		return;
133
134	mutex_lock(&mdi->comrade_list_lock);
135
136	if (!is_valid_comrade(mdi, hmdfs_cm(comrade)))
137		destroy_comrade(comrade);
138	else
139		link_comrade(&mdi->comrade_list, comrade);
140
141	mutex_unlock(&mdi->comrade_list_lock);
142}
143
144static int lookup_merge_normal(struct dentry *dentry, unsigned int flags)
145{
146	int ret = -ENOMEM;
147	int devid = -1;
148	struct dentry *pdentry = dget_parent(dentry);
149	struct hmdfs_dentry_info_merge *mdi = hmdfs_dm(dentry);
150	struct hmdfs_sb_info *sbi = hmdfs_sb(dentry->d_sb);
151	char *rname, *ppath, *cpath;
152
153	rname = hmdfs_get_real_dname(dentry, &devid, &mdi->type);
154	if (unlikely(!rname)) {
155		goto out;
156	}
157
158	ppath = hmdfs_merge_get_dentry_relative_path(pdentry);
159	if (unlikely(!ppath)) {
160		hmdfs_err("failed to get parent relative path");
161		goto out_rname;
162	}
163
164	cpath = kzalloc(PATH_MAX, GFP_KERNEL);
165	if (unlikely(!cpath)) {
166		hmdfs_err("failed to get child device_view path");
167		goto out_ppath;
168	}
169
170	if (mdi->type != DT_REG || devid == 0) {
171		snprintf(cpath, PATH_MAX, "device_view/local%s/%s", ppath,
172			rname);
173		merge_lookup_sync(mdi, sbi, 0, cpath, flags);
174	}
175	if (mdi->type == DT_REG && !is_comrade_list_empty(mdi)) {
176		ret = 0;
177		goto found;
178	}
179
180	snprintf(cpath, PATH_MAX, "device_view/%s%s/%s", CLOUD_CID,
181			ppath, rname);
182	merge_lookup_sync(mdi, sbi, CLOUD_DEVICE, cpath, flags);
183
184	ret = -ENOENT;
185	if (!is_comrade_list_empty(mdi))
186		ret = 0;
187
188found:
189	kfree(cpath);
190out_ppath:
191	kfree(ppath);
192out_rname:
193	kfree(rname);
194out:
195	dput(pdentry);
196	return ret;
197}
198
199/**
200 * do_lookup_merge_root - lookup the root of the merge view(root/merge_view)
201 *
202 * It's common for a network filesystem to incur various of faults, so we
203 * intent to show mercy for faults here, except faults reported by the local.
204 */
205static int do_lookup_cloud_merge_root(struct path path_dev,
206				struct dentry *child_dentry, unsigned int flags)
207{
208	struct hmdfs_dentry_comrade *comrade;
209	const int buf_len =
210		max((int)HMDFS_CID_SIZE + 1, (int)sizeof(DEVICE_VIEW_LOCAL));
211	char *buf = kzalloc(buf_len, GFP_KERNEL);
212	LIST_HEAD(head);
213	int ret;
214
215	if (!buf)
216		return -ENOMEM;
217
218	// lookup real_dst/device_view/local
219	memcpy(buf, DEVICE_VIEW_LOCAL, sizeof(DEVICE_VIEW_LOCAL));
220	comrade = lookup_comrade(path_dev, buf, HMDFS_DEVID_LOCAL, flags);
221	if (IS_ERR(comrade)) {
222		ret = PTR_ERR(comrade);
223		goto out;
224	}
225	link_comrade(&head, comrade);
226
227	memcpy(buf, CLOUD_CID, 6);
228	buf[5] = '\0';
229	comrade = lookup_comrade(path_dev, buf, CLOUD_DEVICE, flags);
230	if (IS_ERR(comrade)) {
231		ret = 0;
232		goto out;
233	}
234
235	link_comrade(&head, comrade);
236
237	assign_comrades_unlocked(child_dentry, &head);
238	ret = 0;
239
240out:
241	kfree(buf);
242	return ret;
243}
244
245static int lookup_cloud_merge_root(struct inode *root_inode,
246			     struct dentry *child_dentry, unsigned int flags)
247{
248	struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb);
249	struct path path_dev;
250	int ret = -ENOENT;
251	int buf_len;
252	char *buf = NULL;
253	bool locked, down;
254
255	// consider additional one slash and one '\0'
256	buf_len = strlen(sbi->real_dst) + 1 + sizeof(DEVICE_VIEW_ROOT);
257	if (buf_len > PATH_MAX)
258		return -ENAMETOOLONG;
259
260	buf = kmalloc(buf_len, GFP_KERNEL);
261	if (unlikely(!buf))
262		return -ENOMEM;
263
264	sprintf(buf, "%s/%s", sbi->real_dst, DEVICE_VIEW_ROOT);
265	lock_root_inode_shared(root_inode, &locked, &down);
266	ret = hmdfs_get_path_in_sb(child_dentry->d_sb, buf, LOOKUP_DIRECTORY,
267				   &path_dev);
268	if (ret)
269		goto free_buf;
270
271	ret = do_lookup_cloud_merge_root(path_dev, child_dentry, flags);
272	path_put(&path_dev);
273
274free_buf:
275	kfree(buf);
276	restore_root_inode_sem(root_inode, locked, down);
277	return ret;
278}
279
280// do this in a map-reduce manner
281struct dentry *hmdfs_lookup_cloud_merge(struct inode *parent_inode,
282				  struct dentry *child_dentry,
283				  unsigned int flags)
284{
285	bool create = flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET);
286	struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb);
287	struct hmdfs_inode_info *pii = hmdfs_i(parent_inode);
288	struct inode *child_inode = NULL;
289	struct dentry *ret_dentry = NULL;
290	int err = 0;
291
292	/*
293	 * Internal flags like LOOKUP_CREATE should not pass to device view.
294	 * LOOKUP_REVAL is needed because dentry cache in hmdfs might be stale
295	 * after rename in lower fs. LOOKUP_DIRECTORY is not needed because
296	 * merge_view can do the judgement that whether result is directory or
297	 * not.
298	 */
299	flags = flags & LOOKUP_REVAL;
300
301	child_dentry->d_fsdata = NULL;
302
303	if (child_dentry->d_name.len > NAME_MAX) {
304		err = -ENAMETOOLONG;
305		goto out;
306	}
307
308	err = init_hmdfs_dentry_info_merge(sbi, child_dentry);
309	if (unlikely(err))
310		goto out;
311
312	if (pii->inode_type == HMDFS_LAYER_ZERO) {
313		hmdfs_dm(child_dentry)->dentry_type = HMDFS_LAYER_FIRST_MERGE_CLOUD;
314		err = lookup_cloud_merge_root(parent_inode, child_dentry, flags);
315	} else {
316		hmdfs_dm(child_dentry)->dentry_type = HMDFS_LAYER_OTHER_MERGE_CLOUD;
317		err = lookup_merge_normal(child_dentry, flags);
318	}
319
320	if (!err) {
321		struct hmdfs_inode_info *info = NULL;
322
323		child_inode = fill_inode_merge(parent_inode->i_sb, parent_inode,
324					       child_dentry, NULL);
325		if (IS_ERR(child_inode)) {
326			err = PTR_ERR(child_inode);
327			goto out;
328		}
329		info = hmdfs_i(child_inode);
330		if (info->inode_type == HMDFS_LAYER_FIRST_MERGE)
331			hmdfs_root_inode_perm_init(child_inode);
332		else
333			check_and_fixup_ownership_remote(parent_inode,
334							 child_inode,
335							 child_dentry);
336
337		ret_dentry = d_splice_alias(child_inode, child_dentry);
338		if (IS_ERR(ret_dentry)) {
339			clear_comrades(child_dentry);
340			err = PTR_ERR(ret_dentry);
341			goto out;
342		}
343		if (ret_dentry)
344			child_dentry = ret_dentry;
345
346		goto out;
347	}
348
349	if ((err == -ENOENT) && create)
350		err = 0;
351
352out:
353	return err ? ERR_PTR(err) : ret_dentry;
354}
355
356const struct inode_operations hmdfs_file_iops_cloud_merge = {
357	.getattr = hmdfs_getattr_merge,
358	.setattr = hmdfs_setattr_merge,
359	.permission = hmdfs_permission,
360};
361
362int do_mkdir_cloud_merge(struct inode *parent_inode, struct dentry *child_dentry,
363		   umode_t mode, struct inode *lo_i_parent,
364		   struct dentry *lo_d_child)
365{
366	int ret = 0;
367	struct super_block *sb = parent_inode->i_sb;
368	struct inode *child_inode = NULL;
369
370	ret = vfs_mkdir(lo_i_parent, lo_d_child, mode);
371	if (ret)
372		goto out;
373
374	child_inode =
375		fill_inode_merge(sb, parent_inode, child_dentry, lo_d_child);
376	if (IS_ERR(child_inode)) {
377		ret = PTR_ERR(child_inode);
378		goto out;
379	}
380
381	d_add(child_dentry, child_inode);
382	/* nlink should be increased with the joining of children */
383	set_nlink(parent_inode, 2);
384	hmdfs_update_meta(parent_inode);
385out:
386	return ret;
387}
388
389int do_create_cloud_merge(struct inode *parent_inode, struct dentry *child_dentry,
390		    umode_t mode, bool want_excl, struct inode *lo_i_parent,
391		    struct dentry *lo_d_child)
392{
393	int ret = 0;
394	struct super_block *sb = parent_inode->i_sb;
395	struct inode *child_inode = NULL;
396
397	ret = vfs_create(lo_i_parent, lo_d_child, mode, want_excl);
398	if (ret)
399		goto out;
400
401	child_inode =
402		fill_inode_merge(sb, parent_inode, child_dentry, lo_d_child);
403	if (IS_ERR(child_inode)) {
404		ret = PTR_ERR(child_inode);
405		goto out;
406	}
407
408	d_add(child_dentry, child_inode);
409	/* nlink should be increased with the joining of children */
410	set_nlink(parent_inode, 2);
411	hmdfs_update_meta(parent_inode);
412out:
413	return ret;
414}
415
416int hmdfs_do_ops_cloud_merge(struct inode *i_parent, struct dentry *d_child,
417		       struct dentry *lo_d_child, struct path path,
418		       struct hmdfs_recursive_para *rec_op_para)
419{
420	int ret = 0;
421
422	if (rec_op_para->is_last) {
423		switch (rec_op_para->opcode) {
424		case F_MKDIR_MERGE:
425			ret = do_mkdir_cloud_merge(i_parent, d_child,
426					     rec_op_para->mode,
427					     d_inode(path.dentry), lo_d_child);
428			break;
429		case F_CREATE_MERGE:
430			ret = do_create_cloud_merge(i_parent, d_child,
431					      rec_op_para->mode,
432					      rec_op_para->want_excl,
433					      d_inode(path.dentry), lo_d_child);
434			break;
435		default:
436			ret = -EINVAL;
437			break;
438		}
439	} else {
440		ret = vfs_mkdir(d_inode(path.dentry), lo_d_child,
441				rec_op_para->mode);
442	}
443	if (ret)
444		hmdfs_err("vfs_ops failed, ops %d, err = %d",
445			  rec_op_para->opcode, ret);
446	return ret;
447}
448
449int hmdfs_create_lower_cloud_dentry(struct inode *i_parent, struct dentry *d_child,
450			      struct dentry *lo_d_parent, bool is_dir,
451			      struct hmdfs_recursive_para *rec_op_para)
452{
453	struct hmdfs_sb_info *sbi = i_parent->i_sb->s_fs_info;
454	struct hmdfs_dentry_comrade *new_comrade = NULL;
455	struct dentry *lo_d_child = NULL;
456	char *path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
457	char *absolute_path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
458	char *path_name = NULL;
459	struct path path = { .mnt = NULL, .dentry = NULL };
460	int ret = 0;
461
462	if (unlikely(!path_buf || !absolute_path_buf)) {
463		ret = -ENOMEM;
464		goto out;
465	}
466
467	path_name = dentry_path_raw(lo_d_parent, path_buf, PATH_MAX);
468	if (IS_ERR(path_name)) {
469		ret = PTR_ERR(path_name);
470		goto out;
471	}
472	if ((strlen(sbi->real_dst) + strlen(path_name) +
473	     strlen(d_child->d_name.name) + 2) > PATH_MAX) {
474		ret = -ENAMETOOLONG;
475		goto out;
476	}
477
478	sprintf(absolute_path_buf, "%s%s/%s", sbi->real_dst, path_name,
479		d_child->d_name.name);
480
481	if (is_dir)
482		lo_d_child = kern_path_create(AT_FDCWD, absolute_path_buf,
483					      &path, LOOKUP_DIRECTORY);
484	else
485		lo_d_child = kern_path_create(AT_FDCWD, absolute_path_buf,
486					      &path, 0);
487	if (IS_ERR(lo_d_child)) {
488		ret = PTR_ERR(lo_d_child);
489		goto out;
490	}
491	// to ensure link_comrade after vfs_mkdir succeed
492	ret = hmdfs_do_ops_cloud_merge(i_parent, d_child, lo_d_child, path,
493				 rec_op_para);
494	if (ret)
495		goto out_put;
496	new_comrade = alloc_comrade(lo_d_child, HMDFS_DEVID_LOCAL);
497	if (IS_ERR(new_comrade)) {
498		ret = PTR_ERR(new_comrade);
499		goto out_put;
500	} else {
501		link_comrade_unlocked(d_child, new_comrade);
502	}
503
504	update_inode_attr(d_inode(d_child), d_child);
505
506out_put:
507	done_path_create(&path, lo_d_child);
508out:
509	kfree(absolute_path_buf);
510	kfree(path_buf);
511	return ret;
512}
513
514static int create_lo_d_parent_recur(struct dentry *d_parent,
515				    struct dentry *d_child, umode_t mode,
516				    struct hmdfs_recursive_para *rec_op_para)
517{
518	struct dentry *lo_d_parent, *d_pparent;
519	int ret = 0;
520
521	lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
522	if (!lo_d_parent) {
523		d_pparent = dget_parent(d_parent);
524		ret = create_lo_d_parent_recur(d_pparent, d_parent,
525					       d_inode(d_parent)->i_mode,
526					       rec_op_para);
527		dput(d_pparent);
528		if (ret)
529			goto out;
530		lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
531		if (!lo_d_parent) {
532			ret = -ENOENT;
533			goto out;
534		}
535	}
536	rec_op_para->is_last = false;
537	rec_op_para->mode = mode;
538	ret = hmdfs_create_lower_cloud_dentry(d_inode(d_parent), d_child, lo_d_parent,
539					true, rec_op_para);
540out:
541	dput(lo_d_parent);
542	return ret;
543}
544
545int create_lo_d_cloud_child(struct inode *i_parent, struct dentry *d_child,
546		      bool is_dir, struct hmdfs_recursive_para *rec_op_para)
547{
548	struct dentry *d_pparent, *lo_d_parent, *lo_d_child;
549	struct dentry *d_parent = dget_parent(d_child);
550	int ret = 0;
551	mode_t d_child_mode = rec_op_para->mode;
552
553	lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
554	if (!lo_d_parent) {
555		d_pparent = dget_parent(d_parent);
556		ret = create_lo_d_parent_recur(d_pparent, d_parent,
557					       d_inode(d_parent)->i_mode,
558					       rec_op_para);
559		dput(d_pparent);
560		if (unlikely(ret)) {
561			lo_d_child = ERR_PTR(ret);
562			goto out;
563		}
564		lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
565		if (!lo_d_parent) {
566			lo_d_child = ERR_PTR(-ENOENT);
567			goto out;
568		}
569	}
570	rec_op_para->is_last = true;
571	rec_op_para->mode = d_child_mode;
572	ret = hmdfs_create_lower_cloud_dentry(i_parent, d_child, lo_d_parent, is_dir,
573					rec_op_para);
574
575out:
576	dput(d_parent);
577	dput(lo_d_parent);
578	return ret;
579}
580
581int hmdfs_mkdir_cloud_merge(struct inode *dir, struct dentry *dentry, umode_t mode)
582{
583	int ret = 0;
584	struct hmdfs_recursive_para *rec_op_para = NULL;
585
586	// confict_name  & file_type is checked by hmdfs_mkdir_local
587	if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON) {
588		ret = -EACCES;
589		goto out;
590	}
591	rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL);
592	if (!rec_op_para) {
593		ret = -ENOMEM;
594		goto out;
595	}
596
597	hmdfs_init_recursive_para(rec_op_para, F_MKDIR_MERGE, mode, false,
598				  NULL);
599	ret = create_lo_d_cloud_child(dir, dentry, true, rec_op_para);
600out:
601	hmdfs_trace_merge(trace_hmdfs_mkdir_merge, dir, dentry, ret);
602	if (ret)
603		d_drop(dentry);
604	kfree(rec_op_para);
605	return ret;
606}
607
608int hmdfs_create_cloud_merge(struct inode *dir, struct dentry *dentry, umode_t mode,
609		       bool want_excl)
610{
611	struct hmdfs_recursive_para *rec_op_para = NULL;
612	int ret = 0;
613
614	rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL);
615	if (!rec_op_para) {
616		ret = -ENOMEM;
617		goto out;
618	}
619	hmdfs_init_recursive_para(rec_op_para, F_CREATE_MERGE, mode, want_excl,
620				  NULL);
621	// confict_name  & file_type is checked by hmdfs_create_local
622	ret = create_lo_d_cloud_child(dir, dentry, false, rec_op_para);
623out:
624	hmdfs_trace_merge(trace_hmdfs_create_merge, dir, dentry, ret);
625	if (ret)
626		d_drop(dentry);
627	kfree(rec_op_para);
628	return ret;
629}
630
631static int rename_lo_d_cloud_child(struct hmdfs_rename_para *rename_para,
632				   struct hmdfs_recursive_para *rec_op_para)
633{
634	struct dentry *d_pparent, *lo_d_parent;
635	struct dentry *d_parent = dget_parent(rename_para->new_dentry);
636	int ret = 0;
637
638	lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
639	if (!lo_d_parent) {
640		d_pparent = dget_parent(d_parent);
641		ret = create_lo_d_parent_recur(d_pparent, d_parent,
642					       d_inode(d_parent)->i_mode,
643					       rec_op_para);
644		dput(d_pparent);
645		if (unlikely(ret))
646			goto out;
647		lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
648		if (!lo_d_parent) {
649			ret = -ENOENT;
650			goto out;
651		}
652	}
653	ret = do_rename_merge(rename_para->old_dir, rename_para->old_dentry,
654			      rename_para->new_dir, rename_para->new_dentry,
655			      rename_para->flags);
656
657out:
658	dput(d_parent);
659	dput(lo_d_parent);
660	return ret;
661}
662
663static int hmdfs_rename_cloud_merge(struct inode *old_dir,
664				    struct dentry *old_dentry,
665				    struct inode *new_dir,
666				    struct dentry *new_dentry,
667				    unsigned int flags)
668{
669	struct hmdfs_recursive_para *rec_op_para = NULL;
670	struct hmdfs_rename_para rename_para = { old_dir, old_dentry, new_dir,
671						 new_dentry, flags };
672	int ret = 0;
673
674	if (hmdfs_file_type(old_dentry->d_name.name) != HMDFS_TYPE_COMMON ||
675	    hmdfs_file_type(new_dentry->d_name.name) != HMDFS_TYPE_COMMON) {
676		ret = -EACCES;
677		goto rename_out;
678	}
679
680	if (hmdfs_i(old_dir)->inode_type != hmdfs_i(new_dir)->inode_type) {
681		hmdfs_err("in different view");
682		ret = -EPERM;
683		goto rename_out;
684	}
685
686	rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL);
687	if (!rec_op_para) {
688		ret = -ENOMEM;
689		goto rename_out;
690	}
691	trace_hmdfs_rename_merge(old_dir, old_dentry, new_dir, new_dentry,
692				 flags);
693
694	hmdfs_init_recursive_para(rec_op_para, F_MKDIR_MERGE, 0, 0, NULL);
695	ret = rename_lo_d_cloud_child(&rename_para, rec_op_para);
696	if (ret != 0) {
697		d_drop(new_dentry);
698	} else {
699		hmdfs_update_meta(old_dir);
700		if (old_dir != new_dir)
701			hmdfs_update_meta(new_dir);
702	}
703
704	if (S_ISREG(old_dentry->d_inode->i_mode) && !ret)
705		d_invalidate(old_dentry);
706rename_out:
707	kfree(rec_op_para);
708	return ret;
709}
710
711void hmdfs_update_meta(struct inode *dir)
712{
713	dir->i_ctime = dir->i_mtime = current_time(dir);
714}
715
716const struct inode_operations hmdfs_dir_iops_cloud_merge = {
717	.lookup = hmdfs_lookup_cloud_merge,
718	.mkdir = hmdfs_mkdir_cloud_merge,
719	.create = hmdfs_create_cloud_merge,
720	.rmdir = hmdfs_rmdir_merge,
721	.unlink = hmdfs_unlink_merge,
722	.rename = hmdfs_rename_cloud_merge,
723	.permission = hmdfs_permission,
724};
725