• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
22 struct kmem_cache *hmdfs_dentry_merge_cachep;
23 
hmdfs_get_fst_lo_d(struct dentry * dentry)24 struct 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 
hmdfs_get_lo_d(struct dentry * dentry,int dev_id)39 struct 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 
update_inode_attr(struct inode * inode,struct dentry * child_dentry)56 void 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 
get_num_comrades(struct dentry * dentry)85 int 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 
fill_inode_merge(struct super_block * sb,struct inode * parent_inode,struct dentry * child_dentry,struct dentry * lo_d_dentry)98 static 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);
159 out:
160 	dput(fst_lo_d);
161 	return inode;
162 bad_inode:
163 	iget_failed(inode);
164 	return ERR_PTR(ret);
165 }
166 
alloc_comrade(struct dentry * lo_d,int dev_id)167 struct 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 
link_comrade(struct list_head * onstack_comrades_head,struct hmdfs_dentry_comrade * comrade)182 void 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  */
assign_comrades_unlocked(struct dentry * child_dentry,struct list_head * onstack_comrades_head)209 void 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 
lookup_comrade(struct path lower_path,const char * d_name,int dev_id,unsigned int flags)220 struct 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  */
conf_name_trans_nop(struct dentry * d)244 static 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  */
conf_name_trans_dir(struct dentry * d)254 static 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  */
conf_name_trans_reg(struct dentry * d,int * dev_id)266 static 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 
check_filename(const char * name,int len)303 int 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 
merge_lookup_comrade(struct hmdfs_sb_info * sbi,const char * name,int devid,unsigned int flags)345 static 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);
369 root_put:
370 	path_put(&root);
371 out:
372 	hmdfs_revert_creds(old_cred);
373 	return comrade;
374 }
375 
is_valid_comrade(struct hmdfs_dentry_info_merge * mdi,umode_t mode)376 bool 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 
merge_lookup_work_func(struct work_struct * work)395 static 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 
425 out:
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 
merge_lookup_async(struct hmdfs_dentry_info_merge * mdi,struct hmdfs_sb_info * sbi,int devid,const char * name,unsigned int flags)435 int 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;
461 out:
462 	return err;
463 }
464 
hmdfs_get_real_dname(struct dentry * dentry,int * devid,int * type)465 char *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 
lookup_merge_normal(struct dentry * dentry,unsigned int flags)480 static 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);
538 out_ppath:
539 	kfree(ppath);
540 out_rname:
541 	kfree(rname);
542 out:
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  */
do_lookup_merge_root(struct path path_dev,struct dentry * child_dentry,unsigned int flags)553 static 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 
594 out:
595 	kfree(buf);
596 	return ret;
597 }
598 
599 // mkdir -p
lock_root_inode_shared(struct inode * root,bool * locked,bool * down)600 void 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 
restore_root_inode_sem(struct inode * root,bool locked,bool down)630 void 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 
lookup_merge_root(struct inode * root_inode,struct dentry * child_dentry,unsigned int flags)640 static 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 
669 free_buf:
670 	kfree(buf);
671 	restore_root_inode_sem(root_inode, locked, down);
672 	return ret;
673 }
674 
init_hmdfs_dentry_info_merge(struct hmdfs_sb_info * sbi,struct dentry * dentry)675 int 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
hmdfs_lookup_merge(struct inode * parent_inode,struct dentry * child_dentry,unsigned int flags)698 struct 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 
769 out:
770 	return err ? ERR_PTR(err) : ret_dentry;
771 }
772 
hmdfs_getattr_merge(const struct path * path,struct kstat * stat,u32 request_mask,unsigned int flags)773 int 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);
789 out:
790 	dput(lower_path.dentry);
791 	return ret;
792 }
793 
hmdfs_setattr_merge(struct dentry * dentry,struct iattr * ia)794 int 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 
828 out:
829 	dput(lower_dentry);
830 	return err;
831 }
832 
833 const struct inode_operations hmdfs_file_iops_merge = {
834 	.getattr = hmdfs_getattr_merge,
835 	.setattr = hmdfs_setattr_merge,
836 	.permission = hmdfs_permission,
837 };
838 
do_mkdir_merge(struct inode * parent_inode,struct dentry * child_dentry,umode_t mode,struct inode * lo_i_parent,struct dentry * lo_d_child)839 int 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);
863 out:
864 	return ret;
865 }
866 
do_create_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)867 int 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);
891 out:
892 	return ret;
893 }
894 
hmdfs_do_ops_merge(struct inode * i_parent,struct dentry * d_child,struct dentry * lo_d_child,struct path path,struct hmdfs_recursive_para * rec_op_para)895 int 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 
hmdfs_create_lower_dentry(struct inode * i_parent,struct dentry * d_child,struct dentry * lo_d_parent,bool is_dir,struct hmdfs_recursive_para * rec_op_para)928 int 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 
985 out_put:
986 	done_path_create(&path, lo_d_child);
987 out:
988 	kfree(absolute_path_buf);
989 	kfree(path_buf);
990 	return ret;
991 }
992 
create_lo_d_parent_recur(struct dentry * d_parent,struct dentry * d_child,umode_t mode,struct hmdfs_recursive_para * rec_op_para)993 static 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);
1022 out:
1023 	dput(lo_d_parent);
1024 	return ret;
1025 }
1026 
create_lo_d_child(struct inode * i_parent,struct dentry * d_child,bool is_dir,struct hmdfs_recursive_para * rec_op_para)1027 int 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 
1060 out:
1061 	dput(d_parent);
1062 	dput(lo_d_parent);
1063 	return ret;
1064 }
1065 
hmdfs_init_recursive_para(struct hmdfs_recursive_para * rec_op_para,int opcode,mode_t mode,bool want_excl,const char * name)1066 void 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 
hmdfs_mkdir_merge(struct inode * dir,struct dentry * dentry,umode_t mode)1077 int 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);
1096 out:
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 
hmdfs_create_merge(struct inode * dir,struct dentry * dentry,umode_t mode,bool want_excl)1104 int 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);
1119 out:
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 
do_rmdir_merge(struct inode * dir,struct dentry * dentry)1127 int 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 
hmdfs_rmdir_merge(struct inode * dir,struct dentry * dentry)1153 int 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);
1170 out:
1171 	hmdfs_trace_merge(trace_hmdfs_rmdir_merge, dir, dentry, ret);
1172 	return ret;
1173 }
1174 
do_unlink_merge(struct inode * dir,struct dentry * dentry)1175 int 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 
hmdfs_unlink_merge(struct inode * dir,struct dentry * dentry)1215 int 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);
1233 out:
1234 	return ret;
1235 }
1236 
do_rename_merge(struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)1237 int 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);
1318 no_comrade:
1319 		done_path_create(&lo_p_new, lo_d_new);
1320 		dput(lo_d_old_dir);
1321 		dput(lo_d_new_dir);
1322 	}
1323 out:
1324 	kfree(abs_path_buf);
1325 	kfree(path_buf);
1326 	return ret;
1327 }
1328 
hmdfs_rename_merge(struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)1329 int 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 
1392 rename_out:
1393 	kfree(old_dir_buf);
1394 	kfree(new_dir_buf);
1395 	return ret;
1396 }
1397 
1398 const 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