Commit f40aadb2 authored by Dave Chinner's avatar Dave Chinner Committed by Dave Chinner
Browse files

xfs: use perag through unlink processing



Unlinked lists are held in the perag, and freeing of inodes needs to
be passed a perag, too, so look up the perag early in the unlink
processing and use it throughout.

Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
parent 8237fbf5
Loading
Loading
Loading
Loading
+10 −13
Original line number Original line Diff line number Diff line
@@ -2134,35 +2134,33 @@ xfs_difree_finobt(
 */
 */
int
int
xfs_difree(
xfs_difree(
	struct xfs_trans	*tp,		/* transaction pointer */
	struct xfs_trans	*tp,
	xfs_ino_t		inode,		/* inode to be freed */
	struct xfs_perag	*pag,
	struct xfs_icluster	*xic)	/* cluster info if deleted */
	xfs_ino_t		inode,
	struct xfs_icluster	*xic)
{
{
	/* REFERENCED */
	/* REFERENCED */
	xfs_agblock_t		agbno;	/* block number containing inode */
	xfs_agblock_t		agbno;	/* block number containing inode */
	struct xfs_buf		*agbp;	/* buffer for allocation group header */
	struct xfs_buf		*agbp;	/* buffer for allocation group header */
	xfs_agino_t		agino;	/* allocation group inode number */
	xfs_agino_t		agino;	/* allocation group inode number */
	xfs_agnumber_t		agno;	/* allocation group number */
	int			error;	/* error return value */
	int			error;	/* error return value */
	struct xfs_mount	*mp = tp->t_mountp;
	struct xfs_mount	*mp = tp->t_mountp;
	struct xfs_inobt_rec_incore rec;/* btree record */
	struct xfs_inobt_rec_incore rec;/* btree record */
	struct xfs_perag	*pag;


	/*
	/*
	 * Break up inode number into its components.
	 * Break up inode number into its components.
	 */
	 */
	agno = XFS_INO_TO_AGNO(mp, inode);
	if (pag->pag_agno != XFS_INO_TO_AGNO(mp, inode)) {
	if (agno >= mp->m_sb.sb_agcount) {
		xfs_warn(mp, "%s: agno != pag->pag_agno (%d != %d).",
		xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).",
			__func__, XFS_INO_TO_AGNO(mp, inode), pag->pag_agno);
			__func__, agno, mp->m_sb.sb_agcount);
		ASSERT(0);
		ASSERT(0);
		return -EINVAL;
		return -EINVAL;
	}
	}
	agino = XFS_INO_TO_AGINO(mp, inode);
	agino = XFS_INO_TO_AGINO(mp, inode);
	if (inode != XFS_AGINO_TO_INO(mp, agno, agino))  {
	if (inode != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino))  {
		xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).",
		xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).",
			__func__, (unsigned long long)inode,
			__func__, (unsigned long long)inode,
			(unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino));
			(unsigned long long)XFS_AGINO_TO_INO(mp, pag->pag_agno, agino));
		ASSERT(0);
		ASSERT(0);
		return -EINVAL;
		return -EINVAL;
	}
	}
@@ -2176,7 +2174,7 @@ xfs_difree(
	/*
	/*
	 * Get the allocation group header.
	 * Get the allocation group header.
	 */
	 */
	error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
	error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, &agbp);
	if (error) {
	if (error) {
		xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.",
		xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.",
			__func__, error);
			__func__, error);
@@ -2186,7 +2184,6 @@ xfs_difree(
	/*
	/*
	 * Fix up the inode allocation btree.
	 * Fix up the inode allocation btree.
	 */
	 */
	pag = agbp->b_pag;
	error = xfs_difree_inobt(mp, tp, agbp, pag, agino, xic, &rec);
	error = xfs_difree_inobt(mp, tp, agbp, pag, agino, xic, &rec);
	if (error)
	if (error)
		goto error0;
		goto error0;
+2 −11
Original line number Original line Diff line number Diff line
@@ -39,17 +39,8 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o)
int xfs_dialloc(struct xfs_trans **tpp, xfs_ino_t parent, umode_t mode,
int xfs_dialloc(struct xfs_trans **tpp, xfs_ino_t parent, umode_t mode,
		xfs_ino_t *new_ino);
		xfs_ino_t *new_ino);


/*
int xfs_difree(struct xfs_trans *tp, struct xfs_perag *pag,
 * Free disk inode.  Carefully avoids touching the incore inode, all
		xfs_ino_t ino, struct xfs_icluster *ifree);
 * manipulations incore are the caller's responsibility.
 * The on-disk inode is not changed by this operation, only the
 * btree (free inode mask) is changed.
 */
int					/* error */
xfs_difree(
	struct xfs_trans *tp,		/* transaction pointer */
	xfs_ino_t	inode,		/* inode to be freed */
	struct xfs_icluster *ifree);	/* cluster info if deleted */


/*
/*
 * Return the location of the inode in imap, for mapping it into a buffer.
 * Return the location of the inode in imap, for mapping it into a buffer.
+75 −56
Original line number Original line Diff line number Diff line
@@ -45,7 +45,8 @@ kmem_zone_t *xfs_inode_zone;
#define	XFS_ITRUNC_MAX_EXTENTS	2
#define	XFS_ITRUNC_MAX_EXTENTS	2


STATIC int xfs_iunlink(struct xfs_trans *, struct xfs_inode *);
STATIC int xfs_iunlink(struct xfs_trans *, struct xfs_inode *);
STATIC int xfs_iunlink_remove(struct xfs_trans *, struct xfs_inode *);
STATIC int xfs_iunlink_remove(struct xfs_trans *tp, struct xfs_perag *pag,
	struct xfs_inode *);


/*
/*
 * helper function to extract extent size hint from inode
 * helper function to extract extent size hint from inode
@@ -1241,7 +1242,11 @@ xfs_link(
	 * Handle initial link state of O_TMPFILE inode
	 * Handle initial link state of O_TMPFILE inode
	 */
	 */
	if (VFS_I(sip)->i_nlink == 0) {
	if (VFS_I(sip)->i_nlink == 0) {
		error = xfs_iunlink_remove(tp, sip);
		struct xfs_perag	*pag;

		pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, sip->i_ino));
		error = xfs_iunlink_remove(tp, pag, sip);
		xfs_perag_put(pag);
		if (error)
		if (error)
			goto error_return;
			goto error_return;
	}
	}
@@ -1934,7 +1939,7 @@ xfs_iunlink_destroy(
STATIC int
STATIC int
xfs_iunlink_update_bucket(
xfs_iunlink_update_bucket(
	struct xfs_trans	*tp,
	struct xfs_trans	*tp,
	xfs_agnumber_t		agno,
	struct xfs_perag	*pag,
	struct xfs_buf		*agibp,
	struct xfs_buf		*agibp,
	unsigned int		bucket_index,
	unsigned int		bucket_index,
	xfs_agino_t		new_agino)
	xfs_agino_t		new_agino)
@@ -1943,10 +1948,10 @@ xfs_iunlink_update_bucket(
	xfs_agino_t		old_value;
	xfs_agino_t		old_value;
	int			offset;
	int			offset;


	ASSERT(xfs_verify_agino_or_null(tp->t_mountp, agno, new_agino));
	ASSERT(xfs_verify_agino_or_null(tp->t_mountp, pag->pag_agno, new_agino));


	old_value = be32_to_cpu(agi->agi_unlinked[bucket_index]);
	old_value = be32_to_cpu(agi->agi_unlinked[bucket_index]);
	trace_xfs_iunlink_update_bucket(tp->t_mountp, agno, bucket_index,
	trace_xfs_iunlink_update_bucket(tp->t_mountp, pag->pag_agno, bucket_index,
			old_value, new_agino);
			old_value, new_agino);


	/*
	/*
@@ -1970,7 +1975,7 @@ xfs_iunlink_update_bucket(
STATIC void
STATIC void
xfs_iunlink_update_dinode(
xfs_iunlink_update_dinode(
	struct xfs_trans	*tp,
	struct xfs_trans	*tp,
	xfs_agnumber_t		agno,
	struct xfs_perag	*pag,
	xfs_agino_t		agino,
	xfs_agino_t		agino,
	struct xfs_buf		*ibp,
	struct xfs_buf		*ibp,
	struct xfs_dinode	*dip,
	struct xfs_dinode	*dip,
@@ -1980,9 +1985,9 @@ xfs_iunlink_update_dinode(
	struct xfs_mount	*mp = tp->t_mountp;
	struct xfs_mount	*mp = tp->t_mountp;
	int			offset;
	int			offset;


	ASSERT(xfs_verify_agino_or_null(mp, agno, next_agino));
	ASSERT(xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino));


	trace_xfs_iunlink_update_dinode(mp, agno, agino,
	trace_xfs_iunlink_update_dinode(mp, pag->pag_agno, agino,
			be32_to_cpu(dip->di_next_unlinked), next_agino);
			be32_to_cpu(dip->di_next_unlinked), next_agino);


	dip->di_next_unlinked = cpu_to_be32(next_agino);
	dip->di_next_unlinked = cpu_to_be32(next_agino);
@@ -2000,7 +2005,7 @@ STATIC int
xfs_iunlink_update_inode(
xfs_iunlink_update_inode(
	struct xfs_trans	*tp,
	struct xfs_trans	*tp,
	struct xfs_inode	*ip,
	struct xfs_inode	*ip,
	xfs_agnumber_t		agno,
	struct xfs_perag	*pag,
	xfs_agino_t		next_agino,
	xfs_agino_t		next_agino,
	xfs_agino_t		*old_next_agino)
	xfs_agino_t		*old_next_agino)
{
{
@@ -2010,7 +2015,7 @@ xfs_iunlink_update_inode(
	xfs_agino_t		old_value;
	xfs_agino_t		old_value;
	int			error;
	int			error;


	ASSERT(xfs_verify_agino_or_null(mp, agno, next_agino));
	ASSERT(xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino));


	error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &ibp);
	error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &ibp);
	if (error)
	if (error)
@@ -2019,7 +2024,7 @@ xfs_iunlink_update_inode(


	/* Make sure the old pointer isn't garbage. */
	/* Make sure the old pointer isn't garbage. */
	old_value = be32_to_cpu(dip->di_next_unlinked);
	old_value = be32_to_cpu(dip->di_next_unlinked);
	if (!xfs_verify_agino_or_null(mp, agno, old_value)) {
	if (!xfs_verify_agino_or_null(mp, pag->pag_agno, old_value)) {
		xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
		xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
				sizeof(*dip), __this_address);
				sizeof(*dip), __this_address);
		error = -EFSCORRUPTED;
		error = -EFSCORRUPTED;
@@ -2042,7 +2047,7 @@ xfs_iunlink_update_inode(
	}
	}


	/* Ok, update the new pointer. */
	/* Ok, update the new pointer. */
	xfs_iunlink_update_dinode(tp, agno, XFS_INO_TO_AGINO(mp, ip->i_ino),
	xfs_iunlink_update_dinode(tp, pag, XFS_INO_TO_AGINO(mp, ip->i_ino),
			ibp, dip, &ip->i_imap, next_agino);
			ibp, dip, &ip->i_imap, next_agino);
	return 0;
	return 0;
out:
out:
@@ -2063,10 +2068,10 @@ xfs_iunlink(
	struct xfs_inode	*ip)
	struct xfs_inode	*ip)
{
{
	struct xfs_mount	*mp = tp->t_mountp;
	struct xfs_mount	*mp = tp->t_mountp;
	struct xfs_perag	*pag;
	struct xfs_agi		*agi;
	struct xfs_agi		*agi;
	struct xfs_buf		*agibp;
	struct xfs_buf		*agibp;
	xfs_agino_t		next_agino;
	xfs_agino_t		next_agino;
	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
	xfs_agino_t		agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
	xfs_agino_t		agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
	short			bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS;
	short			bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS;
	int			error;
	int			error;
@@ -2075,10 +2080,12 @@ xfs_iunlink(
	ASSERT(VFS_I(ip)->i_mode != 0);
	ASSERT(VFS_I(ip)->i_mode != 0);
	trace_xfs_iunlink(ip);
	trace_xfs_iunlink(ip);


	pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));

	/* Get the agi buffer first.  It ensures lock ordering on the list. */
	/* Get the agi buffer first.  It ensures lock ordering on the list. */
	error = xfs_read_agi(mp, tp, agno, &agibp);
	error = xfs_read_agi(mp, tp, pag->pag_agno, &agibp);
	if (error)
	if (error)
		return error;
		goto out;
	agi = agibp->b_addr;
	agi = agibp->b_addr;


	/*
	/*
@@ -2088,9 +2095,10 @@ xfs_iunlink(
	 */
	 */
	next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
	next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
	if (next_agino == agino ||
	if (next_agino == agino ||
	    !xfs_verify_agino_or_null(mp, agno, next_agino)) {
	    !xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino)) {
		xfs_buf_mark_corrupt(agibp);
		xfs_buf_mark_corrupt(agibp);
		return -EFSCORRUPTED;
		error = -EFSCORRUPTED;
		goto out;
	}
	}


	if (next_agino != NULLAGINO) {
	if (next_agino != NULLAGINO) {
@@ -2100,23 +2108,26 @@ xfs_iunlink(
		 * There is already another inode in the bucket, so point this
		 * There is already another inode in the bucket, so point this
		 * inode to the current head of the list.
		 * inode to the current head of the list.
		 */
		 */
		error = xfs_iunlink_update_inode(tp, ip, agno, next_agino,
		error = xfs_iunlink_update_inode(tp, ip, pag, next_agino,
				&old_agino);
				&old_agino);
		if (error)
		if (error)
			return error;
			goto out;
		ASSERT(old_agino == NULLAGINO);
		ASSERT(old_agino == NULLAGINO);


		/*
		/*
		 * agino has been unlinked, add a backref from the next inode
		 * agino has been unlinked, add a backref from the next inode
		 * back to agino.
		 * back to agino.
		 */
		 */
		error = xfs_iunlink_add_backref(agibp->b_pag, agino, next_agino);
		error = xfs_iunlink_add_backref(pag, agino, next_agino);
		if (error)
		if (error)
			return error;
			goto out;
	}
	}


	/* Point the head of the list to point to this inode. */
	/* Point the head of the list to point to this inode. */
	return xfs_iunlink_update_bucket(tp, agno, agibp, bucket_index, agino);
	error = xfs_iunlink_update_bucket(tp, pag, agibp, bucket_index, agino);
out:
	xfs_perag_put(pag);
	return error;
}
}


/* Return the imap, dinode pointer, and buffer for an inode. */
/* Return the imap, dinode pointer, and buffer for an inode. */
@@ -2164,14 +2175,13 @@ xfs_iunlink_map_ino(
STATIC int
STATIC int
xfs_iunlink_map_prev(
xfs_iunlink_map_prev(
	struct xfs_trans	*tp,
	struct xfs_trans	*tp,
	xfs_agnumber_t		agno,
	struct xfs_perag	*pag,
	xfs_agino_t		head_agino,
	xfs_agino_t		head_agino,
	xfs_agino_t		target_agino,
	xfs_agino_t		target_agino,
	xfs_agino_t		*agino,
	xfs_agino_t		*agino,
	struct xfs_imap		*imap,
	struct xfs_imap		*imap,
	struct xfs_dinode	**dipp,
	struct xfs_dinode	**dipp,
	struct xfs_buf		**bpp,
	struct xfs_buf		**bpp)
	struct xfs_perag	*pag)
{
{
	struct xfs_mount	*mp = tp->t_mountp;
	struct xfs_mount	*mp = tp->t_mountp;
	xfs_agino_t		next_agino;
	xfs_agino_t		next_agino;
@@ -2183,7 +2193,8 @@ xfs_iunlink_map_prev(
	/* See if our backref cache can find it faster. */
	/* See if our backref cache can find it faster. */
	*agino = xfs_iunlink_lookup_backref(pag, target_agino);
	*agino = xfs_iunlink_lookup_backref(pag, target_agino);
	if (*agino != NULLAGINO) {
	if (*agino != NULLAGINO) {
		error = xfs_iunlink_map_ino(tp, agno, *agino, imap, dipp, bpp);
		error = xfs_iunlink_map_ino(tp, pag->pag_agno, *agino, imap,
				dipp, bpp);
		if (error)
		if (error)
			return error;
			return error;


@@ -2199,7 +2210,7 @@ xfs_iunlink_map_prev(
		WARN_ON_ONCE(1);
		WARN_ON_ONCE(1);
	}
	}


	trace_xfs_iunlink_map_prev_fallback(mp, agno);
	trace_xfs_iunlink_map_prev_fallback(mp, pag->pag_agno);


	/* Otherwise, walk the entire bucket until we find it. */
	/* Otherwise, walk the entire bucket until we find it. */
	next_agino = head_agino;
	next_agino = head_agino;
@@ -2210,8 +2221,8 @@ xfs_iunlink_map_prev(
			xfs_trans_brelse(tp, *bpp);
			xfs_trans_brelse(tp, *bpp);


		*agino = next_agino;
		*agino = next_agino;
		error = xfs_iunlink_map_ino(tp, agno, next_agino, imap, dipp,
		error = xfs_iunlink_map_ino(tp, pag->pag_agno, next_agino, imap,
				bpp);
				dipp, bpp);
		if (error)
		if (error)
			return error;
			return error;


@@ -2220,7 +2231,7 @@ xfs_iunlink_map_prev(
		 * Make sure this pointer is valid and isn't an obvious
		 * Make sure this pointer is valid and isn't an obvious
		 * infinite loop.
		 * infinite loop.
		 */
		 */
		if (!xfs_verify_agino(mp, agno, unlinked_agino) ||
		if (!xfs_verify_agino(mp, pag->pag_agno, unlinked_agino) ||
		    next_agino == unlinked_agino) {
		    next_agino == unlinked_agino) {
			XFS_CORRUPTION_ERROR(__func__,
			XFS_CORRUPTION_ERROR(__func__,
					XFS_ERRLEVEL_LOW, mp,
					XFS_ERRLEVEL_LOW, mp,
@@ -2240,6 +2251,7 @@ xfs_iunlink_map_prev(
STATIC int
STATIC int
xfs_iunlink_remove(
xfs_iunlink_remove(
	struct xfs_trans	*tp,
	struct xfs_trans	*tp,
	struct xfs_perag	*pag,
	struct xfs_inode	*ip)
	struct xfs_inode	*ip)
{
{
	struct xfs_mount	*mp = tp->t_mountp;
	struct xfs_mount	*mp = tp->t_mountp;
@@ -2247,7 +2259,6 @@ xfs_iunlink_remove(
	struct xfs_buf		*agibp;
	struct xfs_buf		*agibp;
	struct xfs_buf		*last_ibp;
	struct xfs_buf		*last_ibp;
	struct xfs_dinode	*last_dip = NULL;
	struct xfs_dinode	*last_dip = NULL;
	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
	xfs_agino_t		agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
	xfs_agino_t		agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
	xfs_agino_t		next_agino;
	xfs_agino_t		next_agino;
	xfs_agino_t		head_agino;
	xfs_agino_t		head_agino;
@@ -2257,7 +2268,7 @@ xfs_iunlink_remove(
	trace_xfs_iunlink_remove(ip);
	trace_xfs_iunlink_remove(ip);


	/* Get the agi buffer first.  It ensures lock ordering on the list. */
	/* Get the agi buffer first.  It ensures lock ordering on the list. */
	error = xfs_read_agi(mp, tp, agno, &agibp);
	error = xfs_read_agi(mp, tp, pag->pag_agno, &agibp);
	if (error)
	if (error)
		return error;
		return error;
	agi = agibp->b_addr;
	agi = agibp->b_addr;
@@ -2267,7 +2278,7 @@ xfs_iunlink_remove(
	 * go on.  Make sure the head pointer isn't garbage.
	 * go on.  Make sure the head pointer isn't garbage.
	 */
	 */
	head_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
	head_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
	if (!xfs_verify_agino(mp, agno, head_agino)) {
	if (!xfs_verify_agino(mp, pag->pag_agno, head_agino)) {
		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
				agi, sizeof(*agi));
				agi, sizeof(*agi));
		return -EFSCORRUPTED;
		return -EFSCORRUPTED;
@@ -2278,7 +2289,7 @@ xfs_iunlink_remove(
	 * the old pointer value so that we can update whatever was previous
	 * the old pointer value so that we can update whatever was previous
	 * to us in the list to point to whatever was next in the list.
	 * to us in the list to point to whatever was next in the list.
	 */
	 */
	error = xfs_iunlink_update_inode(tp, ip, agno, NULLAGINO, &next_agino);
	error = xfs_iunlink_update_inode(tp, ip, pag, NULLAGINO, &next_agino);
	if (error)
	if (error)
		return error;
		return error;


@@ -2290,8 +2301,7 @@ xfs_iunlink_remove(
	 * this inode's backref to point from the next inode.
	 * this inode's backref to point from the next inode.
	 */
	 */
	if (next_agino != NULLAGINO) {
	if (next_agino != NULLAGINO) {
		error = xfs_iunlink_change_backref(agibp->b_pag, next_agino,
		error = xfs_iunlink_change_backref(pag, next_agino, NULLAGINO);
				NULLAGINO);
		if (error)
		if (error)
			return error;
			return error;
	}
	}
@@ -2301,14 +2311,13 @@ xfs_iunlink_remove(
		xfs_agino_t	prev_agino;
		xfs_agino_t	prev_agino;


		/* We need to search the list for the inode being freed. */
		/* We need to search the list for the inode being freed. */
		error = xfs_iunlink_map_prev(tp, agno, head_agino, agino,
		error = xfs_iunlink_map_prev(tp, pag, head_agino, agino,
				&prev_agino, &imap, &last_dip, &last_ibp,
				&prev_agino, &imap, &last_dip, &last_ibp);
				agibp->b_pag);
		if (error)
		if (error)
			return error;
			return error;


		/* Point the previous inode on the list to the next inode. */
		/* Point the previous inode on the list to the next inode. */
		xfs_iunlink_update_dinode(tp, agno, prev_agino, last_ibp,
		xfs_iunlink_update_dinode(tp, pag, prev_agino, last_ibp,
				last_dip, &imap, next_agino);
				last_dip, &imap, next_agino);


		/*
		/*
@@ -2324,7 +2333,7 @@ xfs_iunlink_remove(
	}
	}


	/* Point the head of the list to the next unlinked inode. */
	/* Point the head of the list to the next unlinked inode. */
	return xfs_iunlink_update_bucket(tp, agno, agibp, bucket_index,
	return xfs_iunlink_update_bucket(tp, pag, agibp, bucket_index,
			next_agino);
			next_agino);
}
}


@@ -2335,12 +2344,11 @@ xfs_iunlink_remove(
 */
 */
static void
static void
xfs_ifree_mark_inode_stale(
xfs_ifree_mark_inode_stale(
	struct xfs_buf		*bp,
	struct xfs_perag	*pag,
	struct xfs_inode	*free_ip,
	struct xfs_inode	*free_ip,
	xfs_ino_t		inum)
	xfs_ino_t		inum)
{
{
	struct xfs_mount	*mp = bp->b_mount;
	struct xfs_mount	*mp = pag->pag_mount;
	struct xfs_perag	*pag = bp->b_pag;
	struct xfs_inode_log_item *iip;
	struct xfs_inode_log_item *iip;
	struct xfs_inode	*ip;
	struct xfs_inode	*ip;


@@ -2430,10 +2438,11 @@ xfs_ifree_mark_inode_stale(
 * inodes that are in memory - they all must be marked stale and attached to
 * inodes that are in memory - they all must be marked stale and attached to
 * the cluster buffer.
 * the cluster buffer.
 */
 */
STATIC int
static int
xfs_ifree_cluster(
xfs_ifree_cluster(
	struct xfs_inode	*free_ip,
	struct xfs_trans	*tp,
	struct xfs_trans	*tp,
	struct xfs_perag	*pag,
	struct xfs_inode	*free_ip,
	struct xfs_icluster	*xic)
	struct xfs_icluster	*xic)
{
{
	struct xfs_mount	*mp = free_ip->i_mount;
	struct xfs_mount	*mp = free_ip->i_mount;
@@ -2495,7 +2504,7 @@ xfs_ifree_cluster(
		 * already marked XFS_ISTALE.
		 * already marked XFS_ISTALE.
		 */
		 */
		for (i = 0; i < igeo->inodes_per_cluster; i++)
		for (i = 0; i < igeo->inodes_per_cluster; i++)
			xfs_ifree_mark_inode_stale(bp, free_ip, inum + i);
			xfs_ifree_mark_inode_stale(pag, free_ip, inum + i);


		xfs_trans_stale_inode_buf(tp, bp);
		xfs_trans_stale_inode_buf(tp, bp);
		xfs_trans_binval(tp, bp);
		xfs_trans_binval(tp, bp);
@@ -2518,9 +2527,11 @@ xfs_ifree(
	struct xfs_trans	*tp,
	struct xfs_trans	*tp,
	struct xfs_inode	*ip)
	struct xfs_inode	*ip)
{
{
	int			error;
	struct xfs_mount	*mp = ip->i_mount;
	struct xfs_perag	*pag;
	struct xfs_icluster	xic = { 0 };
	struct xfs_icluster	xic = { 0 };
	struct xfs_inode_log_item *iip = ip->i_itemp;
	struct xfs_inode_log_item *iip = ip->i_itemp;
	int			error;


	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
	ASSERT(VFS_I(ip)->i_nlink == 0);
	ASSERT(VFS_I(ip)->i_nlink == 0);
@@ -2528,16 +2539,18 @@ xfs_ifree(
	ASSERT(ip->i_disk_size == 0 || !S_ISREG(VFS_I(ip)->i_mode));
	ASSERT(ip->i_disk_size == 0 || !S_ISREG(VFS_I(ip)->i_mode));
	ASSERT(ip->i_nblocks == 0);
	ASSERT(ip->i_nblocks == 0);


	pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));

	/*
	/*
	 * Pull the on-disk inode from the AGI unlinked list.
	 * Pull the on-disk inode from the AGI unlinked list.
	 */
	 */
	error = xfs_iunlink_remove(tp, ip);
	error = xfs_iunlink_remove(tp, pag, ip);
	if (error)
	if (error)
		return error;
		goto out;


	error = xfs_difree(tp, ip->i_ino, &xic);
	error = xfs_difree(tp, pag, ip->i_ino, &xic);
	if (error)
	if (error)
		return error;
		goto out;


	/*
	/*
	 * Free any local-format data sitting around before we reset the
	 * Free any local-format data sitting around before we reset the
@@ -2552,7 +2565,7 @@ xfs_ifree(


	VFS_I(ip)->i_mode = 0;		/* mark incore inode as free */
	VFS_I(ip)->i_mode = 0;		/* mark incore inode as free */
	ip->i_diflags = 0;
	ip->i_diflags = 0;
	ip->i_diflags2 = ip->i_mount->m_ino_geo.new_diflags2;
	ip->i_diflags2 = mp->m_ino_geo.new_diflags2;
	ip->i_forkoff = 0;		/* mark the attr fork not in use */
	ip->i_forkoff = 0;		/* mark the attr fork not in use */
	ip->i_df.if_format = XFS_DINODE_FMT_EXTENTS;
	ip->i_df.if_format = XFS_DINODE_FMT_EXTENTS;
	if (xfs_iflags_test(ip, XFS_IPRESERVE_DM_FIELDS))
	if (xfs_iflags_test(ip, XFS_IPRESERVE_DM_FIELDS))
@@ -2571,8 +2584,9 @@ xfs_ifree(
	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);


	if (xic.deleted)
	if (xic.deleted)
		error = xfs_ifree_cluster(ip, tp, &xic);
		error = xfs_ifree_cluster(tp, pag, ip, &xic);

out:
	xfs_perag_put(pag);
	return error;
	return error;
}
}


@@ -3176,8 +3190,13 @@ xfs_rename(
	 * in future.
	 * in future.
	 */
	 */
	if (wip) {
	if (wip) {
		struct xfs_perag	*pag;

		ASSERT(VFS_I(wip)->i_nlink == 0);
		ASSERT(VFS_I(wip)->i_nlink == 0);
		error = xfs_iunlink_remove(tp, wip);

		pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, wip->i_ino));
		error = xfs_iunlink_remove(tp, pag, wip);
		xfs_perag_put(pag);
		if (error)
		if (error)
			goto out_trans_cancel;
			goto out_trans_cancel;