Skip to content

Commit

Permalink
xfs: Add parent pointers to rename
Browse files Browse the repository at this point in the history
This patch removes the old parent pointer attribute during the rename
operation, and re-adds the updated parent pointer.  In the case of
xfs_cross_rename, we modify the routine not to roll the transaction just
yet.  We will do this after the parent pointer is added in the calling
xfs_rename function.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
  • Loading branch information
allisonhenderson committed May 5, 2022
1 parent 72ff733 commit 5e63097
Showing 1 changed file with 101 additions and 36 deletions.
137 changes: 101 additions & 36 deletions fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -3150,7 +3150,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);
return 0;

out_trans_abort:
xfs_trans_cancel(tp);
Expand Down Expand Up @@ -3197,26 +3197,52 @@ xfs_rename_alloc_whiteout(
*/
int
xfs_rename(
struct user_namespace *mnt_userns,
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,
unsigned int flags)
{
struct xfs_mount *mp = src_dp->i_mount;
struct xfs_trans *tp;
struct xfs_inode *wip = NULL; /* whiteout inode */
struct xfs_inode *inodes[__XFS_SORT_INODES];
int i;
int num_inodes = __XFS_SORT_INODES;
bool new_parent = (src_dp != target_dp);
bool src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode);
int spaceres;
bool retried = false;
int error, nospace_error = 0;
struct user_namespace *mnt_userns,
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,
unsigned int flags)
{
struct xfs_mount *mp = src_dp->i_mount;
struct xfs_trans *tp;
struct xfs_inode *wip = NULL; /* whiteout inode */
struct xfs_inode *inodes[__XFS_SORT_INODES];
int i;
int num_inodes = __XFS_SORT_INODES;
bool new_parent = (src_dp != target_dp);
bool src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode);
int spaceres;
bool retried = false;
int error, nospace_error = 0;
struct xfs_parent_name_rec new_rec;
struct xfs_parent_name_rec old_rec;
xfs_dir2_dataptr_t new_diroffset;
xfs_dir2_dataptr_t old_diroffset;
struct xfs_da_args new_args = {
.dp = src_ip,
.geo = mp->m_attr_geo,
.whichfork = XFS_ATTR_FORK,
.attr_filter = XFS_ATTR_PARENT,
.op_flags = XFS_DA_OP_OKNOENT,
.name = (const uint8_t *)&new_rec,
.namelen = sizeof(new_rec),
.value = (void *)target_name->name,
.valuelen = target_name->len,
};
struct xfs_da_args old_args = {
.dp = src_ip,
.geo = mp->m_attr_geo,
.whichfork = XFS_ATTR_FORK,
.attr_filter = XFS_ATTR_PARENT,
.op_flags = XFS_DA_OP_OKNOENT,
.name = (const uint8_t *)&old_rec,
.namelen = sizeof(old_rec),
.value = NULL,
.valuelen = 0,
};

trace_xfs_rename(src_dp, target_dp, src_name, target_name);

Expand All @@ -3239,6 +3265,11 @@ xfs_rename(

xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, wip,
inodes, &num_inodes);
if (xfs_has_larp(mp)) {
error = xfs_attr_use_log_assist(mp);
if (error)
goto out_release_wip;
}

retry:
nospace_error = 0;
Expand All @@ -3251,7 +3282,7 @@ xfs_rename(
&tp);
}
if (error)
goto out_release_wip;
goto drop_incompat;

/*
* Attach the dquots to the inodes
Expand All @@ -3273,14 +3304,14 @@ xfs_rename(
* we can rely on either trans_commit or trans_cancel to unlock
* them.
*/
xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, src_dp, 0);
if (new_parent)
xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, target_dp, 0);
xfs_trans_ijoin(tp, src_ip, 0);
if (target_ip)
xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, target_ip, 0);
if (wip)
xfs_trans_ijoin(tp, wip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, wip, 0);

/*
* If we are using project inheritance, we only allow renames
Expand All @@ -3290,15 +3321,16 @@ xfs_rename(
if (unlikely((target_dp->i_diflags & XFS_DIFLAG_PROJINHERIT) &&
target_dp->i_projid != src_ip->i_projid)) {
error = -EXDEV;
goto out_trans_cancel;
goto out_unlock;
}

/* RENAME_EXCHANGE is unique from here on. */
if (flags & RENAME_EXCHANGE)
return xfs_cross_rename(tp, src_dp, src_name, src_ip,
if (flags & RENAME_EXCHANGE) {
error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
target_dp, target_name, target_ip,
spaceres);

goto out_pptr;
}
/*
* Try to reserve quota to handle an expansion of the target directory.
* We'll allow the rename to continue in reservationless mode if we hit
Expand Down Expand Up @@ -3412,7 +3444,7 @@ xfs_rename(
* to account for the ".." reference from the new entry.
*/
error = xfs_dir_createname(tp, target_dp, target_name,
src_ip->i_ino, spaceres, NULL);
src_ip->i_ino, spaceres, &new_diroffset);
if (error)
goto out_trans_cancel;

Expand All @@ -3433,7 +3465,7 @@ xfs_rename(
* name at the destination directory, remove it first.
*/
error = xfs_dir_replace(tp, target_dp, target_name,
src_ip->i_ino, spaceres, NULL);
src_ip->i_ino, spaceres, &new_diroffset);
if (error)
goto out_trans_cancel;

Expand Down Expand Up @@ -3467,7 +3499,7 @@ xfs_rename(
* directory.
*/
error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
target_dp->i_ino, spaceres, NULL);
target_dp->i_ino, spaceres, &new_diroffset);
ASSERT(error != -EEXIST);
if (error)
goto out_trans_cancel;
Expand Down Expand Up @@ -3506,26 +3538,59 @@ xfs_rename(
*/
if (wip)
error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
spaceres, NULL);
spaceres, &old_diroffset);
else
error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
spaceres, NULL);
spaceres, &old_diroffset);

if (error)
goto out_trans_cancel;

out_pptr:
if (xfs_sb_version_hasparent(&mp->m_sb)) {
new_args.trans = tp;
xfs_init_parent_name_rec(&new_rec, target_dp, new_diroffset);
new_args.hashval = xfs_da_hashname(new_args.name,
new_args.namelen);
error = xfs_attr_defer_add(&new_args);
if (error)
goto out_trans_cancel;

old_args.trans = tp;
xfs_init_parent_name_rec(&old_rec, src_dp, old_diroffset);
old_args.hashval = xfs_da_hashname(old_args.name,
old_args.namelen);
error = xfs_attr_defer_remove(&old_args);
if (error)
goto out_trans_cancel;
}

xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);
if (new_parent)
xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE);

error = xfs_finish_rename(tp);

out_unlock:
if (wip)
xfs_irele(wip);
if (wip)
xfs_iunlock(wip, XFS_ILOCK_EXCL);
if (target_ip)
xfs_iunlock(target_ip, XFS_ILOCK_EXCL);
xfs_iunlock(src_ip, XFS_ILOCK_EXCL);
if (new_parent)
xfs_iunlock(target_dp, XFS_ILOCK_EXCL);
xfs_iunlock(src_dp, XFS_ILOCK_EXCL);

return error;

out_trans_cancel:
xfs_trans_cancel(tp);
drop_incompat:
if (xfs_has_larp(mp))
xlog_drop_incompat_feat(mp->m_log);
out_release_wip:
if (wip)
xfs_irele(wip);
Expand Down

0 comments on commit 5e63097

Please sign in to comment.