mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
xfs: Add support to RENAME_EXCHANGE flag
Adds a new function named xfs_cross_rename(), responsible for handling requests from sys_renameat2() using RENAME_EXCHANGE flag. Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
parent
dbe1b5ca26
commit
d31a182545
@ -2655,6 +2655,124 @@ xfs_sort_for_rename(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* xfs_cross_rename()
|
||||
*
|
||||
* responsible for handling RENAME_EXCHANGE flag in renameat2() sytemcall
|
||||
*/
|
||||
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,
|
||||
struct xfs_bmap_free *free_list,
|
||||
xfs_fsblock_t *first_block,
|
||||
int spaceres)
|
||||
{
|
||||
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,
|
||||
first_block, free_list, spaceres);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/* Swap inode number for dirent in second parent */
|
||||
error = xfs_dir_replace(tp, dp2, name2,
|
||||
ip1->i_ino,
|
||||
first_block, free_list, spaceres);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* If we're renaming one or more directories across different parents,
|
||||
* update the respective ".." entries (and link counts) to match the new
|
||||
* parents.
|
||||
*/
|
||||
if (dp1 != dp2) {
|
||||
dp2_flags = XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;
|
||||
|
||||
if (S_ISDIR(ip2->i_d.di_mode)) {
|
||||
error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot,
|
||||
dp1->i_ino, first_block,
|
||||
free_list, spaceres);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/* transfer ip2 ".." reference to dp1 */
|
||||
if (!S_ISDIR(ip1->i_d.di_mode)) {
|
||||
error = xfs_droplink(tp, dp2);
|
||||
if (error)
|
||||
goto out;
|
||||
error = xfs_bumplink(tp, dp1);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Although ip1 isn't changed here, userspace needs
|
||||
* to be warned about the change, so that applications
|
||||
* relying on it (like backup ones), will properly
|
||||
* notify the change
|
||||
*/
|
||||
ip1_flags |= XFS_ICHGTIME_CHG;
|
||||
ip2_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;
|
||||
}
|
||||
|
||||
if (S_ISDIR(ip1->i_d.di_mode)) {
|
||||
error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot,
|
||||
dp2->i_ino, first_block,
|
||||
free_list, spaceres);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/* transfer ip1 ".." reference to dp2 */
|
||||
if (!S_ISDIR(ip2->i_d.di_mode)) {
|
||||
error = xfs_droplink(tp, dp1);
|
||||
if (error)
|
||||
goto out;
|
||||
error = xfs_bumplink(tp, dp2);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Although ip2 isn't changed here, userspace needs
|
||||
* to be warned about the change, so that applications
|
||||
* relying on it (like backup ones), will properly
|
||||
* notify the change
|
||||
*/
|
||||
ip1_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG;
|
||||
ip2_flags |= XFS_ICHGTIME_CHG;
|
||||
}
|
||||
}
|
||||
|
||||
if (ip1_flags) {
|
||||
xfs_trans_ichgtime(tp, ip1, ip1_flags);
|
||||
xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE);
|
||||
}
|
||||
if (ip2_flags) {
|
||||
xfs_trans_ichgtime(tp, ip2, ip2_flags);
|
||||
xfs_trans_log_inode(tp, ip2, XFS_ILOG_CORE);
|
||||
}
|
||||
if (dp2_flags) {
|
||||
xfs_trans_ichgtime(tp, dp2, dp2_flags);
|
||||
xfs_trans_log_inode(tp, dp2, XFS_ILOG_CORE);
|
||||
}
|
||||
xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
|
||||
xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* xfs_rename
|
||||
*/
|
||||
@ -2665,7 +2783,8 @@ xfs_rename(
|
||||
xfs_inode_t *src_ip,
|
||||
xfs_inode_t *target_dp,
|
||||
struct xfs_name *target_name,
|
||||
xfs_inode_t *target_ip)
|
||||
xfs_inode_t *target_ip,
|
||||
unsigned int flags)
|
||||
{
|
||||
xfs_trans_t *tp = NULL;
|
||||
xfs_mount_t *mp = src_dp->i_mount;
|
||||
@ -2742,6 +2861,18 @@ xfs_rename(
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle RENAME_EXCHANGE flags
|
||||
*/
|
||||
if (flags & RENAME_EXCHANGE) {
|
||||
error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
|
||||
target_dp, target_name, target_ip,
|
||||
&free_list, &first_block, spaceres);
|
||||
if (error)
|
||||
goto abort_return;
|
||||
goto finish_rename;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the target.
|
||||
*/
|
||||
@ -2881,6 +3012,7 @@ xfs_rename(
|
||||
if (new_parent)
|
||||
xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE);
|
||||
|
||||
finish_rename:
|
||||
/*
|
||||
* If this is a synchronous mount, make sure that the
|
||||
* rename transaction goes to disk before returning to
|
||||
|
@ -338,7 +338,7 @@ int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip,
|
||||
int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name,
|
||||
struct xfs_inode *src_ip, struct xfs_inode *target_dp,
|
||||
struct xfs_name *target_name,
|
||||
struct xfs_inode *target_ip);
|
||||
struct xfs_inode *target_ip, unsigned int flags);
|
||||
|
||||
void xfs_ilock(xfs_inode_t *, uint);
|
||||
int xfs_ilock_nowait(xfs_inode_t *, uint);
|
||||
|
@ -384,19 +384,23 @@ xfs_vn_rename(
|
||||
unsigned int flags)
|
||||
{
|
||||
struct inode *new_inode = ndentry->d_inode;
|
||||
int omode = 0;
|
||||
struct xfs_name oname;
|
||||
struct xfs_name nname;
|
||||
|
||||
/* XFS does not support RENAME_EXCHANGE yet */
|
||||
if (flags & ~RENAME_NOREPLACE)
|
||||
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
|
||||
return -EINVAL;
|
||||
|
||||
xfs_dentry_to_name(&oname, odentry, 0);
|
||||
/* if we are exchanging files, we need to set i_mode of both files */
|
||||
if (flags & RENAME_EXCHANGE)
|
||||
omode = ndentry->d_inode->i_mode;
|
||||
|
||||
xfs_dentry_to_name(&oname, odentry, omode);
|
||||
xfs_dentry_to_name(&nname, ndentry, odentry->d_inode->i_mode);
|
||||
|
||||
return xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode),
|
||||
XFS_I(ndir), &nname,
|
||||
new_inode ? XFS_I(new_inode) : NULL);
|
||||
new_inode ? XFS_I(new_inode) : NULL, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user