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 info = hmdfs_i(child_inode);
743 if (info->inode_type == HMDFS_LAYER_FIRST_MERGE)
744 hmdfs_root_inode_perm_init(child_inode);
745 else
746 check_and_fixup_ownership_remote(parent_inode,
747 child_inode,
748 child_dentry);
749
750 ret_dentry = d_splice_alias(child_inode, child_dentry);
751 if (IS_ERR(ret_dentry)) {
752 clear_comrades(child_dentry);
753 err = PTR_ERR(ret_dentry);
754 goto out;
755 }
756 if (ret_dentry)
757 child_dentry = ret_dentry;
758
759 goto out;
760 }
761
762 if ((err == -ENOENT) && create)
763 err = 0;
764
765 out:
766 return err ? ERR_PTR(err) : ret_dentry;
767 }
768
hmdfs_getattr_merge(const struct path * path,struct kstat * stat,u32 request_mask,unsigned int flags)769 int hmdfs_getattr_merge(const struct path *path, struct kstat *stat,
770 u32 request_mask, unsigned int flags)
771 {
772 int ret;
773 struct path lower_path = {
774 .dentry = hmdfs_get_fst_lo_d(path->dentry),
775 .mnt = path->mnt,
776 };
777
778 if (unlikely(!lower_path.dentry)) {
779 hmdfs_err("Fatal! No comrades");
780 ret = -EINVAL;
781 goto out;
782 }
783
784 ret = vfs_getattr(&lower_path, stat, request_mask, flags);
785 out:
786 dput(lower_path.dentry);
787 return ret;
788 }
789
hmdfs_setattr_merge(struct dentry * dentry,struct iattr * ia)790 int hmdfs_setattr_merge(struct dentry *dentry, struct iattr *ia)
791 {
792 struct inode *inode = d_inode(dentry);
793 struct dentry *lower_dentry = hmdfs_get_fst_lo_d(dentry);
794 struct inode *lower_inode = NULL;
795 struct iattr lower_ia;
796 unsigned int ia_valid = ia->ia_valid;
797 int err = 0;
798 kuid_t tmp_uid;
799
800 if (!lower_dentry) {
801 WARN_ON(1);
802 err = -EINVAL;
803 goto out;
804 }
805
806 lower_inode = d_inode(lower_dentry);
807 memcpy(&lower_ia, ia, sizeof(lower_ia));
808 if (ia_valid & ATTR_FILE)
809 lower_ia.ia_file = hmdfs_f(ia->ia_file)->lower_file;
810 lower_ia.ia_valid &= ~(ATTR_UID | ATTR_GID | ATTR_MODE);
811
812 inode_lock(lower_inode);
813 tmp_uid = hmdfs_override_inode_uid(lower_inode);
814
815 err = notify_change(lower_dentry, &lower_ia, NULL);
816 i_size_write(inode, i_size_read(lower_inode));
817 inode->i_atime = lower_inode->i_atime;
818 inode->i_mtime = lower_inode->i_mtime;
819 inode->i_ctime = lower_inode->i_ctime;
820 hmdfs_revert_inode_uid(lower_inode, tmp_uid);
821
822 inode_unlock(lower_inode);
823
824 out:
825 dput(lower_dentry);
826 return err;
827 }
828
829 const struct inode_operations hmdfs_file_iops_merge = {
830 .getattr = hmdfs_getattr_merge,
831 .setattr = hmdfs_setattr_merge,
832 .permission = hmdfs_permission,
833 };
834
do_mkdir_merge(struct inode * parent_inode,struct dentry * child_dentry,umode_t mode,struct inode * lo_i_parent,struct dentry * lo_d_child)835 int do_mkdir_merge(struct inode *parent_inode, struct dentry *child_dentry,
836 umode_t mode, struct inode *lo_i_parent,
837 struct dentry *lo_d_child)
838 {
839 int ret = 0;
840 struct super_block *sb = parent_inode->i_sb;
841 struct inode *child_inode = NULL;
842
843 ret = vfs_mkdir(lo_i_parent, lo_d_child, mode);
844 if (ret)
845 goto out;
846
847 child_inode =
848 fill_inode_merge(sb, parent_inode, child_dentry, lo_d_child);
849 if (IS_ERR(child_inode)) {
850 ret = PTR_ERR(child_inode);
851 goto out;
852 }
853 check_and_fixup_ownership_remote(parent_inode, child_inode,
854 child_dentry);
855
856 d_add(child_dentry, child_inode);
857 /* nlink should be increased with the joining of children */
858 set_nlink(parent_inode, 2);
859 out:
860 return ret;
861 }
862
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)863 int do_create_merge(struct inode *parent_inode, struct dentry *child_dentry,
864 umode_t mode, bool want_excl, struct inode *lo_i_parent,
865 struct dentry *lo_d_child)
866 {
867 int ret = 0;
868 struct super_block *sb = parent_inode->i_sb;
869 struct inode *child_inode = NULL;
870
871 ret = vfs_create(lo_i_parent, lo_d_child, mode, want_excl);
872 if (ret)
873 goto out;
874
875 child_inode =
876 fill_inode_merge(sb, parent_inode, child_dentry, lo_d_child);
877 if (IS_ERR(child_inode)) {
878 ret = PTR_ERR(child_inode);
879 goto out;
880 }
881 check_and_fixup_ownership_remote(parent_inode, child_inode,
882 child_dentry);
883
884 d_add(child_dentry, child_inode);
885 /* nlink should be increased with the joining of children */
886 set_nlink(parent_inode, 2);
887 out:
888 return ret;
889 }
890
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)891 int hmdfs_do_ops_merge(struct inode *i_parent, struct dentry *d_child,
892 struct dentry *lo_d_child, struct path path,
893 struct hmdfs_recursive_para *rec_op_para)
894 {
895 int ret = 0;
896
897 if (rec_op_para->is_last) {
898 switch (rec_op_para->opcode) {
899 case F_MKDIR_MERGE:
900 ret = do_mkdir_merge(i_parent, d_child,
901 rec_op_para->mode,
902 d_inode(path.dentry), lo_d_child);
903 break;
904 case F_CREATE_MERGE:
905 ret = do_create_merge(i_parent, d_child,
906 rec_op_para->mode,
907 rec_op_para->want_excl,
908 d_inode(path.dentry), lo_d_child);
909 break;
910 default:
911 ret = -EINVAL;
912 break;
913 }
914 } else {
915 ret = vfs_mkdir(d_inode(path.dentry), lo_d_child,
916 rec_op_para->mode);
917 }
918 if (ret)
919 hmdfs_err("vfs_ops failed, ops %d, err = %d",
920 rec_op_para->opcode, ret);
921 return ret;
922 }
923
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)924 int hmdfs_create_lower_dentry(struct inode *i_parent, struct dentry *d_child,
925 struct dentry *lo_d_parent, bool is_dir,
926 struct hmdfs_recursive_para *rec_op_para)
927 {
928 struct hmdfs_sb_info *sbi = i_parent->i_sb->s_fs_info;
929 struct hmdfs_dentry_comrade *new_comrade = NULL;
930 struct dentry *lo_d_child = NULL;
931 char *path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
932 char *absolute_path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
933 char *path_name = NULL;
934 struct path path = { .mnt = NULL, .dentry = NULL };
935 int ret = 0;
936
937 if (unlikely(!path_buf || !absolute_path_buf)) {
938 ret = -ENOMEM;
939 goto out;
940 }
941
942 path_name = dentry_path_raw(lo_d_parent, path_buf, PATH_MAX);
943 if (IS_ERR(path_name)) {
944 ret = PTR_ERR(path_name);
945 goto out;
946 }
947 if ((strlen(sbi->real_dst) + strlen(path_name) +
948 strlen(d_child->d_name.name) + 2) > PATH_MAX) {
949 ret = -ENAMETOOLONG;
950 goto out;
951 }
952
953 sprintf(absolute_path_buf, "%s%s/%s", sbi->real_dst, path_name,
954 d_child->d_name.name);
955
956 if (is_dir)
957 lo_d_child = kern_path_create(AT_FDCWD, absolute_path_buf,
958 &path, LOOKUP_DIRECTORY);
959 else
960 lo_d_child = kern_path_create(AT_FDCWD, absolute_path_buf,
961 &path, 0);
962 if (IS_ERR(lo_d_child)) {
963 ret = PTR_ERR(lo_d_child);
964 goto out;
965 }
966 // to ensure link_comrade after vfs_mkdir succeed
967 ret = hmdfs_do_ops_merge(i_parent, d_child, lo_d_child, path,
968 rec_op_para);
969 if (ret)
970 goto out_put;
971 new_comrade = alloc_comrade(lo_d_child, HMDFS_DEVID_LOCAL);
972 if (IS_ERR(new_comrade)) {
973 ret = PTR_ERR(new_comrade);
974 goto out_put;
975 } else {
976 link_comrade_unlocked(d_child, new_comrade);
977 }
978
979 update_inode_attr(d_inode(d_child), d_child);
980
981 out_put:
982 done_path_create(&path, lo_d_child);
983 out:
984 kfree(absolute_path_buf);
985 kfree(path_buf);
986 return ret;
987 }
988
create_lo_d_parent_recur(struct dentry * d_parent,struct dentry * d_child,umode_t mode,struct hmdfs_recursive_para * rec_op_para)989 static int create_lo_d_parent_recur(struct dentry *d_parent,
990 struct dentry *d_child, umode_t mode,
991 struct hmdfs_recursive_para *rec_op_para)
992 {
993 struct dentry *lo_d_parent, *d_pparent;
994 struct hmdfs_dentry_info_merge *pmdi = NULL;
995 int ret = 0;
996
997 pmdi = hmdfs_dm(d_parent);
998 wait_event(pmdi->wait_queue, !has_merge_lookup_work(pmdi));
999 lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
1000 if (!lo_d_parent) {
1001 d_pparent = dget_parent(d_parent);
1002 ret = create_lo_d_parent_recur(d_pparent, d_parent,
1003 d_inode(d_parent)->i_mode,
1004 rec_op_para);
1005 dput(d_pparent);
1006 if (ret)
1007 goto out;
1008 lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
1009 if (!lo_d_parent) {
1010 ret = -ENOENT;
1011 goto out;
1012 }
1013 }
1014 rec_op_para->is_last = false;
1015 rec_op_para->mode = mode;
1016 ret = hmdfs_create_lower_dentry(d_inode(d_parent), d_child, lo_d_parent,
1017 true, rec_op_para);
1018 out:
1019 dput(lo_d_parent);
1020 return ret;
1021 }
1022
create_lo_d_child(struct inode * i_parent,struct dentry * d_child,bool is_dir,struct hmdfs_recursive_para * rec_op_para)1023 int create_lo_d_child(struct inode *i_parent, struct dentry *d_child,
1024 bool is_dir, struct hmdfs_recursive_para *rec_op_para)
1025 {
1026 struct dentry *d_pparent, *lo_d_parent, *lo_d_child;
1027 struct dentry *d_parent = dget_parent(d_child);
1028 struct hmdfs_dentry_info_merge *pmdi = hmdfs_dm(d_parent);
1029 int ret = 0;
1030 mode_t d_child_mode = rec_op_para->mode;
1031
1032 wait_event(pmdi->wait_queue, !has_merge_lookup_work(pmdi));
1033
1034 lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
1035 if (!lo_d_parent) {
1036 d_pparent = dget_parent(d_parent);
1037 ret = create_lo_d_parent_recur(d_pparent, d_parent,
1038 d_inode(d_parent)->i_mode,
1039 rec_op_para);
1040 dput(d_pparent);
1041 if (unlikely(ret)) {
1042 lo_d_child = ERR_PTR(ret);
1043 goto out;
1044 }
1045 lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
1046 if (!lo_d_parent) {
1047 lo_d_child = ERR_PTR(-ENOENT);
1048 goto out;
1049 }
1050 }
1051 rec_op_para->is_last = true;
1052 rec_op_para->mode = d_child_mode;
1053 ret = hmdfs_create_lower_dentry(i_parent, d_child, lo_d_parent, is_dir,
1054 rec_op_para);
1055
1056 out:
1057 dput(d_parent);
1058 dput(lo_d_parent);
1059 return ret;
1060 }
1061
hmdfs_init_recursive_para(struct hmdfs_recursive_para * rec_op_para,int opcode,mode_t mode,bool want_excl,const char * name)1062 void hmdfs_init_recursive_para(struct hmdfs_recursive_para *rec_op_para,
1063 int opcode, mode_t mode, bool want_excl,
1064 const char *name)
1065 {
1066 rec_op_para->is_last = true;
1067 rec_op_para->opcode = opcode;
1068 rec_op_para->mode = mode;
1069 rec_op_para->want_excl = want_excl;
1070 rec_op_para->name = name;
1071 }
1072
hmdfs_mkdir_merge(struct inode * dir,struct dentry * dentry,umode_t mode)1073 int hmdfs_mkdir_merge(struct inode *dir, struct dentry *dentry, umode_t mode)
1074 {
1075 int ret = 0;
1076 struct hmdfs_recursive_para *rec_op_para = NULL;
1077
1078 // confict_name & file_type is checked by hmdfs_mkdir_local
1079 if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON) {
1080 ret = -EACCES;
1081 goto out;
1082 }
1083 rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL);
1084 if (!rec_op_para) {
1085 ret = -ENOMEM;
1086 goto out;
1087 }
1088
1089 hmdfs_init_recursive_para(rec_op_para, F_MKDIR_MERGE, mode, false,
1090 NULL);
1091 ret = create_lo_d_child(dir, dentry, true, rec_op_para);
1092 out:
1093 hmdfs_trace_merge(trace_hmdfs_mkdir_merge, dir, dentry, ret);
1094 if (ret)
1095 d_drop(dentry);
1096 kfree(rec_op_para);
1097 return ret;
1098 }
1099
hmdfs_create_merge(struct inode * dir,struct dentry * dentry,umode_t mode,bool want_excl)1100 int hmdfs_create_merge(struct inode *dir, struct dentry *dentry, umode_t mode,
1101 bool want_excl)
1102 {
1103 struct hmdfs_recursive_para *rec_op_para = NULL;
1104 int ret = 0;
1105
1106 rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL);
1107 if (!rec_op_para) {
1108 ret = -ENOMEM;
1109 goto out;
1110 }
1111 hmdfs_init_recursive_para(rec_op_para, F_CREATE_MERGE, mode, want_excl,
1112 NULL);
1113 // confict_name & file_type is checked by hmdfs_create_local
1114 ret = create_lo_d_child(dir, dentry, false, rec_op_para);
1115 out:
1116 hmdfs_trace_merge(trace_hmdfs_create_merge, dir, dentry, ret);
1117 if (ret)
1118 d_drop(dentry);
1119 kfree(rec_op_para);
1120 return ret;
1121 }
1122
do_rmdir_merge(struct inode * dir,struct dentry * dentry)1123 int do_rmdir_merge(struct inode *dir, struct dentry *dentry)
1124 {
1125 int ret = 0;
1126 struct hmdfs_dentry_info_merge *dim = hmdfs_dm(dentry);
1127 struct hmdfs_dentry_comrade *comrade = NULL;
1128 struct dentry *lo_d = NULL;
1129 struct dentry *lo_d_dir = NULL;
1130 struct inode *lo_i_dir = NULL;
1131
1132 wait_event(dim->wait_queue, !has_merge_lookup_work(dim));
1133
1134 mutex_lock(&dim->comrade_list_lock);
1135 list_for_each_entry(comrade, &(dim->comrade_list), list) {
1136 lo_d = comrade->lo_d;
1137 lo_d_dir = lock_parent(lo_d);
1138 lo_i_dir = d_inode(lo_d_dir);
1139 ret = vfs_rmdir(lo_i_dir, lo_d);
1140 unlock_dir(lo_d_dir);
1141 if (ret)
1142 break;
1143 }
1144 mutex_unlock(&dim->comrade_list_lock);
1145 hmdfs_trace_merge(trace_hmdfs_rmdir_merge, dir, dentry, ret);
1146 return ret;
1147 }
1148
hmdfs_rmdir_merge(struct inode * dir,struct dentry * dentry)1149 int hmdfs_rmdir_merge(struct inode *dir, struct dentry *dentry)
1150 {
1151 int ret = 0;
1152
1153 if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON) {
1154 ret = -EACCES;
1155 goto out;
1156 }
1157
1158 ret = do_rmdir_merge(dir, dentry);
1159 if (ret) {
1160 hmdfs_err("rm dir failed:%d", ret);
1161 goto out;
1162 }
1163
1164 hmdfs_update_meta(dir);
1165 d_drop(dentry);
1166 out:
1167 hmdfs_trace_merge(trace_hmdfs_rmdir_merge, dir, dentry, ret);
1168 return ret;
1169 }
1170
do_unlink_merge(struct inode * dir,struct dentry * dentry)1171 int do_unlink_merge(struct inode *dir, struct dentry *dentry)
1172 {
1173 int ret = 0;
1174 struct hmdfs_dentry_info_merge *dim = hmdfs_dm(dentry);
1175 struct hmdfs_dentry_comrade *comrade = NULL;
1176 struct dentry *lo_d = NULL;
1177 struct dentry *lo_d_dir = NULL;
1178 struct dentry *lo_d_lookup = NULL;
1179 struct inode *lo_i_dir = NULL;
1180
1181 wait_event(dim->wait_queue, !has_merge_lookup_work(dim));
1182
1183 mutex_lock(&dim->comrade_list_lock);
1184 list_for_each_entry(comrade, &(dim->comrade_list), list) {
1185 lo_d = comrade->lo_d;
1186 dget(lo_d);
1187 lo_d_dir = lock_parent(lo_d);
1188 /* lo_d could be unhashed, need to lookup again here */
1189 lo_d_lookup = lookup_one_len(lo_d->d_name.name, lo_d_dir,
1190 strlen(lo_d->d_name.name));
1191 if (IS_ERR(lo_d_lookup)) {
1192 ret = PTR_ERR(lo_d_lookup);
1193 hmdfs_err("lookup_one_len failed, err = %d", ret);
1194 unlock_dir(lo_d_dir);
1195 dput(lo_d);
1196 break;
1197 }
1198 lo_i_dir = d_inode(lo_d_dir);
1199 ret = vfs_unlink(lo_i_dir, lo_d_lookup, NULL);
1200 dput(lo_d_lookup);
1201 unlock_dir(lo_d_dir);
1202 dput(lo_d);
1203 if (ret)
1204 break;
1205 }
1206 mutex_unlock(&dim->comrade_list_lock);
1207
1208 return ret;
1209 }
1210
hmdfs_unlink_merge(struct inode * dir,struct dentry * dentry)1211 int hmdfs_unlink_merge(struct inode *dir, struct dentry *dentry)
1212 {
1213 int ret = 0;
1214
1215 if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON) {
1216 ret = -EACCES;
1217 goto out;
1218 }
1219
1220 ret = do_unlink_merge(dir, dentry);
1221 if (ret) {
1222 hmdfs_err("unlink failed:%d", ret);
1223 goto out;
1224 } else {
1225 hmdfs_update_meta(dir);
1226 }
1227
1228 d_drop(dentry);
1229 out:
1230 return ret;
1231 }
1232
do_rename_merge(struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)1233 int do_rename_merge(struct inode *old_dir, struct dentry *old_dentry,
1234 struct inode *new_dir, struct dentry *new_dentry,
1235 unsigned int flags)
1236 {
1237 int ret = 0;
1238 struct hmdfs_sb_info *sbi = (old_dir->i_sb)->s_fs_info;
1239 struct hmdfs_dentry_info_merge *dim = hmdfs_dm(old_dentry);
1240 struct hmdfs_dentry_comrade *comrade = NULL, *new_comrade = NULL;
1241 struct path lo_p_new = { .mnt = NULL, .dentry = NULL };
1242 struct inode *lo_i_old_dir = NULL, *lo_i_new_dir = NULL;
1243 struct dentry *lo_d_old_dir = NULL, *lo_d_old = NULL,
1244 *lo_d_new_dir = NULL, *lo_d_new = NULL;
1245 struct dentry *d_new_dir = NULL;
1246 char *path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
1247 char *abs_path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
1248 char *path_name = NULL;
1249 struct hmdfs_dentry_info_merge *pmdi = NULL;
1250
1251 if (flags & ~RENAME_NOREPLACE) {
1252 ret = -EINVAL;
1253 goto out;
1254 }
1255
1256 if (unlikely(!path_buf || !abs_path_buf)) {
1257 ret = -ENOMEM;
1258 goto out;
1259 }
1260
1261 wait_event(dim->wait_queue, !has_merge_lookup_work(dim));
1262
1263 list_for_each_entry(comrade, &dim->comrade_list, list) {
1264 lo_d_old = comrade->lo_d;
1265 d_new_dir = d_find_alias(new_dir);
1266 pmdi = hmdfs_dm(d_new_dir);
1267 wait_event(pmdi->wait_queue, !has_merge_lookup_work(pmdi));
1268 lo_d_new_dir = hmdfs_get_lo_d(d_new_dir, comrade->dev_id);
1269 dput(d_new_dir);
1270
1271 if (!lo_d_new_dir)
1272 continue;
1273 path_name = dentry_path_raw(lo_d_new_dir, path_buf, PATH_MAX);
1274 dput(lo_d_new_dir);
1275 if (IS_ERR(path_name)) {
1276 ret = PTR_ERR(path_name);
1277 continue;
1278 }
1279
1280 if (strlen(sbi->real_dst) + strlen(path_name) +
1281 strlen(new_dentry->d_name.name) + 2 > PATH_MAX) {
1282 ret = -ENAMETOOLONG;
1283 goto out;
1284 }
1285
1286 snprintf(abs_path_buf, PATH_MAX, "%s%s/%s", sbi->real_dst,
1287 path_name, new_dentry->d_name.name);
1288 if (S_ISDIR(d_inode(old_dentry)->i_mode))
1289 lo_d_new = kern_path_create(AT_FDCWD, abs_path_buf,
1290 &lo_p_new,
1291 LOOKUP_DIRECTORY);
1292 else
1293 lo_d_new = kern_path_create(AT_FDCWD, abs_path_buf,
1294 &lo_p_new, 0);
1295 if (IS_ERR(lo_d_new)) {
1296 ret = PTR_ERR(lo_d_new);
1297 goto out;
1298 }
1299
1300 lo_d_new_dir = dget_parent(lo_d_new);
1301 lo_i_new_dir = d_inode(lo_d_new_dir);
1302 lo_d_old_dir = dget_parent(lo_d_old);
1303 lo_i_old_dir = d_inode(lo_d_old_dir);
1304
1305 ret = vfs_rename(lo_i_old_dir, lo_d_old, lo_i_new_dir, lo_d_new,
1306 NULL, flags);
1307 new_comrade = alloc_comrade(lo_p_new.dentry, comrade->dev_id);
1308 if (IS_ERR(new_comrade)) {
1309 ret = PTR_ERR(new_comrade);
1310 goto no_comrade;
1311 }
1312
1313 link_comrade_unlocked(new_dentry, new_comrade);
1314 no_comrade:
1315 done_path_create(&lo_p_new, lo_d_new);
1316 dput(lo_d_old_dir);
1317 dput(lo_d_new_dir);
1318 }
1319 out:
1320 kfree(abs_path_buf);
1321 kfree(path_buf);
1322 return ret;
1323 }
1324
hmdfs_rename_merge(struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)1325 int hmdfs_rename_merge(struct inode *old_dir, struct dentry *old_dentry,
1326 struct inode *new_dir, struct dentry *new_dentry,
1327 unsigned int flags)
1328 {
1329 char *old_dir_buf = NULL;
1330 char *new_dir_buf = NULL;
1331 char *old_dir_path = NULL;
1332 char *new_dir_path = NULL;
1333 struct dentry *old_dir_dentry = NULL;
1334 struct dentry *new_dir_dentry = NULL;
1335 int ret = 0;
1336
1337 if (hmdfs_file_type(old_dentry->d_name.name) != HMDFS_TYPE_COMMON ||
1338 hmdfs_file_type(new_dentry->d_name.name) != HMDFS_TYPE_COMMON) {
1339 ret = -EACCES;
1340 goto rename_out;
1341 }
1342
1343 if (hmdfs_i(old_dir)->inode_type != hmdfs_i(new_dir)->inode_type) {
1344 hmdfs_err("in different view");
1345 ret = -EPERM;
1346 goto rename_out;
1347 }
1348
1349 old_dir_buf = kmalloc(PATH_MAX, GFP_KERNEL);
1350 new_dir_buf = kmalloc(PATH_MAX, GFP_KERNEL);
1351 if (!old_dir_buf || !new_dir_buf) {
1352 ret = -ENOMEM;
1353 goto rename_out;
1354 }
1355
1356 new_dir_dentry = d_find_alias(new_dir);
1357 if (!new_dir_dentry) {
1358 ret = -EINVAL;
1359 goto rename_out;
1360 }
1361
1362 old_dir_dentry = d_find_alias(old_dir);
1363 if (!old_dir_dentry) {
1364 ret = -EINVAL;
1365 dput(new_dir_dentry);
1366 goto rename_out;
1367 }
1368
1369 old_dir_path = dentry_path_raw(old_dir_dentry, old_dir_buf, PATH_MAX);
1370 new_dir_path = dentry_path_raw(new_dir_dentry, new_dir_buf, PATH_MAX);
1371 dput(new_dir_dentry);
1372 dput(old_dir_dentry);
1373 if (strcmp(old_dir_path, new_dir_path)) {
1374 ret = -EPERM;
1375 goto rename_out;
1376 }
1377
1378 trace_hmdfs_rename_merge(old_dir, old_dentry, new_dir, new_dentry,
1379 flags);
1380 ret = do_rename_merge(old_dir, old_dentry, new_dir, new_dentry, flags);
1381
1382 if (ret != 0)
1383 d_drop(new_dentry);
1384
1385 if (S_ISREG(old_dentry->d_inode->i_mode) && !ret)
1386 d_invalidate(old_dentry);
1387
1388 rename_out:
1389 kfree(old_dir_buf);
1390 kfree(new_dir_buf);
1391 return ret;
1392 }
1393
1394 const struct inode_operations hmdfs_dir_iops_merge = {
1395 .lookup = hmdfs_lookup_merge,
1396 .mkdir = hmdfs_mkdir_merge,
1397 .create = hmdfs_create_merge,
1398 .rmdir = hmdfs_rmdir_merge,
1399 .unlink = hmdfs_unlink_merge,
1400 .rename = hmdfs_rename_merge,
1401 .permission = hmdfs_permission,
1402 };
1403