• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
fill_inode_merge(struct super_block * sb,struct inode * parent_inode,struct dentry * child_dentry,struct dentry * lo_d_dentry)22 static 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);
83 out:
84 	dput(fst_lo_d);
85 	return inode;
86 bad_inode:
87 	iget_failed(inode);
88 	return ERR_PTR(ret);
89 }
90 
91 static struct hmdfs_dentry_comrade *
cloud_merge_lookup_comrade(struct hmdfs_sb_info * sbi,const char * name,int devid,unsigned int flags)92 cloud_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);
116 root_put:
117 	path_put(&root);
118 out:
119 	return comrade;
120 }
121 
merge_lookup_sync(struct hmdfs_dentry_info_merge * mdi,struct hmdfs_sb_info * sbi,int devid,const char * name,unsigned int flags)122 static 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 
lookup_merge_normal(struct dentry * dentry,unsigned int flags)144 static 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 	mutex_lock(&mdi->work_lock);
183 	merge_lookup_async(mdi, sbi, CLOUD_DEVICE, cpath, flags);
184 	mutex_unlock(&mdi->work_lock);
185 	if (is_comrade_list_empty(mdi))
186 		wait_event(mdi->wait_queue, is_merge_lookup_end(mdi));
187 
188 	ret = -ENOENT;
189 	if (!is_comrade_list_empty(mdi))
190 		ret = 0;
191 
192 found:
193 	kfree(cpath);
194 out_ppath:
195 	kfree(ppath);
196 out_rname:
197 	kfree(rname);
198 out:
199 	dput(pdentry);
200 	return ret;
201 }
202 
203 /**
204  * do_lookup_merge_root - lookup the root of the merge view(root/merge_view)
205  *
206  * It's common for a network filesystem to incur various of faults, so we
207  * intent to show mercy for faults here, except faults reported by the local.
208  */
do_lookup_cloud_merge_root(struct path path_dev,struct dentry * child_dentry,unsigned int flags)209 static int do_lookup_cloud_merge_root(struct path path_dev,
210 				struct dentry *child_dentry, unsigned int flags)
211 {
212 	struct hmdfs_dentry_comrade *comrade;
213 	const int buf_len =
214 		max((int)HMDFS_CID_SIZE + 1, (int)sizeof(DEVICE_VIEW_LOCAL));
215 	char *buf = kzalloc(buf_len, GFP_KERNEL);
216 	LIST_HEAD(head);
217 	int ret;
218 
219 	if (!buf)
220 		return -ENOMEM;
221 
222 	// lookup real_dst/device_view/local
223 	memcpy(buf, DEVICE_VIEW_LOCAL, sizeof(DEVICE_VIEW_LOCAL));
224 	comrade = lookup_comrade(path_dev, buf, HMDFS_DEVID_LOCAL, flags);
225 	if (IS_ERR(comrade)) {
226 		ret = PTR_ERR(comrade);
227 		goto out;
228 	}
229 	link_comrade(&head, comrade);
230 
231 	memcpy(buf, CLOUD_CID, 6);
232 	buf[5] = '\0';
233 	comrade = lookup_comrade(path_dev, buf, CLOUD_DEVICE, flags);
234 	if (IS_ERR(comrade)) {
235 		ret = 0;
236 		goto out;
237 	}
238 
239 	link_comrade(&head, comrade);
240 
241 	assign_comrades_unlocked(child_dentry, &head);
242 	ret = 0;
243 
244 out:
245 	kfree(buf);
246 	return ret;
247 }
248 
lookup_cloud_merge_root(struct inode * root_inode,struct dentry * child_dentry,unsigned int flags)249 static int lookup_cloud_merge_root(struct inode *root_inode,
250 			     struct dentry *child_dentry, unsigned int flags)
251 {
252 	struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb);
253 	struct path path_dev;
254 	int ret = -ENOENT;
255 	int buf_len;
256 	char *buf = NULL;
257 	bool locked, down;
258 
259 	// consider additional one slash and one '\0'
260 	buf_len = strlen(sbi->real_dst) + 1 + sizeof(DEVICE_VIEW_ROOT);
261 	if (buf_len > PATH_MAX)
262 		return -ENAMETOOLONG;
263 
264 	buf = kmalloc(buf_len, GFP_KERNEL);
265 	if (unlikely(!buf))
266 		return -ENOMEM;
267 
268 	sprintf(buf, "%s/%s", sbi->real_dst, DEVICE_VIEW_ROOT);
269 	lock_root_inode_shared(root_inode, &locked, &down);
270 	ret = hmdfs_get_path_in_sb(child_dentry->d_sb, buf, LOOKUP_DIRECTORY,
271 				   &path_dev);
272 	if (ret)
273 		goto free_buf;
274 
275 	ret = do_lookup_cloud_merge_root(path_dev, child_dentry, flags);
276 	path_put(&path_dev);
277 
278 free_buf:
279 	kfree(buf);
280 	restore_root_inode_sem(root_inode, locked, down);
281 	return ret;
282 }
283 
284 // do this in a map-reduce manner
hmdfs_lookup_cloud_merge(struct inode * parent_inode,struct dentry * child_dentry,unsigned int flags)285 struct dentry *hmdfs_lookup_cloud_merge(struct inode *parent_inode,
286 				  struct dentry *child_dentry,
287 				  unsigned int flags)
288 {
289 	bool create = flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET);
290 	struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb);
291 	struct hmdfs_inode_info *pii = hmdfs_i(parent_inode);
292 	struct inode *child_inode = NULL;
293 	struct dentry *ret_dentry = NULL;
294 	int err = 0;
295 
296 	/*
297 	 * Internal flags like LOOKUP_CREATE should not pass to device view.
298 	 * LOOKUP_REVAL is needed because dentry cache in hmdfs might be stale
299 	 * after rename in lower fs. LOOKUP_DIRECTORY is not needed because
300 	 * merge_view can do the judgement that whether result is directory or
301 	 * not.
302 	 */
303 	flags = flags & LOOKUP_REVAL;
304 
305 	child_dentry->d_fsdata = NULL;
306 
307 	if (child_dentry->d_name.len > NAME_MAX) {
308 		err = -ENAMETOOLONG;
309 		goto out;
310 	}
311 
312 	err = init_hmdfs_dentry_info_merge(sbi, child_dentry);
313 	if (unlikely(err))
314 		goto out;
315 
316 	if (pii->inode_type == HMDFS_LAYER_ZERO) {
317 		hmdfs_dm(child_dentry)->dentry_type = HMDFS_LAYER_FIRST_MERGE_CLOUD;
318 		err = lookup_cloud_merge_root(parent_inode, child_dentry, flags);
319 	} else {
320 		hmdfs_dm(child_dentry)->dentry_type = HMDFS_LAYER_OTHER_MERGE_CLOUD;
321 		err = lookup_merge_normal(child_dentry, flags);
322 	}
323 
324 	if (!err) {
325 		struct hmdfs_inode_info *info = NULL;
326 
327 		child_inode = fill_inode_merge(parent_inode->i_sb, parent_inode,
328 					       child_dentry, NULL);
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 
352 out:
353 	return err ? ERR_PTR(err) : ret_dentry;
354 }
355 
356 const struct inode_operations hmdfs_file_iops_cloud_merge = {
357 	.getattr = hmdfs_getattr_merge,
358 	.setattr = hmdfs_setattr_merge,
359 	.permission = hmdfs_permission,
360 };
361 
do_mkdir_cloud_merge(struct inode * parent_inode,struct dentry * child_dentry,umode_t mode,struct inode * lo_i_parent,struct dentry * lo_d_child)362 int 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);
385 out:
386 	return ret;
387 }
388 
do_create_cloud_merge(struct inode * parent_inode,struct dentry * child_dentry,umode_t mode,bool want_excl,struct inode * lo_i_parent,struct dentry * lo_d_child)389 int 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);
412 out:
413 	return ret;
414 }
415 
hmdfs_do_ops_cloud_merge(struct inode * i_parent,struct dentry * d_child,struct dentry * lo_d_child,struct path path,struct hmdfs_recursive_para * rec_op_para)416 int 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 
hmdfs_create_lower_cloud_dentry(struct inode * i_parent,struct dentry * d_child,struct dentry * lo_d_parent,bool is_dir,struct hmdfs_recursive_para * rec_op_para)449 int 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 
506 out_put:
507 	done_path_create(&path, lo_d_child);
508 out:
509 	kfree(absolute_path_buf);
510 	kfree(path_buf);
511 	return ret;
512 }
513 
create_lo_d_parent_recur(struct dentry * d_parent,struct dentry * d_child,umode_t mode,struct hmdfs_recursive_para * rec_op_para)514 static 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 	struct hmdfs_dentry_info_merge *pmdi = NULL;
520 	int ret = 0;
521 
522 	pmdi = hmdfs_dm(d_parent);
523 	wait_event(pmdi->wait_queue, !has_merge_lookup_work(pmdi));
524 	lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
525 	if (!lo_d_parent) {
526 		d_pparent = dget_parent(d_parent);
527 		ret = create_lo_d_parent_recur(d_pparent, d_parent,
528 					       d_inode(d_parent)->i_mode,
529 					       rec_op_para);
530 		dput(d_pparent);
531 		if (ret)
532 			goto out;
533 		lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
534 		if (!lo_d_parent) {
535 			ret = -ENOENT;
536 			goto out;
537 		}
538 	}
539 	rec_op_para->is_last = false;
540 	rec_op_para->mode = mode;
541 	ret = hmdfs_create_lower_cloud_dentry(d_inode(d_parent), d_child, lo_d_parent,
542 					true, rec_op_para);
543 out:
544 	dput(lo_d_parent);
545 	return ret;
546 }
547 
create_lo_d_cloud_child(struct inode * i_parent,struct dentry * d_child,bool is_dir,struct hmdfs_recursive_para * rec_op_para)548 int create_lo_d_cloud_child(struct inode *i_parent, struct dentry *d_child,
549 		      bool is_dir, struct hmdfs_recursive_para *rec_op_para)
550 {
551 	struct dentry *d_pparent, *lo_d_parent, *lo_d_child;
552 	struct dentry *d_parent = dget_parent(d_child);
553 	struct hmdfs_dentry_info_merge *pmdi = hmdfs_dm(d_parent);
554 	int ret = 0;
555 	mode_t d_child_mode = rec_op_para->mode;
556 
557 	wait_event(pmdi->wait_queue, !has_merge_lookup_work(pmdi));
558 
559 	lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
560 	if (!lo_d_parent) {
561 		d_pparent = dget_parent(d_parent);
562 		ret = create_lo_d_parent_recur(d_pparent, d_parent,
563 					       d_inode(d_parent)->i_mode,
564 					       rec_op_para);
565 		dput(d_pparent);
566 		if (unlikely(ret)) {
567 			lo_d_child = ERR_PTR(ret);
568 			goto out;
569 		}
570 		lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
571 		if (!lo_d_parent) {
572 			lo_d_child = ERR_PTR(-ENOENT);
573 			goto out;
574 		}
575 	}
576 	rec_op_para->is_last = true;
577 	rec_op_para->mode = d_child_mode;
578 	ret = hmdfs_create_lower_cloud_dentry(i_parent, d_child, lo_d_parent, is_dir,
579 					rec_op_para);
580 
581 out:
582 	dput(d_parent);
583 	dput(lo_d_parent);
584 	return ret;
585 }
586 
hmdfs_mkdir_cloud_merge(struct inode * dir,struct dentry * dentry,umode_t mode)587 int hmdfs_mkdir_cloud_merge(struct inode *dir, struct dentry *dentry, umode_t mode)
588 {
589 	int ret = 0;
590 	struct hmdfs_recursive_para *rec_op_para = NULL;
591 
592 	// confict_name  & file_type is checked by hmdfs_mkdir_local
593 	if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON) {
594 		ret = -EACCES;
595 		goto out;
596 	}
597 	rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL);
598 	if (!rec_op_para) {
599 		ret = -ENOMEM;
600 		goto out;
601 	}
602 
603 	hmdfs_init_recursive_para(rec_op_para, F_MKDIR_MERGE, mode, false,
604 				  NULL);
605 	ret = create_lo_d_cloud_child(dir, dentry, true, rec_op_para);
606 out:
607 	hmdfs_trace_merge(trace_hmdfs_mkdir_merge, dir, dentry, ret);
608 	if (ret)
609 		d_drop(dentry);
610 	kfree(rec_op_para);
611 	return ret;
612 }
613 
hmdfs_create_cloud_merge(struct inode * dir,struct dentry * dentry,umode_t mode,bool want_excl)614 int hmdfs_create_cloud_merge(struct inode *dir, struct dentry *dentry, umode_t mode,
615 		       bool want_excl)
616 {
617 	struct hmdfs_recursive_para *rec_op_para = NULL;
618 	int ret = 0;
619 
620 	rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL);
621 	if (!rec_op_para) {
622 		ret = -ENOMEM;
623 		goto out;
624 	}
625 	hmdfs_init_recursive_para(rec_op_para, F_CREATE_MERGE, mode, want_excl,
626 				  NULL);
627 	// confict_name  & file_type is checked by hmdfs_create_local
628 	ret = create_lo_d_cloud_child(dir, dentry, false, rec_op_para);
629 out:
630 	hmdfs_trace_merge(trace_hmdfs_create_merge, dir, dentry, ret);
631 	if (ret)
632 		d_drop(dentry);
633 	kfree(rec_op_para);
634 	return ret;
635 }
636 
rename_lo_d_cloud_child(struct hmdfs_rename_para * rename_para,struct hmdfs_recursive_para * rec_op_para)637 static int rename_lo_d_cloud_child(struct hmdfs_rename_para *rename_para,
638 				   struct hmdfs_recursive_para *rec_op_para)
639 {
640 	struct dentry *d_pparent, *lo_d_parent;
641 	struct dentry *d_parent = dget_parent(rename_para->new_dentry);
642 	struct hmdfs_dentry_info_merge *pmdi = hmdfs_dm(d_parent);
643 	int ret = 0;
644 
645 	wait_event(pmdi->wait_queue, !has_merge_lookup_work(pmdi));
646 
647 	lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
648 	if (!lo_d_parent) {
649 		d_pparent = dget_parent(d_parent);
650 		ret = create_lo_d_parent_recur(d_pparent, d_parent,
651 					       d_inode(d_parent)->i_mode,
652 					       rec_op_para);
653 		dput(d_pparent);
654 		if (unlikely(ret))
655 			goto out;
656 		lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
657 		if (!lo_d_parent) {
658 			ret = -ENOENT;
659 			goto out;
660 		}
661 	}
662 	ret = do_rename_merge(rename_para->old_dir, rename_para->old_dentry,
663 			      rename_para->new_dir, rename_para->new_dentry,
664 			      rename_para->flags);
665 
666 out:
667 	dput(d_parent);
668 	dput(lo_d_parent);
669 	return ret;
670 }
671 
hmdfs_rename_cloud_merge(struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)672 static int hmdfs_rename_cloud_merge(struct inode *old_dir,
673 				    struct dentry *old_dentry,
674 				    struct inode *new_dir,
675 				    struct dentry *new_dentry,
676 				    unsigned int flags)
677 {
678 	struct hmdfs_recursive_para *rec_op_para = NULL;
679 	struct hmdfs_rename_para rename_para = { old_dir, old_dentry, new_dir,
680 						 new_dentry, flags };
681 	int ret = 0;
682 
683 	if (hmdfs_file_type(old_dentry->d_name.name) != HMDFS_TYPE_COMMON ||
684 	    hmdfs_file_type(new_dentry->d_name.name) != HMDFS_TYPE_COMMON) {
685 		ret = -EACCES;
686 		goto rename_out;
687 	}
688 
689 	if (hmdfs_i(old_dir)->inode_type != hmdfs_i(new_dir)->inode_type) {
690 		hmdfs_err("in different view");
691 		ret = -EPERM;
692 		goto rename_out;
693 	}
694 
695 	if (hmdfs_d(old_dentry)->device_id != hmdfs_d(new_dentry)->device_id) {
696 		ret = -EXDEV;
697 		goto rename_out;
698 	}
699 
700 	rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL);
701 	if (!rec_op_para) {
702 		ret = -ENOMEM;
703 		goto rename_out;
704 	}
705 	trace_hmdfs_rename_merge(old_dir, old_dentry, new_dir, new_dentry,
706 				 flags);
707 
708 	hmdfs_init_recursive_para(rec_op_para, F_MKDIR_MERGE, 0, 0, NULL);
709 	ret = rename_lo_d_cloud_child(&rename_para, rec_op_para);
710 	if (ret != 0) {
711 		d_drop(new_dentry);
712 	} else {
713 		hmdfs_update_meta(old_dir);
714 		if (old_dir != new_dir)
715 			hmdfs_update_meta(new_dir);
716 	}
717 
718 	if (S_ISREG(old_dentry->d_inode->i_mode) && !ret)
719 		d_invalidate(old_dentry);
720 rename_out:
721 	kfree(rec_op_para);
722 	return ret;
723 }
724 
hmdfs_update_meta(struct inode * dir)725 void hmdfs_update_meta(struct inode *dir)
726 {
727 	dir->i_ctime = dir->i_mtime = current_time(dir);
728 }
729 
730 const struct inode_operations hmdfs_dir_iops_cloud_merge = {
731 	.lookup = hmdfs_lookup_cloud_merge,
732 	.mkdir = hmdfs_mkdir_cloud_merge,
733 	.create = hmdfs_create_cloud_merge,
734 	.rmdir = hmdfs_rmdir_merge,
735 	.unlink = hmdfs_unlink_merge,
736 	.rename = hmdfs_rename_cloud_merge,
737 	.permission = hmdfs_permission,
738 };
739