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 22static 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); 83out: 84 dput(fst_lo_d); 85 return inode; 86bad_inode: 87 iget_failed(inode); 88 return ERR_PTR(ret); 89} 90 91static struct hmdfs_dentry_comrade * 92cloud_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); 116root_put: 117 path_put(&root); 118out: 119 return comrade; 120} 121 122static 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 144static 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 188found: 189 kfree(cpath); 190out_ppath: 191 kfree(ppath); 192out_rname: 193 kfree(rname); 194out: 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 */ 205static 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 240out: 241 kfree(buf); 242 return ret; 243} 244 245static 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 274free_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 281struct 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 352out: 353 return err ? ERR_PTR(err) : ret_dentry; 354} 355 356const struct inode_operations hmdfs_file_iops_cloud_merge = { 357 .getattr = hmdfs_getattr_merge, 358 .setattr = hmdfs_setattr_merge, 359 .permission = hmdfs_permission, 360}; 361 362int 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); 385out: 386 return ret; 387} 388 389int 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); 412out: 413 return ret; 414} 415 416int 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 449int 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 506out_put: 507 done_path_create(&path, lo_d_child); 508out: 509 kfree(absolute_path_buf); 510 kfree(path_buf); 511 return ret; 512} 513 514static 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); 540out: 541 dput(lo_d_parent); 542 return ret; 543} 544 545int 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 575out: 576 dput(d_parent); 577 dput(lo_d_parent); 578 return ret; 579} 580 581int 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); 600out: 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 608int 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); 623out: 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 631static 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 657out: 658 dput(d_parent); 659 dput(lo_d_parent); 660 return ret; 661} 662 663static 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); 706rename_out: 707 kfree(rec_op_para); 708 return ret; 709} 710 711void hmdfs_update_meta(struct inode *dir) 712{ 713 dir->i_ctime = dir->i_mtime = current_time(dir); 714} 715 716const 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