diff options
Diffstat (limited to 'fs/xfs/xfs_inode.c')
-rw-r--r-- | fs/xfs/xfs_inode.c | 136 |
1 files changed, 135 insertions, 1 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 41f804e740d7..daafa1f6d260 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -1995,6 +1995,7 @@ xfs_iunlink( | |||
1995 | agi->agi_unlinked[bucket_index] = cpu_to_be32(agino); | 1995 | agi->agi_unlinked[bucket_index] = cpu_to_be32(agino); |
1996 | offset = offsetof(xfs_agi_t, agi_unlinked) + | 1996 | offset = offsetof(xfs_agi_t, agi_unlinked) + |
1997 | (sizeof(xfs_agino_t) * bucket_index); | 1997 | (sizeof(xfs_agino_t) * bucket_index); |
1998 | xfs_trans_buf_set_type(tp, agibp, XFS_BLFT_AGI_BUF); | ||
1998 | xfs_trans_log_buf(tp, agibp, offset, | 1999 | xfs_trans_log_buf(tp, agibp, offset, |
1999 | (offset + sizeof(xfs_agino_t) - 1)); | 2000 | (offset + sizeof(xfs_agino_t) - 1)); |
2000 | return 0; | 2001 | return 0; |
@@ -2086,6 +2087,7 @@ xfs_iunlink_remove( | |||
2086 | agi->agi_unlinked[bucket_index] = cpu_to_be32(next_agino); | 2087 | agi->agi_unlinked[bucket_index] = cpu_to_be32(next_agino); |
2087 | offset = offsetof(xfs_agi_t, agi_unlinked) + | 2088 | offset = offsetof(xfs_agi_t, agi_unlinked) + |
2088 | (sizeof(xfs_agino_t) * bucket_index); | 2089 | (sizeof(xfs_agino_t) * bucket_index); |
2090 | xfs_trans_buf_set_type(tp, agibp, XFS_BLFT_AGI_BUF); | ||
2089 | xfs_trans_log_buf(tp, agibp, offset, | 2091 | xfs_trans_log_buf(tp, agibp, offset, |
2090 | (offset + sizeof(xfs_agino_t) - 1)); | 2092 | (offset + sizeof(xfs_agino_t) - 1)); |
2091 | } else { | 2093 | } else { |
@@ -2656,6 +2658,124 @@ xfs_sort_for_rename( | |||
2656 | } | 2658 | } |
2657 | 2659 | ||
2658 | /* | 2660 | /* |
2661 | * xfs_cross_rename() | ||
2662 | * | ||
2663 | * responsible for handling RENAME_EXCHANGE flag in renameat2() sytemcall | ||
2664 | */ | ||
2665 | STATIC int | ||
2666 | xfs_cross_rename( | ||
2667 | struct xfs_trans *tp, | ||
2668 | struct xfs_inode *dp1, | ||
2669 | struct xfs_name *name1, | ||
2670 | struct xfs_inode *ip1, | ||
2671 | struct xfs_inode *dp2, | ||
2672 | struct xfs_name *name2, | ||
2673 | struct xfs_inode *ip2, | ||
2674 | struct xfs_bmap_free *free_list, | ||
2675 | xfs_fsblock_t *first_block, | ||
2676 | int spaceres) | ||
2677 | { | ||
2678 | int error = 0; | ||
2679 | int ip1_flags = 0; | ||
2680 | int ip2_flags = 0; | ||
2681 | int dp2_flags = 0; | ||
2682 | |||
2683 | /* Swap inode number for dirent in first parent */ | ||
2684 | error = xfs_dir_replace(tp, dp1, name1, | ||
2685 | ip2->i_ino, | ||
2686 | first_block, free_list, spaceres); | ||
2687 | if (error) | ||
2688 | goto out; | ||
2689 | |||
2690 | /* Swap inode number for dirent in second parent */ | ||
2691 | error = xfs_dir_replace(tp, dp2, name2, | ||
2692 | ip1->i_ino, | ||
2693 | first_block, free_list, spaceres); | ||
2694 | if (error) | ||
2695 | goto out; | ||
2696 | |||
2697 | /* | ||
2698 | * If we're renaming one or more directories across different parents, | ||
2699 | * update the respective ".." entries (and link counts) to match the new | ||
2700 | * parents. | ||
2701 | */ | ||
2702 | if (dp1 != dp2) { | ||
2703 | dp2_flags = XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; | ||
2704 | |||
2705 | if (S_ISDIR(ip2->i_d.di_mode)) { | ||
2706 | error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot, | ||
2707 | dp1->i_ino, first_block, | ||
2708 | free_list, spaceres); | ||
2709 | if (error) | ||
2710 | goto out; | ||
2711 | |||
2712 | /* transfer ip2 ".." reference to dp1 */ | ||
2713 | if (!S_ISDIR(ip1->i_d.di_mode)) { | ||
2714 | error = xfs_droplink(tp, dp2); | ||
2715 | if (error) | ||
2716 | goto out; | ||
2717 | error = xfs_bumplink(tp, dp1); | ||
2718 | if (error) | ||
2719 | goto out; | ||
2720 | } | ||
2721 | |||
2722 | /* | ||
2723 | * Although ip1 isn't changed here, userspace needs | ||
2724 | * to be warned about the change, so that applications | ||
2725 | * relying on it (like backup ones), will properly | ||
2726 | * notify the change | ||
2727 | */ | ||
2728 | ip1_flags |= XFS_ICHGTIME_CHG; | ||
2729 | ip2_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; | ||
2730 | } | ||
2731 | |||
2732 | if (S_ISDIR(ip1->i_d.di_mode)) { | ||
2733 | error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot, | ||
2734 | dp2->i_ino, first_block, | ||
2735 | free_list, spaceres); | ||
2736 | if (error) | ||
2737 | goto out; | ||
2738 | |||
2739 | /* transfer ip1 ".." reference to dp2 */ | ||
2740 | if (!S_ISDIR(ip2->i_d.di_mode)) { | ||
2741 | error = xfs_droplink(tp, dp1); | ||
2742 | if (error) | ||
2743 | goto out; | ||
2744 | error = xfs_bumplink(tp, dp2); | ||
2745 | if (error) | ||
2746 | goto out; | ||
2747 | } | ||
2748 | |||
2749 | /* | ||
2750 | * Although ip2 isn't changed here, userspace needs | ||
2751 | * to be warned about the change, so that applications | ||
2752 | * relying on it (like backup ones), will properly | ||
2753 | * notify the change | ||
2754 | */ | ||
2755 | ip1_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; | ||
2756 | ip2_flags |= XFS_ICHGTIME_CHG; | ||
2757 | } | ||
2758 | } | ||
2759 | |||
2760 | if (ip1_flags) { | ||
2761 | xfs_trans_ichgtime(tp, ip1, ip1_flags); | ||
2762 | xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE); | ||
2763 | } | ||
2764 | if (ip2_flags) { | ||
2765 | xfs_trans_ichgtime(tp, ip2, ip2_flags); | ||
2766 | xfs_trans_log_inode(tp, ip2, XFS_ILOG_CORE); | ||
2767 | } | ||
2768 | if (dp2_flags) { | ||
2769 | xfs_trans_ichgtime(tp, dp2, dp2_flags); | ||
2770 | xfs_trans_log_inode(tp, dp2, XFS_ILOG_CORE); | ||
2771 | } | ||
2772 | xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | ||
2773 | xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE); | ||
2774 | out: | ||
2775 | return error; | ||
2776 | } | ||
2777 | |||
2778 | /* | ||
2659 | * xfs_rename | 2779 | * xfs_rename |
2660 | */ | 2780 | */ |
2661 | int | 2781 | int |
@@ -2665,7 +2785,8 @@ xfs_rename( | |||
2665 | xfs_inode_t *src_ip, | 2785 | xfs_inode_t *src_ip, |
2666 | xfs_inode_t *target_dp, | 2786 | xfs_inode_t *target_dp, |
2667 | struct xfs_name *target_name, | 2787 | struct xfs_name *target_name, |
2668 | xfs_inode_t *target_ip) | 2788 | xfs_inode_t *target_ip, |
2789 | unsigned int flags) | ||
2669 | { | 2790 | { |
2670 | xfs_trans_t *tp = NULL; | 2791 | xfs_trans_t *tp = NULL; |
2671 | xfs_mount_t *mp = src_dp->i_mount; | 2792 | xfs_mount_t *mp = src_dp->i_mount; |
@@ -2743,6 +2864,18 @@ xfs_rename( | |||
2743 | } | 2864 | } |
2744 | 2865 | ||
2745 | /* | 2866 | /* |
2867 | * Handle RENAME_EXCHANGE flags | ||
2868 | */ | ||
2869 | if (flags & RENAME_EXCHANGE) { | ||
2870 | error = xfs_cross_rename(tp, src_dp, src_name, src_ip, | ||
2871 | target_dp, target_name, target_ip, | ||
2872 | &free_list, &first_block, spaceres); | ||
2873 | if (error) | ||
2874 | goto abort_return; | ||
2875 | goto finish_rename; | ||
2876 | } | ||
2877 | |||
2878 | /* | ||
2746 | * Set up the target. | 2879 | * Set up the target. |
2747 | */ | 2880 | */ |
2748 | if (target_ip == NULL) { | 2881 | if (target_ip == NULL) { |
@@ -2881,6 +3014,7 @@ xfs_rename( | |||
2881 | if (new_parent) | 3014 | if (new_parent) |
2882 | xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE); | 3015 | xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE); |
2883 | 3016 | ||
3017 | finish_rename: | ||
2884 | /* | 3018 | /* |
2885 | * If this is a synchronous mount, make sure that the | 3019 | * If this is a synchronous mount, make sure that the |
2886 | * rename transaction goes to disk before returning to | 3020 | * rename transaction goes to disk before returning to |