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