diff options
Diffstat (limited to 'fs/f2fs/namei.c')
-rw-r--r-- | fs/f2fs/namei.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 1b3cae03c24f..27b03776ffd2 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c | |||
@@ -485,6 +485,169 @@ out: | |||
485 | return err; | 485 | return err; |
486 | } | 486 | } |
487 | 487 | ||
488 | static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, | ||
489 | struct inode *new_dir, struct dentry *new_dentry) | ||
490 | { | ||
491 | struct super_block *sb = old_dir->i_sb; | ||
492 | struct f2fs_sb_info *sbi = F2FS_SB(sb); | ||
493 | struct inode *old_inode = old_dentry->d_inode; | ||
494 | struct inode *new_inode = new_dentry->d_inode; | ||
495 | struct page *old_dir_page, *new_dir_page; | ||
496 | struct page *old_page, *new_page; | ||
497 | struct f2fs_dir_entry *old_dir_entry = NULL, *new_dir_entry = NULL; | ||
498 | struct f2fs_dir_entry *old_entry, *new_entry; | ||
499 | int old_nlink = 0, new_nlink = 0; | ||
500 | int err = -ENOENT; | ||
501 | |||
502 | f2fs_balance_fs(sbi); | ||
503 | |||
504 | old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page); | ||
505 | if (!old_entry) | ||
506 | goto out; | ||
507 | |||
508 | new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name, &new_page); | ||
509 | if (!new_entry) | ||
510 | goto out_old; | ||
511 | |||
512 | /* prepare for updating ".." directory entry info later */ | ||
513 | if (old_dir != new_dir) { | ||
514 | if (S_ISDIR(old_inode->i_mode)) { | ||
515 | err = -EIO; | ||
516 | old_dir_entry = f2fs_parent_dir(old_inode, | ||
517 | &old_dir_page); | ||
518 | if (!old_dir_entry) | ||
519 | goto out_new; | ||
520 | } | ||
521 | |||
522 | if (S_ISDIR(new_inode->i_mode)) { | ||
523 | err = -EIO; | ||
524 | new_dir_entry = f2fs_parent_dir(new_inode, | ||
525 | &new_dir_page); | ||
526 | if (!new_dir_entry) | ||
527 | goto out_old_dir; | ||
528 | } | ||
529 | } | ||
530 | |||
531 | /* | ||
532 | * If cross rename between file and directory those are not | ||
533 | * in the same directory, we will inc nlink of file's parent | ||
534 | * later, so we should check upper boundary of its nlink. | ||
535 | */ | ||
536 | if ((!old_dir_entry || !new_dir_entry) && | ||
537 | old_dir_entry != new_dir_entry) { | ||
538 | old_nlink = old_dir_entry ? -1 : 1; | ||
539 | new_nlink = -old_nlink; | ||
540 | err = -EMLINK; | ||
541 | if ((old_nlink > 0 && old_inode->i_nlink >= F2FS_LINK_MAX) || | ||
542 | (new_nlink > 0 && new_inode->i_nlink >= F2FS_LINK_MAX)) | ||
543 | goto out_new_dir; | ||
544 | } | ||
545 | |||
546 | f2fs_lock_op(sbi); | ||
547 | |||
548 | err = update_dent_inode(old_inode, &new_dentry->d_name); | ||
549 | if (err) | ||
550 | goto out_unlock; | ||
551 | |||
552 | err = update_dent_inode(new_inode, &old_dentry->d_name); | ||
553 | if (err) | ||
554 | goto out_undo; | ||
555 | |||
556 | /* update ".." directory entry info of old dentry */ | ||
557 | if (old_dir_entry) | ||
558 | f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir); | ||
559 | |||
560 | /* update ".." directory entry info of new dentry */ | ||
561 | if (new_dir_entry) | ||
562 | f2fs_set_link(new_inode, new_dir_entry, new_dir_page, old_dir); | ||
563 | |||
564 | /* update directory entry info of old dir inode */ | ||
565 | f2fs_set_link(old_dir, old_entry, old_page, new_inode); | ||
566 | |||
567 | down_write(&F2FS_I(old_inode)->i_sem); | ||
568 | file_lost_pino(old_inode); | ||
569 | up_write(&F2FS_I(old_inode)->i_sem); | ||
570 | |||
571 | update_inode_page(old_inode); | ||
572 | |||
573 | old_dir->i_ctime = CURRENT_TIME; | ||
574 | if (old_nlink) { | ||
575 | down_write(&F2FS_I(old_dir)->i_sem); | ||
576 | if (old_nlink < 0) | ||
577 | drop_nlink(old_dir); | ||
578 | else | ||
579 | inc_nlink(old_dir); | ||
580 | up_write(&F2FS_I(old_dir)->i_sem); | ||
581 | } | ||
582 | mark_inode_dirty(old_dir); | ||
583 | update_inode_page(old_dir); | ||
584 | |||
585 | /* update directory entry info of new dir inode */ | ||
586 | f2fs_set_link(new_dir, new_entry, new_page, old_inode); | ||
587 | |||
588 | down_write(&F2FS_I(new_inode)->i_sem); | ||
589 | file_lost_pino(new_inode); | ||
590 | up_write(&F2FS_I(new_inode)->i_sem); | ||
591 | |||
592 | update_inode_page(new_inode); | ||
593 | |||
594 | new_dir->i_ctime = CURRENT_TIME; | ||
595 | if (new_nlink) { | ||
596 | down_write(&F2FS_I(new_dir)->i_sem); | ||
597 | if (new_nlink < 0) | ||
598 | drop_nlink(new_dir); | ||
599 | else | ||
600 | inc_nlink(new_dir); | ||
601 | up_write(&F2FS_I(new_dir)->i_sem); | ||
602 | } | ||
603 | mark_inode_dirty(new_dir); | ||
604 | update_inode_page(new_dir); | ||
605 | |||
606 | f2fs_unlock_op(sbi); | ||
607 | return 0; | ||
608 | out_undo: | ||
609 | /* Still we may fail to recover name info of f2fs_inode here */ | ||
610 | update_dent_inode(old_inode, &old_dentry->d_name); | ||
611 | out_unlock: | ||
612 | f2fs_unlock_op(sbi); | ||
613 | out_new_dir: | ||
614 | if (new_dir_entry) { | ||
615 | kunmap(new_dir_page); | ||
616 | f2fs_put_page(new_dir_page, 0); | ||
617 | } | ||
618 | out_old_dir: | ||
619 | if (old_dir_entry) { | ||
620 | kunmap(old_dir_page); | ||
621 | f2fs_put_page(old_dir_page, 0); | ||
622 | } | ||
623 | out_new: | ||
624 | kunmap(new_page); | ||
625 | f2fs_put_page(new_page, 0); | ||
626 | out_old: | ||
627 | kunmap(old_page); | ||
628 | f2fs_put_page(old_page, 0); | ||
629 | out: | ||
630 | return err; | ||
631 | } | ||
632 | |||
633 | static int f2fs_rename2(struct inode *old_dir, struct dentry *old_dentry, | ||
634 | struct inode *new_dir, struct dentry *new_dentry, | ||
635 | unsigned int flags) | ||
636 | { | ||
637 | if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) | ||
638 | return -EINVAL; | ||
639 | |||
640 | if (flags & RENAME_EXCHANGE) { | ||
641 | return f2fs_cross_rename(old_dir, old_dentry, | ||
642 | new_dir, new_dentry); | ||
643 | } | ||
644 | /* | ||
645 | * VFS has already handled the new dentry existence case, | ||
646 | * here, we just deal with "RENAME_NOREPLACE" as regular rename. | ||
647 | */ | ||
648 | return f2fs_rename(old_dir, old_dentry, new_dir, new_dentry); | ||
649 | } | ||
650 | |||
488 | static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) | 651 | static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) |
489 | { | 652 | { |
490 | struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); | 653 | struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); |
@@ -542,6 +705,7 @@ const struct inode_operations f2fs_dir_inode_operations = { | |||
542 | .rmdir = f2fs_rmdir, | 705 | .rmdir = f2fs_rmdir, |
543 | .mknod = f2fs_mknod, | 706 | .mknod = f2fs_mknod, |
544 | .rename = f2fs_rename, | 707 | .rename = f2fs_rename, |
708 | .rename2 = f2fs_rename2, | ||
545 | .tmpfile = f2fs_tmpfile, | 709 | .tmpfile = f2fs_tmpfile, |
546 | .getattr = f2fs_getattr, | 710 | .getattr = f2fs_getattr, |
547 | .setattr = f2fs_setattr, | 711 | .setattr = f2fs_setattr, |