xref: /kernel/linux/linux-5.10/fs/hmdfs/inode_merge.c (revision 8c2ecf20)
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * fs/hmdfs/inode_merge.c
4 *
5 * Copyright (c) 2020-2021 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
22struct kmem_cache *hmdfs_dentry_merge_cachep;
23
24struct dentry *hmdfs_get_fst_lo_d(struct dentry *dentry)
25{
26	struct hmdfs_dentry_info_merge *dim = hmdfs_dm(dentry);
27	struct hmdfs_dentry_comrade *comrade = NULL;
28	struct dentry *d = NULL;
29
30	mutex_lock(&dim->comrade_list_lock);
31	comrade = list_first_entry_or_null(&dim->comrade_list,
32					   struct hmdfs_dentry_comrade, list);
33	if (comrade)
34		d = dget(comrade->lo_d);
35	mutex_unlock(&dim->comrade_list_lock);
36	return d;
37}
38
39struct dentry *hmdfs_get_lo_d(struct dentry *dentry, int dev_id)
40{
41	struct hmdfs_dentry_info_merge *dim = hmdfs_dm(dentry);
42	struct hmdfs_dentry_comrade *comrade = NULL;
43	struct dentry *d = NULL;
44
45	mutex_lock(&dim->comrade_list_lock);
46	list_for_each_entry(comrade, &dim->comrade_list, list) {
47		if (comrade->dev_id == dev_id) {
48			d = dget(comrade->lo_d);
49			break;
50		}
51	}
52	mutex_unlock(&dim->comrade_list_lock);
53	return d;
54}
55
56void update_inode_attr(struct inode *inode, struct dentry *child_dentry)
57{
58	struct inode *li = NULL;
59	struct hmdfs_dentry_info_merge *cdi = hmdfs_dm(child_dentry);
60	struct hmdfs_dentry_comrade *comrade = NULL;
61	struct hmdfs_dentry_comrade *fst_comrade = NULL;
62
63	mutex_lock(&cdi->comrade_list_lock);
64	fst_comrade = list_first_entry(&cdi->comrade_list,
65				       struct hmdfs_dentry_comrade, list);
66	list_for_each_entry(comrade, &cdi->comrade_list, list) {
67		li = d_inode(comrade->lo_d);
68		if (!li)
69			continue;
70
71		if (comrade == fst_comrade) {
72			inode->i_atime = li->i_atime;
73			inode->i_ctime = li->i_ctime;
74			inode->i_mtime = li->i_mtime;
75			inode->i_size = li->i_size;
76			continue;
77		}
78
79		if (hmdfs_time_compare(&inode->i_mtime, &li->i_mtime) < 0)
80			inode->i_mtime = li->i_mtime;
81	}
82	mutex_unlock(&cdi->comrade_list_lock);
83}
84
85int get_num_comrades(struct dentry *dentry)
86{
87	struct list_head *pos;
88	struct hmdfs_dentry_info_merge *dim = hmdfs_dm(dentry);
89	int count = 0;
90
91	mutex_lock(&dim->comrade_list_lock);
92	list_for_each(pos, &dim->comrade_list)
93		count++;
94	mutex_unlock(&dim->comrade_list_lock);
95	return count;
96}
97
98static struct inode *fill_inode_merge(struct super_block *sb,
99				      struct inode *parent_inode,
100				      struct dentry *child_dentry,
101				      struct dentry *lo_d_dentry)
102{
103	int ret = 0;
104	struct dentry *fst_lo_d = NULL;
105	struct hmdfs_inode_info *info = NULL;
106	struct inode *inode = NULL;
107	umode_t mode;
108
109	if (lo_d_dentry) {
110		fst_lo_d = lo_d_dentry;
111		dget(fst_lo_d);
112	} else {
113		fst_lo_d = hmdfs_get_fst_lo_d(child_dentry);
114	}
115	if (!fst_lo_d) {
116		inode = ERR_PTR(-EINVAL);
117		goto out;
118	}
119	if (hmdfs_i(parent_inode)->inode_type == HMDFS_LAYER_ZERO)
120		inode = hmdfs_iget_locked_root(sb, HMDFS_ROOT_MERGE, NULL,
121					       NULL);
122	else
123		inode = hmdfs_iget5_locked_merge(sb, fst_lo_d);
124	if (!inode) {
125		hmdfs_err("iget5_locked get inode NULL");
126		inode = ERR_PTR(-ENOMEM);
127		goto out;
128	}
129	if (!(inode->i_state & I_NEW))
130		goto out;
131	info = hmdfs_i(inode);
132	if (hmdfs_i(parent_inode)->inode_type == HMDFS_LAYER_ZERO)
133		info->inode_type = HMDFS_LAYER_FIRST_MERGE;
134	else
135		info->inode_type = HMDFS_LAYER_OTHER_MERGE;
136
137	inode->i_uid = KUIDT_INIT((uid_t)1000);
138	inode->i_gid = KGIDT_INIT((gid_t)1000);
139
140	update_inode_attr(inode, child_dentry);
141	mode = d_inode(fst_lo_d)->i_mode;
142
143	if (S_ISREG(mode)) {
144		inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
145		inode->i_op = &hmdfs_file_iops_merge;
146		inode->i_fop = &hmdfs_file_fops_merge;
147		set_nlink(inode, 1);
148	} else if (S_ISDIR(mode)) {
149		inode->i_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IXOTH;
150		inode->i_op = &hmdfs_dir_iops_merge;
151		inode->i_fop = &hmdfs_dir_fops_merge;
152		set_nlink(inode, get_num_comrades(child_dentry) + 2);
153	} else {
154		ret = -EIO;
155		goto bad_inode;
156	}
157
158	unlock_new_inode(inode);
159out:
160	dput(fst_lo_d);
161	return inode;
162bad_inode:
163	iget_failed(inode);
164	return ERR_PTR(ret);
165}
166
167struct hmdfs_dentry_comrade *alloc_comrade(struct dentry *lo_d, int dev_id)
168{
169	struct hmdfs_dentry_comrade *comrade = NULL;
170
171	// 文件只有一个 comrade,考虑 {comrade, list + list lock}
172	comrade = kzalloc(sizeof(*comrade), GFP_KERNEL);
173	if (unlikely(!comrade))
174		return ERR_PTR(-ENOMEM);
175
176	comrade->lo_d = lo_d;
177	comrade->dev_id = dev_id;
178	dget(lo_d);
179	return comrade;
180}
181
182void link_comrade(struct list_head *onstack_comrades_head,
183		  struct hmdfs_dentry_comrade *comrade)
184{
185	struct hmdfs_dentry_comrade *c = NULL;
186
187	list_for_each_entry(c, onstack_comrades_head, list) {
188		if (likely(c->dev_id != comrade->dev_id))
189			continue;
190		hmdfs_err("Redundant comrade of device %llu", c->dev_id);
191		dput(comrade->lo_d);
192		kfree(comrade);
193		WARN_ON(1);
194		return;
195	}
196
197	if (comrade_is_local(comrade))
198		list_add(&comrade->list, onstack_comrades_head);
199	else
200		list_add_tail(&comrade->list, onstack_comrades_head);
201}
202
203/**
204 * assign_comrades_unlocked - assign a child dentry with comrades
205 *
206 * We tend to setup a local list of all the comrades we found and place the
207 * list onto the dentry_info to achieve atomicity.
208 */
209void assign_comrades_unlocked(struct dentry *child_dentry,
210			      struct list_head *onstack_comrades_head)
211{
212	struct hmdfs_dentry_info_merge *cdi = hmdfs_dm(child_dentry);
213
214	mutex_lock(&cdi->comrade_list_lock);
215	WARN_ON(!list_empty(&cdi->comrade_list));
216	list_splice_init(onstack_comrades_head, &cdi->comrade_list);
217	mutex_unlock(&cdi->comrade_list_lock);
218}
219
220struct hmdfs_dentry_comrade *lookup_comrade(struct path lower_path,
221					    const char *d_name,
222					    int dev_id,
223					    unsigned int flags)
224{
225	struct path path;
226	struct hmdfs_dentry_comrade *comrade = NULL;
227	int err;
228
229	err = vfs_path_lookup(lower_path.dentry, lower_path.mnt, d_name, flags,
230			      &path);
231	if (err)
232		return ERR_PTR(err);
233
234	comrade = alloc_comrade(path.dentry, dev_id);
235	path_put(&path);
236	return comrade;
237}
238
239/**
240 * conf_name_trans_nop - do nothing but copy
241 *
242 * WARNING: always check before translation
243 */
244static char *conf_name_trans_nop(struct dentry *d)
245{
246	return kstrndup(d->d_name.name, d->d_name.len, GFP_KERNEL);
247}
248
249/**
250 * conf_name_trans_dir - conflicted name translation for directory
251 *
252 * WARNING: always check before translation
253 */
254static char *conf_name_trans_dir(struct dentry *d)
255{
256	int len = d->d_name.len - strlen(CONFLICTING_DIR_SUFFIX);
257
258	return kstrndup(d->d_name.name, len, GFP_KERNEL);
259}
260
261/**
262 * conf_name_trans_reg - conflicted name translation for regular file
263 *
264 * WARNING: always check before translation
265 */
266static char *conf_name_trans_reg(struct dentry *d, int *dev_id)
267{
268	int dot_pos, start_cpy_pos, num_len, i;
269	int len = d->d_name.len;
270	char *name = kstrndup(d->d_name.name, d->d_name.len, GFP_KERNEL);
271
272	if (unlikely(!name))
273		return NULL;
274
275	// find the last dot if possible
276	for (dot_pos = len - 1; dot_pos >= 0; dot_pos--) {
277		if (name[dot_pos] == '.')
278			break;
279	}
280	if (dot_pos == -1)
281		dot_pos = len;
282
283	// retrieve the conf sn (i.e. dev_id)
284	num_len = 0;
285	for (i = dot_pos - 1; i >= 0; i--) {
286		if (name[i] >= '0' && name[i] <= '9')
287			num_len++;
288		else
289			break;
290	}
291
292	*dev_id = 0;
293	for (i = 0; i < num_len; i++)
294		*dev_id = *dev_id * 10 + name[dot_pos - num_len + i] - '0';
295
296	// move the file suffix( '\0' included) right after the file name
297	start_cpy_pos =
298		dot_pos - num_len - strlen(CONFLICTING_FILE_CONST_SUFFIX);
299	memmove(name + start_cpy_pos, name + dot_pos, len - dot_pos + 1);
300	return name;
301}
302
303int check_filename(const char *name, int len)
304{
305	int cmp_res = 0;
306
307	if (len >= strlen(CONFLICTING_DIR_SUFFIX)) {
308		cmp_res = strncmp(name + len - strlen(CONFLICTING_DIR_SUFFIX),
309				  CONFLICTING_DIR_SUFFIX,
310				  strlen(CONFLICTING_DIR_SUFFIX));
311		if (cmp_res == 0)
312			return DT_DIR;
313	}
314
315	if (len >= strlen(CONFLICTING_FILE_CONST_SUFFIX)) {
316		int dot_pos, start_cmp_pos, num_len, i;
317
318		for (dot_pos = len - 1; dot_pos >= 0; dot_pos--) {
319			if (name[dot_pos] == '.')
320				break;
321		}
322		if (dot_pos == -1)
323			dot_pos = len;
324
325		num_len = 0;
326		for (i = dot_pos - 1; i >= 0; i--) {
327			if (name[i] >= '0' && name[i] <= '9')
328				num_len++;
329			else
330				break;
331		}
332
333		start_cmp_pos = dot_pos - num_len -
334				strlen(CONFLICTING_FILE_CONST_SUFFIX);
335		cmp_res = strncmp(name + start_cmp_pos,
336				  CONFLICTING_FILE_CONST_SUFFIX,
337				  strlen(CONFLICTING_FILE_CONST_SUFFIX));
338		if (cmp_res == 0)
339			return DT_REG;
340	}
341
342	return 0;
343}
344
345static struct hmdfs_dentry_comrade *merge_lookup_comrade(
346	struct hmdfs_sb_info *sbi, const char *name, int devid,
347	unsigned int flags)
348{
349	int err;
350	struct path root, path;
351	struct hmdfs_dentry_comrade *comrade = NULL;
352	const struct cred *old_cred = hmdfs_override_creds(sbi->cred);
353
354	err = kern_path(sbi->real_dst, LOOKUP_DIRECTORY, &root);
355	if (err) {
356		comrade = ERR_PTR(err);
357		goto out;
358	}
359
360	err = vfs_path_lookup(root.dentry, root.mnt, name, flags, &path);
361	if (err) {
362		comrade = ERR_PTR(err);
363		goto root_put;
364	}
365
366	comrade = alloc_comrade(path.dentry, devid);
367
368	path_put(&path);
369root_put:
370	path_put(&root);
371out:
372	hmdfs_revert_creds(old_cred);
373	return comrade;
374}
375
376bool is_valid_comrade(struct hmdfs_dentry_info_merge *mdi, umode_t mode)
377{
378	if (mdi->type == DT_UNKNOWN) {
379		mdi->type = S_ISDIR(mode) ? DT_DIR : DT_REG;
380		return true;
381	}
382
383	if (mdi->type == DT_DIR && S_ISDIR(mode)) {
384		return true;
385	}
386
387	if (mdi->type == DT_REG && list_empty(&mdi->comrade_list) &&
388		!S_ISDIR(mode)) {
389		return true;
390	}
391
392	return false;
393}
394
395static void merge_lookup_work_func(struct work_struct *work)
396{
397	struct merge_lookup_work *ml_work;
398	struct hmdfs_dentry_comrade *comrade;
399	struct hmdfs_dentry_info_merge *mdi;
400	int found = false;
401
402	ml_work = container_of(work, struct merge_lookup_work, work);
403	mdi = container_of(ml_work->wait_queue,	struct hmdfs_dentry_info_merge,
404		wait_queue);
405
406	trace_hmdfs_merge_lookup_work_enter(ml_work);
407
408	comrade = merge_lookup_comrade(ml_work->sbi, ml_work->name,
409		ml_work->devid, ml_work->flags);
410	if (IS_ERR(comrade)) {
411		mutex_lock(&mdi->work_lock);
412		goto out;
413	}
414
415	mutex_lock(&mdi->work_lock);
416	mutex_lock(&mdi->comrade_list_lock);
417	if (!is_valid_comrade(mdi, hmdfs_cm(comrade))) {
418		destroy_comrade(comrade);
419	} else {
420		found = true;
421		link_comrade(&mdi->comrade_list, comrade);
422	}
423	mutex_unlock(&mdi->comrade_list_lock);
424
425out:
426	if (--mdi->work_count == 0 || found)
427		wake_up_all(ml_work->wait_queue);
428	mutex_unlock(&mdi->work_lock);
429
430	trace_hmdfs_merge_lookup_work_exit(ml_work, found);
431	kfree(ml_work->name);
432	kfree(ml_work);
433}
434
435int merge_lookup_async(struct hmdfs_dentry_info_merge *mdi,
436	struct hmdfs_sb_info *sbi, int devid, const char *name,
437	unsigned int flags)
438{
439	int err = -ENOMEM;
440	struct merge_lookup_work *ml_work;
441
442	ml_work = kmalloc(sizeof(*ml_work), GFP_KERNEL);
443	if (!ml_work)
444		goto out;
445
446	ml_work->name = kstrdup(name, GFP_KERNEL);
447	if (!ml_work->name) {
448		kfree(ml_work);
449		goto out;
450	}
451
452	ml_work->devid = devid;
453	ml_work->flags = flags;
454	ml_work->sbi = sbi;
455	ml_work->wait_queue = &mdi->wait_queue;
456	INIT_WORK(&ml_work->work, merge_lookup_work_func);
457
458	schedule_work(&ml_work->work);
459	++mdi->work_count;
460	err = 0;
461out:
462	return err;
463}
464
465char *hmdfs_get_real_dname(struct dentry *dentry, int *devid, int *type)
466{
467	char *rname;
468
469	*type = check_filename(dentry->d_name.name, dentry->d_name.len);
470	if (*type == DT_REG)
471		rname = conf_name_trans_reg(dentry, devid);
472	else if (*type == DT_DIR)
473		rname = conf_name_trans_dir(dentry);
474	else
475		rname = conf_name_trans_nop(dentry);
476
477	return rname;
478}
479
480static int lookup_merge_normal(struct dentry *dentry, unsigned int flags)
481{
482	int ret = -ENOMEM;
483	int err = 0;
484	int devid = -1;
485	struct dentry *pdentry = dget_parent(dentry);
486	struct hmdfs_dentry_info_merge *mdi = hmdfs_dm(dentry);
487	struct hmdfs_sb_info *sbi = hmdfs_sb(dentry->d_sb);
488	struct hmdfs_peer *peer;
489	char *rname, *ppath, *cpath;
490
491	rname = hmdfs_get_real_dname(dentry, &devid, &mdi->type);
492	if (unlikely(!rname)) {
493		goto out;
494	}
495
496	ppath = hmdfs_merge_get_dentry_relative_path(pdentry);
497	if (unlikely(!ppath)) {
498		hmdfs_err("failed to get parent relative path");
499		goto out_rname;
500	}
501
502	cpath = kzalloc(PATH_MAX, GFP_KERNEL);
503	if (unlikely(!cpath)) {
504		hmdfs_err("failed to get child device_view path");
505		goto out_ppath;
506	}
507
508	mutex_lock(&mdi->work_lock);
509	mutex_lock(&sbi->connections.node_lock);
510	if (mdi->type != DT_REG || devid == 0) {
511		snprintf(cpath, PATH_MAX, "device_view/local%s/%s", ppath,
512			rname);
513		err = merge_lookup_async(mdi, sbi, 0, cpath, flags);
514		if (err)
515			hmdfs_err("failed to create local lookup work");
516	}
517
518	list_for_each_entry(peer, &sbi->connections.node_list, list) {
519		if (mdi->type == DT_REG && peer->device_id != devid)
520			continue;
521		snprintf(cpath, PATH_MAX, "device_view/%s%s/%s", peer->cid,
522			ppath, rname);
523		err = merge_lookup_async(mdi, sbi, peer->device_id, cpath,
524			flags);
525		if (err)
526			hmdfs_err("failed to create remote lookup work");
527	}
528	mutex_unlock(&sbi->connections.node_lock);
529	mutex_unlock(&mdi->work_lock);
530
531	wait_event(mdi->wait_queue, is_merge_lookup_end(mdi));
532
533	ret = -ENOENT;
534	if (!is_comrade_list_empty(mdi))
535		ret = 0;
536
537	kfree(cpath);
538out_ppath:
539	kfree(ppath);
540out_rname:
541	kfree(rname);
542out:
543	dput(pdentry);
544	return ret;
545}
546
547/**
548 * do_lookup_merge_root - lookup the root of the merge view(root/merge_view)
549 *
550 * It's common for a network filesystem to incur various of faults, so we
551 * intent to show mercy for faults here, except faults reported by the local.
552 */
553static int do_lookup_merge_root(struct path path_dev,
554				struct dentry *child_dentry, unsigned int flags)
555{
556	struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb);
557	struct hmdfs_dentry_comrade *comrade;
558	const int buf_len =
559		max((int)HMDFS_CID_SIZE + 1, (int)sizeof(DEVICE_VIEW_LOCAL));
560	char *buf = kzalloc(buf_len, GFP_KERNEL);
561	struct hmdfs_peer *peer;
562	LIST_HEAD(head);
563	int ret;
564
565	if (!buf)
566		return -ENOMEM;
567
568	// lookup real_dst/device_view/local
569	memcpy(buf, DEVICE_VIEW_LOCAL, sizeof(DEVICE_VIEW_LOCAL));
570	comrade = lookup_comrade(path_dev, buf, HMDFS_DEVID_LOCAL, flags);
571	if (IS_ERR(comrade)) {
572		ret = PTR_ERR(comrade);
573		goto out;
574	}
575	link_comrade(&head, comrade);
576
577	// lookup real_dst/device_view/cidxx
578	mutex_lock(&sbi->connections.node_lock);
579	list_for_each_entry(peer, &sbi->connections.node_list, list) {
580		mutex_unlock(&sbi->connections.node_lock);
581		memcpy(buf, peer->cid, HMDFS_CID_SIZE);
582		comrade = lookup_comrade(path_dev, buf, peer->device_id, flags);
583		if (IS_ERR(comrade))
584			continue;
585
586		link_comrade(&head, comrade);
587		mutex_lock(&sbi->connections.node_lock);
588	}
589	mutex_unlock(&sbi->connections.node_lock);
590
591	assign_comrades_unlocked(child_dentry, &head);
592	ret = 0;
593
594out:
595	kfree(buf);
596	return ret;
597}
598
599// mkdir -p
600void lock_root_inode_shared(struct inode *root, bool *locked, bool *down)
601{
602	struct rw_semaphore *sem = &root->i_rwsem;
603#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
604#define RWSEM_READER_OWNED     (1UL << 0)
605#define RWSEM_RD_NONSPINNABLE  (1UL << 1)
606#define RWSEM_WR_NONSPINNABLE  (1UL << 2)
607#define RWSEM_NONSPINNABLE     (RWSEM_RD_NONSPINNABLE | RWSEM_WR_NONSPINNABLE)
608#define RWSEM_OWNER_FLAGS_MASK (RWSEM_READER_OWNED | RWSEM_NONSPINNABLE)
609	struct task_struct *sem_owner =
610		(struct task_struct *)(atomic_long_read(&sem->owner) &
611				       ~RWSEM_OWNER_FLAGS_MASK);
612#else
613	struct task_struct *sem_owner = sem->owner;
614#endif
615
616	*locked = false;
617	*down = false;
618
619	if (sem_owner != current)
620		return;
621
622	// It's us that takes the wsem
623	if (!inode_trylock_shared(root)) {
624		downgrade_write(sem);
625		*down = true;
626	}
627	*locked = true;
628}
629
630void restore_root_inode_sem(struct inode *root, bool locked, bool down)
631{
632	if (!locked)
633		return;
634
635	inode_unlock_shared(root);
636	if (down)
637		inode_lock(root);
638}
639
640static int lookup_merge_root(struct inode *root_inode,
641			     struct dentry *child_dentry, unsigned int flags)
642{
643	struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb);
644	struct path path_dev;
645	int ret = -ENOENT;
646	int buf_len;
647	char *buf = NULL;
648	bool locked, down;
649
650	// consider additional one slash and one '\0'
651	buf_len = strlen(sbi->real_dst) + 1 + sizeof(DEVICE_VIEW_ROOT);
652	if (buf_len > PATH_MAX)
653		return -ENAMETOOLONG;
654
655	buf = kmalloc(buf_len, GFP_KERNEL);
656	if (unlikely(!buf))
657		return -ENOMEM;
658
659	sprintf(buf, "%s/%s", sbi->real_dst, DEVICE_VIEW_ROOT);
660	lock_root_inode_shared(root_inode, &locked, &down);
661	ret = hmdfs_get_path_in_sb(child_dentry->d_sb, buf, LOOKUP_DIRECTORY,
662				   &path_dev);
663	if (ret)
664		goto free_buf;
665
666	ret = do_lookup_merge_root(path_dev, child_dentry, flags);
667	path_put(&path_dev);
668
669free_buf:
670	kfree(buf);
671	restore_root_inode_sem(root_inode, locked, down);
672	return ret;
673}
674
675int init_hmdfs_dentry_info_merge(struct hmdfs_sb_info *sbi,
676	struct dentry *dentry)
677{
678	struct hmdfs_dentry_info_merge *mdi = NULL;
679
680	mdi = kmem_cache_zalloc(hmdfs_dentry_merge_cachep, GFP_NOFS);
681	if (!mdi)
682		return -ENOMEM;
683
684	mdi->ctime = jiffies;
685	mdi->type = DT_UNKNOWN;
686	mdi->work_count = 0;
687	mutex_init(&mdi->work_lock);
688	init_waitqueue_head(&mdi->wait_queue);
689	INIT_LIST_HEAD(&mdi->comrade_list);
690	mutex_init(&mdi->comrade_list_lock);
691
692	d_set_d_op(dentry, &hmdfs_dops_merge);
693	dentry->d_fsdata = mdi;
694	return 0;
695}
696
697// do this in a map-reduce manner
698struct dentry *hmdfs_lookup_merge(struct inode *parent_inode,
699				  struct dentry *child_dentry,
700				  unsigned int flags)
701{
702	bool create = flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET);
703	struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb);
704	struct hmdfs_inode_info *pii = hmdfs_i(parent_inode);
705	struct inode *child_inode = NULL;
706	struct dentry *ret_dentry = NULL;
707	int err = 0;
708
709	/*
710	 * Internal flags like LOOKUP_CREATE should not pass to device view.
711	 * LOOKUP_REVAL is needed because dentry cache in hmdfs might be stale
712	 * after rename in lower fs. LOOKUP_DIRECTORY is not needed because
713	 * merge_view can do the judgement that whether result is directory or
714	 * not.
715	 */
716	flags = flags & LOOKUP_REVAL;
717
718	child_dentry->d_fsdata = NULL;
719
720	if (child_dentry->d_name.len > NAME_MAX) {
721		err = -ENAMETOOLONG;
722		goto out;
723	}
724
725	err = init_hmdfs_dentry_info_merge(sbi, child_dentry);
726	if (unlikely(err))
727		goto out;
728
729	if (pii->inode_type == HMDFS_LAYER_ZERO) {
730		hmdfs_dm(child_dentry)->dentry_type = HMDFS_LAYER_FIRST_MERGE;
731		err = lookup_merge_root(parent_inode, child_dentry, flags);
732	} else {
733		hmdfs_dm(child_dentry)->dentry_type = HMDFS_LAYER_OTHER_MERGE;
734		err = lookup_merge_normal(child_dentry, flags);
735	}
736
737	if (!err) {
738		struct hmdfs_inode_info *info = NULL;
739
740		child_inode = fill_inode_merge(parent_inode->i_sb, parent_inode,
741					       child_dentry, NULL);
742		if (IS_ERR(child_inode)) {
743			err = PTR_ERR(child_inode);
744			goto out;
745		}
746		info = hmdfs_i(child_inode);
747		if (info->inode_type == HMDFS_LAYER_FIRST_MERGE)
748			hmdfs_root_inode_perm_init(child_inode);
749		else
750			check_and_fixup_ownership_remote(parent_inode,
751							 child_inode,
752							 child_dentry);
753
754		ret_dentry = d_splice_alias(child_inode, child_dentry);
755		if (IS_ERR(ret_dentry)) {
756			clear_comrades(child_dentry);
757			err = PTR_ERR(ret_dentry);
758			goto out;
759		}
760		if (ret_dentry)
761			child_dentry = ret_dentry;
762
763		goto out;
764	}
765
766	if ((err == -ENOENT) && create)
767		err = 0;
768
769out:
770	return err ? ERR_PTR(err) : ret_dentry;
771}
772
773int hmdfs_getattr_merge(const struct path *path, struct kstat *stat,
774			       u32 request_mask, unsigned int flags)
775{
776	int ret;
777	struct path lower_path = {
778		.dentry = hmdfs_get_fst_lo_d(path->dentry),
779		.mnt = path->mnt,
780	};
781
782	if (unlikely(!lower_path.dentry)) {
783		hmdfs_err("Fatal! No comrades");
784		ret = -EINVAL;
785		goto out;
786	}
787
788	ret = vfs_getattr(&lower_path, stat, request_mask, flags);
789out:
790	dput(lower_path.dentry);
791	return ret;
792}
793
794int hmdfs_setattr_merge(struct dentry *dentry, struct iattr *ia)
795{
796	struct inode *inode = d_inode(dentry);
797	struct dentry *lower_dentry = hmdfs_get_fst_lo_d(dentry);
798	struct inode *lower_inode = NULL;
799	struct iattr lower_ia;
800	unsigned int ia_valid = ia->ia_valid;
801	int err = 0;
802	kuid_t tmp_uid;
803
804	if (!lower_dentry) {
805		WARN_ON(1);
806		err = -EINVAL;
807		goto out;
808	}
809
810	lower_inode = d_inode(lower_dentry);
811	memcpy(&lower_ia, ia, sizeof(lower_ia));
812	if (ia_valid & ATTR_FILE)
813		lower_ia.ia_file = hmdfs_f(ia->ia_file)->lower_file;
814	lower_ia.ia_valid &= ~(ATTR_UID | ATTR_GID | ATTR_MODE);
815
816	inode_lock(lower_inode);
817	tmp_uid = hmdfs_override_inode_uid(lower_inode);
818
819	err = notify_change(lower_dentry, &lower_ia, NULL);
820	i_size_write(inode, i_size_read(lower_inode));
821	inode->i_atime = lower_inode->i_atime;
822	inode->i_mtime = lower_inode->i_mtime;
823	inode->i_ctime = lower_inode->i_ctime;
824	hmdfs_revert_inode_uid(lower_inode, tmp_uid);
825
826	inode_unlock(lower_inode);
827
828out:
829	dput(lower_dentry);
830	return err;
831}
832
833const struct inode_operations hmdfs_file_iops_merge = {
834	.getattr = hmdfs_getattr_merge,
835	.setattr = hmdfs_setattr_merge,
836	.permission = hmdfs_permission,
837};
838
839int do_mkdir_merge(struct inode *parent_inode, struct dentry *child_dentry,
840		   umode_t mode, struct inode *lo_i_parent,
841		   struct dentry *lo_d_child)
842{
843	int ret = 0;
844	struct super_block *sb = parent_inode->i_sb;
845	struct inode *child_inode = NULL;
846
847	ret = vfs_mkdir(lo_i_parent, lo_d_child, mode);
848	if (ret)
849		goto out;
850
851	child_inode =
852		fill_inode_merge(sb, parent_inode, child_dentry, lo_d_child);
853	if (IS_ERR(child_inode)) {
854		ret = PTR_ERR(child_inode);
855		goto out;
856	}
857	check_and_fixup_ownership_remote(parent_inode, child_inode,
858					 child_dentry);
859
860	d_add(child_dentry, child_inode);
861	/* nlink should be increased with the joining of children */
862	set_nlink(parent_inode, 2);
863out:
864	return ret;
865}
866
867int do_create_merge(struct inode *parent_inode, struct dentry *child_dentry,
868		    umode_t mode, bool want_excl, struct inode *lo_i_parent,
869		    struct dentry *lo_d_child)
870{
871	int ret = 0;
872	struct super_block *sb = parent_inode->i_sb;
873	struct inode *child_inode = NULL;
874
875	ret = vfs_create(lo_i_parent, lo_d_child, mode, want_excl);
876	if (ret)
877		goto out;
878
879	child_inode =
880		fill_inode_merge(sb, parent_inode, child_dentry, lo_d_child);
881	if (IS_ERR(child_inode)) {
882		ret = PTR_ERR(child_inode);
883		goto out;
884	}
885	check_and_fixup_ownership_remote(parent_inode, child_inode,
886					 child_dentry);
887
888	d_add(child_dentry, child_inode);
889	/* nlink should be increased with the joining of children */
890	set_nlink(parent_inode, 2);
891out:
892	return ret;
893}
894
895int hmdfs_do_ops_merge(struct inode *i_parent, struct dentry *d_child,
896		       struct dentry *lo_d_child, struct path path,
897		       struct hmdfs_recursive_para *rec_op_para)
898{
899	int ret = 0;
900
901	if (rec_op_para->is_last) {
902		switch (rec_op_para->opcode) {
903		case F_MKDIR_MERGE:
904			ret = do_mkdir_merge(i_parent, d_child,
905					     rec_op_para->mode,
906					     d_inode(path.dentry), lo_d_child);
907			break;
908		case F_CREATE_MERGE:
909			ret = do_create_merge(i_parent, d_child,
910					      rec_op_para->mode,
911					      rec_op_para->want_excl,
912					      d_inode(path.dentry), lo_d_child);
913			break;
914		default:
915			ret = -EINVAL;
916			break;
917		}
918	} else {
919		ret = vfs_mkdir(d_inode(path.dentry), lo_d_child,
920				rec_op_para->mode);
921	}
922	if (ret)
923		hmdfs_err("vfs_ops failed, ops %d, err = %d",
924			  rec_op_para->opcode, ret);
925	return ret;
926}
927
928int hmdfs_create_lower_dentry(struct inode *i_parent, struct dentry *d_child,
929			      struct dentry *lo_d_parent, bool is_dir,
930			      struct hmdfs_recursive_para *rec_op_para)
931{
932	struct hmdfs_sb_info *sbi = i_parent->i_sb->s_fs_info;
933	struct hmdfs_dentry_comrade *new_comrade = NULL;
934	struct dentry *lo_d_child = NULL;
935	char *path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
936	char *absolute_path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
937	char *path_name = NULL;
938	struct path path = { .mnt = NULL, .dentry = NULL };
939	int ret = 0;
940
941	if (unlikely(!path_buf || !absolute_path_buf)) {
942		ret = -ENOMEM;
943		goto out;
944	}
945
946	path_name = dentry_path_raw(lo_d_parent, path_buf, PATH_MAX);
947	if (IS_ERR(path_name)) {
948		ret = PTR_ERR(path_name);
949		goto out;
950	}
951	if ((strlen(sbi->real_dst) + strlen(path_name) +
952	     strlen(d_child->d_name.name) + 2) > PATH_MAX) {
953		ret = -ENAMETOOLONG;
954		goto out;
955	}
956
957	sprintf(absolute_path_buf, "%s%s/%s", sbi->real_dst, path_name,
958		d_child->d_name.name);
959
960	if (is_dir)
961		lo_d_child = kern_path_create(AT_FDCWD, absolute_path_buf,
962					      &path, LOOKUP_DIRECTORY);
963	else
964		lo_d_child = kern_path_create(AT_FDCWD, absolute_path_buf,
965					      &path, 0);
966	if (IS_ERR(lo_d_child)) {
967		ret = PTR_ERR(lo_d_child);
968		goto out;
969	}
970	// to ensure link_comrade after vfs_mkdir succeed
971	ret = hmdfs_do_ops_merge(i_parent, d_child, lo_d_child, path,
972				 rec_op_para);
973	if (ret)
974		goto out_put;
975	new_comrade = alloc_comrade(lo_d_child, HMDFS_DEVID_LOCAL);
976	if (IS_ERR(new_comrade)) {
977		ret = PTR_ERR(new_comrade);
978		goto out_put;
979	} else {
980		link_comrade_unlocked(d_child, new_comrade);
981	}
982
983	update_inode_attr(d_inode(d_child), d_child);
984
985out_put:
986	done_path_create(&path, lo_d_child);
987out:
988	kfree(absolute_path_buf);
989	kfree(path_buf);
990	return ret;
991}
992
993static int create_lo_d_parent_recur(struct dentry *d_parent,
994				    struct dentry *d_child, umode_t mode,
995				    struct hmdfs_recursive_para *rec_op_para)
996{
997	struct dentry *lo_d_parent, *d_pparent;
998	struct hmdfs_dentry_info_merge *pmdi = NULL;
999	int ret = 0;
1000
1001	pmdi = hmdfs_dm(d_parent);
1002	wait_event(pmdi->wait_queue, !has_merge_lookup_work(pmdi));
1003	lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
1004	if (!lo_d_parent) {
1005		d_pparent = dget_parent(d_parent);
1006		ret = create_lo_d_parent_recur(d_pparent, d_parent,
1007					       d_inode(d_parent)->i_mode,
1008					       rec_op_para);
1009		dput(d_pparent);
1010		if (ret)
1011			goto out;
1012		lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
1013		if (!lo_d_parent) {
1014			ret = -ENOENT;
1015			goto out;
1016		}
1017	}
1018	rec_op_para->is_last = false;
1019	rec_op_para->mode = mode;
1020	ret = hmdfs_create_lower_dentry(d_inode(d_parent), d_child, lo_d_parent,
1021					true, rec_op_para);
1022out:
1023	dput(lo_d_parent);
1024	return ret;
1025}
1026
1027int create_lo_d_child(struct inode *i_parent, struct dentry *d_child,
1028		      bool is_dir, struct hmdfs_recursive_para *rec_op_para)
1029{
1030	struct dentry *d_pparent, *lo_d_parent, *lo_d_child;
1031	struct dentry *d_parent = dget_parent(d_child);
1032	struct hmdfs_dentry_info_merge *pmdi = hmdfs_dm(d_parent);
1033	int ret = 0;
1034	mode_t d_child_mode = rec_op_para->mode;
1035
1036	wait_event(pmdi->wait_queue, !has_merge_lookup_work(pmdi));
1037
1038	lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
1039	if (!lo_d_parent) {
1040		d_pparent = dget_parent(d_parent);
1041		ret = create_lo_d_parent_recur(d_pparent, d_parent,
1042					       d_inode(d_parent)->i_mode,
1043					       rec_op_para);
1044		dput(d_pparent);
1045		if (unlikely(ret)) {
1046			lo_d_child = ERR_PTR(ret);
1047			goto out;
1048		}
1049		lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
1050		if (!lo_d_parent) {
1051			lo_d_child = ERR_PTR(-ENOENT);
1052			goto out;
1053		}
1054	}
1055	rec_op_para->is_last = true;
1056	rec_op_para->mode = d_child_mode;
1057	ret = hmdfs_create_lower_dentry(i_parent, d_child, lo_d_parent, is_dir,
1058					rec_op_para);
1059
1060out:
1061	dput(d_parent);
1062	dput(lo_d_parent);
1063	return ret;
1064}
1065
1066void hmdfs_init_recursive_para(struct hmdfs_recursive_para *rec_op_para,
1067			       int opcode, mode_t mode, bool want_excl,
1068			       const char *name)
1069{
1070	rec_op_para->is_last = true;
1071	rec_op_para->opcode = opcode;
1072	rec_op_para->mode = mode;
1073	rec_op_para->want_excl = want_excl;
1074	rec_op_para->name = name;
1075}
1076
1077int hmdfs_mkdir_merge(struct inode *dir, struct dentry *dentry, umode_t mode)
1078{
1079	int ret = 0;
1080	struct hmdfs_recursive_para *rec_op_para = NULL;
1081
1082	// confict_name  & file_type is checked by hmdfs_mkdir_local
1083	if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON) {
1084		ret = -EACCES;
1085		goto out;
1086	}
1087	rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL);
1088	if (!rec_op_para) {
1089		ret = -ENOMEM;
1090		goto out;
1091	}
1092
1093	hmdfs_init_recursive_para(rec_op_para, F_MKDIR_MERGE, mode, false,
1094				  NULL);
1095	ret = create_lo_d_child(dir, dentry, true, rec_op_para);
1096out:
1097	hmdfs_trace_merge(trace_hmdfs_mkdir_merge, dir, dentry, ret);
1098	if (ret)
1099		d_drop(dentry);
1100	kfree(rec_op_para);
1101	return ret;
1102}
1103
1104int hmdfs_create_merge(struct inode *dir, struct dentry *dentry, umode_t mode,
1105		       bool want_excl)
1106{
1107	struct hmdfs_recursive_para *rec_op_para = NULL;
1108	int ret = 0;
1109
1110	rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL);
1111	if (!rec_op_para) {
1112		ret = -ENOMEM;
1113		goto out;
1114	}
1115	hmdfs_init_recursive_para(rec_op_para, F_CREATE_MERGE, mode, want_excl,
1116				  NULL);
1117	// confict_name  & file_type is checked by hmdfs_create_local
1118	ret = create_lo_d_child(dir, dentry, false, rec_op_para);
1119out:
1120	hmdfs_trace_merge(trace_hmdfs_create_merge, dir, dentry, ret);
1121	if (ret)
1122		d_drop(dentry);
1123	kfree(rec_op_para);
1124	return ret;
1125}
1126
1127int do_rmdir_merge(struct inode *dir, struct dentry *dentry)
1128{
1129	int ret = 0;
1130	struct hmdfs_dentry_info_merge *dim = hmdfs_dm(dentry);
1131	struct hmdfs_dentry_comrade *comrade = NULL;
1132	struct dentry *lo_d = NULL;
1133	struct dentry *lo_d_dir = NULL;
1134	struct inode *lo_i_dir = NULL;
1135
1136	wait_event(dim->wait_queue, !has_merge_lookup_work(dim));
1137
1138	mutex_lock(&dim->comrade_list_lock);
1139	list_for_each_entry(comrade, &(dim->comrade_list), list) {
1140		lo_d = comrade->lo_d;
1141		lo_d_dir = lock_parent(lo_d);
1142		lo_i_dir = d_inode(lo_d_dir);
1143		ret = vfs_rmdir(lo_i_dir, lo_d);
1144		unlock_dir(lo_d_dir);
1145		if (ret)
1146			break;
1147	}
1148	mutex_unlock(&dim->comrade_list_lock);
1149	hmdfs_trace_merge(trace_hmdfs_rmdir_merge, dir, dentry, ret);
1150	return ret;
1151}
1152
1153int hmdfs_rmdir_merge(struct inode *dir, struct dentry *dentry)
1154{
1155	int ret = 0;
1156
1157	if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON) {
1158		ret = -EACCES;
1159		goto out;
1160	}
1161
1162	ret = do_rmdir_merge(dir, dentry);
1163	if (ret) {
1164		hmdfs_err("rm dir failed:%d", ret);
1165		goto out;
1166	}
1167
1168	hmdfs_update_meta(dir);
1169	d_drop(dentry);
1170out:
1171	hmdfs_trace_merge(trace_hmdfs_rmdir_merge, dir, dentry, ret);
1172	return ret;
1173}
1174
1175int do_unlink_merge(struct inode *dir, struct dentry *dentry)
1176{
1177	int ret = 0;
1178	struct hmdfs_dentry_info_merge *dim = hmdfs_dm(dentry);
1179	struct hmdfs_dentry_comrade *comrade = NULL;
1180	struct dentry *lo_d = NULL;
1181	struct dentry *lo_d_dir = NULL;
1182	struct dentry *lo_d_lookup = NULL;
1183	struct inode *lo_i_dir = NULL;
1184
1185	wait_event(dim->wait_queue, !has_merge_lookup_work(dim));
1186
1187	mutex_lock(&dim->comrade_list_lock);
1188	list_for_each_entry(comrade, &(dim->comrade_list), list) {
1189		lo_d = comrade->lo_d;
1190		dget(lo_d);
1191		lo_d_dir = lock_parent(lo_d);
1192		/* lo_d could be unhashed, need to lookup again here */
1193		lo_d_lookup = lookup_one_len(lo_d->d_name.name, lo_d_dir,
1194					     strlen(lo_d->d_name.name));
1195		if (IS_ERR(lo_d_lookup)) {
1196			ret = PTR_ERR(lo_d_lookup);
1197			hmdfs_err("lookup_one_len failed, err = %d", ret);
1198			unlock_dir(lo_d_dir);
1199			dput(lo_d);
1200			break;
1201		}
1202		lo_i_dir = d_inode(lo_d_dir);
1203		ret = vfs_unlink(lo_i_dir, lo_d_lookup, NULL);
1204		dput(lo_d_lookup);
1205		unlock_dir(lo_d_dir);
1206		dput(lo_d);
1207		if (ret)
1208			break;
1209	}
1210	mutex_unlock(&dim->comrade_list_lock);
1211
1212	return ret;
1213}
1214
1215int hmdfs_unlink_merge(struct inode *dir, struct dentry *dentry)
1216{
1217	int ret = 0;
1218
1219	if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON) {
1220		ret = -EACCES;
1221		goto out;
1222	}
1223
1224	ret = do_unlink_merge(dir, dentry);
1225	if (ret) {
1226		hmdfs_err("unlink failed:%d", ret);
1227		goto out;
1228	} else {
1229		hmdfs_update_meta(dir);
1230	}
1231
1232	d_drop(dentry);
1233out:
1234	return ret;
1235}
1236
1237int do_rename_merge(struct inode *old_dir, struct dentry *old_dentry,
1238		    struct inode *new_dir, struct dentry *new_dentry,
1239		    unsigned int flags)
1240{
1241	int ret = 0;
1242	struct hmdfs_sb_info *sbi = (old_dir->i_sb)->s_fs_info;
1243	struct hmdfs_dentry_info_merge *dim = hmdfs_dm(old_dentry);
1244	struct hmdfs_dentry_comrade *comrade = NULL, *new_comrade = NULL;
1245	struct path lo_p_new = { .mnt = NULL, .dentry = NULL };
1246	struct inode *lo_i_old_dir = NULL, *lo_i_new_dir = NULL;
1247	struct dentry *lo_d_old_dir = NULL, *lo_d_old = NULL,
1248		      *lo_d_new_dir = NULL, *lo_d_new = NULL;
1249	struct dentry *d_new_dir = NULL;
1250	char *path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
1251	char *abs_path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
1252	char *path_name = NULL;
1253	struct hmdfs_dentry_info_merge *pmdi = NULL;
1254
1255	if (flags & ~RENAME_NOREPLACE) {
1256		ret = -EINVAL;
1257		goto out;
1258	}
1259
1260	if (unlikely(!path_buf || !abs_path_buf)) {
1261		ret = -ENOMEM;
1262		goto out;
1263	}
1264
1265	wait_event(dim->wait_queue, !has_merge_lookup_work(dim));
1266
1267	list_for_each_entry(comrade, &dim->comrade_list, list) {
1268		lo_d_old = comrade->lo_d;
1269		d_new_dir = d_find_alias(new_dir);
1270		pmdi = hmdfs_dm(d_new_dir);
1271		wait_event(pmdi->wait_queue, !has_merge_lookup_work(pmdi));
1272		lo_d_new_dir = hmdfs_get_lo_d(d_new_dir, comrade->dev_id);
1273		dput(d_new_dir);
1274
1275		if (!lo_d_new_dir)
1276			continue;
1277		path_name = dentry_path_raw(lo_d_new_dir, path_buf, PATH_MAX);
1278		dput(lo_d_new_dir);
1279		if (IS_ERR(path_name)) {
1280			ret = PTR_ERR(path_name);
1281			continue;
1282		}
1283
1284		if (strlen(sbi->real_dst) + strlen(path_name) +
1285		    strlen(new_dentry->d_name.name) + 2 > PATH_MAX) {
1286			ret = -ENAMETOOLONG;
1287			goto out;
1288		}
1289
1290		snprintf(abs_path_buf, PATH_MAX, "%s%s/%s", sbi->real_dst,
1291			 path_name, new_dentry->d_name.name);
1292		if (S_ISDIR(d_inode(old_dentry)->i_mode))
1293			lo_d_new = kern_path_create(AT_FDCWD, abs_path_buf,
1294						    &lo_p_new,
1295						    LOOKUP_DIRECTORY);
1296		else
1297			lo_d_new = kern_path_create(AT_FDCWD, abs_path_buf,
1298						    &lo_p_new, 0);
1299		if (IS_ERR(lo_d_new)) {
1300			ret = PTR_ERR(lo_d_new);
1301			goto out;
1302		}
1303
1304		lo_d_new_dir = dget_parent(lo_d_new);
1305		lo_i_new_dir = d_inode(lo_d_new_dir);
1306		lo_d_old_dir = dget_parent(lo_d_old);
1307		lo_i_old_dir = d_inode(lo_d_old_dir);
1308
1309		ret = vfs_rename(lo_i_old_dir, lo_d_old, lo_i_new_dir, lo_d_new,
1310				 NULL, flags);
1311		new_comrade = alloc_comrade(lo_p_new.dentry, comrade->dev_id);
1312		if (IS_ERR(new_comrade)) {
1313			ret = PTR_ERR(new_comrade);
1314			goto no_comrade;
1315		}
1316
1317		link_comrade_unlocked(new_dentry, new_comrade);
1318no_comrade:
1319		done_path_create(&lo_p_new, lo_d_new);
1320		dput(lo_d_old_dir);
1321		dput(lo_d_new_dir);
1322	}
1323out:
1324	kfree(abs_path_buf);
1325	kfree(path_buf);
1326	return ret;
1327}
1328
1329int hmdfs_rename_merge(struct inode *old_dir, struct dentry *old_dentry,
1330		       struct inode *new_dir, struct dentry *new_dentry,
1331		       unsigned int flags)
1332{
1333	char *old_dir_buf = NULL;
1334	char *new_dir_buf = NULL;
1335	char *old_dir_path = NULL;
1336	char *new_dir_path = NULL;
1337	struct dentry *old_dir_dentry = NULL;
1338	struct dentry *new_dir_dentry = NULL;
1339	int ret = 0;
1340
1341	if (hmdfs_file_type(old_dentry->d_name.name) != HMDFS_TYPE_COMMON ||
1342	    hmdfs_file_type(new_dentry->d_name.name) != HMDFS_TYPE_COMMON) {
1343		ret = -EACCES;
1344		goto rename_out;
1345	}
1346
1347	if (hmdfs_i(old_dir)->inode_type != hmdfs_i(new_dir)->inode_type) {
1348		hmdfs_err("in different view");
1349		ret = -EPERM;
1350		goto rename_out;
1351	}
1352
1353	old_dir_buf = kmalloc(PATH_MAX, GFP_KERNEL);
1354	new_dir_buf = kmalloc(PATH_MAX, GFP_KERNEL);
1355	if (!old_dir_buf || !new_dir_buf) {
1356		ret = -ENOMEM;
1357		goto rename_out;
1358	}
1359
1360	new_dir_dentry = d_find_alias(new_dir);
1361	if (!new_dir_dentry) {
1362		ret = -EINVAL;
1363		goto rename_out;
1364	}
1365
1366	old_dir_dentry = d_find_alias(old_dir);
1367	if (!old_dir_dentry) {
1368		ret = -EINVAL;
1369		dput(new_dir_dentry);
1370		goto rename_out;
1371	}
1372
1373	old_dir_path = dentry_path_raw(old_dir_dentry, old_dir_buf, PATH_MAX);
1374	new_dir_path = dentry_path_raw(new_dir_dentry, new_dir_buf, PATH_MAX);
1375	dput(new_dir_dentry);
1376	dput(old_dir_dentry);
1377	if (strcmp(old_dir_path, new_dir_path)) {
1378		ret = -EPERM;
1379		goto rename_out;
1380	}
1381
1382	trace_hmdfs_rename_merge(old_dir, old_dentry, new_dir, new_dentry,
1383				 flags);
1384	ret = do_rename_merge(old_dir, old_dentry, new_dir, new_dentry, flags);
1385
1386	if (ret != 0)
1387		d_drop(new_dentry);
1388
1389	if (S_ISREG(old_dentry->d_inode->i_mode) && !ret)
1390		d_invalidate(old_dentry);
1391
1392rename_out:
1393	kfree(old_dir_buf);
1394	kfree(new_dir_buf);
1395	return ret;
1396}
1397
1398const struct inode_operations hmdfs_dir_iops_merge = {
1399	.lookup = hmdfs_lookup_merge,
1400	.mkdir = hmdfs_mkdir_merge,
1401	.create = hmdfs_create_merge,
1402	.rmdir = hmdfs_rmdir_merge,
1403	.unlink = hmdfs_unlink_merge,
1404	.rename = hmdfs_rename_merge,
1405	.permission = hmdfs_permission,
1406};
1407