aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_inode.c134
-rw-r--r--fs/xfs/xfs_inode.h2
-rw-r--r--fs/xfs/xfs_iops.c12
3 files changed, 142 insertions, 6 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 41f804e740d7..9916aef60997 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2656,6 +2656,124 @@ xfs_sort_for_rename(
2656} 2656}
2657 2657
2658/* 2658/*
2659 * xfs_cross_rename()
2660 *
2661 * responsible for handling RENAME_EXCHANGE flag in renameat2() sytemcall
2662 */
2663STATIC int
2664xfs_cross_rename(
2665 struct xfs_trans *tp,
2666 struct xfs_inode *dp1,
2667 struct xfs_name *name1,
2668 struct xfs_inode *ip1,
2669 struct xfs_inode *dp2,
2670 struct xfs_name *name2,
2671 struct xfs_inode *ip2,
2672 struct xfs_bmap_free *free_list,
2673 xfs_fsblock_t *first_block,
2674 int spaceres)
2675{
2676 int error = 0;
2677 int ip1_flags = 0;
2678 int ip2_flags = 0;
2679 int dp2_flags = 0;
2680
2681 /* Swap inode number for dirent in first parent */
2682 error = xfs_dir_replace(tp, dp1, name1,
2683 ip2->i_ino,
2684 first_block, free_list, spaceres);
2685 if (error)
2686 goto out;
2687
2688 /* Swap inode number for dirent in second parent */
2689 error = xfs_dir_replace(tp, dp2, name2,
2690 ip1->i_ino,
2691 first_block, free_list, spaceres);
2692 if (error)
2693 goto out;
2694
2695 /*
2696 * If we're renaming one or more directories across different parents,
2697 * update the respective ".." entries (and link counts) to match the new
2698 * parents.
2699 */
2700 if (dp1 != dp2) {
2701 dp2_flags = XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;
2702
2703 if (S_ISDIR(ip2->i_d.di_mode)) {
2704 error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot,
2705 dp1->i_ino, first_block,
2706 free_list, spaceres);
2707 if (error)
2708 goto out;
2709
2710 /* transfer ip2 ".." reference to dp1 */
2711 if (!S_ISDIR(ip1->i_d.di_mode)) {
2712 error = xfs_droplink(tp, dp2);
2713 if (error)
2714 goto out;
2715 error = xfs_bumplink(tp, dp1);
2716 if (error)
2717 goto out;
2718 }
2719
2720 /*
2721 * Although ip1 isn't changed here, userspace needs
2722 * to be warned about the change, so that applications
2723 * relying on it (like backup ones), will properly
2724 * notify the change
2725 */
2726 ip1_flags |= XFS_ICHGTIME_CHG;
2727 ip2_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;
2728 }
2729
2730 if (S_ISDIR(ip1->i_d.di_mode)) {
2731 error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot,
2732 dp2->i_ino, first_block,
2733 free_list, spaceres);
2734 if (error)
2735 goto out;
2736
2737 /* transfer ip1 ".." reference to dp2 */
2738 if (!S_ISDIR(ip2->i_d.di_mode)) {
2739 error = xfs_droplink(tp, dp1);
2740 if (error)
2741 goto out;
2742 error = xfs_bumplink(tp, dp2);
2743 if (error)
2744 goto out;
2745 }
2746
2747 /*
2748 * Although ip2 isn't changed here, userspace needs
2749 * to be warned about the change, so that applications
2750 * relying on it (like backup ones), will properly
2751 * notify the change
2752 */
2753 ip1_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;
2754 ip2_flags |= XFS_ICHGTIME_CHG;
2755 }
2756 }
2757
2758 if (ip1_flags) {
2759 xfs_trans_ichgtime(tp, ip1, ip1_flags);
2760 xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE);
2761 }
2762 if (ip2_flags) {
2763 xfs_trans_ichgtime(tp, ip2, ip2_flags);
2764 xfs_trans_log_inode(tp, ip2, XFS_ILOG_CORE);
2765 }
2766 if (dp2_flags) {
2767 xfs_trans_ichgtime(tp, dp2, dp2_flags);
2768 xfs_trans_log_inode(tp, dp2, XFS_ILOG_CORE);
2769 }
2770 xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
2771 xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE);
2772out:
2773 return error;
2774}
2775
2776/*
2659 * xfs_rename 2777 * xfs_rename
2660 */ 2778 */
2661int 2779int
@@ -2665,7 +2783,8 @@ xfs_rename(
2665 xfs_inode_t *src_ip, 2783 xfs_inode_t *src_ip,
2666 xfs_inode_t *target_dp, 2784 xfs_inode_t *target_dp,
2667 struct xfs_name *target_name, 2785 struct xfs_name *target_name,
2668 xfs_inode_t *target_ip) 2786 xfs_inode_t *target_ip,
2787 unsigned int flags)
2669{ 2788{
2670 xfs_trans_t *tp = NULL; 2789 xfs_trans_t *tp = NULL;
2671 xfs_mount_t *mp = src_dp->i_mount; 2790 xfs_mount_t *mp = src_dp->i_mount;
@@ -2743,6 +2862,18 @@ xfs_rename(
2743 } 2862 }
2744 2863
2745 /* 2864 /*
2865 * Handle RENAME_EXCHANGE flags
2866 */
2867 if (flags & RENAME_EXCHANGE) {
2868 error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
2869 target_dp, target_name, target_ip,
2870 &free_list, &first_block, spaceres);
2871 if (error)
2872 goto abort_return;
2873 goto finish_rename;
2874 }
2875
2876 /*
2746 * Set up the target. 2877 * Set up the target.
2747 */ 2878 */
2748 if (target_ip == NULL) { 2879 if (target_ip == NULL) {
@@ -2881,6 +3012,7 @@ xfs_rename(
2881 if (new_parent) 3012 if (new_parent)
2882 xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE); 3013 xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE);
2883 3014
3015finish_rename:
2884 /* 3016 /*
2885 * If this is a synchronous mount, make sure that the 3017 * If this is a synchronous mount, make sure that the
2886 * rename transaction goes to disk before returning to 3018 * rename transaction goes to disk before returning to
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 4ed2ba9342dc..f7722960b69c 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -338,7 +338,7 @@ int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip,
338int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name, 338int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name,
339 struct xfs_inode *src_ip, struct xfs_inode *target_dp, 339 struct xfs_inode *src_ip, struct xfs_inode *target_dp,
340 struct xfs_name *target_name, 340 struct xfs_name *target_name,
341 struct xfs_inode *target_ip); 341 struct xfs_inode *target_ip, unsigned int flags);
342 342
343void xfs_ilock(xfs_inode_t *, uint); 343void xfs_ilock(xfs_inode_t *, uint);
344int xfs_ilock_nowait(xfs_inode_t *, uint); 344int xfs_ilock_nowait(xfs_inode_t *, uint);
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index abb838a565ee..ce80eeb8faa4 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -384,19 +384,23 @@ xfs_vn_rename(
384 unsigned int flags) 384 unsigned int flags)
385{ 385{
386 struct inode *new_inode = ndentry->d_inode; 386 struct inode *new_inode = ndentry->d_inode;
387 int omode = 0;
387 struct xfs_name oname; 388 struct xfs_name oname;
388 struct xfs_name nname; 389 struct xfs_name nname;
389 390
390 /* XFS does not support RENAME_EXCHANGE yet */ 391 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
391 if (flags & ~RENAME_NOREPLACE)
392 return -EINVAL; 392 return -EINVAL;
393 393
394 xfs_dentry_to_name(&oname, odentry, 0); 394 /* if we are exchanging files, we need to set i_mode of both files */
395 if (flags & RENAME_EXCHANGE)
396 omode = ndentry->d_inode->i_mode;
397
398 xfs_dentry_to_name(&oname, odentry, omode);
395 xfs_dentry_to_name(&nname, ndentry, odentry->d_inode->i_mode); 399 xfs_dentry_to_name(&nname, ndentry, odentry->d_inode->i_mode);
396 400
397 return xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode), 401 return xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode),
398 XFS_I(ndir), &nname, 402 XFS_I(ndir), &nname,
399 new_inode ? XFS_I(new_inode) : NULL); 403 new_inode ? XFS_I(new_inode) : NULL, flags);
400} 404}
401 405
402/* 406/*