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 |
