Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5bd606b authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Alex Elder
Browse files

xfs: remove xfs_bmap_add_extent



There is no real need to the xfs_bmap_add_extent, as the callers
know what kind of extents they need to it.  Removing it means
duplicating the extents to btree conversion logic in three places,
but overall it's still much simpler code and quite a bit less code.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAlex Elder <aelder@sgi.com>
parent 27a3f8f2
Loading
Loading
Loading
Loading
+173 −243
Original line number Original line Diff line number Diff line
@@ -50,17 +50,22 @@
#include "xfs_trace.h"
#include "xfs_trace.h"




#ifdef DEBUG
STATIC void
xfs_bmap_check_leaf_extents(xfs_btree_cur_t *cur, xfs_inode_t *ip, int whichfork);
#endif

kmem_zone_t		*xfs_bmap_free_item_zone;
kmem_zone_t		*xfs_bmap_free_item_zone;


/*
/*
 * Prototypes for internal bmap routines.
 * Prototypes for internal bmap routines.
 */
 */


#ifdef DEBUG
STATIC void
xfs_bmap_check_leaf_extents(
	struct xfs_btree_cur	*cur,
	struct xfs_inode	*ip,
	int			whichfork);
#else
#define xfs_bmap_check_leaf_extents(cur, ip, whichfork)		do { } while (0)
#endif



/*
/*
 * Called from xfs_bmap_add_attrfork to handle extents format files.
 * Called from xfs_bmap_add_attrfork to handle extents format files.
@@ -84,47 +89,6 @@ xfs_bmap_add_attrfork_local(
	xfs_bmap_free_t		*flist,		/* blocks to free at commit */
	xfs_bmap_free_t		*flist,		/* blocks to free at commit */
	int			*flags);	/* inode logging flags */
	int			*flags);	/* inode logging flags */


/*
 * Called by xfs_bmap_add_extent to handle cases converting a delayed
 * allocation to a real allocation.
 */
STATIC int				/* error */
xfs_bmap_add_extent_delay_real(
	struct xfs_trans	*tp,	/* transaction pointer */
	xfs_inode_t		*ip,	/* incore inode pointer */
	xfs_extnum_t		*idx,	/* extent number to update/insert */
	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
	xfs_filblks_t		*dnew,	/* new delayed-alloc indirect blocks */
	xfs_fsblock_t		*first,	/* pointer to firstblock variable */
	xfs_bmap_free_t		*flist,	/* list of extents to be freed */
	int			*logflagsp); /* inode logging flags */

/*
 * Called by xfs_bmap_add_extent to handle cases converting a hole
 * to a real allocation.
 */
STATIC int				/* error */
xfs_bmap_add_extent_hole_real(
	xfs_inode_t		*ip,	/* incore inode pointer */
	xfs_extnum_t		*idx,	/* extent number to update/insert */
	xfs_btree_cur_t		*cur,	/* if null, not a btree */
	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
	int			*logflagsp, /* inode logging flags */
	int			whichfork); /* data or attr fork */

/*
 * Called by xfs_bmap_add_extent to handle cases converting an unwritten
 * allocation to a real allocation or vice versa.
 */
STATIC int				/* error */
xfs_bmap_add_extent_unwritten_real(
	xfs_inode_t		*ip,	/* incore inode pointer */
	xfs_extnum_t		*idx,	/* extent number to update/insert */
	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
	int			*logflagsp); /* inode logging flags */

/*
/*
 * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file.
 * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file.
 * It figures out where to ask the underlying allocator to put the new extent.
 * It figures out where to ask the underlying allocator to put the new extent.
@@ -407,147 +371,7 @@ xfs_bmap_add_attrfork_local(
}
}


/*
/*
 * Update file extent records and the btree after allocating space.
 * Convert a delayed allocation to a real allocation.
 */
STATIC int				/* error */
xfs_bmap_add_extent(
	struct xfs_trans	*tp,	/* transaction pointer */
	xfs_inode_t		*ip,	/* incore inode pointer */
	xfs_extnum_t		*idx,	/* extent number to update/insert */
	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
	xfs_fsblock_t		*first,	/* pointer to firstblock variable */
	xfs_bmap_free_t		*flist,	/* list of extents to be freed */
	int			*logflagsp, /* inode logging flags */
	int			whichfork) /* data or attr fork */
{
	xfs_btree_cur_t		*cur;	/* btree cursor or null */
	xfs_filblks_t		da_new; /* new count del alloc blocks used */
	xfs_filblks_t		da_old; /* old count del alloc blocks used */
	int			error;	/* error return value */
	xfs_ifork_t		*ifp;	/* inode fork ptr */
	int			logflags; /* returned value */
	xfs_extnum_t		nextents; /* number of extents in file now */

	XFS_STATS_INC(xs_add_exlist);

	cur = *curp;
	ifp = XFS_IFORK_PTR(ip, whichfork);
	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
	da_old = da_new = 0;
	error = 0;

	ASSERT(*idx >= 0);
	ASSERT(*idx <= nextents);
	ASSERT(!isnullstartblock(new->br_startblock));

	/*
	 * Real allocation off the end of the file.
	 */
	if (*idx == nextents) {
		if (cur)
			ASSERT((cur->bc_private.b.flags &
				XFS_BTCUR_BPRV_WASDEL) == 0);
		error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new,
				&logflags, whichfork);
	} else {
		xfs_bmbt_irec_t	prev;	/* old extent at offset idx */

		/*
		 * Get the record referred to by idx.
		 */
		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx), &prev);
		/*
		 * If it's a real allocation record, and the new allocation ends
		 * after the start of the referred to record, then we're filling
		 * in a delayed or unwritten allocation with a real one, or
		 * converting real back to unwritten.
		 */
		if (!isnullstartblock(new->br_startblock) &&
		    new->br_startoff + new->br_blockcount > prev.br_startoff) {
			if (prev.br_state != XFS_EXT_UNWRITTEN &&
			    isnullstartblock(prev.br_startblock)) {
				da_old = startblockval(prev.br_startblock);
				if (cur)
					ASSERT(cur->bc_private.b.flags &
						XFS_BTCUR_BPRV_WASDEL);
				error = xfs_bmap_add_extent_delay_real(tp, ip,
						idx, &cur, new, &da_new,
						first, flist, &logflags);
			} else {
				ASSERT(new->br_state == XFS_EXT_NORM ||
				       new->br_state == XFS_EXT_UNWRITTEN);

				error = xfs_bmap_add_extent_unwritten_real(ip,
						idx, &cur, new, &logflags);
				if (error)
					goto done;
			}
		}
		/*
		 * Otherwise we're filling in a hole with an allocation.
		 */
		else {
			if (cur)
				ASSERT((cur->bc_private.b.flags &
					XFS_BTCUR_BPRV_WASDEL) == 0);
			error = xfs_bmap_add_extent_hole_real(ip, idx, cur,
					new, &logflags, whichfork);
		}
	}

	if (error)
		goto done;
	ASSERT(*curp == cur || *curp == NULL);

	/*
	 * Convert to a btree if necessary.
	 */
	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
	    XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) {
		int	tmp_logflags;	/* partial log flag return val */

		ASSERT(cur == NULL);
		error = xfs_bmap_extents_to_btree(tp, ip, first,
			flist, &cur, da_old > 0, &tmp_logflags, whichfork);
		logflags |= tmp_logflags;
		if (error)
			goto done;
	}
	/*
	 * Adjust for changes in reserved delayed indirect blocks.
	 * Nothing to do for disk quotas here.
	 */
	if (da_old || da_new) {
		xfs_filblks_t	nblks;

		nblks = da_new;
		if (cur)
			nblks += cur->bc_private.b.allocated;
		ASSERT(nblks <= da_old);
		if (nblks < da_old)
			xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS,
				(int64_t)(da_old - nblks), 0);
	}
	/*
	 * Clear out the allocated field, done with it now in any case.
	 */
	if (cur) {
		cur->bc_private.b.allocated = 0;
		*curp = cur;
	}
done:
#ifdef DEBUG
	if (!error)
		xfs_bmap_check_leaf_extents(*curp, ip, whichfork);
#endif
	*logflagsp = logflags;
	return error;
}

/*
 * Called by xfs_bmap_add_extent to handle cases converting a delayed
 * allocation to a real allocation.
 */
 */
STATIC int				/* error */
STATIC int				/* error */
xfs_bmap_add_extent_delay_real(
xfs_bmap_add_extent_delay_real(
@@ -556,7 +380,6 @@ xfs_bmap_add_extent_delay_real(
	xfs_extnum_t		*idx,	/* extent number to update/insert */
	xfs_extnum_t		*idx,	/* extent number to update/insert */
	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
	xfs_filblks_t		*dnew,	/* new delayed-alloc indirect blocks */
	xfs_fsblock_t		*first,	/* pointer to firstblock variable */
	xfs_fsblock_t		*first,	/* pointer to firstblock variable */
	xfs_bmap_free_t		*flist,	/* list of extents to be freed */
	xfs_bmap_free_t		*flist,	/* list of extents to be freed */
	int			*logflagsp) /* inode logging flags */
	int			*logflagsp) /* inode logging flags */
@@ -572,10 +395,24 @@ xfs_bmap_add_extent_delay_real(
					/* left is 0, right is 1, prev is 2 */
					/* left is 0, right is 1, prev is 2 */
	int			rval=0;	/* return value (logging flags) */
	int			rval=0;	/* return value (logging flags) */
	int			state = 0;/* state bits, accessed thru macros */
	int			state = 0;/* state bits, accessed thru macros */
	xfs_filblks_t		temp=0;	/* value for dnew calculations */
	xfs_filblks_t		da_new; /* new count del alloc blocks used */
	xfs_filblks_t		temp2=0;/* value for dnew calculations */
	xfs_filblks_t		da_old; /* old count del alloc blocks used */
	xfs_filblks_t		temp=0;	/* value for da_new calculations */
	xfs_filblks_t		temp2=0;/* value for da_new calculations */
	int			tmp_rval;	/* partial logging flags */
	int			tmp_rval;	/* partial logging flags */


	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
	cur = *curp;

	ASSERT(*idx >= 0);
	ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
	ASSERT(!isnullstartblock(new->br_startblock));
	ASSERT(!cur || (cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));

	XFS_STATS_INC(xs_add_exlist);

	*logflagsp = 0;

#define	LEFT		r[0]
#define	LEFT		r[0]
#define	RIGHT		r[1]
#define	RIGHT		r[1]
#define	PREV		r[2]
#define	PREV		r[2]
@@ -583,14 +420,15 @@ xfs_bmap_add_extent_delay_real(
	/*
	/*
	 * Set up a bunch of variables to make the tests simpler.
	 * Set up a bunch of variables to make the tests simpler.
	 */
	 */
	cur = *curp;
	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
	ep = xfs_iext_get_ext(ifp, *idx);
	ep = xfs_iext_get_ext(ifp, *idx);
	xfs_bmbt_get_all(ep, &PREV);
	xfs_bmbt_get_all(ep, &PREV);
	new_endoff = new->br_startoff + new->br_blockcount;
	new_endoff = new->br_startoff + new->br_blockcount;
	ASSERT(PREV.br_startoff <= new->br_startoff);
	ASSERT(PREV.br_startoff <= new->br_startoff);
	ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff);
	ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff);


	da_old = startblockval(PREV.br_startblock);
	da_new = 0;

	/*
	/*
	 * Set flags determining what part of the previous delayed allocation
	 * Set flags determining what part of the previous delayed allocation
	 * extent is being replaced by a real allocation.
	 * extent is being replaced by a real allocation.
@@ -688,7 +526,6 @@ xfs_bmap_add_extent_delay_real(
					RIGHT.br_blockcount, LEFT.br_state)))
					RIGHT.br_blockcount, LEFT.br_state)))
				goto done;
				goto done;
		}
		}
		*dnew = 0;
		break;
		break;


	case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG:
	case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG:
@@ -719,7 +556,6 @@ xfs_bmap_add_extent_delay_real(
					PREV.br_blockcount, LEFT.br_state)))
					PREV.br_blockcount, LEFT.br_state)))
				goto done;
				goto done;
		}
		}
		*dnew = 0;
		break;
		break;


	case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
	case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
@@ -749,8 +585,6 @@ xfs_bmap_add_extent_delay_real(
					RIGHT.br_blockcount, PREV.br_state)))
					RIGHT.br_blockcount, PREV.br_state)))
				goto done;
				goto done;
		}
		}

		*dnew = 0;
		break;
		break;


	case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING:
	case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING:
@@ -778,8 +612,6 @@ xfs_bmap_add_extent_delay_real(
				goto done;
				goto done;
			XFS_WANT_CORRUPTED_GOTO(i == 1, done);
			XFS_WANT_CORRUPTED_GOTO(i == 1, done);
		}
		}

		*dnew = 0;
		break;
		break;


	case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG:
	case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG:
@@ -813,13 +645,12 @@ xfs_bmap_add_extent_delay_real(
					LEFT.br_state)))
					LEFT.br_state)))
				goto done;
				goto done;
		}
		}
		temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
		da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
			startblockval(PREV.br_startblock));
			startblockval(PREV.br_startblock));
		xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
		xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
		trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
		trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);


		--*idx;
		--*idx;
		*dnew = temp;
		break;
		break;


	case BMAP_LEFT_FILLING:
	case BMAP_LEFT_FILLING:
@@ -856,14 +687,12 @@ xfs_bmap_add_extent_delay_real(
			if (error)
			if (error)
				goto done;
				goto done;
		}
		}
		temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
		da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
			startblockval(PREV.br_startblock) -
			startblockval(PREV.br_startblock) -
			(cur ? cur->bc_private.b.allocated : 0));
			(cur ? cur->bc_private.b.allocated : 0));
		ep = xfs_iext_get_ext(ifp, *idx + 1);
		ep = xfs_iext_get_ext(ifp, *idx + 1);
		xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
		xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
		trace_xfs_bmap_post_update(ip, *idx + 1, state, _THIS_IP_);
		trace_xfs_bmap_post_update(ip, *idx + 1, state, _THIS_IP_);

		*dnew = temp;
		break;
		break;


	case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
	case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
@@ -896,14 +725,13 @@ xfs_bmap_add_extent_delay_real(
				goto done;
				goto done;
		}
		}


		temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
		da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
			startblockval(PREV.br_startblock));
			startblockval(PREV.br_startblock));
		trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
		trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
		xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
		xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
		trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
		trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);


		++*idx;
		++*idx;
		*dnew = temp;
		break;
		break;


	case BMAP_RIGHT_FILLING:
	case BMAP_RIGHT_FILLING:
@@ -939,15 +767,14 @@ xfs_bmap_add_extent_delay_real(
			if (error)
			if (error)
				goto done;
				goto done;
		}
		}
		temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
		da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
			startblockval(PREV.br_startblock) -
			startblockval(PREV.br_startblock) -
			(cur ? cur->bc_private.b.allocated : 0));
			(cur ? cur->bc_private.b.allocated : 0));
		ep = xfs_iext_get_ext(ifp, *idx);
		ep = xfs_iext_get_ext(ifp, *idx);
		xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
		xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
		trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
		trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);


		++*idx;
		++*idx;
		*dnew = temp;
		break;
		break;


	case 0:
	case 0:
@@ -1029,7 +856,7 @@ xfs_bmap_add_extent_delay_real(
		trace_xfs_bmap_post_update(ip, *idx + 2, state, _THIS_IP_);
		trace_xfs_bmap_post_update(ip, *idx + 2, state, _THIS_IP_);


		++*idx;
		++*idx;
		*dnew = temp + temp2;
		da_new = temp + temp2;
		break;
		break;


	case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
	case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
@@ -1044,9 +871,39 @@ xfs_bmap_add_extent_delay_real(
		 */
		 */
		ASSERT(0);
		ASSERT(0);
	}
	}

	/* convert to a btree if necessary */
	if (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS &&
	    XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > ifp->if_ext_max) {
		int	tmp_logflags;	/* partial log flag return val */

		ASSERT(cur == NULL);
		error = xfs_bmap_extents_to_btree(tp, ip, first, flist, &cur,
				da_old > 0, &tmp_logflags, XFS_DATA_FORK);
		*logflagsp |= tmp_logflags;
		if (error)
			goto done;
	}

	/* adjust for changes in reserved delayed indirect blocks */
	if (da_old || da_new) {
		temp = da_new;
		if (cur)
			temp += cur->bc_private.b.allocated;
		ASSERT(temp <= da_old);
		if (temp < da_old)
			xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS,
				(int64_t)(da_old - temp), 0);
	}

	/* clear out the allocated field, done with it now in any case. */
	if (cur) {
		cur->bc_private.b.allocated = 0;
		*curp = cur;
		*curp = cur;
	}
	xfs_bmap_check_leaf_extents(cur, ip, XFS_DATA_FORK);
done:
done:
	*logflagsp = rval;
	*logflagsp |= rval;
	return error;
	return error;
#undef	LEFT
#undef	LEFT
#undef	RIGHT
#undef	RIGHT
@@ -1054,15 +911,17 @@ xfs_bmap_add_extent_delay_real(
}
}


/*
/*
 * Called by xfs_bmap_add_extent to handle cases converting an unwritten
 * Convert an unwritten allocation to a real allocation or vice versa.
 * allocation to a real allocation or vice versa.
 */
 */
STATIC int				/* error */
STATIC int				/* error */
xfs_bmap_add_extent_unwritten_real(
xfs_bmap_add_extent_unwritten_real(
	struct xfs_trans	*tp,
	xfs_inode_t		*ip,	/* incore inode pointer */
	xfs_inode_t		*ip,	/* incore inode pointer */
	xfs_extnum_t		*idx,	/* extent number to update/insert */
	xfs_extnum_t		*idx,	/* extent number to update/insert */
	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */
	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
	xfs_fsblock_t		*first,	/* pointer to firstblock variable */
	xfs_bmap_free_t		*flist,	/* list of extents to be freed */
	int			*logflagsp) /* inode logging flags */
	int			*logflagsp) /* inode logging flags */
{
{
	xfs_btree_cur_t		*cur;	/* btree cursor */
	xfs_btree_cur_t		*cur;	/* btree cursor */
@@ -1078,15 +937,25 @@ xfs_bmap_add_extent_unwritten_real(
	int			rval=0;	/* return value (logging flags) */
	int			rval=0;	/* return value (logging flags) */
	int			state = 0;/* state bits, accessed thru macros */
	int			state = 0;/* state bits, accessed thru macros */


	*logflagsp = 0;

	cur = *curp;
	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);

	ASSERT(*idx >= 0);
	ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
	ASSERT(!isnullstartblock(new->br_startblock));

	XFS_STATS_INC(xs_add_exlist);

#define	LEFT		r[0]
#define	LEFT		r[0]
#define	RIGHT		r[1]
#define	RIGHT		r[1]
#define	PREV		r[2]
#define	PREV		r[2]

	/*
	/*
	 * Set up a bunch of variables to make the tests simpler.
	 * Set up a bunch of variables to make the tests simpler.
	 */
	 */
	error = 0;
	error = 0;
	cur = *curp;
	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
	ep = xfs_iext_get_ext(ifp, *idx);
	ep = xfs_iext_get_ext(ifp, *idx);
	xfs_bmbt_get_all(ep, &PREV);
	xfs_bmbt_get_all(ep, &PREV);
	newext = new->br_state;
	newext = new->br_state;
@@ -1537,9 +1406,29 @@ xfs_bmap_add_extent_unwritten_real(
		 */
		 */
		ASSERT(0);
		ASSERT(0);
	}
	}

	/* convert to a btree if necessary */
	if (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS &&
	    XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > ifp->if_ext_max) {
		int	tmp_logflags;	/* partial log flag return val */

		ASSERT(cur == NULL);
		error = xfs_bmap_extents_to_btree(tp, ip, first, flist, &cur,
				0, &tmp_logflags, XFS_DATA_FORK);
		*logflagsp |= tmp_logflags;
		if (error)
			goto done;
	}

	/* clear out the allocated field, done with it now in any case. */
	if (cur) {
		cur->bc_private.b.allocated = 0;
		*curp = cur;
		*curp = cur;
	}

	xfs_bmap_check_leaf_extents(*curp, ip, XFS_DATA_FORK);
done:
done:
	*logflagsp = rval;
	*logflagsp |= rval;
	return error;
	return error;
#undef	LEFT
#undef	LEFT
#undef	RIGHT
#undef	RIGHT
@@ -1691,30 +1580,42 @@ xfs_bmap_add_extent_hole_delay(
}
}


/*
/*
 * Called by xfs_bmap_add_extent to handle cases converting a hole
 * Convert a hole to a real allocation.
 * to a real allocation.
 */
 */
STATIC int				/* error */
STATIC int				/* error */
xfs_bmap_add_extent_hole_real(
xfs_bmap_add_extent_hole_real(
	struct xfs_trans	*tp,
	xfs_inode_t		*ip,	/* incore inode pointer */
	xfs_inode_t		*ip,	/* incore inode pointer */
	xfs_extnum_t		*idx,	/* extent number to update/insert */
	xfs_extnum_t		*idx,	/* extent number to update/insert */
	xfs_btree_cur_t		*cur,	/* if null, not a btree */
	xfs_btree_cur_t		**curp,	/* if null, not a btree */
	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
	xfs_fsblock_t		*first,	/* pointer to firstblock variable */
	xfs_bmap_free_t		*flist,	/* list of extents to be freed */
	int			*logflagsp, /* inode logging flags */
	int			*logflagsp, /* inode logging flags */
	int			whichfork) /* data or attr fork */
	int			whichfork) /* data or attr fork */
{
{
	int			error;	/* error return value */
	int			error;	/* error return value */
	int			i;	/* temp state */
	int			i;	/* temp state */
	xfs_btree_cur_t		*cur;	/* if null, not a btree */
	xfs_ifork_t		*ifp;	/* inode fork pointer */
	xfs_ifork_t		*ifp;	/* inode fork pointer */
	xfs_bmbt_irec_t		left;	/* left neighbor extent entry */
	xfs_bmbt_irec_t		left;	/* left neighbor extent entry */
	xfs_bmbt_irec_t		right;	/* right neighbor extent entry */
	xfs_bmbt_irec_t		right;	/* right neighbor extent entry */
	int			rval=0;	/* return value (logging flags) */
	int			rval=0;	/* return value (logging flags) */
	int			state;	/* state bits, accessed thru macros */
	int			state;	/* state bits, accessed thru macros */


	*logflagsp = 0;

	ifp = XFS_IFORK_PTR(ip, whichfork);
	ifp = XFS_IFORK_PTR(ip, whichfork);
	ASSERT(*idx <= ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t));
	cur = *curp;
	state = 0;

	ASSERT(*idx >= 0);
	ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
	ASSERT(!isnullstartblock(new->br_startblock));
	ASSERT(!cur || !(cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));

	XFS_STATS_INC(xs_add_exlist);


	state = 0;
	if (whichfork == XFS_ATTR_FORK)
	if (whichfork == XFS_ATTR_FORK)
		state |= BMAP_ATTRFORK;
		state |= BMAP_ATTRFORK;


@@ -1897,8 +1798,28 @@ xfs_bmap_add_extent_hole_real(
		}
		}
		break;
		break;
	}
	}

	/* convert to a btree if necessary */
	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
	    XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) {
		int	tmp_logflags;	/* partial log flag return val */

		ASSERT(cur == NULL);
		error = xfs_bmap_extents_to_btree(tp, ip, first,
			flist, &cur, 0, &tmp_logflags, whichfork);
		*logflagsp |= tmp_logflags;
		if (error)
			goto done;
	}

	/* clear out the allocated field, done with it now in any case. */
	if (cur) {
		cur->bc_private.b.allocated = 0;
		*curp = cur;
	}
	xfs_bmap_check_leaf_extents(cur, ip, whichfork);
done:
done:
	*logflagsp = rval;
	*logflagsp |= rval;
	return error;
	return error;
}
}


@@ -4792,14 +4713,22 @@ xfs_bmapi_allocate(
	    xfs_sb_version_hasextflgbit(&mp->m_sb))
	    xfs_sb_version_hasextflgbit(&mp->m_sb))
		bma->gotp->br_state = XFS_EXT_UNWRITTEN;
		bma->gotp->br_state = XFS_EXT_UNWRITTEN;


	error = xfs_bmap_add_extent(bma->tp, bma->ip, lastx, cur, bma->gotp,
	if (bma->wasdel) {
				    firstblock, flist, logflags, whichfork);
		error = xfs_bmap_add_extent_delay_real(bma->tp, bma->ip, lastx,
				cur, bma->gotp, firstblock, flist, logflags);
	} else {
		error = xfs_bmap_add_extent_hole_real(bma->tp, bma->ip, lastx,
				cur, bma->gotp, firstblock, flist, logflags,
				whichfork);
	}

	if (error)
	if (error)
		return error;
		return error;


	/*
	/*
	 * Update our extent pointer, given that xfs_bmap_add_extent  might
	 * Update our extent pointer, given that xfs_bmap_add_extent_delay_real
	 * have merged it into one of the neighbouring ones.
	 * or xfs_bmap_add_extent_hole_real might have merged it into one of
	 * the neighbouring ones.
	 */
	 */
	xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp);
	xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp);


@@ -4854,14 +4783,15 @@ xfs_bmapi_convert_unwritten(
	mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
	mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
				? XFS_EXT_NORM : XFS_EXT_UNWRITTEN;
				? XFS_EXT_NORM : XFS_EXT_UNWRITTEN;


	error = xfs_bmap_add_extent(bma->tp, bma->ip, lastx, cur, mval,
	error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, lastx,
				firstblock, flist, logflags, whichfork);
			cur, mval, firstblock, flist, logflags);
	if (error)
	if (error)
		return error;
		return error;


	/*
	/*
	 * Update our extent pointer, given that xfs_bmap_add_extent  might
	 * Update our extent pointer, given that
	 * have merged it into one of the neighbouring ones.
	 * xfs_bmap_add_extent_unwritten_real might have merged it into one
	 * of the neighbouring ones.
	 */
	 */
	xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp);
	xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp);


@@ -5287,9 +5217,9 @@ xfs_bunmapi(
				del.br_blockcount = mod;
				del.br_blockcount = mod;
			}
			}
			del.br_state = XFS_EXT_UNWRITTEN;
			del.br_state = XFS_EXT_UNWRITTEN;
			error = xfs_bmap_add_extent(tp, ip, &lastx, &cur, &del,
			error = xfs_bmap_add_extent_unwritten_real(tp, ip,
				firstblock, flist, &logflags,
					&lastx, &cur, &del, firstblock, flist,
				XFS_DATA_FORK);
					&logflags);
			if (error)
			if (error)
				goto error0;
				goto error0;
			goto nodelete;
			goto nodelete;
@@ -5345,18 +5275,18 @@ xfs_bunmapi(
				}
				}
				prev.br_state = XFS_EXT_UNWRITTEN;
				prev.br_state = XFS_EXT_UNWRITTEN;
				lastx--;
				lastx--;
				error = xfs_bmap_add_extent(tp, ip, &lastx,
				error = xfs_bmap_add_extent_unwritten_real(tp,
						&cur, &prev, firstblock, flist,
						ip, &lastx, &cur, &prev,
						&logflags, XFS_DATA_FORK);
						firstblock, flist, &logflags);
				if (error)
				if (error)
					goto error0;
					goto error0;
				goto nodelete;
				goto nodelete;
			} else {
			} else {
				ASSERT(del.br_state == XFS_EXT_NORM);
				ASSERT(del.br_state == XFS_EXT_NORM);
				del.br_state = XFS_EXT_UNWRITTEN;
				del.br_state = XFS_EXT_UNWRITTEN;
				error = xfs_bmap_add_extent(tp, ip, &lastx,
				error = xfs_bmap_add_extent_unwritten_real(tp,
						&cur, &del, firstblock, flist,
						ip, &lastx, &cur, &del,
						&logflags, XFS_DATA_FORK);
						firstblock, flist, &logflags);
				if (error)
				if (error)
					goto error0;
					goto error0;
				goto nodelete;
				goto nodelete;