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 22struct kmem_cache *hmdfs_dentry_merge_cachep; 23 24struct 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 39struct 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 56void 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 85int 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 98static 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); 159out: 160 dput(fst_lo_d); 161 return inode; 162bad_inode: 163 iget_failed(inode); 164 return ERR_PTR(ret); 165} 166 167struct 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 182void 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 */ 209void 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 220struct 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 */ 244static 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 */ 254static 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 */ 266static 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 303int 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 345static 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); 369root_put: 370 path_put(&root); 371out: 372 hmdfs_revert_creds(old_cred); 373 return comrade; 374} 375 376bool 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 395static 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 425out: 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 435int 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; 461out: 462 return err; 463} 464 465char *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 480static 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); 538out_ppath: 539 kfree(ppath); 540out_rname: 541 kfree(rname); 542out: 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 */ 553static 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 594out: 595 kfree(buf); 596 return ret; 597} 598 599// mkdir -p 600void 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 630void 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 640static 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 669free_buf: 670 kfree(buf); 671 restore_root_inode_sem(root_inode, locked, down); 672 return ret; 673} 674 675int 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 698struct 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 769out: 770 return err ? ERR_PTR(err) : ret_dentry; 771} 772 773int hmdfs_getattr_merge(struct mnt_idmap *idmap, 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); 789out: 790 dput(lower_path.dentry); 791 return ret; 792} 793 794int hmdfs_setattr_merge(struct mnt_idmap *idmap, 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(&nop_mnt_idmap, 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 828out: 829 dput(lower_dentry); 830 return err; 831} 832 833const struct inode_operations hmdfs_file_iops_merge = { 834 .getattr = hmdfs_getattr_merge, 835 .setattr = hmdfs_setattr_merge, 836 .permission = hmdfs_permission, 837}; 838 839int 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(&nop_mnt_idmap, 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); 863out: 864 return ret; 865} 866 867int 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(&nop_mnt_idmap, 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); 891out: 892 return ret; 893} 894 895int 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(&nop_mnt_idmap, 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 928int 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 985out_put: 986 done_path_create(&path, lo_d_child); 987out: 988 kfree(absolute_path_buf); 989 kfree(path_buf); 990 return ret; 991} 992 993static 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); 1022out: 1023 dput(lo_d_parent); 1024 return ret; 1025} 1026 1027int 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 1060out: 1061 dput(d_parent); 1062 dput(lo_d_parent); 1063 return ret; 1064} 1065 1066void 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 1077int hmdfs_mkdir_merge(struct mnt_idmap *idmap, 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); 1096out: 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 1104int hmdfs_create_merge(struct mnt_idmap *idmap, 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); 1119out: 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 1127int 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(&nop_mnt_idmap, 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 1153int 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); 1170out: 1171 hmdfs_trace_merge(trace_hmdfs_rmdir_merge, dir, dentry, ret); 1172 return ret; 1173} 1174 1175int 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(&nop_mnt_idmap, 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 1215int 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); 1233out: 1234 return ret; 1235} 1236 1237int 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 struct renamedata rename_data; 1255 1256 if (flags & ~RENAME_NOREPLACE) { 1257 ret = -EINVAL; 1258 goto out; 1259 } 1260 1261 if (unlikely(!path_buf || !abs_path_buf)) { 1262 ret = -ENOMEM; 1263 goto out; 1264 } 1265 1266 wait_event(dim->wait_queue, !has_merge_lookup_work(dim)); 1267 1268 list_for_each_entry(comrade, &dim->comrade_list, list) { 1269 lo_d_old = comrade->lo_d; 1270 d_new_dir = d_find_alias(new_dir); 1271 pmdi = hmdfs_dm(d_new_dir); 1272 wait_event(pmdi->wait_queue, !has_merge_lookup_work(pmdi)); 1273 lo_d_new_dir = hmdfs_get_lo_d(d_new_dir, comrade->dev_id); 1274 dput(d_new_dir); 1275 1276 if (!lo_d_new_dir) 1277 continue; 1278 path_name = dentry_path_raw(lo_d_new_dir, path_buf, PATH_MAX); 1279 dput(lo_d_new_dir); 1280 if (IS_ERR(path_name)) { 1281 ret = PTR_ERR(path_name); 1282 continue; 1283 } 1284 1285 if (strlen(sbi->real_dst) + strlen(path_name) + 1286 strlen(new_dentry->d_name.name) + 2 > PATH_MAX) { 1287 ret = -ENAMETOOLONG; 1288 goto out; 1289 } 1290 1291 snprintf(abs_path_buf, PATH_MAX, "%s%s/%s", sbi->real_dst, 1292 path_name, new_dentry->d_name.name); 1293 if (S_ISDIR(d_inode(old_dentry)->i_mode)) 1294 lo_d_new = kern_path_create(AT_FDCWD, abs_path_buf, 1295 &lo_p_new, 1296 LOOKUP_DIRECTORY); 1297 else 1298 lo_d_new = kern_path_create(AT_FDCWD, abs_path_buf, 1299 &lo_p_new, 0); 1300 if (IS_ERR(lo_d_new)) { 1301 ret = PTR_ERR(lo_d_new); 1302 goto out; 1303 } 1304 1305 lo_d_new_dir = dget_parent(lo_d_new); 1306 lo_i_new_dir = d_inode(lo_d_new_dir); 1307 lo_d_old_dir = dget_parent(lo_d_old); 1308 lo_i_old_dir = d_inode(lo_d_old_dir); 1309 1310 rename_data.old_mnt_idmap = &nop_mnt_idmap; 1311 rename_data.old_dir = lo_i_old_dir; 1312 rename_data.old_dentry = lo_d_old; 1313 rename_data.new_mnt_idmap = &nop_mnt_idmap; 1314 rename_data.new_dir = lo_i_new_dir; 1315 rename_data.new_dentry = lo_d_new; 1316 rename_data.flags = flags; 1317 ret = vfs_rename(&rename_data); 1318 1319 new_comrade = alloc_comrade(lo_p_new.dentry, comrade->dev_id); 1320 if (IS_ERR(new_comrade)) { 1321 ret = PTR_ERR(new_comrade); 1322 goto no_comrade; 1323 } 1324 1325 link_comrade_unlocked(new_dentry, new_comrade); 1326no_comrade: 1327 done_path_create(&lo_p_new, lo_d_new); 1328 dput(lo_d_old_dir); 1329 dput(lo_d_new_dir); 1330 } 1331out: 1332 kfree(abs_path_buf); 1333 kfree(path_buf); 1334 return ret; 1335} 1336 1337int hmdfs_rename_merge(struct mnt_idmap *idmap, struct inode *old_dir, struct dentry *old_dentry, 1338 struct inode *new_dir, struct dentry *new_dentry, 1339 unsigned int flags) 1340{ 1341 char *old_dir_buf = NULL; 1342 char *new_dir_buf = NULL; 1343 char *old_dir_path = NULL; 1344 char *new_dir_path = NULL; 1345 struct dentry *old_dir_dentry = NULL; 1346 struct dentry *new_dir_dentry = NULL; 1347 int ret = 0; 1348 1349 if (hmdfs_file_type(old_dentry->d_name.name) != HMDFS_TYPE_COMMON || 1350 hmdfs_file_type(new_dentry->d_name.name) != HMDFS_TYPE_COMMON) { 1351 ret = -EACCES; 1352 goto rename_out; 1353 } 1354 1355 if (hmdfs_i(old_dir)->inode_type != hmdfs_i(new_dir)->inode_type) { 1356 hmdfs_err("in different view"); 1357 ret = -EPERM; 1358 goto rename_out; 1359 } 1360 1361 old_dir_buf = kmalloc(PATH_MAX, GFP_KERNEL); 1362 new_dir_buf = kmalloc(PATH_MAX, GFP_KERNEL); 1363 if (!old_dir_buf || !new_dir_buf) { 1364 ret = -ENOMEM; 1365 goto rename_out; 1366 } 1367 1368 new_dir_dentry = d_find_alias(new_dir); 1369 if (!new_dir_dentry) { 1370 ret = -EINVAL; 1371 goto rename_out; 1372 } 1373 1374 old_dir_dentry = d_find_alias(old_dir); 1375 if (!old_dir_dentry) { 1376 ret = -EINVAL; 1377 dput(new_dir_dentry); 1378 goto rename_out; 1379 } 1380 1381 old_dir_path = dentry_path_raw(old_dir_dentry, old_dir_buf, PATH_MAX); 1382 new_dir_path = dentry_path_raw(new_dir_dentry, new_dir_buf, PATH_MAX); 1383 dput(new_dir_dentry); 1384 dput(old_dir_dentry); 1385 if (strcmp(old_dir_path, new_dir_path)) { 1386 ret = -EPERM; 1387 goto rename_out; 1388 } 1389 1390 trace_hmdfs_rename_merge(old_dir, old_dentry, new_dir, new_dentry, 1391 flags); 1392 ret = do_rename_merge(old_dir, old_dentry, new_dir, new_dentry, flags); 1393 1394 if (ret != 0) 1395 d_drop(new_dentry); 1396 1397 if (S_ISREG(old_dentry->d_inode->i_mode) && !ret) 1398 d_invalidate(old_dentry); 1399 1400rename_out: 1401 kfree(old_dir_buf); 1402 kfree(new_dir_buf); 1403 return ret; 1404} 1405 1406const struct inode_operations hmdfs_dir_iops_merge = { 1407 .lookup = hmdfs_lookup_merge, 1408 .mkdir = hmdfs_mkdir_merge, 1409 .create = hmdfs_create_merge, 1410 .rmdir = hmdfs_rmdir_merge, 1411 .unlink = hmdfs_unlink_merge, 1412 .rename = hmdfs_rename_merge, 1413 .permission = hmdfs_permission, 1414}; 1415