From: Allison Henderson <allison.henderson@xxxxxxxxxx> This patch removes the parent pointer attribute during unlink Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx> Signed-off-by: Allison Henderson <allison.henderson@xxxxxxxxxx> Reviewed-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- fs/xfs/libxfs/xfs_attr.c | 2 +- fs/xfs/libxfs/xfs_attr.h | 1 + fs/xfs/libxfs/xfs_parent.c | 17 ++++++++++++++++ fs/xfs/libxfs/xfs_parent.h | 5 +++++ fs/xfs/libxfs/xfs_trans_space.h | 2 -- fs/xfs/xfs_inode.c | 42 +++++++++++++++++++++++++++++++++------ 6 files changed, 59 insertions(+), 10 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index f68d41f0f998..a8db44728b11 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -946,7 +946,7 @@ xfs_attr_defer_replace( } /* Removes an attribute for an inode as a deferred operation */ -static int +int xfs_attr_defer_remove( struct xfs_da_args *args) { diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index 0cf23f5117ad..033005542b9e 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/libxfs/xfs_attr.h @@ -545,6 +545,7 @@ bool xfs_attr_is_leaf(struct xfs_inode *ip); int xfs_attr_get_ilocked(struct xfs_da_args *args); int xfs_attr_get(struct xfs_da_args *args); int xfs_attr_defer_add(struct xfs_da_args *args); +int xfs_attr_defer_remove(struct xfs_da_args *args); int xfs_attr_set(struct xfs_da_args *args); int xfs_attr_set_iter(struct xfs_attr_intent *attr); int xfs_attr_remove_iter(struct xfs_attr_intent *attr); diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index 6b6d415319e6..245855a5f969 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -115,6 +115,23 @@ xfs_parent_defer_add( return xfs_attr_defer_add(args); } +int +xfs_parent_defer_remove( + struct xfs_trans *tp, + struct xfs_inode *dp, + struct xfs_parent_defer *parent, + xfs_dir2_dataptr_t diroffset, + struct xfs_inode *child) +{ + struct xfs_da_args *args = &parent->args; + + xfs_init_parent_name_rec(&parent->rec, dp, diroffset); + args->trans = tp; + args->dp = child; + args->hashval = xfs_da_hashname(args->name, args->namelen); + return xfs_attr_defer_remove(args); +} + void __xfs_parent_cancel( xfs_mount_t *mp, diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index d5a8c8e52cb5..0f39d033d84e 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/libxfs/xfs_parent.h @@ -40,6 +40,11 @@ xfs_parent_start( int xfs_parent_defer_add(struct xfs_trans *tp, struct xfs_parent_defer *parent, struct xfs_inode *dp, struct xfs_name *parent_name, xfs_dir2_dataptr_t diroffset, struct xfs_inode *child); +int xfs_parent_defer_remove(struct xfs_trans *tp, struct xfs_inode *dp, + struct xfs_parent_defer *parent, + xfs_dir2_dataptr_t diroffset, + struct xfs_inode *child); + void __xfs_parent_cancel(struct xfs_mount *mp, struct xfs_parent_defer *parent); static inline void diff --git a/fs/xfs/libxfs/xfs_trans_space.h b/fs/xfs/libxfs/xfs_trans_space.h index 25a55650baf4..b5ab6701e7fb 100644 --- a/fs/xfs/libxfs/xfs_trans_space.h +++ b/fs/xfs/libxfs/xfs_trans_space.h @@ -91,8 +91,6 @@ XFS_DQUOT_CLUSTER_SIZE_FSB) #define XFS_QM_QINOCREATE_SPACE_RES(mp) \ XFS_IALLOC_SPACE_RES(mp) -#define XFS_REMOVE_SPACE_RES(mp) \ - XFS_DIRREMOVE_SPACE_RES(mp) #define XFS_RENAME_SPACE_RES(mp,nl) \ (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_IFREE_SPACE_RES(mp) \ diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index b4318df03b5c..7b34ca2de569 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2477,6 +2477,19 @@ xfs_iunpin_wait( __xfs_iunpin_wait(ip); } +static unsigned int +xfs_remove_space_res( + struct xfs_mount *mp, + unsigned int namelen) +{ + unsigned int ret = XFS_DIRREMOVE_SPACE_RES(mp); + + if (xfs_has_parent(mp)) + ret += xfs_pptr_calc_space_res(mp, namelen); + + return ret; +} + /* * Removing an inode from the namespace involves removing the directory entry * and dropping the link count on the inode. Removing the directory entry can @@ -2506,16 +2519,18 @@ xfs_iunpin_wait( */ int xfs_remove( - xfs_inode_t *dp, + struct xfs_inode *dp, struct xfs_name *name, - xfs_inode_t *ip) + struct xfs_inode *ip) { - xfs_mount_t *mp = dp->i_mount; - xfs_trans_t *tp = NULL; + struct xfs_mount *mp = dp->i_mount; + struct xfs_trans *tp = NULL; int is_dir = S_ISDIR(VFS_I(ip)->i_mode); int dontcare; int error = 0; uint resblks; + xfs_dir2_dataptr_t dir_offset; + struct xfs_parent_defer *parent = NULL; trace_xfs_remove(dp, name); @@ -2530,6 +2545,10 @@ xfs_remove( if (error) goto std_return; + error = xfs_parent_start(mp, &parent); + if (error) + goto std_return; + /* * We try to get the real space reservation first, allowing for * directory btree deletion(s) implying possible bmap insert(s). If we @@ -2541,12 +2560,12 @@ xfs_remove( * the directory code can handle a reservationless update and we don't * want to prevent a user from trying to free space by deleting things. */ - resblks = XFS_REMOVE_SPACE_RES(mp); + resblks = xfs_remove_space_res(mp, name->len); error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, ip, &resblks, &tp, &dontcare); if (error) { ASSERT(error != -ENOSPC); - goto std_return; + goto out_parent; } /* @@ -2600,12 +2619,18 @@ xfs_remove( if (error) goto out_trans_cancel; - error = xfs_dir_removename(tp, dp, name, ip->i_ino, resblks, NULL); + error = xfs_dir_removename(tp, dp, name, ip->i_ino, resblks, &dir_offset); if (error) { ASSERT(error != -ENOENT); goto out_trans_cancel; } + if (parent) { + error = xfs_parent_defer_remove(tp, dp, parent, dir_offset, ip); + if (error) + goto out_trans_cancel; + } + /* * If this is a synchronous mount, make sure that the * remove transaction goes to disk before returning to @@ -2623,6 +2648,7 @@ xfs_remove( xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_parent_finish(mp, parent); return 0; out_trans_cancel: @@ -2630,6 +2656,8 @@ xfs_remove( out_unlock: xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL); + out_parent: + xfs_parent_finish(mp, parent); std_return: return error; }