From: Allison Henderson <allison.henderson@xxxxxxxxxx> Cross renames are handled separately from standard renames, and need different handling to update the parent attributes correctly. Reviewed-by: Darrick J. Wong <djwong@xxxxxxxxxx> Signed-off-by: Allison Henderson <allison.henderson@xxxxxxxxxx> --- fs/xfs/xfs_inode.c | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 5ad934358791..6d364a48e3cc 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2743,19 +2743,22 @@ xfs_finish_rename( */ STATIC int xfs_cross_rename( - struct xfs_trans *tp, - struct xfs_inode *dp1, - struct xfs_name *name1, - struct xfs_inode *ip1, - struct xfs_inode *dp2, - struct xfs_name *name2, - struct xfs_inode *ip2, - int spaceres) + struct xfs_trans *tp, + struct xfs_inode *dp1, + struct xfs_name *name1, + struct xfs_inode *ip1, + struct xfs_parent_defer *ip1_pptr, + struct xfs_inode *dp2, + struct xfs_name *name2, + struct xfs_inode *ip2, + struct xfs_parent_defer *ip2_pptr, + int spaceres) { - int error = 0; - int ip1_flags = 0; - int ip2_flags = 0; - int dp2_flags = 0; + struct xfs_mount *mp = dp1->i_mount; + int error = 0; + int ip1_flags = 0; + int ip2_flags = 0; + int dp2_flags = 0; /* Swap inode number for dirent in first parent */ error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, spaceres); @@ -2824,6 +2827,18 @@ xfs_cross_rename( } } + if (xfs_has_parent(mp)) { + error = xfs_parent_replace(tp, ip1_pptr, dp1, name1, dp2, + name2, ip1); + if (error) + goto out_trans_abort; + + error = xfs_parent_replace(tp, ip2_pptr, dp2, name2, dp1, + name1, ip2); + if (error) + goto out_trans_abort; + } + if (ip1_flags) { xfs_trans_ichgtime(tp, ip1, ip1_flags); xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE); @@ -2838,6 +2853,7 @@ xfs_cross_rename( } xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE); + return xfs_finish_rename(tp); out_trans_abort: @@ -3052,8 +3068,8 @@ xfs_rename( /* RENAME_EXCHANGE is unique from here on. */ if (flags & RENAME_EXCHANGE) { error = xfs_cross_rename(tp, src_dp, src_name, src_ip, - target_dp, target_name, target_ip, - spaceres); + src_ip_pptr, target_dp, target_name, target_ip, + tgt_ip_pptr, spaceres); goto out_unlock; }