diff options
| author | Dave Chinner <david@fromorbit.com> | 2015-03-24 23:29:13 -0400 |
|---|---|---|
| committer | Dave Chinner <david@fromorbit.com> | 2015-03-24 23:29:13 -0400 |
| commit | d41bb03444147305e955cdd53753f0493e4d9e28 (patch) | |
| tree | 37535eb32e725933b0c24df5c52c123b187fa910 /fs/xfs | |
| parent | 88e8fda99a4c99a1a6482510655dbd88cccd221b (diff) | |
| parent | 7dcf5c3e4527cfa2807567b00387cf2ed5e07f00 (diff) | |
Merge branch 'xfs-rename-whiteout' into for-next
Conflicts:
fs/xfs/xfs_inode.c
Diffstat (limited to 'fs/xfs')
| -rw-r--r-- | fs/xfs/xfs_inode.c | 408 | ||||
| -rw-r--r-- | fs/xfs/xfs_iops.c | 2 |
2 files changed, 239 insertions, 171 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 5a44f1cc820c..8394f6f17120 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -391,15 +391,14 @@ xfs_lock_inumorder(int lock_mode, int subclass) | |||
| 391 | } | 391 | } |
| 392 | 392 | ||
| 393 | /* | 393 | /* |
| 394 | * The following routine will lock n inodes in exclusive mode. | 394 | * The following routine will lock n inodes in exclusive mode. We assume the |
| 395 | * We assume the caller calls us with the inodes in i_ino order. | 395 | * caller calls us with the inodes in i_ino order. |
| 396 | * | 396 | * |
| 397 | * We need to detect deadlock where an inode that we lock | 397 | * We need to detect deadlock where an inode that we lock is in the AIL and we |
| 398 | * is in the AIL and we start waiting for another inode that is locked | 398 | * start waiting for another inode that is locked by a thread in a long running |
| 399 | * by a thread in a long running transaction (such as truncate). This can | 399 | * transaction (such as truncate). This can result in deadlock since the long |
| 400 | * result in deadlock since the long running trans might need to wait | 400 | * running trans might need to wait for the inode we just locked in order to |
| 401 | * for the inode we just locked in order to push the tail and free space | 401 | * push the tail and free space in the log. |
| 402 | * in the log. | ||
| 403 | */ | 402 | */ |
| 404 | void | 403 | void |
| 405 | xfs_lock_inodes( | 404 | xfs_lock_inodes( |
| @@ -410,30 +409,27 @@ xfs_lock_inodes( | |||
| 410 | int attempts = 0, i, j, try_lock; | 409 | int attempts = 0, i, j, try_lock; |
| 411 | xfs_log_item_t *lp; | 410 | xfs_log_item_t *lp; |
| 412 | 411 | ||
| 413 | ASSERT(ips && (inodes >= 2)); /* we need at least two */ | 412 | /* currently supports between 2 and 5 inodes */ |
| 413 | ASSERT(ips && inodes >= 2 && inodes <= 5); | ||
| 414 | 414 | ||
| 415 | try_lock = 0; | 415 | try_lock = 0; |
| 416 | i = 0; | 416 | i = 0; |
| 417 | |||
| 418 | again: | 417 | again: |
| 419 | for (; i < inodes; i++) { | 418 | for (; i < inodes; i++) { |
| 420 | ASSERT(ips[i]); | 419 | ASSERT(ips[i]); |
| 421 | 420 | ||
| 422 | if (i && (ips[i] == ips[i-1])) /* Already locked */ | 421 | if (i && (ips[i] == ips[i - 1])) /* Already locked */ |
| 423 | continue; | 422 | continue; |
| 424 | 423 | ||
| 425 | /* | 424 | /* |
| 426 | * If try_lock is not set yet, make sure all locked inodes | 425 | * If try_lock is not set yet, make sure all locked inodes are |
| 427 | * are not in the AIL. | 426 | * not in the AIL. If any are, set try_lock to be used later. |
| 428 | * If any are, set try_lock to be used later. | ||
| 429 | */ | 427 | */ |
| 430 | |||
| 431 | if (!try_lock) { | 428 | if (!try_lock) { |
| 432 | for (j = (i - 1); j >= 0 && !try_lock; j--) { | 429 | for (j = (i - 1); j >= 0 && !try_lock; j--) { |
| 433 | lp = (xfs_log_item_t *)ips[j]->i_itemp; | 430 | lp = (xfs_log_item_t *)ips[j]->i_itemp; |
| 434 | if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { | 431 | if (lp && (lp->li_flags & XFS_LI_IN_AIL)) |
| 435 | try_lock++; | 432 | try_lock++; |
| 436 | } | ||
| 437 | } | 433 | } |
| 438 | } | 434 | } |
| 439 | 435 | ||
| @@ -443,51 +439,42 @@ again: | |||
| 443 | * we can't get any, we must release all we have | 439 | * we can't get any, we must release all we have |
| 444 | * and try again. | 440 | * and try again. |
| 445 | */ | 441 | */ |
| 442 | if (!try_lock) { | ||
| 443 | xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i)); | ||
| 444 | continue; | ||
| 445 | } | ||
| 446 | |||
| 447 | /* try_lock means we have an inode locked that is in the AIL. */ | ||
| 448 | ASSERT(i != 0); | ||
| 449 | if (xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) | ||
| 450 | continue; | ||
| 446 | 451 | ||
| 447 | if (try_lock) { | 452 | /* |
| 448 | /* try_lock must be 0 if i is 0. */ | 453 | * Unlock all previous guys and try again. xfs_iunlock will try |
| 454 | * to push the tail if the inode is in the AIL. | ||
| 455 | */ | ||
| 456 | attempts++; | ||
| 457 | for (j = i - 1; j >= 0; j--) { | ||
| 449 | /* | 458 | /* |
| 450 | * try_lock means we have an inode locked | 459 | * Check to see if we've already unlocked this one. Not |
| 451 | * that is in the AIL. | 460 | * the first one going back, and the inode ptr is the |
| 461 | * same. | ||
| 452 | */ | 462 | */ |
| 453 | ASSERT(i != 0); | 463 | if (j != (i - 1) && ips[j] == ips[j + 1]) |
| 454 | if (!xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) { | 464 | continue; |
| 455 | attempts++; | ||
| 456 | |||
| 457 | /* | ||
| 458 | * Unlock all previous guys and try again. | ||
| 459 | * xfs_iunlock will try to push the tail | ||
| 460 | * if the inode is in the AIL. | ||
| 461 | */ | ||
| 462 | |||
| 463 | for(j = i - 1; j >= 0; j--) { | ||
| 464 | |||
| 465 | /* | ||
| 466 | * Check to see if we've already | ||
| 467 | * unlocked this one. | ||
| 468 | * Not the first one going back, | ||
| 469 | * and the inode ptr is the same. | ||
| 470 | */ | ||
| 471 | if ((j != (i - 1)) && ips[j] == | ||
| 472 | ips[j+1]) | ||
| 473 | continue; | ||
| 474 | |||
| 475 | xfs_iunlock(ips[j], lock_mode); | ||
| 476 | } | ||
| 477 | 465 | ||
| 478 | if ((attempts % 5) == 0) { | 466 | xfs_iunlock(ips[j], lock_mode); |
| 479 | delay(1); /* Don't just spin the CPU */ | 467 | } |
| 468 | |||
| 469 | if ((attempts % 5) == 0) { | ||
| 470 | delay(1); /* Don't just spin the CPU */ | ||
| 480 | #ifdef DEBUG | 471 | #ifdef DEBUG |
| 481 | xfs_lock_delays++; | 472 | xfs_lock_delays++; |
| 482 | #endif | 473 | #endif |
| 483 | } | ||
| 484 | i = 0; | ||
| 485 | try_lock = 0; | ||
| 486 | goto again; | ||
| 487 | } | ||
| 488 | } else { | ||
| 489 | xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i)); | ||
| 490 | } | 474 | } |
| 475 | i = 0; | ||
| 476 | try_lock = 0; | ||
| 477 | goto again; | ||
| 491 | } | 478 | } |
| 492 | 479 | ||
| 493 | #ifdef DEBUG | 480 | #ifdef DEBUG |
| @@ -2681,19 +2668,22 @@ xfs_remove( | |||
| 2681 | /* | 2668 | /* |
| 2682 | * Enter all inodes for a rename transaction into a sorted array. | 2669 | * Enter all inodes for a rename transaction into a sorted array. |
| 2683 | */ | 2670 | */ |
| 2671 | #define __XFS_SORT_INODES 5 | ||
| 2684 | STATIC void | 2672 | STATIC void |
| 2685 | xfs_sort_for_rename( | 2673 | xfs_sort_for_rename( |
| 2686 | xfs_inode_t *dp1, /* in: old (source) directory inode */ | 2674 | struct xfs_inode *dp1, /* in: old (source) directory inode */ |
| 2687 | xfs_inode_t *dp2, /* in: new (target) directory inode */ | 2675 | struct xfs_inode *dp2, /* in: new (target) directory inode */ |
| 2688 | xfs_inode_t *ip1, /* in: inode of old entry */ | 2676 | struct xfs_inode *ip1, /* in: inode of old entry */ |
| 2689 | xfs_inode_t *ip2, /* in: inode of new entry, if it | 2677 | struct xfs_inode *ip2, /* in: inode of new entry */ |
| 2690 | already exists, NULL otherwise. */ | 2678 | struct xfs_inode *wip, /* in: whiteout inode */ |
| 2691 | xfs_inode_t **i_tab,/* out: array of inode returned, sorted */ | 2679 | struct xfs_inode **i_tab,/* out: sorted array of inodes */ |
| 2692 | int *num_inodes) /* out: number of inodes in array */ | 2680 | int *num_inodes) /* in/out: inodes in array */ |
| 2693 | { | 2681 | { |
| 2694 | xfs_inode_t *temp; | ||
| 2695 | int i, j; | 2682 | int i, j; |
| 2696 | 2683 | ||
| 2684 | ASSERT(*num_inodes == __XFS_SORT_INODES); | ||
| 2685 | memset(i_tab, 0, *num_inodes * sizeof(struct xfs_inode *)); | ||
| 2686 | |||
| 2697 | /* | 2687 | /* |
| 2698 | * i_tab contains a list of pointers to inodes. We initialize | 2688 | * i_tab contains a list of pointers to inodes. We initialize |
| 2699 | * the table here & we'll sort it. We will then use it to | 2689 | * the table here & we'll sort it. We will then use it to |
| @@ -2701,25 +2691,24 @@ xfs_sort_for_rename( | |||
| 2701 | * | 2691 | * |
| 2702 | * Note that the table may contain duplicates. e.g., dp1 == dp2. | 2692 | * Note that the table may contain duplicates. e.g., dp1 == dp2. |
| 2703 | */ | 2693 | */ |
| 2704 | i_tab[0] = dp1; | 2694 | i = 0; |
| 2705 | i_tab[1] = dp2; | 2695 | i_tab[i++] = dp1; |
| 2706 | i_tab[2] = ip1; | 2696 | i_tab[i++] = dp2; |
| 2707 | if (ip2) { | 2697 | i_tab[i++] = ip1; |
| 2708 | *num_inodes = 4; | 2698 | if (ip2) |
| 2709 | i_tab[3] = ip2; | 2699 | i_tab[i++] = ip2; |
| 2710 | } else { | 2700 | if (wip) |
| 2711 | *num_inodes = 3; | 2701 | i_tab[i++] = wip; |
| 2712 | i_tab[3] = NULL; | 2702 | *num_inodes = i; |
| 2713 | } | ||
| 2714 | 2703 | ||
| 2715 | /* | 2704 | /* |
| 2716 | * Sort the elements via bubble sort. (Remember, there are at | 2705 | * Sort the elements via bubble sort. (Remember, there are at |
| 2717 | * most 4 elements to sort, so this is adequate.) | 2706 | * most 5 elements to sort, so this is adequate.) |
| 2718 | */ | 2707 | */ |
| 2719 | for (i = 0; i < *num_inodes; i++) { | 2708 | for (i = 0; i < *num_inodes; i++) { |
| 2720 | for (j = 1; j < *num_inodes; j++) { | 2709 | for (j = 1; j < *num_inodes; j++) { |
| 2721 | if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) { | 2710 | if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) { |
| 2722 | temp = i_tab[j]; | 2711 | struct xfs_inode *temp = i_tab[j]; |
| 2723 | i_tab[j] = i_tab[j-1]; | 2712 | i_tab[j] = i_tab[j-1]; |
| 2724 | i_tab[j-1] = temp; | 2713 | i_tab[j-1] = temp; |
| 2725 | } | 2714 | } |
| @@ -2727,6 +2716,31 @@ xfs_sort_for_rename( | |||
| 2727 | } | 2716 | } |
| 2728 | } | 2717 | } |
| 2729 | 2718 | ||
| 2719 | static int | ||
| 2720 | xfs_finish_rename( | ||
| 2721 | struct xfs_trans *tp, | ||
| 2722 | struct xfs_bmap_free *free_list) | ||
| 2723 | { | ||
| 2724 | int committed = 0; | ||
| 2725 | int error; | ||
| 2726 | |||
| 2727 | /* | ||
| 2728 | * If this is a synchronous mount, make sure that the rename transaction | ||
| 2729 | * goes to disk before returning to the user. | ||
| 2730 | */ | ||
| 2731 | if (tp->t_mountp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) | ||
| 2732 | xfs_trans_set_sync(tp); | ||
| 2733 | |||
| 2734 | error = xfs_bmap_finish(&tp, free_list, &committed); | ||
| 2735 | if (error) { | ||
| 2736 | xfs_bmap_cancel(free_list); | ||
| 2737 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); | ||
| 2738 | return error; | ||
| 2739 | } | ||
| 2740 | |||
| 2741 | return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | ||
| 2742 | } | ||
| 2743 | |||
| 2730 | /* | 2744 | /* |
| 2731 | * xfs_cross_rename() | 2745 | * xfs_cross_rename() |
| 2732 | * | 2746 | * |
| @@ -2755,14 +2769,14 @@ xfs_cross_rename( | |||
| 2755 | ip2->i_ino, | 2769 | ip2->i_ino, |
| 2756 | first_block, free_list, spaceres); | 2770 | first_block, free_list, spaceres); |
| 2757 | if (error) | 2771 | if (error) |
| 2758 | goto out; | 2772 | goto out_trans_abort; |
| 2759 | 2773 | ||
| 2760 | /* Swap inode number for dirent in second parent */ | 2774 | /* Swap inode number for dirent in second parent */ |
| 2761 | error = xfs_dir_replace(tp, dp2, name2, | 2775 | error = xfs_dir_replace(tp, dp2, name2, |
| 2762 | ip1->i_ino, | 2776 | ip1->i_ino, |
| 2763 | first_block, free_list, spaceres); | 2777 | first_block, free_list, spaceres); |
| 2764 | if (error) | 2778 | if (error) |
| 2765 | goto out; | 2779 | goto out_trans_abort; |
| 2766 | 2780 | ||
| 2767 | /* | 2781 | /* |
| 2768 | * If we're renaming one or more directories across different parents, | 2782 | * If we're renaming one or more directories across different parents, |
| @@ -2777,16 +2791,16 @@ xfs_cross_rename( | |||
| 2777 | dp1->i_ino, first_block, | 2791 | dp1->i_ino, first_block, |
| 2778 | free_list, spaceres); | 2792 | free_list, spaceres); |
| 2779 | if (error) | 2793 | if (error) |
| 2780 | goto out; | 2794 | goto out_trans_abort; |
| 2781 | 2795 | ||
| 2782 | /* transfer ip2 ".." reference to dp1 */ | 2796 | /* transfer ip2 ".." reference to dp1 */ |
| 2783 | if (!S_ISDIR(ip1->i_d.di_mode)) { | 2797 | if (!S_ISDIR(ip1->i_d.di_mode)) { |
| 2784 | error = xfs_droplink(tp, dp2); | 2798 | error = xfs_droplink(tp, dp2); |
| 2785 | if (error) | 2799 | if (error) |
| 2786 | goto out; | 2800 | goto out_trans_abort; |
| 2787 | error = xfs_bumplink(tp, dp1); | 2801 | error = xfs_bumplink(tp, dp1); |
| 2788 | if (error) | 2802 | if (error) |
| 2789 | goto out; | 2803 | goto out_trans_abort; |
| 2790 | } | 2804 | } |
| 2791 | 2805 | ||
| 2792 | /* | 2806 | /* |
| @@ -2804,16 +2818,16 @@ xfs_cross_rename( | |||
| 2804 | dp2->i_ino, first_block, | 2818 | dp2->i_ino, first_block, |
| 2805 | free_list, spaceres); | 2819 | free_list, spaceres); |
| 2806 | if (error) | 2820 | if (error) |
| 2807 | goto out; | 2821 | goto out_trans_abort; |
| 2808 | 2822 | ||
| 2809 | /* transfer ip1 ".." reference to dp2 */ | 2823 | /* transfer ip1 ".." reference to dp2 */ |
| 2810 | if (!S_ISDIR(ip2->i_d.di_mode)) { | 2824 | if (!S_ISDIR(ip2->i_d.di_mode)) { |
| 2811 | error = xfs_droplink(tp, dp1); | 2825 | error = xfs_droplink(tp, dp1); |
| 2812 | if (error) | 2826 | if (error) |
| 2813 | goto out; | 2827 | goto out_trans_abort; |
| 2814 | error = xfs_bumplink(tp, dp2); | 2828 | error = xfs_bumplink(tp, dp2); |
| 2815 | if (error) | 2829 | if (error) |
| 2816 | goto out; | 2830 | goto out_trans_abort; |
| 2817 | } | 2831 | } |
| 2818 | 2832 | ||
| 2819 | /* | 2833 | /* |
| @@ -2841,66 +2855,108 @@ xfs_cross_rename( | |||
| 2841 | } | 2855 | } |
| 2842 | xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 2856 | xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| 2843 | xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE); | 2857 | xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE); |
| 2844 | out: | 2858 | return xfs_finish_rename(tp, free_list); |
| 2859 | |||
| 2860 | out_trans_abort: | ||
| 2861 | xfs_bmap_cancel(free_list); | ||
| 2862 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); | ||
| 2845 | return error; | 2863 | return error; |
| 2846 | } | 2864 | } |
| 2847 | 2865 | ||
| 2848 | /* | 2866 | /* |
| 2867 | * xfs_rename_alloc_whiteout() | ||
| 2868 | * | ||
| 2869 | * Return a referenced, unlinked, unlocked inode that that can be used as a | ||
| 2870 | * whiteout in a rename transaction. We use a tmpfile inode here so that if we | ||
| 2871 | * crash between allocating the inode and linking it into the rename transaction | ||
| 2872 | * recovery will free the inode and we won't leak it. | ||
| 2873 | */ | ||
| 2874 | static int | ||
| 2875 | xfs_rename_alloc_whiteout( | ||
| 2876 | struct xfs_inode *dp, | ||
| 2877 | struct xfs_inode **wip) | ||
| 2878 | { | ||
| 2879 | struct xfs_inode *tmpfile; | ||
| 2880 | int error; | ||
| 2881 | |||
| 2882 | error = xfs_create_tmpfile(dp, NULL, S_IFCHR | WHITEOUT_MODE, &tmpfile); | ||
| 2883 | if (error) | ||
| 2884 | return error; | ||
| 2885 | |||
| 2886 | /* Satisfy xfs_bumplink that this is a real tmpfile */ | ||
| 2887 | xfs_finish_inode_setup(tmpfile); | ||
| 2888 | VFS_I(tmpfile)->i_state |= I_LINKABLE; | ||
| 2889 | |||
| 2890 | *wip = tmpfile; | ||
| 2891 | return 0; | ||
| 2892 | } | ||
| 2893 | |||
| 2894 | /* | ||
| 2849 | * xfs_rename | 2895 | * xfs_rename |
| 2850 | */ | 2896 | */ |
| 2851 | int | 2897 | int |
| 2852 | xfs_rename( | 2898 | xfs_rename( |
| 2853 | xfs_inode_t *src_dp, | 2899 | struct xfs_inode *src_dp, |
| 2854 | struct xfs_name *src_name, | 2900 | struct xfs_name *src_name, |
| 2855 | xfs_inode_t *src_ip, | 2901 | struct xfs_inode *src_ip, |
| 2856 | xfs_inode_t *target_dp, | 2902 | struct xfs_inode *target_dp, |
| 2857 | struct xfs_name *target_name, | 2903 | struct xfs_name *target_name, |
| 2858 | xfs_inode_t *target_ip, | 2904 | struct xfs_inode *target_ip, |
| 2859 | unsigned int flags) | 2905 | unsigned int flags) |
| 2860 | { | 2906 | { |
| 2861 | xfs_trans_t *tp = NULL; | 2907 | struct xfs_mount *mp = src_dp->i_mount; |
| 2862 | xfs_mount_t *mp = src_dp->i_mount; | 2908 | struct xfs_trans *tp; |
| 2863 | int new_parent; /* moving to a new dir */ | 2909 | struct xfs_bmap_free free_list; |
| 2864 | int src_is_directory; /* src_name is a directory */ | 2910 | xfs_fsblock_t first_block; |
| 2865 | int error; | 2911 | struct xfs_inode *wip = NULL; /* whiteout inode */ |
| 2866 | xfs_bmap_free_t free_list; | 2912 | struct xfs_inode *inodes[__XFS_SORT_INODES]; |
| 2867 | xfs_fsblock_t first_block; | 2913 | int num_inodes = __XFS_SORT_INODES; |
| 2868 | int cancel_flags; | 2914 | int new_parent = (src_dp != target_dp); |
| 2869 | int committed; | 2915 | int src_is_directory = S_ISDIR(src_ip->i_d.di_mode); |
| 2870 | xfs_inode_t *inodes[4]; | 2916 | int cancel_flags = 0; |
| 2871 | int spaceres; | 2917 | int spaceres; |
| 2872 | int num_inodes; | 2918 | int error; |
| 2873 | 2919 | ||
| 2874 | trace_xfs_rename(src_dp, target_dp, src_name, target_name); | 2920 | trace_xfs_rename(src_dp, target_dp, src_name, target_name); |
| 2875 | 2921 | ||
| 2876 | new_parent = (src_dp != target_dp); | 2922 | if ((flags & RENAME_EXCHANGE) && !target_ip) |
| 2877 | src_is_directory = S_ISDIR(src_ip->i_d.di_mode); | 2923 | return -EINVAL; |
| 2924 | |||
| 2925 | /* | ||
| 2926 | * If we are doing a whiteout operation, allocate the whiteout inode | ||
| 2927 | * we will be placing at the target and ensure the type is set | ||
| 2928 | * appropriately. | ||
| 2929 | */ | ||
| 2930 | if (flags & RENAME_WHITEOUT) { | ||
| 2931 | ASSERT(!(flags & (RENAME_NOREPLACE | RENAME_EXCHANGE))); | ||
| 2932 | error = xfs_rename_alloc_whiteout(target_dp, &wip); | ||
| 2933 | if (error) | ||
| 2934 | return error; | ||
| 2935 | |||
| 2936 | /* setup target dirent info as whiteout */ | ||
| 2937 | src_name->type = XFS_DIR3_FT_CHRDEV; | ||
| 2938 | } | ||
| 2878 | 2939 | ||
| 2879 | xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, | 2940 | xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, wip, |
| 2880 | inodes, &num_inodes); | 2941 | inodes, &num_inodes); |
| 2881 | 2942 | ||
| 2882 | xfs_bmap_init(&free_list, &first_block); | ||
| 2883 | tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME); | 2943 | tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME); |
| 2884 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | ||
| 2885 | spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len); | 2944 | spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len); |
| 2886 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_rename, spaceres, 0); | 2945 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_rename, spaceres, 0); |
| 2887 | if (error == -ENOSPC) { | 2946 | if (error == -ENOSPC) { |
| 2888 | spaceres = 0; | 2947 | spaceres = 0; |
| 2889 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_rename, 0, 0); | 2948 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_rename, 0, 0); |
| 2890 | } | 2949 | } |
| 2891 | if (error) { | 2950 | if (error) |
| 2892 | xfs_trans_cancel(tp, 0); | 2951 | goto out_trans_cancel; |
| 2893 | goto std_return; | 2952 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; |
| 2894 | } | ||
| 2895 | 2953 | ||
| 2896 | /* | 2954 | /* |
| 2897 | * Attach the dquots to the inodes | 2955 | * Attach the dquots to the inodes |
| 2898 | */ | 2956 | */ |
| 2899 | error = xfs_qm_vop_rename_dqattach(inodes); | 2957 | error = xfs_qm_vop_rename_dqattach(inodes); |
| 2900 | if (error) { | 2958 | if (error) |
| 2901 | xfs_trans_cancel(tp, cancel_flags); | 2959 | goto out_trans_cancel; |
| 2902 | goto std_return; | ||
| 2903 | } | ||
| 2904 | 2960 | ||
| 2905 | /* | 2961 | /* |
| 2906 | * Lock all the participating inodes. Depending upon whether | 2962 | * Lock all the participating inodes. Depending upon whether |
| @@ -2921,6 +2977,8 @@ xfs_rename( | |||
| 2921 | xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL); | 2977 | xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL); |
| 2922 | if (target_ip) | 2978 | if (target_ip) |
| 2923 | xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL); | 2979 | xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL); |
| 2980 | if (wip) | ||
| 2981 | xfs_trans_ijoin(tp, wip, XFS_ILOCK_EXCL); | ||
| 2924 | 2982 | ||
| 2925 | /* | 2983 | /* |
| 2926 | * If we are using project inheritance, we only allow renames | 2984 | * If we are using project inheritance, we only allow renames |
| @@ -2930,24 +2988,16 @@ xfs_rename( | |||
| 2930 | if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && | 2988 | if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && |
| 2931 | (xfs_get_projid(target_dp) != xfs_get_projid(src_ip)))) { | 2989 | (xfs_get_projid(target_dp) != xfs_get_projid(src_ip)))) { |
| 2932 | error = -EXDEV; | 2990 | error = -EXDEV; |
| 2933 | goto error_return; | 2991 | goto out_trans_cancel; |
| 2934 | } | 2992 | } |
| 2935 | 2993 | ||
| 2936 | /* | 2994 | xfs_bmap_init(&free_list, &first_block); |
| 2937 | * Handle RENAME_EXCHANGE flags | 2995 | |
| 2938 | */ | 2996 | /* RENAME_EXCHANGE is unique from here on. */ |
| 2939 | if (flags & RENAME_EXCHANGE) { | 2997 | if (flags & RENAME_EXCHANGE) |
| 2940 | if (target_ip == NULL) { | 2998 | return xfs_cross_rename(tp, src_dp, src_name, src_ip, |
| 2941 | error = -EINVAL; | 2999 | target_dp, target_name, target_ip, |
| 2942 | goto error_return; | 3000 | &free_list, &first_block, spaceres); |
| 2943 | } | ||
| 2944 | error = xfs_cross_rename(tp, src_dp, src_name, src_ip, | ||
| 2945 | target_dp, target_name, target_ip, | ||
| 2946 | &free_list, &first_block, spaceres); | ||
| 2947 | if (error) | ||
| 2948 | goto abort_return; | ||
| 2949 | goto finish_rename; | ||
| 2950 | } | ||
| 2951 | 3001 | ||
| 2952 | /* | 3002 | /* |
| 2953 | * Set up the target. | 3003 | * Set up the target. |
| @@ -2960,7 +3010,7 @@ xfs_rename( | |||
| 2960 | if (!spaceres) { | 3010 | if (!spaceres) { |
| 2961 | error = xfs_dir_canenter(tp, target_dp, target_name); | 3011 | error = xfs_dir_canenter(tp, target_dp, target_name); |
| 2962 | if (error) | 3012 | if (error) |
| 2963 | goto error_return; | 3013 | goto out_trans_cancel; |
| 2964 | } | 3014 | } |
| 2965 | /* | 3015 | /* |
| 2966 | * If target does not exist and the rename crosses | 3016 | * If target does not exist and the rename crosses |
| @@ -2971,9 +3021,9 @@ xfs_rename( | |||
| 2971 | src_ip->i_ino, &first_block, | 3021 | src_ip->i_ino, &first_block, |
| 2972 | &free_list, spaceres); | 3022 | &free_list, spaceres); |
| 2973 | if (error == -ENOSPC) | 3023 | if (error == -ENOSPC) |
| 2974 | goto error_return; | 3024 | goto out_bmap_cancel; |
| 2975 | if (error) | 3025 | if (error) |
| 2976 | goto abort_return; | 3026 | goto out_trans_abort; |
| 2977 | 3027 | ||
| 2978 | xfs_trans_ichgtime(tp, target_dp, | 3028 | xfs_trans_ichgtime(tp, target_dp, |
| 2979 | XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 3029 | XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| @@ -2981,7 +3031,7 @@ xfs_rename( | |||
| 2981 | if (new_parent && src_is_directory) { | 3031 | if (new_parent && src_is_directory) { |
| 2982 | error = xfs_bumplink(tp, target_dp); | 3032 | error = xfs_bumplink(tp, target_dp); |
| 2983 | if (error) | 3033 | if (error) |
| 2984 | goto abort_return; | 3034 | goto out_trans_abort; |
| 2985 | } | 3035 | } |
| 2986 | } else { /* target_ip != NULL */ | 3036 | } else { /* target_ip != NULL */ |
| 2987 | /* | 3037 | /* |
| @@ -2996,7 +3046,7 @@ xfs_rename( | |||
| 2996 | if (!(xfs_dir_isempty(target_ip)) || | 3046 | if (!(xfs_dir_isempty(target_ip)) || |
| 2997 | (target_ip->i_d.di_nlink > 2)) { | 3047 | (target_ip->i_d.di_nlink > 2)) { |
| 2998 | error = -EEXIST; | 3048 | error = -EEXIST; |
| 2999 | goto error_return; | 3049 | goto out_trans_cancel; |
| 3000 | } | 3050 | } |
| 3001 | } | 3051 | } |
| 3002 | 3052 | ||
| @@ -3013,7 +3063,7 @@ xfs_rename( | |||
| 3013 | src_ip->i_ino, | 3063 | src_ip->i_ino, |
| 3014 | &first_block, &free_list, spaceres); | 3064 | &first_block, &free_list, spaceres); |
| 3015 | if (error) | 3065 | if (error) |
| 3016 | goto abort_return; | 3066 | goto out_trans_abort; |
| 3017 | 3067 | ||
| 3018 | xfs_trans_ichgtime(tp, target_dp, | 3068 | xfs_trans_ichgtime(tp, target_dp, |
| 3019 | XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 3069 | XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| @@ -3024,7 +3074,7 @@ xfs_rename( | |||
| 3024 | */ | 3074 | */ |
| 3025 | error = xfs_droplink(tp, target_ip); | 3075 | error = xfs_droplink(tp, target_ip); |
| 3026 | if (error) | 3076 | if (error) |
| 3027 | goto abort_return; | 3077 | goto out_trans_abort; |
| 3028 | 3078 | ||
| 3029 | if (src_is_directory) { | 3079 | if (src_is_directory) { |
| 3030 | /* | 3080 | /* |
| @@ -3032,7 +3082,7 @@ xfs_rename( | |||
| 3032 | */ | 3082 | */ |
| 3033 | error = xfs_droplink(tp, target_ip); | 3083 | error = xfs_droplink(tp, target_ip); |
| 3034 | if (error) | 3084 | if (error) |
| 3035 | goto abort_return; | 3085 | goto out_trans_abort; |
| 3036 | } | 3086 | } |
| 3037 | } /* target_ip != NULL */ | 3087 | } /* target_ip != NULL */ |
| 3038 | 3088 | ||
| @@ -3049,7 +3099,7 @@ xfs_rename( | |||
| 3049 | &first_block, &free_list, spaceres); | 3099 | &first_block, &free_list, spaceres); |
| 3050 | ASSERT(error != -EEXIST); | 3100 | ASSERT(error != -EEXIST); |
| 3051 | if (error) | 3101 | if (error) |
| 3052 | goto abort_return; | 3102 | goto out_trans_abort; |
| 3053 | } | 3103 | } |
| 3054 | 3104 | ||
| 3055 | /* | 3105 | /* |
| @@ -3075,49 +3125,67 @@ xfs_rename( | |||
| 3075 | */ | 3125 | */ |
| 3076 | error = xfs_droplink(tp, src_dp); | 3126 | error = xfs_droplink(tp, src_dp); |
| 3077 | if (error) | 3127 | if (error) |
| 3078 | goto abort_return; | 3128 | goto out_trans_abort; |
| 3079 | } | 3129 | } |
| 3080 | 3130 | ||
| 3081 | error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino, | 3131 | /* |
| 3132 | * For whiteouts, we only need to update the source dirent with the | ||
| 3133 | * inode number of the whiteout inode rather than removing it | ||
| 3134 | * altogether. | ||
| 3135 | */ | ||
| 3136 | if (wip) { | ||
| 3137 | error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino, | ||
| 3082 | &first_block, &free_list, spaceres); | 3138 | &first_block, &free_list, spaceres); |
| 3139 | } else | ||
| 3140 | error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino, | ||
| 3141 | &first_block, &free_list, spaceres); | ||
| 3083 | if (error) | 3142 | if (error) |
| 3084 | goto abort_return; | 3143 | goto out_trans_abort; |
| 3085 | |||
| 3086 | xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | ||
| 3087 | xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE); | ||
| 3088 | if (new_parent) | ||
| 3089 | xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE); | ||
| 3090 | 3144 | ||
| 3091 | finish_rename: | ||
| 3092 | /* | 3145 | /* |
| 3093 | * If this is a synchronous mount, make sure that the | 3146 | * For whiteouts, we need to bump the link count on the whiteout inode. |
| 3094 | * rename transaction goes to disk before returning to | 3147 | * This means that failures all the way up to this point leave the inode |
| 3095 | * the user. | 3148 | * on the unlinked list and so cleanup is a simple matter of dropping |
| 3149 | * the remaining reference to it. If we fail here after bumping the link | ||
| 3150 | * count, we're shutting down the filesystem so we'll never see the | ||
| 3151 | * intermediate state on disk. | ||
| 3096 | */ | 3152 | */ |
| 3097 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { | 3153 | if (wip) { |
| 3098 | xfs_trans_set_sync(tp); | 3154 | ASSERT(wip->i_d.di_nlink == 0); |
| 3099 | } | 3155 | error = xfs_bumplink(tp, wip); |
| 3156 | if (error) | ||
| 3157 | goto out_trans_abort; | ||
| 3158 | error = xfs_iunlink_remove(tp, wip); | ||
| 3159 | if (error) | ||
| 3160 | goto out_trans_abort; | ||
| 3161 | xfs_trans_log_inode(tp, wip, XFS_ILOG_CORE); | ||
| 3100 | 3162 | ||
| 3101 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 3163 | /* |
| 3102 | if (error) { | 3164 | * Now we have a real link, clear the "I'm a tmpfile" state |
| 3103 | xfs_bmap_cancel(&free_list); | 3165 | * flag from the inode so it doesn't accidentally get misused in |
| 3104 | xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | | 3166 | * future. |
| 3105 | XFS_TRANS_ABORT)); | 3167 | */ |
| 3106 | goto std_return; | 3168 | VFS_I(wip)->i_state &= ~I_LINKABLE; |
| 3107 | } | 3169 | } |
| 3108 | 3170 | ||
| 3109 | /* | 3171 | xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| 3110 | * trans_commit will unlock src_ip, target_ip & decrement | 3172 | xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE); |
| 3111 | * the vnode references. | 3173 | if (new_parent) |
| 3112 | */ | 3174 | xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE); |
| 3113 | return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | ||
| 3114 | 3175 | ||
| 3115 | abort_return: | 3176 | error = xfs_finish_rename(tp, &free_list); |
| 3177 | if (wip) | ||
| 3178 | IRELE(wip); | ||
| 3179 | return error; | ||
| 3180 | |||
| 3181 | out_trans_abort: | ||
| 3116 | cancel_flags |= XFS_TRANS_ABORT; | 3182 | cancel_flags |= XFS_TRANS_ABORT; |
| 3117 | error_return: | 3183 | out_bmap_cancel: |
| 3118 | xfs_bmap_cancel(&free_list); | 3184 | xfs_bmap_cancel(&free_list); |
| 3185 | out_trans_cancel: | ||
| 3119 | xfs_trans_cancel(tp, cancel_flags); | 3186 | xfs_trans_cancel(tp, cancel_flags); |
| 3120 | std_return: | 3187 | if (wip) |
| 3188 | IRELE(wip); | ||
| 3121 | return error; | 3189 | return error; |
| 3122 | } | 3190 | } |
| 3123 | 3191 | ||
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 8b9e6887e315..015d6a366b16 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c | |||
| @@ -394,7 +394,7 @@ xfs_vn_rename( | |||
| 394 | struct xfs_name oname; | 394 | struct xfs_name oname; |
| 395 | struct xfs_name nname; | 395 | struct xfs_name nname; |
| 396 | 396 | ||
| 397 | if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) | 397 | if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) |
| 398 | return -EINVAL; | 398 | return -EINVAL; |
| 399 | 399 | ||
| 400 | /* if we are exchanging files, we need to set i_mode of both files */ | 400 | /* if we are exchanging files, we need to set i_mode of both files */ |
