Re: [PATCH 12/18] xfs: introduce the xfs_iext_cursor abstraction

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Oct 31, 2017 at 04:22:24PM +0200, Christoph Hellwig wrote:
> Add a new xfs_iext_cursor structure to hide the direct extent map
> index manipulations. In addition to the existing lookup/get/insert/
> remove and update routines new primitives to get the first and last
> extent cursor, as well as moving up and down by one extent are
> provided.  Also new are convenience to increment/decrement the
> cursor and retreive the new extent, as well as to peek into the
> previous/next extent without updating the cursor and last but not
> least a macro to iterate over all extents in a fork.
> 
> Signed-off-by: Christoph Hellwig <hch@xxxxxx>
> ---
>  fs/xfs/libxfs/xfs_bmap.c       | 432 ++++++++++++++++++++---------------------
>  fs/xfs/libxfs/xfs_bmap.h       |  12 +-
>  fs/xfs/libxfs/xfs_inode_fork.c |  75 +++----
>  fs/xfs/libxfs/xfs_inode_fork.h |  87 ++++++++-
>  fs/xfs/libxfs/xfs_types.h      |   3 +
>  fs/xfs/scrub/bmap.c            |   6 +-
>  fs/xfs/scrub/dir.c             |  14 +-
>  fs/xfs/xfs_bmap_util.c         |  12 +-
>  fs/xfs/xfs_dir2_readdir.c      |   8 +-
>  fs/xfs/xfs_dquot.c             |   4 +-
>  fs/xfs/xfs_iomap.c             |  13 +-
>  fs/xfs/xfs_reflink.c           |  56 +++---
>  fs/xfs/xfs_trace.h             |  12 +-
>  13 files changed, 401 insertions(+), 333 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index 56482bf6280d..453dc1ae76ab 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -671,8 +671,9 @@ xfs_bmap_extents_to_btree(
>  	xfs_bmbt_key_t		*kp;		/* root block key pointer */
>  	xfs_mount_t		*mp;		/* mount structure */
>  	xfs_bmbt_ptr_t		*pp;		/* root block address pointer */
> +	struct xfs_iext_cursor	ext;
>  	struct xfs_bmbt_irec	rec;
> -	xfs_extnum_t		i = 0, cnt = 0;
> +	xfs_extnum_t		cnt = 0;
>  
>  	mp = ip->i_mount;
>  	ASSERT(whichfork != XFS_COW_FORK);
> @@ -751,7 +752,7 @@ xfs_bmap_extents_to_btree(
>  				XFS_BTNUM_BMAP, 0, 0, ip->i_ino,
>  				XFS_BTREE_LONG_PTRS);
>  
> -	while (xfs_iext_get_extent(ifp, i++, &rec)) {
> +	for_each_iext(ifp, &ext, &rec) {

I'm torn here, because everything else has "xfs" in the name somewhere.
Consistently done we end up with this uglyness:

xfs_iext_for_each_extent(ifp, &ext, &rec) {

But ... it's syntactic sugar applied to a for loop.  I like sugar.

for_each_xfs_iext() { ... } ?

Not sure, I rarely add such things to header files.  The English works
better in this second version, so I think I like this (for_each_iext).

Anyone have strong opinions about this?

>  		if (isnullstartblock(rec.br_startblock))
>  			continue;
>  		arp = XFS_BMBT_REC_ADDR(mp, ablock, 1 + cnt);
> @@ -827,6 +828,7 @@ xfs_bmap_local_to_extents(
>  	xfs_alloc_arg_t	args;		/* allocation arguments */
>  	xfs_buf_t	*bp;		/* buffer for extent block */
>  	struct xfs_bmbt_irec rec;
> +	struct xfs_iext_cursor ext;

I was expecting an extent map cursor to have 'cur' in the name --
'ext' misleads me into thinking that 'ext' is an actual extent.

struct xfs_iext_cursor	*icur;

Also, xfs_iext_insert names its cursor parameter *cur, so why ext here?

For now I'm going to assume that xfs_iext_{first,last,next,prev} will
actually do something with the ifp parameter in the near future.

--D

>  
>  	/*
>  	 * We don't want to deal with the case of keeping inode data inline yet.
> @@ -893,7 +895,8 @@ xfs_bmap_local_to_extents(
>  	rec.br_startblock = args.fsbno;
>  	rec.br_blockcount = 1;
>  	rec.br_state = XFS_EXT_NORM;
> -	xfs_iext_insert(ip, 0, 1, &rec, 0);
> +	xfs_iext_first(ifp, &ext);
> +	xfs_iext_insert(ip, &ext, 1, &rec, 0);
>  
>  	XFS_IFORK_NEXT_SET(ip, whichfork, 1);
>  	ip->i_d.di_nblocks = 1;
> @@ -1173,6 +1176,7 @@ xfs_iread_extents(
>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
>  	xfs_extnum_t		nextents = XFS_IFORK_NEXTENTS(ip, whichfork);
>  	struct xfs_btree_block	*block = ifp->if_broot;
> +	struct xfs_iext_cursor	ext;
>  	xfs_fsblock_t		bno;
>  	struct xfs_buf		*bp;
>  	xfs_extnum_t		i, j;
> @@ -1222,6 +1226,7 @@ xfs_iread_extents(
>  	 * Here with bp and block set to the leftmost leaf node in the tree.
>  	 */
>  	i = 0;
> +	xfs_iext_first(ifp, &ext);
>  
>  	/*
>  	 * Loop over all leaf nodes.  Copy information to the extent records.
> @@ -1263,7 +1268,8 @@ xfs_iread_extents(
>  			}
>  			trp->l0 = be64_to_cpu(frp->l0);
>  			trp->l1 = be64_to_cpu(frp->l1);
> -			trace_xfs_read_extent(ip, i, state, _THIS_IP_);
> +			trace_xfs_read_extent(ip, &ext, state, _THIS_IP_);
> +			xfs_iext_next(ifp, &ext);
>  		}
>  		xfs_trans_brelse(tp, bp);
>  		bno = nextbno;
> @@ -1311,7 +1317,7 @@ xfs_bmap_first_unused(
>  {
>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
>  	struct xfs_bmbt_irec	got;
> -	xfs_extnum_t		idx = 0;
> +	struct xfs_iext_cursor	ext;
>  	xfs_fileoff_t		lastaddr = 0;
>  	xfs_fileoff_t		lowest, max;
>  	int			error;
> @@ -1332,7 +1338,7 @@ xfs_bmap_first_unused(
>  	}
>  
>  	lowest = max = *first_unused;
> -	while (xfs_iext_get_extent(ifp, idx++, &got)) {
> +	for_each_iext(ifp, &ext, &got) {
>  		/*
>  		 * See if the hole before this extent will work.
>  		 */
> @@ -1362,7 +1368,7 @@ xfs_bmap_last_before(
>  {
>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
>  	struct xfs_bmbt_irec	got;
> -	xfs_extnum_t		idx;
> +	struct xfs_iext_cursor	ext;
>  	int			error;
>  
>  	switch (XFS_IFORK_FORMAT(ip, whichfork)) {
> @@ -1382,7 +1388,7 @@ xfs_bmap_last_before(
>  			return error;
>  	}
>  
> -	if (!xfs_iext_lookup_extent_before(ip, ifp, last_block, &idx, &got))
> +	if (!xfs_iext_lookup_extent_before(ip, ifp, last_block, &ext, &got))
>  		*last_block = 0;
>  	return 0;
>  }
> @@ -1396,8 +1402,8 @@ xfs_bmap_last_extent(
>  	int			*is_empty)
>  {
>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
> +	struct xfs_iext_cursor	ext;
>  	int			error;
> -	int			nextents;
>  
>  	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
>  		error = xfs_iread_extents(tp, ip, whichfork);
> @@ -1405,14 +1411,11 @@ xfs_bmap_last_extent(
>  			return error;
>  	}
>  
> -	nextents = xfs_iext_count(ifp);
> -	if (nextents == 0) {
> +	xfs_iext_last(ifp, &ext);
> +	if (!xfs_iext_get_extent(ifp, &ext, rec))
>  		*is_empty = 1;
> -		return 0;
> -	}
> -
> -	xfs_iext_get_extent(ifp, nextents - 1, rec);
> -	*is_empty = 0;
> +	else
> +		*is_empty = 0;
>  	return 0;
>  }
>  
> @@ -1500,6 +1503,7 @@ xfs_bmap_one_block(
>  	xfs_ifork_t	*ifp;		/* inode fork pointer */
>  	int		rval;		/* return value */
>  	xfs_bmbt_irec_t	s;		/* internal version of extent */
> +	struct xfs_iext_cursor ext;
>  
>  #ifndef DEBUG
>  	if (whichfork == XFS_DATA_FORK)
> @@ -1511,7 +1515,8 @@ xfs_bmap_one_block(
>  		return 0;
>  	ifp = XFS_IFORK_PTR(ip, whichfork);
>  	ASSERT(ifp->if_flags & XFS_IFEXTENTS);
> -	xfs_iext_get_extent(ifp, 0, &s);
> +	xfs_iext_first(ifp, &ext);
> +	xfs_iext_get_extent(ifp, &ext, &s);
>  	rval = s.br_startoff == 0 && s.br_blockcount == 1;
>  	if (rval && whichfork == XFS_DATA_FORK)
>  		ASSERT(XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize);
> @@ -1553,8 +1558,6 @@ xfs_bmap_add_extent_delay_real(
>  	nextents = (whichfork == XFS_COW_FORK ? &bma->ip->i_cnextents :
>  						&bma->ip->i_d.di_nextents);
>  
> -	ASSERT(bma->idx >= 0);
> -	ASSERT(bma->idx <= xfs_iext_count(ifp));
>  	ASSERT(!isnullstartblock(new->br_startblock));
>  	ASSERT(!bma->cur ||
>  	       (bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));
> @@ -1568,7 +1571,7 @@ xfs_bmap_add_extent_delay_real(
>  	/*
>  	 * Set up a bunch of variables to make the tests simpler.
>  	 */
> -	xfs_iext_get_extent(ifp, bma->idx, &PREV);
> +	xfs_iext_get_extent(ifp, &bma->ext, &PREV);
>  	new_endoff = new->br_startoff + new->br_blockcount;
>  	ASSERT(isnullstartblock(PREV.br_startblock));
>  	ASSERT(PREV.br_startoff <= new->br_startoff);
> @@ -1590,10 +1593,8 @@ xfs_bmap_add_extent_delay_real(
>  	 * Check and set flags if this segment has a left neighbor.
>  	 * Don't set contiguous if the combined extent would be too large.
>  	 */
> -	if (bma->idx > 0) {
> +	if (xfs_iext_peek_prev_extent(ifp, &bma->ext, &LEFT)) {
>  		state |= BMAP_LEFT_VALID;
> -		xfs_iext_get_extent(ifp, bma->idx - 1, &LEFT);
> -
>  		if (isnullstartblock(LEFT.br_startblock))
>  			state |= BMAP_LEFT_DELAY;
>  	}
> @@ -1610,10 +1611,8 @@ xfs_bmap_add_extent_delay_real(
>  	 * Don't set contiguous if the combined extent would be too large.
>  	 * Also check for all-three-contiguous being too large.
>  	 */
> -	if (bma->idx < xfs_iext_count(ifp) - 1) {
> +	if (xfs_iext_peek_next_extent(ifp, &bma->ext, &RIGHT)) {
>  		state |= BMAP_RIGHT_VALID;
> -		xfs_iext_get_extent(ifp, bma->idx + 1, &RIGHT);
> -
>  		if (isnullstartblock(RIGHT.br_startblock))
>  			state |= BMAP_RIGHT_DELAY;
>  	}
> @@ -1645,9 +1644,9 @@ xfs_bmap_add_extent_delay_real(
>  		 */
>  		LEFT.br_blockcount += PREV.br_blockcount + RIGHT.br_blockcount;
>  
> -		xfs_iext_remove(bma->ip, bma->idx, 2, state);
> -		bma->idx--;
> -		xfs_iext_update_extent(bma->ip, state, bma->idx, &LEFT);
> +		xfs_iext_remove(bma->ip, &bma->ext, 2, state);
> +		xfs_iext_prev(ifp, &bma->ext);
> +		xfs_iext_update_extent(bma->ip, state, &bma->ext, &LEFT);
>  		(*nextents)--;
>  
>  		if (bma->cur == NULL)
> @@ -1680,9 +1679,9 @@ xfs_bmap_add_extent_delay_real(
>  		old = LEFT;
>  		LEFT.br_blockcount += PREV.br_blockcount;
>  
> -		xfs_iext_remove(bma->ip, bma->idx, 1, state);
> -		bma->idx--;
> -		xfs_iext_update_extent(bma->ip, state, bma->idx, &LEFT);
> +		xfs_iext_remove(bma->ip, &bma->ext, 1, state);
> +		xfs_iext_prev(ifp, &bma->ext);
> +		xfs_iext_update_extent(bma->ip, state, &bma->ext, &LEFT);
>  
>  		if (bma->cur == NULL)
>  			rval = XFS_ILOG_DEXT;
> @@ -1706,10 +1705,10 @@ xfs_bmap_add_extent_delay_real(
>  		PREV.br_startblock = new->br_startblock;
>  		PREV.br_blockcount += RIGHT.br_blockcount;
>  
> -		bma->idx++;
> -		xfs_iext_remove(bma->ip, bma->idx, 1, state);
> -		bma->idx--;
> -		xfs_iext_update_extent(bma->ip, state, bma->idx, &PREV);
> +		xfs_iext_next(ifp, &bma->ext);
> +		xfs_iext_remove(bma->ip, &bma->ext, 1, state);
> +		xfs_iext_prev(ifp, &bma->ext);
> +		xfs_iext_update_extent(bma->ip, state, &bma->ext, &PREV);
>  
>  		if (bma->cur == NULL)
>  			rval = XFS_ILOG_DEXT;
> @@ -1733,7 +1732,7 @@ xfs_bmap_add_extent_delay_real(
>  		 */
>  		PREV.br_startblock = new->br_startblock;
>  		PREV.br_state = new->br_state;
> -		xfs_iext_update_extent(bma->ip, state, bma->idx, &PREV);
> +		xfs_iext_update_extent(bma->ip, state, &bma->ext, &PREV);
>  
>  		(*nextents)++;
>  		if (bma->cur == NULL)
> @@ -1767,9 +1766,9 @@ xfs_bmap_add_extent_delay_real(
>  		PREV.br_startoff += new->br_blockcount;
>  		PREV.br_startblock = nullstartblock(da_new);
>  
> -		xfs_iext_update_extent(bma->ip, state, bma->idx, &PREV);
> -		bma->idx--;
> -		xfs_iext_update_extent(bma->ip, state, bma->idx, &LEFT);
> +		xfs_iext_update_extent(bma->ip, state, &bma->ext, &PREV);
> +		xfs_iext_prev(ifp, &bma->ext);
> +		xfs_iext_update_extent(bma->ip, state, &bma->ext, &LEFT);
>  
>  		if (bma->cur == NULL)
>  			rval = XFS_ILOG_DEXT;
> @@ -1783,7 +1782,6 @@ xfs_bmap_add_extent_delay_real(
>  			if (error)
>  				goto done;
>  		}
> -
>  		break;
>  
>  	case BMAP_LEFT_FILLING:
> @@ -1791,7 +1789,7 @@ xfs_bmap_add_extent_delay_real(
>  		 * Filling in the first part of a previous delayed allocation.
>  		 * The left neighbor is not contiguous.
>  		 */
> -		xfs_iext_update_extent(bma->ip, state, bma->idx, new);
> +		xfs_iext_update_extent(bma->ip, state, &bma->ext, new);
>  		(*nextents)++;
>  		if (bma->cur == NULL)
>  			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
> @@ -1824,7 +1822,9 @@ xfs_bmap_add_extent_delay_real(
>  		PREV.br_startoff = new_endoff;
>  		PREV.br_blockcount = temp;
>  		PREV.br_startblock = nullstartblock(da_new);
> -		xfs_iext_insert(bma->ip, bma->idx + 1, 1, &PREV, state);
> +		xfs_iext_next(ifp, &bma->ext);
> +		xfs_iext_insert(bma->ip, &bma->ext, 1, &PREV, state);
> +		xfs_iext_prev(ifp, &bma->ext);
>  		break;
>  
>  	case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
> @@ -1857,9 +1857,9 @@ xfs_bmap_add_extent_delay_real(
>  		PREV.br_blockcount = temp;
>  		PREV.br_startblock = nullstartblock(da_new);
>  
> -		xfs_iext_update_extent(bma->ip, state, bma->idx, &PREV);
> -		bma->idx++;
> -		xfs_iext_update_extent(bma->ip, state, bma->idx, &RIGHT);
> +		xfs_iext_update_extent(bma->ip, state, &bma->ext, &PREV);
> +		xfs_iext_next(ifp, &bma->ext);
> +		xfs_iext_update_extent(bma->ip, state, &bma->ext, &RIGHT);
>  		break;
>  
>  	case BMAP_RIGHT_FILLING:
> @@ -1867,7 +1867,7 @@ xfs_bmap_add_extent_delay_real(
>  		 * Filling in the last part of a previous delayed allocation.
>  		 * The right neighbor is not contiguous.
>  		 */
> -		xfs_iext_update_extent(bma->ip, state, bma->idx, new);
> +		xfs_iext_update_extent(bma->ip, state, &bma->ext, new);
>  		(*nextents)++;
>  		if (bma->cur == NULL)
>  			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;
> @@ -1899,9 +1899,8 @@ xfs_bmap_add_extent_delay_real(
>  
>  		PREV.br_startblock = nullstartblock(da_new);
>  		PREV.br_blockcount = temp;
> -		xfs_iext_insert(bma->ip, bma->idx, 1, &PREV, state);
> -
> -		bma->idx++;
> +		xfs_iext_insert(bma->ip, &bma->ext, 1, &PREV, state);
> +		xfs_iext_next(ifp, &bma->ext);
>  		break;
>  
>  	case 0:
> @@ -1944,10 +1943,11 @@ xfs_bmap_add_extent_delay_real(
>  		PREV.br_startblock =
>  			nullstartblock(xfs_bmap_worst_indlen(bma->ip,
>  					PREV.br_blockcount));
> -		xfs_iext_update_extent(bma->ip, state, bma->idx, &PREV);
> +		xfs_iext_update_extent(bma->ip, state, &bma->ext, &PREV);
>  
>  		/* insert LEFT (r[0]) and RIGHT (r[1]) at the same time */
> -		xfs_iext_insert(bma->ip, bma->idx + 1, 2, &LEFT, state);
> +		xfs_iext_next(ifp, &bma->ext);
> +		xfs_iext_insert(bma->ip, &bma->ext, 2, &LEFT, state);
>  		(*nextents)++;
>  
>  		if (bma->cur == NULL)
> @@ -1975,7 +1975,6 @@ xfs_bmap_add_extent_delay_real(
>  
>  		da_new = startblockval(PREV.br_startblock) +
>  			 startblockval(RIGHT.br_startblock);
> -		bma->idx++;
>  		break;
>  
>  	case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
> @@ -2039,7 +2038,7 @@ xfs_bmap_add_extent_unwritten_real(
>  	struct xfs_trans	*tp,
>  	xfs_inode_t		*ip,	/* incore inode pointer */
>  	int			whichfork,
> -	xfs_extnum_t		*idx,	/* extent number to update/insert */
> +	struct xfs_iext_cursor	*ext,
>  	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 */
> @@ -2063,8 +2062,6 @@ xfs_bmap_add_extent_unwritten_real(
>  	cur = *curp;
>  	ifp = XFS_IFORK_PTR(ip, whichfork);
>  
> -	ASSERT(*idx >= 0);
> -	ASSERT(*idx <= xfs_iext_count(ifp));
>  	ASSERT(!isnullstartblock(new->br_startblock));
>  
>  	XFS_STATS_INC(mp, xs_add_exlist);
> @@ -2077,7 +2074,7 @@ xfs_bmap_add_extent_unwritten_real(
>  	 * Set up a bunch of variables to make the tests simpler.
>  	 */
>  	error = 0;
> -	xfs_iext_get_extent(ifp, *idx, &PREV);
> +	xfs_iext_get_extent(ifp, ext, &PREV);
>  	ASSERT(new->br_state != PREV.br_state);
>  	new_endoff = new->br_startoff + new->br_blockcount;
>  	ASSERT(PREV.br_startoff <= new->br_startoff);
> @@ -2096,10 +2093,8 @@ xfs_bmap_add_extent_unwritten_real(
>  	 * Check and set flags if this segment has a left neighbor.
>  	 * Don't set contiguous if the combined extent would be too large.
>  	 */
> -	if (*idx > 0) {
> +	if (xfs_iext_peek_prev_extent(ifp, ext, &LEFT)) {
>  		state |= BMAP_LEFT_VALID;
> -		xfs_iext_get_extent(ifp, *idx - 1, &LEFT);
> -
>  		if (isnullstartblock(LEFT.br_startblock))
>  			state |= BMAP_LEFT_DELAY;
>  	}
> @@ -2116,9 +2111,8 @@ xfs_bmap_add_extent_unwritten_real(
>  	 * Don't set contiguous if the combined extent would be too large.
>  	 * Also check for all-three-contiguous being too large.
>  	 */
> -	if (*idx < xfs_iext_count(ifp) - 1) {
> +	if (xfs_iext_peek_next_extent(ifp, ext, &RIGHT)) {
>  		state |= BMAP_RIGHT_VALID;
> -		xfs_iext_get_extent(ifp, *idx + 1, &RIGHT);
>  		if (isnullstartblock(RIGHT.br_startblock))
>  			state |= BMAP_RIGHT_DELAY;
>  	}
> @@ -2149,9 +2143,9 @@ xfs_bmap_add_extent_unwritten_real(
>  		 */
>  		LEFT.br_blockcount += PREV.br_blockcount + RIGHT.br_blockcount;
>  
> -		xfs_iext_remove(ip, *idx, 2, state);
> -		--*idx;
> -		xfs_iext_update_extent(ip, state, *idx, &LEFT);
> +		xfs_iext_remove(ip, ext, 2, state);
> +		xfs_iext_prev(ifp, ext);
> +		xfs_iext_update_extent(ip, state, ext, &LEFT);
>  		XFS_IFORK_NEXT_SET(ip, whichfork,
>  				XFS_IFORK_NEXTENTS(ip, whichfork) - 2);
>  		if (cur == NULL)
> @@ -2187,9 +2181,9 @@ xfs_bmap_add_extent_unwritten_real(
>  		 */
>  		LEFT.br_blockcount += PREV.br_blockcount;
>  
> -		xfs_iext_remove(ip, *idx, 1, state);
> -		--*idx;
> -		xfs_iext_update_extent(ip, state, *idx, &LEFT);
> +		xfs_iext_remove(ip, ext, 1, state);
> +		xfs_iext_prev(ifp, ext);
> +		xfs_iext_update_extent(ip, state, ext, &LEFT);
>  		XFS_IFORK_NEXT_SET(ip, whichfork,
>  				XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
>  		if (cur == NULL)
> @@ -2220,10 +2214,10 @@ xfs_bmap_add_extent_unwritten_real(
>  		PREV.br_blockcount += RIGHT.br_blockcount;
>  		PREV.br_state = new->br_state;
>  
> -		++*idx;
> -		xfs_iext_remove(ip, *idx, 1, state);
> -		--*idx;
> -		xfs_iext_update_extent(ip, state, *idx, &PREV);
> +		xfs_iext_next(ifp, ext);
> +		xfs_iext_remove(ip, ext, 1, state);
> +		xfs_iext_prev(ifp, ext);
> +		xfs_iext_update_extent(ip, state, ext, &PREV);
>  
>  		XFS_IFORK_NEXT_SET(ip, whichfork,
>  				XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
> @@ -2254,7 +2248,7 @@ xfs_bmap_add_extent_unwritten_real(
>  		 * the new one.
>  		 */
>  		PREV.br_state = new->br_state;
> -		xfs_iext_update_extent(ip, state, *idx, &PREV);
> +		xfs_iext_update_extent(ip, state, ext, &PREV);
>  
>  		if (cur == NULL)
>  			rval = XFS_ILOG_DEXT;
> @@ -2282,9 +2276,9 @@ xfs_bmap_add_extent_unwritten_real(
>  		PREV.br_startblock += new->br_blockcount;
>  		PREV.br_blockcount -= new->br_blockcount;
>  
> -		xfs_iext_update_extent(ip, state, *idx, &PREV);
> -		--*idx;
> -		xfs_iext_update_extent(ip, state, *idx, &LEFT);
> +		xfs_iext_update_extent(ip, state, ext, &PREV);
> +		xfs_iext_prev(ifp, ext);
> +		xfs_iext_update_extent(ip, state, ext, &LEFT);
>  
>  		if (cur == NULL)
>  			rval = XFS_ILOG_DEXT;
> @@ -2316,8 +2310,8 @@ xfs_bmap_add_extent_unwritten_real(
>  		PREV.br_startblock += new->br_blockcount;
>  		PREV.br_blockcount -= new->br_blockcount;
>  
> -		xfs_iext_update_extent(ip, state, *idx, &PREV);
> -		xfs_iext_insert(ip, *idx, 1, new, state);
> +		xfs_iext_update_extent(ip, state, ext, &PREV);
> +		xfs_iext_insert(ip, ext, 1, new, state);
>  		XFS_IFORK_NEXT_SET(ip, whichfork,
>  				XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
>  		if (cur == NULL)
> @@ -2350,9 +2344,9 @@ xfs_bmap_add_extent_unwritten_real(
>  		RIGHT.br_startblock = new->br_startblock;
>  		RIGHT.br_blockcount += new->br_blockcount;
>  
> -		xfs_iext_update_extent(ip, state, *idx, &PREV);
> -		++*idx;
> -		xfs_iext_update_extent(ip, state, *idx, &RIGHT);
> +		xfs_iext_update_extent(ip, state, ext, &PREV);
> +		xfs_iext_next(ifp, ext);
> +		xfs_iext_update_extent(ip, state, ext, &RIGHT);
>  
>  		if (cur == NULL)
>  			rval = XFS_ILOG_DEXT;
> @@ -2382,9 +2376,9 @@ xfs_bmap_add_extent_unwritten_real(
>  		old = PREV;
>  		PREV.br_blockcount -= new->br_blockcount;
>  
> -		xfs_iext_update_extent(ip, state, *idx, &PREV);
> -		++*idx;
> -		xfs_iext_insert(ip, *idx, 1, new, state);
> +		xfs_iext_update_extent(ip, state, ext, &PREV);
> +		xfs_iext_next(ifp, ext);
> +		xfs_iext_insert(ip, ext, 1, new, state);
>  
>  		XFS_IFORK_NEXT_SET(ip, whichfork,
>  				XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
> @@ -2425,9 +2419,9 @@ xfs_bmap_add_extent_unwritten_real(
>  		r[1].br_startblock = new->br_startblock + new->br_blockcount;
>  		r[1].br_state = PREV.br_state;
>  
> -		xfs_iext_update_extent(ip, state, *idx, &PREV);
> -		++*idx;
> -		xfs_iext_insert(ip, *idx, 2, &r[0], state);
> +		xfs_iext_update_extent(ip, state, ext, &PREV);
> +		xfs_iext_next(ifp, ext);
> +		xfs_iext_insert(ip, ext, 2, &r[0], state);
>  
>  		XFS_IFORK_NEXT_SET(ip, whichfork,
>  				XFS_IFORK_NEXTENTS(ip, whichfork) + 2);
> @@ -2516,7 +2510,7 @@ STATIC void
>  xfs_bmap_add_extent_hole_delay(
>  	xfs_inode_t		*ip,	/* incore inode pointer */
>  	int			whichfork,
> -	xfs_extnum_t		*idx,	/* extent number to update/insert */
> +	struct xfs_iext_cursor	*ext,
>  	xfs_bmbt_irec_t		*new)	/* new data to add to file extents */
>  {
>  	xfs_ifork_t		*ifp;	/* inode fork pointer */
> @@ -2533,10 +2527,8 @@ xfs_bmap_add_extent_hole_delay(
>  	/*
>  	 * Check and set flags if this segment has a left neighbor
>  	 */
> -	if (*idx > 0) {
> +	if (xfs_iext_peek_prev_extent(ifp, ext, &left)) {
>  		state |= BMAP_LEFT_VALID;
> -		xfs_iext_get_extent(ifp, *idx - 1, &left);
> -
>  		if (isnullstartblock(left.br_startblock))
>  			state |= BMAP_LEFT_DELAY;
>  	}
> @@ -2545,10 +2537,8 @@ xfs_bmap_add_extent_hole_delay(
>  	 * Check and set flags if the current (right) segment exists.
>  	 * If it doesn't exist, we're converting the hole at end-of-file.
>  	 */
> -	if (*idx < xfs_iext_count(ifp)) {
> +	if (xfs_iext_get_extent(ifp, ext, &right)) {
>  		state |= BMAP_RIGHT_VALID;
> -		xfs_iext_get_extent(ifp, *idx, &right);
> -
>  		if (isnullstartblock(right.br_startblock))
>  			state |= BMAP_RIGHT_DELAY;
>  	}
> @@ -2591,9 +2581,9 @@ xfs_bmap_add_extent_hole_delay(
>  		left.br_startblock = nullstartblock(newlen);
>  		left.br_blockcount = temp;
>  
> -		xfs_iext_remove(ip, *idx, 1, state);
> -		--*idx;
> -		xfs_iext_update_extent(ip, state, *idx, &left);
> +		xfs_iext_remove(ip, ext, 1, state);
> +		xfs_iext_prev(ifp, ext);
> +		xfs_iext_update_extent(ip, state, ext, &left);
>  		break;
>  
>  	case BMAP_LEFT_CONTIG:
> @@ -2611,8 +2601,8 @@ xfs_bmap_add_extent_hole_delay(
>  		left.br_blockcount = temp;
>  		left.br_startblock = nullstartblock(newlen);
>  
> -		--*idx;
> -		xfs_iext_update_extent(ip, state, *idx, &left);
> +		xfs_iext_prev(ifp, ext);
> +		xfs_iext_update_extent(ip, state, ext, &left);
>  		break;
>  
>  	case BMAP_RIGHT_CONTIG:
> @@ -2629,7 +2619,7 @@ xfs_bmap_add_extent_hole_delay(
>  		right.br_startoff = new->br_startoff;
>  		right.br_startblock = nullstartblock(newlen);
>  		right.br_blockcount = temp;
> -		xfs_iext_update_extent(ip, state, *idx, &right);
> +		xfs_iext_update_extent(ip, state, ext, &right);
>  		break;
>  
>  	case 0:
> @@ -2639,7 +2629,7 @@ xfs_bmap_add_extent_hole_delay(
>  		 * Insert a new entry.
>  		 */
>  		oldlen = newlen = 0;
> -		xfs_iext_insert(ip, *idx, 1, new, state);
> +		xfs_iext_insert(ip, ext, 1, new, state);
>  		break;
>  	}
>  	if (oldlen != newlen) {
> @@ -2660,7 +2650,7 @@ xfs_bmap_add_extent_hole_real(
>  	struct xfs_trans	*tp,
>  	struct xfs_inode	*ip,
>  	int			whichfork,
> -	xfs_extnum_t		*idx,
> +	struct xfs_iext_cursor	*ext,
>  	struct xfs_btree_cur	**curp,
>  	struct xfs_bmbt_irec	*new,
>  	xfs_fsblock_t		*first,
> @@ -2678,8 +2668,6 @@ xfs_bmap_add_extent_hole_real(
>  	int			state = xfs_bmap_fork_to_state(whichfork);
>  	struct xfs_bmbt_irec	old;
>  
> -	ASSERT(*idx >= 0);
> -	ASSERT(*idx <= xfs_iext_count(ifp));
>  	ASSERT(!isnullstartblock(new->br_startblock));
>  	ASSERT(!cur || !(cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));
>  
> @@ -2688,9 +2676,8 @@ xfs_bmap_add_extent_hole_real(
>  	/*
>  	 * Check and set flags if this segment has a left neighbor.
>  	 */
> -	if (*idx > 0) {
> +	if (xfs_iext_peek_prev_extent(ifp, ext, &left)) {
>  		state |= BMAP_LEFT_VALID;
> -		xfs_iext_get_extent(ifp, *idx - 1, &left);
>  		if (isnullstartblock(left.br_startblock))
>  			state |= BMAP_LEFT_DELAY;
>  	}
> @@ -2699,9 +2686,8 @@ xfs_bmap_add_extent_hole_real(
>  	 * Check and set flags if this segment has a current value.
>  	 * Not true if we're inserting into the "hole" at eof.
>  	 */
> -	if (*idx < xfs_iext_count(ifp)) {
> +	if (xfs_iext_get_extent(ifp, ext, &right)) {
>  		state |= BMAP_RIGHT_VALID;
> -		xfs_iext_get_extent(ifp, *idx, &right);
>  		if (isnullstartblock(right.br_startblock))
>  			state |= BMAP_RIGHT_DELAY;
>  	}
> @@ -2740,9 +2726,9 @@ xfs_bmap_add_extent_hole_real(
>  		 */
>  		left.br_blockcount += new->br_blockcount + right.br_blockcount;
>  
> -		xfs_iext_remove(ip, *idx, 1, state);
> -		--*idx;
> -		xfs_iext_update_extent(ip, state, *idx, &left);
> +		xfs_iext_remove(ip, ext, 1, state);
> +		xfs_iext_prev(ifp, ext);
> +		xfs_iext_update_extent(ip, state, ext, &left);
>  
>  		XFS_IFORK_NEXT_SET(ip, whichfork,
>  			XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
> @@ -2777,8 +2763,8 @@ xfs_bmap_add_extent_hole_real(
>  		old = left;
>  		left.br_blockcount += new->br_blockcount;
>  
> -		--*idx;
> -		xfs_iext_update_extent(ip, state, *idx, &left);
> +		xfs_iext_prev(ifp, ext);
> +		xfs_iext_update_extent(ip, state, ext, &left);
>  
>  		if (cur == NULL) {
>  			rval = xfs_ilog_fext(whichfork);
> @@ -2805,7 +2791,7 @@ xfs_bmap_add_extent_hole_real(
>  		right.br_startoff = new->br_startoff;
>  		right.br_startblock = new->br_startblock;
>  		right.br_blockcount += new->br_blockcount;
> -		xfs_iext_update_extent(ip, state, *idx, &right);
> +		xfs_iext_update_extent(ip, state, ext, &right);
>  
>  		if (cur == NULL) {
>  			rval = xfs_ilog_fext(whichfork);
> @@ -2827,7 +2813,7 @@ xfs_bmap_add_extent_hole_real(
>  		 * real allocation.
>  		 * Insert a new entry.
>  		 */
> -		xfs_iext_insert(ip, *idx, 1, new, state);
> +		xfs_iext_insert(ip, ext, 1, new, state);
>  		XFS_IFORK_NEXT_SET(ip, whichfork,
>  			XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
>  		if (cur == NULL) {
> @@ -3777,7 +3763,7 @@ xfs_bmapi_read(
>  	struct xfs_bmbt_irec	got;
>  	xfs_fileoff_t		obno;
>  	xfs_fileoff_t		end;
> -	xfs_extnum_t		idx;
> +	struct xfs_iext_cursor	ext;
>  	int			error;
>  	bool			eof = false;
>  	int			n = 0;
> @@ -3819,7 +3805,7 @@ xfs_bmapi_read(
>  			return error;
>  	}
>  
> -	if (!xfs_iext_lookup_extent(ip, ifp, bno, &idx, &got))
> +	if (!xfs_iext_lookup_extent(ip, ifp, bno, &ext, &got))
>  		eof = true;
>  	end = bno + len;
>  	obno = bno;
> @@ -3851,7 +3837,7 @@ xfs_bmapi_read(
>  			break;
>  
>  		/* Else go on to the next record. */
> -		if (!xfs_iext_get_extent(ifp, ++idx, &got))
> +		if (!xfs_iext_next_extent(ifp, &ext, &got))
>  			eof = true;
>  	}
>  	*nmap = n;
> @@ -3879,7 +3865,7 @@ xfs_bmapi_reserve_delalloc(
>  	xfs_filblks_t		len,
>  	xfs_filblks_t		prealloc,
>  	struct xfs_bmbt_irec	*got,
> -	xfs_extnum_t		*lastx,
> +	struct xfs_iext_cursor	*ext,
>  	int			eof)
>  {
>  	struct xfs_mount	*mp = ip->i_mount;
> @@ -3909,7 +3895,7 @@ xfs_bmapi_reserve_delalloc(
>  	if (extsz) {
>  		struct xfs_bmbt_irec	prev;
>  
> -		if (!xfs_iext_get_extent(ifp, *lastx - 1, &prev))
> +		if (!xfs_iext_peek_prev_extent(ifp, ext, &prev))
>  			prev.br_startoff = NULLFILEOFF;
>  
>  		error = xfs_bmap_extsize_align(mp, got, &prev, extsz, rt, eof,
> @@ -3958,7 +3944,7 @@ xfs_bmapi_reserve_delalloc(
>  	got->br_blockcount = alen;
>  	got->br_state = XFS_EXT_NORM;
>  
> -	xfs_bmap_add_extent_hole_delay(ip, whichfork, lastx, got);
> +	xfs_bmap_add_extent_hole_delay(ip, whichfork, ext, got);
>  
>  	/*
>  	 * Tag the inode if blocks were preallocated. Note that COW fork
> @@ -4003,8 +3989,7 @@ xfs_bmapi_allocate(
>  	if (bma->wasdel) {
>  		bma->length = (xfs_extlen_t)bma->got.br_blockcount;
>  		bma->offset = bma->got.br_startoff;
> -		if (bma->idx)
> -			xfs_iext_get_extent(ifp, bma->idx - 1, &bma->prev);
> +		xfs_iext_peek_prev_extent(ifp, &bma->ext, &bma->prev);
>  	} else {
>  		bma->length = XFS_FILBLKS_MIN(bma->length, MAXEXTLEN);
>  		if (!bma->eof)
> @@ -4089,7 +4074,7 @@ xfs_bmapi_allocate(
>  		error = xfs_bmap_add_extent_delay_real(bma, whichfork);
>  	else
>  		error = xfs_bmap_add_extent_hole_real(bma->tp, bma->ip,
> -				whichfork, &bma->idx, &bma->cur, &bma->got,
> +				whichfork, &bma->ext, &bma->cur, &bma->got,
>  				bma->firstblock, bma->dfops, &bma->logflags);
>  
>  	bma->logflags |= tmp_logflags;
> @@ -4101,7 +4086,7 @@ xfs_bmapi_allocate(
>  	 * or xfs_bmap_add_extent_hole_real might have merged it into one of
>  	 * the neighbouring ones.
>  	 */
> -	xfs_iext_get_extent(ifp, bma->idx, &bma->got);
> +	xfs_iext_get_extent(ifp, &bma->ext, &bma->got);
>  
>  	ASSERT(bma->got.br_startoff <= bma->offset);
>  	ASSERT(bma->got.br_startoff + bma->got.br_blockcount >=
> @@ -4159,7 +4144,7 @@ xfs_bmapi_convert_unwritten(
>  	}
>  
>  	error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, whichfork,
> -			&bma->idx, &bma->cur, mval, bma->firstblock, bma->dfops,
> +			&bma->ext, &bma->cur, mval, bma->firstblock, bma->dfops,
>  			&tmp_logflags);
>  	/*
>  	 * Log the inode core unconditionally in the unwritten extent conversion
> @@ -4182,7 +4167,7 @@ xfs_bmapi_convert_unwritten(
>  	 * xfs_bmap_add_extent_unwritten_real might have merged it into one
>  	 * of the neighbouring ones.
>  	 */
> -	xfs_iext_get_extent(ifp, bma->idx, &bma->got);
> +	xfs_iext_get_extent(ifp, &bma->ext, &bma->got);
>  
>  	/*
>  	 * We may have combined previously unwritten space with written space,
> @@ -4301,9 +4286,9 @@ xfs_bmapi_write(
>  	end = bno + len;
>  	obno = bno;
>  
> -	if (!xfs_iext_lookup_extent(ip, ifp, bno, &bma.idx, &bma.got))
> +	if (!xfs_iext_lookup_extent(ip, ifp, bno, &bma.ext, &bma.got))
>  		eof = true;
> -	if (!xfs_iext_get_extent(ifp, bma.idx - 1, &bma.prev))
> +	if (!xfs_iext_peek_prev_extent(ifp, &bma.ext, &bma.prev))
>  		bma.prev.br_startoff = NULLFILEOFF;
>  	bma.tp = tp;
>  	bma.ip = ip;
> @@ -4408,7 +4393,7 @@ xfs_bmapi_write(
>  
>  		/* Else go on to the next record. */
>  		bma.prev = bma.got;
> -		if (!xfs_iext_get_extent(ifp, ++bma.idx, &bma.got))
> +		if (!xfs_iext_next_extent(ifp, &bma.ext, &bma.got))
>  			eof = true;
>  	}
>  	*nmap = n;
> @@ -4481,7 +4466,7 @@ xfs_bmapi_remap(
>  	struct xfs_btree_cur	*cur = NULL;
>  	xfs_fsblock_t		firstblock = NULLFSBLOCK;
>  	struct xfs_bmbt_irec	got;
> -	xfs_extnum_t		idx;
> +	struct xfs_iext_cursor	ext;
>  	int			logflags = 0, error;
>  
>  	ASSERT(len > 0);
> @@ -4505,7 +4490,7 @@ xfs_bmapi_remap(
>  			return error;
>  	}
>  
> -	if (xfs_iext_lookup_extent(ip, ifp, bno, &idx, &got)) {
> +	if (xfs_iext_lookup_extent(ip, ifp, bno, &ext, &got)) {
>  		/* make sure we only reflink into a hole. */
>  		ASSERT(got.br_startoff > bno);
>  		ASSERT(got.br_startoff - bno >= len);
> @@ -4526,7 +4511,7 @@ xfs_bmapi_remap(
>  	got.br_blockcount = len;
>  	got.br_state = XFS_EXT_NORM;
>  
> -	error = xfs_bmap_add_extent_hole_real(tp, ip, XFS_DATA_FORK, &idx, &cur,
> +	error = xfs_bmap_add_extent_hole_real(tp, ip, XFS_DATA_FORK, &ext, &cur,
>  			&got, &firstblock, dfops, &logflags);
>  	if (error)
>  		goto error0;
> @@ -4643,7 +4628,7 @@ int
>  xfs_bmap_del_extent_delay(
>  	struct xfs_inode	*ip,
>  	int			whichfork,
> -	xfs_extnum_t		*idx,
> +	struct xfs_iext_cursor	*ext,
>  	struct xfs_bmbt_irec	*got,
>  	struct xfs_bmbt_irec	*del)
>  {
> @@ -4665,8 +4650,6 @@ xfs_bmap_del_extent_delay(
>  	da_old = startblockval(got->br_startblock);
>  	da_new = 0;
>  
> -	ASSERT(*idx >= 0);
> -	ASSERT(*idx <= xfs_iext_count(ifp));
>  	ASSERT(del->br_blockcount > 0);
>  	ASSERT(got->br_startoff <= del->br_startoff);
>  	ASSERT(got_endoff >= del_endoff);
> @@ -4700,8 +4683,8 @@ xfs_bmap_del_extent_delay(
>  		/*
>  		 * Matches the whole extent.  Delete the entry.
>  		 */
> -		xfs_iext_remove(ip, *idx, 1, state);
> -		--*idx;
> +		xfs_iext_remove(ip, ext, 1, state);
> +		xfs_iext_prev(ifp, ext);
>  		break;
>  	case BMAP_LEFT_FILLING:
>  		/*
> @@ -4712,7 +4695,7 @@ xfs_bmap_del_extent_delay(
>  		da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip,
>  				got->br_blockcount), da_old);
>  		got->br_startblock = nullstartblock((int)da_new);
> -		xfs_iext_update_extent(ip, state, *idx, got);
> +		xfs_iext_update_extent(ip, state, ext, got);
>  		break;
>  	case BMAP_RIGHT_FILLING:
>  		/*
> @@ -4722,7 +4705,7 @@ xfs_bmap_del_extent_delay(
>  		da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip,
>  				got->br_blockcount), da_old);
>  		got->br_startblock = nullstartblock((int)da_new);
> -		xfs_iext_update_extent(ip, state, *idx, got);
> +		xfs_iext_update_extent(ip, state, ext, got);
>  		break;
>  	case 0:
>  		/*
> @@ -4750,9 +4733,9 @@ xfs_bmap_del_extent_delay(
>  		new.br_state = got->br_state;
>  		new.br_startblock = nullstartblock((int)new_indlen);
>  
> -		xfs_iext_update_extent(ip, state, *idx, got);
> -		++*idx;
> -		xfs_iext_insert(ip, *idx, 1, &new, state);
> +		xfs_iext_update_extent(ip, state, ext, got);
> +		xfs_iext_next(ifp, ext);
> +		xfs_iext_insert(ip, ext, 1, &new, state);
>  
>  		da_new = got_indlen + new_indlen - stolen;
>  		del->br_blockcount -= stolen;
> @@ -4771,7 +4754,7 @@ xfs_bmap_del_extent_delay(
>  void
>  xfs_bmap_del_extent_cow(
>  	struct xfs_inode	*ip,
> -	xfs_extnum_t		*idx,
> +	struct xfs_iext_cursor	*ext,
>  	struct xfs_bmbt_irec	*got,
>  	struct xfs_bmbt_irec	*del)
>  {
> @@ -4786,8 +4769,6 @@ xfs_bmap_del_extent_cow(
>  	del_endoff = del->br_startoff + del->br_blockcount;
>  	got_endoff = got->br_startoff + got->br_blockcount;
>  
> -	ASSERT(*idx >= 0);
> -	ASSERT(*idx <= xfs_iext_count(ifp));
>  	ASSERT(del->br_blockcount > 0);
>  	ASSERT(got->br_startoff <= del->br_startoff);
>  	ASSERT(got_endoff >= del_endoff);
> @@ -4803,8 +4784,8 @@ xfs_bmap_del_extent_cow(
>  		/*
>  		 * Matches the whole extent.  Delete the entry.
>  		 */
> -		xfs_iext_remove(ip, *idx, 1, state);
> -		--*idx;
> +		xfs_iext_remove(ip, ext, 1, state);
> +		xfs_iext_prev(ifp, ext);
>  		break;
>  	case BMAP_LEFT_FILLING:
>  		/*
> @@ -4813,14 +4794,14 @@ xfs_bmap_del_extent_cow(
>  		got->br_startoff = del_endoff;
>  		got->br_blockcount -= del->br_blockcount;
>  		got->br_startblock = del->br_startblock + del->br_blockcount;
> -		xfs_iext_update_extent(ip, state, *idx, got);
> +		xfs_iext_update_extent(ip, state, ext, got);
>  		break;
>  	case BMAP_RIGHT_FILLING:
>  		/*
>  		 * Deleting the last part of the extent.
>  		 */
>  		got->br_blockcount -= del->br_blockcount;
> -		xfs_iext_update_extent(ip, state, *idx, got);
> +		xfs_iext_update_extent(ip, state, ext, got);
>  		break;
>  	case 0:
>  		/*
> @@ -4833,9 +4814,9 @@ xfs_bmap_del_extent_cow(
>  		new.br_state = got->br_state;
>  		new.br_startblock = del->br_startblock + del->br_blockcount;
>  
> -		xfs_iext_update_extent(ip, state, *idx, got);
> -		++*idx;
> -		xfs_iext_insert(ip, *idx, 1, &new, state);
> +		xfs_iext_update_extent(ip, state, ext, got);
> +		xfs_iext_next(ifp, ext);
> +		xfs_iext_insert(ip, ext, 1, &new, state);
>  		break;
>  	}
>  }
> @@ -4848,7 +4829,7 @@ STATIC int				/* error */
>  xfs_bmap_del_extent_real(
>  	xfs_inode_t		*ip,	/* incore inode pointer */
>  	xfs_trans_t		*tp,	/* current transaction pointer */
> -	xfs_extnum_t		*idx,	/* extent number to update/delete */
> +	struct xfs_iext_cursor	*ext,
>  	struct xfs_defer_ops	*dfops,	/* list of extents to be freed */
>  	xfs_btree_cur_t		*cur,	/* if null, not a btree */
>  	xfs_bmbt_irec_t		*del,	/* data to remove from extents */
> @@ -4877,9 +4858,8 @@ xfs_bmap_del_extent_real(
>  	XFS_STATS_INC(mp, xs_del_exlist);
>  
>  	ifp = XFS_IFORK_PTR(ip, whichfork);
> -	ASSERT((*idx >= 0) && (*idx < xfs_iext_count(ifp)));
>  	ASSERT(del->br_blockcount > 0);
> -	xfs_iext_get_extent(ifp, *idx, &got);
> +	xfs_iext_get_extent(ifp, ext, &got);
>  	ASSERT(got.br_startoff <= del->br_startoff);
>  	del_endoff = del->br_startoff + del->br_blockcount;
>  	got_endoff = got.br_startoff + got.br_blockcount;
> @@ -4944,9 +4924,8 @@ xfs_bmap_del_extent_real(
>  		/*
>  		 * Matches the whole extent.  Delete the entry.
>  		 */
> -		xfs_iext_remove(ip, *idx, 1, state);
> -		--*idx;
> -
> +		xfs_iext_remove(ip, ext, 1, state);
> +		xfs_iext_prev(ifp, ext);
>  		XFS_IFORK_NEXT_SET(ip, whichfork,
>  			XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
>  		flags |= XFS_ILOG_CORE;
> @@ -4965,7 +4944,7 @@ xfs_bmap_del_extent_real(
>  		got.br_startoff = del_endoff;
>  		got.br_startblock = del_endblock;
>  		got.br_blockcount -= del->br_blockcount;
> -		xfs_iext_update_extent(ip, state, *idx, &got);
> +		xfs_iext_update_extent(ip, state, ext, &got);
>  		if (!cur) {
>  			flags |= xfs_ilog_fext(whichfork);
>  			break;
> @@ -4979,7 +4958,7 @@ xfs_bmap_del_extent_real(
>  		 * Deleting the last part of the extent.
>  		 */
>  		got.br_blockcount -= del->br_blockcount;
> -		xfs_iext_update_extent(ip, state, *idx, &got);
> +		xfs_iext_update_extent(ip, state, ext, &got);
>  		if (!cur) {
>  			flags |= xfs_ilog_fext(whichfork);
>  			break;
> @@ -4995,7 +4974,7 @@ xfs_bmap_del_extent_real(
>  		old = got;
>  
>  		got.br_blockcount = del->br_startoff - got.br_startoff;
> -		xfs_iext_update_extent(ip, state, *idx, &got);
> +		xfs_iext_update_extent(ip, state, ext, &got);
>  
>  		new.br_startoff = del_endoff;
>  		new.br_blockcount = got_endoff - del_endoff;
> @@ -5039,7 +5018,7 @@ xfs_bmap_del_extent_real(
>  				 * Reset the extent record back
>  				 * to the original value.
>  				 */
> -				xfs_iext_update_extent(ip, state, *idx, &old);
> +				xfs_iext_update_extent(ip, state, ext, &old);
>  				flags = 0;
>  				error = -ENOSPC;
>  				goto done;
> @@ -5049,8 +5028,8 @@ xfs_bmap_del_extent_real(
>  			flags |= xfs_ilog_fext(whichfork);
>  		XFS_IFORK_NEXT_SET(ip, whichfork,
>  			XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
> -		++*idx;
> -		xfs_iext_insert(ip, *idx, 1, &new, state);
> +		xfs_iext_next(ifp, ext);
> +		xfs_iext_insert(ip, ext, 1, &new, state);
>  		break;
>  	}
>  
> @@ -5113,7 +5092,6 @@ __xfs_bunmapi(
>  	xfs_bmbt_irec_t		got;		/* current extent record */
>  	xfs_ifork_t		*ifp;		/* inode fork pointer */
>  	int			isrt;		/* freeing in rt area */
> -	xfs_extnum_t		lastx;		/* last extent index used */
>  	int			logflags;	/* transaction logging flags */
>  	xfs_extlen_t		mod;		/* rt extent offset */
>  	xfs_mount_t		*mp;		/* mount structure */
> @@ -5125,6 +5103,8 @@ __xfs_bunmapi(
>  	xfs_fileoff_t		max_len;
>  	xfs_agnumber_t		prev_agno = NULLAGNUMBER, agno;
>  	xfs_fileoff_t		end;
> +	struct xfs_iext_cursor	ext;
> +	bool			done = false;
>  
>  	trace_xfs_bunmap(ip, start, len, flags, _RET_IP_);
>  
> @@ -5167,7 +5147,7 @@ __xfs_bunmapi(
>  	isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
>  	end = start + len;
>  
> -	if (!xfs_iext_lookup_extent_before(ip, ifp, &end, &lastx, &got)) {
> +	if (!xfs_iext_lookup_extent_before(ip, ifp, &end, &ext, &got)) {
>  		*rlen = 0;
>  		return 0;
>  	}
> @@ -5194,16 +5174,16 @@ __xfs_bunmapi(
>  	}
>  
>  	extno = 0;
> -	while (end != (xfs_fileoff_t)-1 && end >= start && lastx >= 0 &&
> +	while (end != (xfs_fileoff_t)-1 && end >= start &&
>  	       (nexts == 0 || extno < nexts) && max_len > 0) {
>  		/*
>  		 * Is the found extent after a hole in which end lives?
>  		 * Just back up to the previous extent, if so.
>  		 */
> -		if (got.br_startoff > end) {
> -			if (--lastx < 0)
> -				break;
> -			xfs_iext_get_extent(ifp, lastx, &got);
> +		if (got.br_startoff > end &&
> +		    !xfs_iext_prev_extent(ifp, &ext, &got)) {
> +			done = true;
> +			break;
>  		}
>  		/*
>  		 * Is the last block of this extent before the range
> @@ -5266,10 +5246,10 @@ __xfs_bunmapi(
>  				ASSERT(end >= mod);
>  				end -= mod > del.br_blockcount ?
>  					del.br_blockcount : mod;
> -				if (end < got.br_startoff) {
> -					if (--lastx >= 0)
> -						xfs_iext_get_extent(ifp, lastx,
> -								&got);
> +				if (end < got.br_startoff &&
> +				    !xfs_iext_prev_extent(ifp, &ext, &got)) {
> +					done = true;
> +					break;
>  				}
>  				continue;
>  			}
> @@ -5290,7 +5270,7 @@ __xfs_bunmapi(
>  			}
>  			del.br_state = XFS_EXT_UNWRITTEN;
>  			error = xfs_bmap_add_extent_unwritten_real(tp, ip,
> -					whichfork, &lastx, &cur, &del,
> +					whichfork, &ext, &cur, &del,
>  					firstblock, dfops, &logflags);
>  			if (error)
>  				goto error0;
> @@ -5317,8 +5297,11 @@ __xfs_bunmapi(
>  				 */
>  				ASSERT(end >= del.br_blockcount);
>  				end -= del.br_blockcount;
> -				if (got.br_startoff > end && --lastx >= 0)
> -					xfs_iext_get_extent(ifp, lastx, &got);
> +				if (got.br_startoff > end &&
> +				    !xfs_iext_prev_extent(ifp, &ext, &got)) {
> +					done = true;
> +					break;
> +				}
>  				continue;
>  			} else if (del.br_state == XFS_EXT_UNWRITTEN) {
>  				struct xfs_bmbt_irec	prev;
> @@ -5329,8 +5312,8 @@ __xfs_bunmapi(
>  				 * Unwrite the killed part of that one and
>  				 * try again.
>  				 */
> -				ASSERT(lastx > 0);
> -				xfs_iext_get_extent(ifp, lastx - 1, &prev);
> +				if (!xfs_iext_prev_extent(ifp, &ext, &prev))
> +					ASSERT(0);
>  				ASSERT(prev.br_state == XFS_EXT_NORM);
>  				ASSERT(!isnullstartblock(prev.br_startblock));
>  				ASSERT(del.br_startblock ==
> @@ -5342,9 +5325,8 @@ __xfs_bunmapi(
>  					prev.br_startoff = start;
>  				}
>  				prev.br_state = XFS_EXT_UNWRITTEN;
> -				lastx--;
>  				error = xfs_bmap_add_extent_unwritten_real(tp,
> -						ip, whichfork, &lastx, &cur,
> +						ip, whichfork, &ext, &cur,
>  						&prev, firstblock, dfops,
>  						&logflags);
>  				if (error)
> @@ -5354,7 +5336,7 @@ __xfs_bunmapi(
>  				ASSERT(del.br_state == XFS_EXT_NORM);
>  				del.br_state = XFS_EXT_UNWRITTEN;
>  				error = xfs_bmap_add_extent_unwritten_real(tp,
> -						ip, whichfork, &lastx, &cur,
> +						ip, whichfork, &ext, &cur,
>  						&del, firstblock, dfops,
>  						&logflags);
>  				if (error)
> @@ -5364,10 +5346,10 @@ __xfs_bunmapi(
>  		}
>  
>  		if (wasdel) {
> -			error = xfs_bmap_del_extent_delay(ip, whichfork, &lastx,
> +			error = xfs_bmap_del_extent_delay(ip, whichfork, &ext,
>  					&got, &del);
>  		} else {
> -			error = xfs_bmap_del_extent_real(ip, tp, &lastx, dfops,
> +			error = xfs_bmap_del_extent_real(ip, tp, &ext, dfops,
>  					cur, &del, &tmp_logflags, whichfork,
>  					flags);
>  			logflags |= tmp_logflags;
> @@ -5383,15 +5365,16 @@ __xfs_bunmapi(
>  		 * If not done go on to the next (previous) record.
>  		 */
>  		if (end != (xfs_fileoff_t)-1 && end >= start) {
> -			if (lastx >= 0) {
> -				xfs_iext_get_extent(ifp, lastx, &got);
> -				if (got.br_startoff > end && --lastx >= 0)
> -					xfs_iext_get_extent(ifp, lastx, &got);
> +			if (!xfs_iext_get_extent(ifp, &ext, &got) ||
> +			    (got.br_startoff > end &&
> +			     !xfs_iext_prev_extent(ifp, &ext, &got))) {
> +				done = true;
> +				break;
>  			}
>  			extno++;
>  		}
>  	}
> -	if (end == (xfs_fileoff_t)-1 || end < start || lastx < 0)
> +	if (done || end == (xfs_fileoff_t)-1 || end < start)
>  		*rlen = 0;
>  	else
>  		*rlen = end - start + 1;
> @@ -5512,7 +5495,7 @@ xfs_bmse_merge(
>  	struct xfs_inode		*ip,
>  	int				whichfork,
>  	xfs_fileoff_t			shift,		/* shift fsb */
> -	int				*current_ext,	/* idx of gotp */
> +	struct xfs_iext_cursor		*ext,
>  	struct xfs_bmbt_irec		*got,		/* extent to shift */
>  	struct xfs_bmbt_irec		*left,		/* preceding extent */
>  	struct xfs_btree_cur		*cur,
> @@ -5567,10 +5550,10 @@ xfs_bmse_merge(
>  		return error;
>  
>  done:
> -	xfs_iext_remove(ip, *current_ext, 1, 0);
> -	--*current_ext;
> -	xfs_iext_update_extent(ip, xfs_bmap_fork_to_state(whichfork),
> -			*current_ext, &new);
> +	xfs_iext_remove(ip, ext, 1, 0);
> +	xfs_iext_prev(XFS_IFORK_PTR(ip, whichfork), ext);
> +	xfs_iext_update_extent(ip, xfs_bmap_fork_to_state(whichfork), ext,
> +			&new);
>  
>  	/* update reverse mapping. rmap functions merge the rmaps for us */
>  	error = xfs_rmap_unmap_extent(mp, dfops, ip, whichfork, got);
> @@ -5585,7 +5568,7 @@ static int
>  xfs_bmap_shift_update_extent(
>  	struct xfs_inode	*ip,
>  	int			whichfork,
> -	xfs_extnum_t		idx,
> +	struct xfs_iext_cursor	*ext,
>  	struct xfs_bmbt_irec	*got,
>  	struct xfs_btree_cur	*cur,
>  	int			*logflags,
> @@ -5613,7 +5596,7 @@ xfs_bmap_shift_update_extent(
>  		*logflags |= XFS_ILOG_DEXT;
>  	}
>  
> -	xfs_iext_update_extent(ip, xfs_bmap_fork_to_state(whichfork), idx, got);
> +	xfs_iext_update_extent(ip, xfs_bmap_fork_to_state(whichfork), ext, got);
>  
>  	/* update reverse mapping */
>  	error = xfs_rmap_unmap_extent(mp, dfops, ip, whichfork, &prev);
> @@ -5638,7 +5621,7 @@ xfs_bmap_collapse_extents(
>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
>  	struct xfs_btree_cur	*cur = NULL;
>  	struct xfs_bmbt_irec	got, prev;
> -	xfs_extnum_t		current_ext;
> +	struct xfs_iext_cursor	ext;
>  	xfs_fileoff_t		new_startoff;
>  	int			error = 0;
>  	int			logflags = 0;
> @@ -5669,14 +5652,14 @@ xfs_bmap_collapse_extents(
>  		cur->bc_private.b.flags = 0;
>  	}
>  
> -	if (!xfs_iext_lookup_extent(ip, ifp, *next_fsb, &current_ext, &got)) {
> +	if (!xfs_iext_lookup_extent(ip, ifp, *next_fsb, &ext, &got)) {
>  		*done = true;
>  		goto del_cursor;
>  	}
>  	XFS_WANT_CORRUPTED_RETURN(mp, !isnullstartblock(got.br_startblock));
>  
>  	new_startoff = got.br_startoff - offset_shift_fsb;
> -	if (xfs_iext_get_extent(ifp, current_ext - 1, &prev)) {
> +	if (xfs_iext_peek_prev_extent(ifp, &ext, &prev)) {
>  		if (new_startoff < prev.br_startoff + prev.br_blockcount) {
>  			error = -EINVAL;
>  			goto del_cursor;
> @@ -5684,8 +5667,8 @@ xfs_bmap_collapse_extents(
>  
>  		if (xfs_bmse_can_merge(&prev, &got, offset_shift_fsb)) {
>  			error = xfs_bmse_merge(ip, whichfork, offset_shift_fsb,
> -					&current_ext, &got, &prev, cur,
> -					&logflags, dfops);
> +					&ext, &got, &prev, cur, &logflags,
> +					dfops);
>  			if (error)
>  				goto del_cursor;
>  			goto done;
> @@ -5697,13 +5680,13 @@ xfs_bmap_collapse_extents(
>  		}
>  	}
>  
> -	error = xfs_bmap_shift_update_extent(ip, whichfork, current_ext, &got,
> -			cur, &logflags, dfops, new_startoff);
> +	error = xfs_bmap_shift_update_extent(ip, whichfork, &ext, &got, cur,
> +			&logflags, dfops, new_startoff);
>  	if (error)
>  		goto del_cursor;
>  
>  done:
> -	if (!xfs_iext_get_extent(ifp, ++current_ext, &got)) {
> +	if (!xfs_iext_next_extent(ifp, &ext, &got)) {
>  		 *done = true;
>  		 goto del_cursor;
>  	}
> @@ -5734,7 +5717,7 @@ xfs_bmap_insert_extents(
>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
>  	struct xfs_btree_cur	*cur = NULL;
>  	struct xfs_bmbt_irec	got, next;
> -	xfs_extnum_t		current_ext;
> +	struct xfs_iext_cursor	ext;
>  	xfs_fileoff_t		new_startoff;
>  	int			error = 0;
>  	int			logflags = 0;
> @@ -5766,15 +5749,14 @@ xfs_bmap_insert_extents(
>  	}
>  
>  	if (*next_fsb == NULLFSBLOCK) {
> -		current_ext = xfs_iext_count(ifp) - 1;
> -		if (!xfs_iext_get_extent(ifp, current_ext, &got) ||
> +		xfs_iext_last(ifp, &ext);
> +		if (!xfs_iext_get_extent(ifp, &ext, &got) ||
>  		    stop_fsb > got.br_startoff) {
>  			*done = true;
>  			goto del_cursor;
>  		}
>  	} else {
> -		if (!xfs_iext_lookup_extent(ip, ifp, *next_fsb, &current_ext,
> -				&got)) {
> +		if (!xfs_iext_lookup_extent(ip, ifp, *next_fsb, &ext, &got)) {
>  			*done = true;
>  			goto del_cursor;
>  		}
> @@ -5787,7 +5769,7 @@ xfs_bmap_insert_extents(
>  	}
>  
>  	new_startoff = got.br_startoff + offset_shift_fsb;
> -	if (xfs_iext_get_extent(ifp, current_ext + 1, &next)) {
> +	if (xfs_iext_peek_next_extent(ifp, &ext, &next)) {
>  		if (new_startoff + got.br_blockcount > next.br_startoff) {
>  			error = -EINVAL;
>  			goto del_cursor;
> @@ -5803,12 +5785,12 @@ xfs_bmap_insert_extents(
>  			WARN_ON_ONCE(1);
>  	}
>  
> -	error = xfs_bmap_shift_update_extent(ip, whichfork, current_ext, &got,
> -			cur, &logflags, dfops, new_startoff);
> +	error = xfs_bmap_shift_update_extent(ip, whichfork, &ext, &got, cur,
> +			&logflags, dfops, new_startoff);
>  	if (error)
>  		goto del_cursor;
>  
> -	if (!xfs_iext_get_extent(ifp, --current_ext, &got) ||
> +	if (!xfs_iext_prev_extent(ifp, &ext, &got) ||
>  	    stop_fsb >= got.br_startoff + got.br_blockcount) {
>  		*done = true;
>  		goto del_cursor;
> @@ -5825,10 +5807,10 @@ xfs_bmap_insert_extents(
>  }
>  
>  /*
> - * Splits an extent into two extents at split_fsb block such that it is
> - * the first block of the current_ext. @current_ext is a target extent
> - * to be split. @split_fsb is a block where the extents is split.
> - * If split_fsb lies in a hole or the first block of extents, just return 0.
> + * Splits an extent into two extents at split_fsb block such that it is the
> + * first block of the current_ext. @ext is a target extent to be split.
> + * @split_fsb is a block where the extents is split.  If split_fsb lies in a
> + * hole or the first block of extents, just return 0.
>   */
>  STATIC int
>  xfs_bmap_split_extent_at(
> @@ -5845,7 +5827,7 @@ xfs_bmap_split_extent_at(
>  	struct xfs_mount		*mp = ip->i_mount;
>  	struct xfs_ifork		*ifp;
>  	xfs_fsblock_t			gotblkcnt; /* new block count for got */
> -	xfs_extnum_t			current_ext;
> +	struct xfs_iext_cursor		ext;
>  	int				error = 0;
>  	int				logflags = 0;
>  	int				i = 0;
> @@ -5873,7 +5855,7 @@ xfs_bmap_split_extent_at(
>  	/*
>  	 * If there are not extents, or split_fsb lies in a hole we are done.
>  	 */
> -	if (!xfs_iext_lookup_extent(ip, ifp, split_fsb, &current_ext, &got) ||
> +	if (!xfs_iext_lookup_extent(ip, ifp, split_fsb, &ext, &got) ||
>  	    got.br_startoff >= split_fsb)
>  		return 0;
>  
> @@ -5895,8 +5877,8 @@ xfs_bmap_split_extent_at(
>  	}
>  
>  	got.br_blockcount = gotblkcnt;
> -	xfs_iext_update_extent(ip, xfs_bmap_fork_to_state(whichfork),
> -			current_ext, &got);
> +	xfs_iext_update_extent(ip, xfs_bmap_fork_to_state(whichfork), &ext,
> +			&got);
>  
>  	logflags = XFS_ILOG_CORE;
>  	if (cur) {
> @@ -5907,8 +5889,8 @@ xfs_bmap_split_extent_at(
>  		logflags |= XFS_ILOG_DEXT;
>  
>  	/* Add new extent */
> -	current_ext++;
> -	xfs_iext_insert(ip, current_ext, 1, &new, 0);
> +	xfs_iext_next(ifp, &ext);
> +	xfs_iext_insert(ip, &ext, 1, &new, 0);
>  	XFS_IFORK_NEXT_SET(ip, whichfork,
>  			   XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
>  
> diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
> index a8777682ba57..195f335f4615 100644
> --- a/fs/xfs/libxfs/xfs_bmap.h
> +++ b/fs/xfs/libxfs/xfs_bmap.h
> @@ -43,7 +43,7 @@ struct xfs_bmalloca {
>  	xfs_fsblock_t		blkno;	/* starting block of new extent */
>  
>  	struct xfs_btree_cur	*cur;	/* btree cursor */
> -	xfs_extnum_t		idx;	/* current extent index */
> +	struct xfs_iext_cursor	ext;
>  	int			nallocs;/* number of extents alloc'd */
>  	int			logflags;/* flags for transaction logging */
>  
> @@ -216,10 +216,11 @@ int	xfs_bunmapi(struct xfs_trans *tp, struct xfs_inode *ip,
>  		xfs_extnum_t nexts, xfs_fsblock_t *firstblock,
>  		struct xfs_defer_ops *dfops, int *done);
>  int	xfs_bmap_del_extent_delay(struct xfs_inode *ip, int whichfork,
> -		xfs_extnum_t *idx, struct xfs_bmbt_irec *got,
> +		struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *got,
> +		struct xfs_bmbt_irec *del);
> +void	xfs_bmap_del_extent_cow(struct xfs_inode *ip,
> +		struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *got,
>  		struct xfs_bmbt_irec *del);
> -void	xfs_bmap_del_extent_cow(struct xfs_inode *ip, xfs_extnum_t *idx,
> -		struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *del);
>  uint	xfs_default_attroffset(struct xfs_inode *ip);
>  int	xfs_bmap_collapse_extents(struct xfs_trans *tp, struct xfs_inode *ip,
>  		xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb,
> @@ -232,7 +233,8 @@ int	xfs_bmap_insert_extents(struct xfs_trans *tp, struct xfs_inode *ip,
>  int	xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset);
>  int	xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork,
>  		xfs_fileoff_t off, xfs_filblks_t len, xfs_filblks_t prealloc,
> -		struct xfs_bmbt_irec *got, xfs_extnum_t *lastx, int eof);
> +		struct xfs_bmbt_irec *got, struct xfs_iext_cursor *cur,
> +		int eof);
>  
>  enum xfs_bmap_intent_type {
>  	XFS_BMAP_MAP = 1,
> diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
> index 7dd77b497fc2..c9e10d4818b7 100644
> --- a/fs/xfs/libxfs/xfs_inode_fork.c
> +++ b/fs/xfs/libxfs/xfs_inode_fork.c
> @@ -343,6 +343,7 @@ xfs_iformat_extents(
>  	int			state = xfs_bmap_fork_to_state(whichfork);
>  	int			nex = XFS_DFORK_NEXTENTS(dip, whichfork);
>  	int			size = nex * sizeof(xfs_bmbt_rec_t);
> +	struct xfs_iext_cursor	ext;
>  	struct xfs_bmbt_rec	*dp;
>  	int			i;
>  
> @@ -369,16 +370,21 @@ xfs_iformat_extents(
>  	ifp->if_bytes = size;
>  	if (size) {
>  		dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork);
> +
> +		xfs_iext_first(ifp, &ext);
>  		for (i = 0; i < nex; i++, dp++) {
>  			xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
> +
>  			if (!xfs_bmbt_validate_extent(mp, whichfork, dp)) {
>  				XFS_ERROR_REPORT("xfs_iformat_extents(2)",
>  						 XFS_ERRLEVEL_LOW, mp);
>  				return -EFSCORRUPTED;
>  			}
> +
>  			ep->l0 = get_unaligned_be64(&dp->l0);
>  			ep->l1 = get_unaligned_be64(&dp->l1);
> -			trace_xfs_read_extent(ip, i, state, _THIS_IP_);
> +			trace_xfs_read_extent(ip, &ext, state, _THIS_IP_);
> +			xfs_iext_next(ifp, &ext);
>  		}
>  	}
>  	ifp->if_flags |= XFS_IFEXTENTS;
> @@ -739,17 +745,18 @@ xfs_iextents_copy(
>  {
>  	int			state = xfs_bmap_fork_to_state(whichfork);
>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
> +	struct xfs_iext_cursor	ext;
>  	struct xfs_bmbt_irec	rec;
> -	int			copied = 0, i = 0;
> +	int			copied = 0;
>  
>  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED));
>  	ASSERT(ifp->if_bytes > 0);
>  
> -	while (xfs_iext_get_extent(ifp, i++, &rec)) {
> +	for_each_iext(ifp, &ext, &rec) {
>  		if (isnullstartblock(rec.br_startblock))
>  			continue;
>  		xfs_bmbt_disk_set_all(dp, &rec);
> -		trace_xfs_write_extent(ip, i, state, _RET_IP_);
> +		trace_xfs_write_extent(ip, &ext, state, _RET_IP_);
>  		ASSERT(xfs_bmbt_validate_extent(ip->i_mount, whichfork, dp));
>  		copied += sizeof(struct xfs_bmbt_rec);
>  		dp++;
> @@ -894,7 +901,7 @@ xfs_iext_state_to_fork(
>  void
>  xfs_iext_insert(
>  	xfs_inode_t	*ip,		/* incore inode pointer */
> -	xfs_extnum_t	idx,		/* starting index of new items */
> +	struct xfs_iext_cursor *cur,
>  	xfs_extnum_t	count,		/* number of inserted items */
>  	xfs_bmbt_irec_t	*new,		/* items to insert */
>  	int		state)		/* type of extent conversion */
> @@ -902,12 +909,12 @@ xfs_iext_insert(
>  	xfs_ifork_t	*ifp = xfs_iext_state_to_fork(ip, state);
>  	xfs_extnum_t	i;		/* extent record index */
>  
> -	trace_xfs_iext_insert(ip, idx, new, state, _RET_IP_);
> +	trace_xfs_iext_insert(ip, cur->idx, new, state, _RET_IP_);
>  
>  	ASSERT(ifp->if_flags & XFS_IFEXTENTS);
> -	xfs_iext_add(ifp, idx, count);
> -	for (i = idx; i < idx + count; i++, new++)
> -		xfs_bmbt_set_all(xfs_iext_get_ext(ifp, i), new);
> +	xfs_iext_add(ifp, cur->idx, count);
> +	for (i = 0; i < count; i++, new++)
> +		xfs_bmbt_set_all(xfs_iext_get_ext(ifp, cur->idx + i), new);
>  }
>  
>  /*
> @@ -1145,7 +1152,7 @@ xfs_iext_add_indirect_multi(
>  void
>  xfs_iext_remove(
>  	xfs_inode_t	*ip,		/* incore inode pointer */
> -	xfs_extnum_t	idx,		/* index to begin removing exts */
> +	struct xfs_iext_cursor *cur,
>  	int		ext_diff,	/* number of extents to remove */
>  	int		state)		/* type of extent conversion */
>  {
> @@ -1153,7 +1160,7 @@ xfs_iext_remove(
>  	xfs_extnum_t	nextents;	/* number of extents in file */
>  	int		new_size;	/* size of extents after removal */
>  
> -	trace_xfs_iext_remove(ip, idx, state, _RET_IP_);
> +	trace_xfs_iext_remove(ip, cur, state, _RET_IP_);
>  
>  	ASSERT(ext_diff > 0);
>  	nextents = xfs_iext_count(ifp);
> @@ -1162,11 +1169,11 @@ xfs_iext_remove(
>  	if (new_size == 0) {
>  		xfs_iext_destroy(ifp);
>  	} else if (ifp->if_flags & XFS_IFEXTIREC) {
> -		xfs_iext_remove_indirect(ifp, idx, ext_diff);
> +		xfs_iext_remove_indirect(ifp, cur->idx, ext_diff);
>  	} else if (ifp->if_real_bytes) {
> -		xfs_iext_remove_direct(ifp, idx, ext_diff);
> +		xfs_iext_remove_direct(ifp, cur->idx, ext_diff);
>  	} else {
> -		xfs_iext_remove_inline(ifp, idx, ext_diff);
> +		xfs_iext_remove_inline(ifp, cur->idx, ext_diff);
>  	}
>  	ifp->if_bytes = new_size;
>  }
> @@ -1913,26 +1920,26 @@ xfs_ifork_init_cow(
>   * Lookup the extent covering bno.
>   *
>   * If there is an extent covering bno return the extent index, and store the
> - * expanded extent structure in *gotp, and the extent index in *idx.
> + * expanded extent structure in *gotp, and the extent cursor in *cur.
>   * If there is no extent covering bno, but there is an extent after it (e.g.
> - * it lies in a hole) return that extent in *gotp and its index in *idx
> + * it lies in a hole) return that extent in *gotp and its cursor in *cur
>   * instead.
> - * If bno is beyond the last extent return false, and return the index after
> - * the last valid index in *idxp.
> + * If bno is beyond the last extent return false, and return an invalid
> + * cursor value.
>   */
>  bool
>  xfs_iext_lookup_extent(
>  	struct xfs_inode	*ip,
>  	struct xfs_ifork	*ifp,
>  	xfs_fileoff_t		bno,
> -	xfs_extnum_t		*idxp,
> +	struct xfs_iext_cursor	*cur,
>  	struct xfs_bmbt_irec	*gotp)
>  {
>  	struct xfs_bmbt_rec_host *ep;
>  
>  	XFS_STATS_INC(ip->i_mount, xs_look_exlist);
>  
> -	ep = xfs_iext_bno_to_ext(ifp, bno, idxp);
> +	ep = xfs_iext_bno_to_ext(ifp, bno, &cur->idx);
>  	if (!ep)
>  		return false;
>  	xfs_bmbt_get_all(ep, gotp);
> @@ -1948,31 +1955,31 @@ xfs_iext_lookup_extent_before(
>  	struct xfs_inode	*ip,
>  	struct xfs_ifork	*ifp,
>  	xfs_fileoff_t		*end,
> -	xfs_extnum_t		*idxp,
> +	struct xfs_iext_cursor	*cur,
>  	struct xfs_bmbt_irec	*gotp)
>  {
> -	if (xfs_iext_lookup_extent(ip, ifp, *end - 1, idxp, gotp) &&
> +	if (xfs_iext_lookup_extent(ip, ifp, *end - 1, cur, gotp) &&
>  	    gotp->br_startoff <= *end - 1)
>  		return true;
> -	if (!xfs_iext_get_extent(ifp, --*idxp, gotp))
> +	if (!xfs_iext_prev_extent(ifp, cur, gotp))
>  		return false;
>  	*end = gotp->br_startoff + gotp->br_blockcount;
>  	return true;
>  }
>  
>  /*
> - * Return true if there is an extent at index idx, and return the expanded
> - * extent structure at idx in that case.  Else return false.
> + * Return true if there is an extent at cursor cur and return the expanded
> + * extent structure at cur in gotp in that case.  Else return false.
>   */
>  bool
>  xfs_iext_get_extent(
>  	struct xfs_ifork	*ifp,
> -	xfs_extnum_t		idx,
> +	struct xfs_iext_cursor	*cur,
>  	struct xfs_bmbt_irec	*gotp)
>  {
> -	if (idx < 0 || idx >= xfs_iext_count(ifp))
> +	if (cur->idx < 0 || cur->idx >= xfs_iext_count(ifp))
>  		return false;
> -	xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), gotp);
> +	xfs_bmbt_get_all(xfs_iext_get_ext(ifp, cur->idx), gotp);
>  	return true;
>  }
>  
> @@ -1980,15 +1987,15 @@ void
>  xfs_iext_update_extent(
>  	struct xfs_inode	*ip,
>  	int			state,
> -	xfs_extnum_t		idx,
> +	struct xfs_iext_cursor	*cur,
>  	struct xfs_bmbt_irec	*gotp)
>  {
>  	struct xfs_ifork	*ifp = xfs_iext_state_to_fork(ip, state);
>  
> -	ASSERT(idx >= 0);
> -	ASSERT(idx < xfs_iext_count(ifp));
> +	ASSERT(cur->idx >= 0);
> +	ASSERT(cur->idx < xfs_iext_count(ifp));
>  
> -	trace_xfs_bmap_pre_update(ip, idx, state, _RET_IP_);
> -	xfs_bmbt_set_all(xfs_iext_get_ext(ifp, idx), gotp);
> -	trace_xfs_bmap_post_update(ip, idx, state, _RET_IP_);
> +	trace_xfs_bmap_pre_update(ip, cur, state, _RET_IP_);
> +	xfs_bmbt_set_all(xfs_iext_get_ext(ifp, cur->idx), gotp);
> +	trace_xfs_bmap_post_update(ip, cur, state, _RET_IP_);
>  }
> diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h
> index 113fd42ec36d..dc347dd9dc78 100644
> --- a/fs/xfs/libxfs/xfs_inode_fork.h
> +++ b/fs/xfs/libxfs/xfs_inode_fork.h
> @@ -151,12 +151,13 @@ void		xfs_init_local_fork(struct xfs_inode *, int, const void *, int);
>  struct xfs_bmbt_rec_host *
>  		xfs_iext_get_ext(struct xfs_ifork *, xfs_extnum_t);
>  xfs_extnum_t	xfs_iext_count(struct xfs_ifork *);
> -void		xfs_iext_insert(struct xfs_inode *, xfs_extnum_t, xfs_extnum_t,
> -				struct xfs_bmbt_irec *, int);
> +void		xfs_iext_insert(struct xfs_inode *, struct xfs_iext_cursor *cur,
> +			xfs_extnum_t, struct xfs_bmbt_irec *, int);
>  void		xfs_iext_add(struct xfs_ifork *, xfs_extnum_t, int);
>  void		xfs_iext_add_indirect_multi(struct xfs_ifork *, int,
>  					    xfs_extnum_t, int);
> -void		xfs_iext_remove(struct xfs_inode *, xfs_extnum_t, int, int);
> +void		xfs_iext_remove(struct xfs_inode *, struct xfs_iext_cursor *,
> +			int, int);
>  void		xfs_iext_remove_inline(struct xfs_ifork *, xfs_extnum_t, int);
>  void		xfs_iext_remove_direct(struct xfs_ifork *, xfs_extnum_t, int);
>  void		xfs_iext_remove_indirect(struct xfs_ifork *, xfs_extnum_t, int);
> @@ -182,15 +183,85 @@ void		xfs_iext_irec_update_extoffs(struct xfs_ifork *, int, int);
>  
>  bool		xfs_iext_lookup_extent(struct xfs_inode *ip,
>  			struct xfs_ifork *ifp, xfs_fileoff_t bno,
> -			xfs_extnum_t *idxp, struct xfs_bmbt_irec *gotp);
> +			struct xfs_iext_cursor *cur,
> +			 struct xfs_bmbt_irec *gotp);
>  bool		xfs_iext_lookup_extent_before(struct xfs_inode *ip,
>  			struct xfs_ifork *ifp, xfs_fileoff_t *end,
> -			xfs_extnum_t *idxp, struct xfs_bmbt_irec *gotp);
> -
> -bool		xfs_iext_get_extent(struct xfs_ifork *ifp, xfs_extnum_t idx,
> +			struct xfs_iext_cursor *cur,
> +			struct xfs_bmbt_irec *gotp);
> +bool		xfs_iext_get_extent(struct xfs_ifork *ifp,
> +			struct xfs_iext_cursor *cur,
>  			struct xfs_bmbt_irec *gotp);
>  void		xfs_iext_update_extent(struct xfs_inode *ip, int state,
> -			xfs_extnum_t idx, struct xfs_bmbt_irec *gotp);
> +			struct xfs_iext_cursor *cur,
> +			struct xfs_bmbt_irec *gotp);
> +
> +static inline void xfs_iext_first(struct xfs_ifork *ifp,
> +		struct xfs_iext_cursor *cur)
> +{
> +	cur->idx = 0;
> +}
> +
> +static inline void xfs_iext_last(struct xfs_ifork *ifp,
> +		struct xfs_iext_cursor *cur)
> +{
> +	cur->idx = xfs_iext_count(ifp) - 1;
> +}
> +
> +static inline void xfs_iext_next(struct xfs_ifork *ifp,
> +		struct xfs_iext_cursor *cur)
> +{
> +	cur->idx++;
> +}
> +
> +static inline void xfs_iext_prev(struct xfs_ifork *ifp,
> +		struct xfs_iext_cursor *cur)
> +{
> +	cur->idx--;
> +}
> +
> +static inline bool xfs_iext_next_extent(struct xfs_ifork *ifp,
> +		struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp)
> +{
> +	xfs_iext_next(ifp, cur);
> +	return xfs_iext_get_extent(ifp, cur, gotp);
> +}
> +
> +static inline bool xfs_iext_prev_extent(struct xfs_ifork *ifp,
> +		struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp)
> +{
> +	xfs_iext_prev(ifp, cur);
> +	return xfs_iext_get_extent(ifp, cur, gotp);
> +}
> +
> +/*
> + * Return the extent after cur in gotp without updating the cursor.
> + */
> +static inline bool xfs_iext_peek_next_extent(struct xfs_ifork *ifp,
> +		struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp)
> +{
> +	struct xfs_iext_cursor ncur = *cur;
> +
> +	xfs_iext_next(ifp, &ncur);
> +	return xfs_iext_get_extent(ifp, &ncur, gotp);
> +}
> +
> +/*
> + * Return the extent before cur in gotp without updating the cursor.
> + */
> +static inline bool xfs_iext_peek_prev_extent(struct xfs_ifork *ifp,
> +		struct xfs_iext_cursor *cur, struct xfs_bmbt_irec *gotp)
> +{
> +	struct xfs_iext_cursor ncur = *cur;
> +
> +	xfs_iext_prev(ifp, &ncur);
> +	return xfs_iext_get_extent(ifp, &ncur, gotp);
> +}
> +
> +#define for_each_iext(ifp, ext, got)			\
> +	for (xfs_iext_first((ifp), (ext));		\
> +	     xfs_iext_get_extent((ifp), (ext), (got));	\
> +	     xfs_iext_next((ifp), (ext)))
>  
>  extern struct kmem_zone	*xfs_ifork_zone;
>  
> diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
> index f04dbfb2f50d..5da6382bdaf1 100644
> --- a/fs/xfs/libxfs/xfs_types.h
> +++ b/fs/xfs/libxfs/xfs_types.h
> @@ -142,5 +142,8 @@ typedef uint32_t	xfs_dqid_t;
>  #define	XFS_NBWORD	(1 << XFS_NBWORDLOG)
>  #define	XFS_WORDMASK	((1 << XFS_WORDLOG) - 1)
>  
> +struct xfs_iext_cursor {
> +	xfs_extnum_t		idx;
> +};
>  
>  #endif	/* __XFS_TYPES_H__ */
> diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
> index 3c17b182616f..778b709dbd0c 100644
> --- a/fs/xfs/scrub/bmap.c
> +++ b/fs/xfs/scrub/bmap.c
> @@ -237,7 +237,7 @@ xfs_scrub_bmap(
>  	struct xfs_inode		*ip = sc->ip;
>  	struct xfs_ifork		*ifp;
>  	xfs_fileoff_t			endoff;
> -	xfs_extnum_t			idx;
> +	struct xfs_iext_cursor		ext;
>  	bool				found;
>  	int				error = 0;
>  
> @@ -317,9 +317,9 @@ xfs_scrub_bmap(
>  	/* Scrub extent records. */
>  	info.lastoff = 0;
>  	ifp = XFS_IFORK_PTR(ip, whichfork);
> -	for (found = xfs_iext_lookup_extent(ip, ifp, 0, &idx, &irec);
> +	for (found = xfs_iext_lookup_extent(ip, ifp, 0, &ext, &irec);
>  	     found != 0;
> -	     found = xfs_iext_get_extent(ifp, ++idx, &irec)) {
> +	     found = xfs_iext_next_extent(ifp, &ext, &irec)) {
>  		if (xfs_scrub_should_terminate(sc, &error))
>  			break;
>  		if (isnullstartblock(irec.br_startblock))
> diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c
> index 169fb10daaaa..46765102638c 100644
> --- a/fs/xfs/scrub/dir.c
> +++ b/fs/xfs/scrub/dir.c
> @@ -614,7 +614,7 @@ xfs_scrub_directory_blocks(
>  	xfs_fileoff_t			leaf_lblk;
>  	xfs_fileoff_t			free_lblk;
>  	xfs_fileoff_t			lblk;
> -	xfs_extnum_t			idx;
> +	struct xfs_iext_cursor		ext;
>  	xfs_dablk_t			dabno;
>  	bool				found;
>  	int				is_block = 0;
> @@ -639,7 +639,7 @@ xfs_scrub_directory_blocks(
>  		goto out;
>  
>  	/* Iterate all the data extents in the directory... */
> -	found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &idx, &got);
> +	found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &ext, &got);
>  	while (found) {
>  		/* Block directories only have a single block at offset 0. */
>  		if (is_block &&
> @@ -676,17 +676,17 @@ xfs_scrub_directory_blocks(
>  		}
>  		dabno = got.br_startoff + got.br_blockcount;
>  		lblk = roundup(dabno, args.geo->fsbcount);
> -		found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &idx, &got);
> +		found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &ext, &got);
>  	}
>  
>  	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
>  		goto out;
>  
>  	/* Look for a leaf1 block, which has free info. */
> -	if (xfs_iext_lookup_extent(sc->ip, ifp, leaf_lblk, &idx, &got) &&
> +	if (xfs_iext_lookup_extent(sc->ip, ifp, leaf_lblk, &ext, &got) &&
>  	    got.br_startoff == leaf_lblk &&
>  	    got.br_blockcount == args.geo->fsbcount &&
> -	    !xfs_iext_get_extent(ifp, ++idx, &got)) {
> +	    !xfs_iext_next_extent(ifp, &ext, &got)) {
>  		if (is_block) {
>  			xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
>  			goto out;
> @@ -702,7 +702,7 @@ xfs_scrub_directory_blocks(
>  
>  	/* Scan for free blocks */
>  	lblk = free_lblk;
> -	found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &idx, &got);
> +	found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &ext, &got);
>  	while (found) {
>  		/*
>  		 * Dirs can't have blocks mapped above 2^32.
> @@ -740,7 +740,7 @@ xfs_scrub_directory_blocks(
>  		}
>  		dabno = got.br_startoff + got.br_blockcount;
>  		lblk = roundup(dabno, args.geo->fsbcount);
> -		found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &idx, &got);
> +		found = xfs_iext_lookup_extent(sc->ip, ifp, lblk, &ext, &got);
>  	}
>  out:
>  	return error;
> diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
> index 170b74c7f2d5..b6b954d5cf54 100644
> --- a/fs/xfs/xfs_bmap_util.c
> +++ b/fs/xfs/xfs_bmap_util.c
> @@ -229,15 +229,17 @@ xfs_bmap_count_leaves(
>  	struct xfs_ifork	*ifp,
>  	xfs_filblks_t		*count)
>  {
> +	struct xfs_iext_cursor	ext;
>  	struct xfs_bmbt_irec	got;
> -	xfs_extnum_t		numrecs = 0, i = 0;
> +	xfs_extnum_t		numrecs = 0;
>  
> -	while (xfs_iext_get_extent(ifp, i++, &got)) {
> +	for_each_iext(ifp, &ext, &got) {
>  		if (!isnullstartblock(got.br_startblock)) {
>  			*count += got.br_blockcount;
>  			numrecs++;
>  		}
>  	}
> +
>  	return numrecs;
>  }
>  
> @@ -525,7 +527,7 @@ xfs_getbmap(
>  	struct xfs_ifork	*ifp;
>  	struct xfs_bmbt_irec	got, rec;
>  	xfs_filblks_t		len;
> -	xfs_extnum_t		idx;
> +	struct xfs_iext_cursor	ext;
>  
>  	if (bmv->bmv_iflags & ~BMV_IF_VALID)
>  		return -EINVAL;
> @@ -629,7 +631,7 @@ xfs_getbmap(
>  			goto out_unlock_ilock;
>  	}
>  
> -	if (!xfs_iext_lookup_extent(ip, ifp, bno, &idx, &got)) {
> +	if (!xfs_iext_lookup_extent(ip, ifp, bno, &ext, &got)) {
>  		/*
>  		 * Report a whole-file hole if the delalloc flag is set to
>  		 * stay compatible with the old implementation.
> @@ -668,7 +670,7 @@ xfs_getbmap(
>  				goto out_unlock_ilock;
>  		} while (xfs_getbmap_next_rec(&rec, bno));
>  
> -		if (!xfs_iext_get_extent(ifp, ++idx, &got)) {
> +		if (!xfs_iext_next_extent(ifp, &ext, &got)) {
>  			xfs_fileoff_t	end = XFS_B_TO_FSB(mp, XFS_ISIZE(ip));
>  
>  			out[bmv->bmv_entries - 1].bmv_oflags |= BMV_OF_LAST;
> diff --git a/fs/xfs/xfs_dir2_readdir.c b/fs/xfs/xfs_dir2_readdir.c
> index 238e3650a9d2..ad54fd775bda 100644
> --- a/fs/xfs/xfs_dir2_readdir.c
> +++ b/fs/xfs/xfs_dir2_readdir.c
> @@ -266,7 +266,7 @@ xfs_dir2_leaf_readbuf(
>  	xfs_dablk_t		next_ra;
>  	xfs_dablk_t		map_off;
>  	xfs_dablk_t		last_da;
> -	xfs_extnum_t		idx;
> +	struct xfs_iext_cursor	ext;
>  	int			ra_want;
>  	int			error = 0;
>  
> @@ -283,7 +283,7 @@ xfs_dir2_leaf_readbuf(
>  	 */
>  	last_da = xfs_dir2_byte_to_da(geo, XFS_DIR2_LEAF_OFFSET);
>  	map_off = xfs_dir2_db_to_da(geo, xfs_dir2_byte_to_db(geo, *cur_off));
> -	if (!xfs_iext_lookup_extent(dp, ifp, map_off, &idx, &map))
> +	if (!xfs_iext_lookup_extent(dp, ifp, map_off, &ext, &map))
>  		goto out;
>  	if (map.br_startoff >= last_da)
>  		goto out;
> @@ -311,7 +311,7 @@ xfs_dir2_leaf_readbuf(
>  	if (next_ra >= last_da)
>  		goto out_no_ra;
>  	if (map.br_blockcount < geo->fsbcount &&
> -	    !xfs_iext_get_extent(ifp, ++idx, &map))
> +	    !xfs_iext_next_extent(ifp, &ext, &map))
>  		goto out_no_ra;
>  	if (map.br_startoff >= last_da)
>  		goto out_no_ra;
> @@ -334,7 +334,7 @@ xfs_dir2_leaf_readbuf(
>  			ra_want -= geo->fsbcount;
>  			next_ra += geo->fsbcount;
>  		}
> -		if (!xfs_iext_get_extent(ifp, ++idx, &map)) {
> +		if (!xfs_iext_next_extent(ifp, &ext, &map)) {
>  			*ra_blk = last_da;
>  			break;
>  		}
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index cd82429d8df7..8338b894d54f 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -703,7 +703,7 @@ xfs_dq_get_next_id(
>  	xfs_dqid_t		next_id = *id + 1; /* simple advance */
>  	uint			lock_flags;
>  	struct xfs_bmbt_irec	got;
> -	xfs_extnum_t		idx;
> +	struct xfs_iext_cursor	cur;
>  	xfs_fsblock_t		start;
>  	int			error = 0;
>  
> @@ -727,7 +727,7 @@ xfs_dq_get_next_id(
>  			return error;
>  	}
>  
> -	if (xfs_iext_lookup_extent(quotip, &quotip->i_df, start, &idx, &got)) {
> +	if (xfs_iext_lookup_extent(quotip, &quotip->i_df, start, &cur, &got)) {
>  		/* contiguous chunk, bump startoff for the id calculation */
>  		if (got.br_startoff < start)
>  			got.br_startoff = start;
> diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
> index f179bdf1644d..046ade883611 100644
> --- a/fs/xfs/xfs_iomap.c
> +++ b/fs/xfs/xfs_iomap.c
> @@ -389,7 +389,7 @@ xfs_iomap_prealloc_size(
>  	struct xfs_inode	*ip,
>  	loff_t			offset,
>  	loff_t			count,
> -	xfs_extnum_t		idx)
> +	struct xfs_iext_cursor	*ext)
>  {
>  	struct xfs_mount	*mp = ip->i_mount;
>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
> @@ -414,7 +414,7 @@ xfs_iomap_prealloc_size(
>  	 */
>  	if ((mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) ||
>  	    XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_dalign) ||
> -	    !xfs_iext_get_extent(ifp, idx - 1, &prev) ||
> +	    !xfs_iext_peek_prev_extent(ifp, ext, &prev) ||
>  	    prev.br_startoff + prev.br_blockcount < offset_fsb)
>  		return mp->m_writeio_blocks;
>  
> @@ -532,7 +532,7 @@ xfs_file_iomap_begin_delay(
>  	xfs_fileoff_t		end_fsb;
>  	int			error = 0, eof = 0;
>  	struct xfs_bmbt_irec	got;
> -	xfs_extnum_t		idx;
> +	struct xfs_iext_cursor	ext;
>  	xfs_fsblock_t		prealloc_blocks = 0;
>  
>  	ASSERT(!XFS_IS_REALTIME_INODE(ip));
> @@ -557,7 +557,7 @@ xfs_file_iomap_begin_delay(
>  			goto out_unlock;
>  	}
>  
> -	eof = !xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got);
> +	eof = !xfs_iext_lookup_extent(ip, ifp, offset_fsb, &ext, &got);
>  	if (!eof && got.br_startoff <= offset_fsb) {
>  		if (xfs_is_reflink_inode(ip)) {
>  			bool		shared;
> @@ -591,7 +591,8 @@ xfs_file_iomap_begin_delay(
>  	end_fsb = min(XFS_B_TO_FSB(mp, offset + count), maxbytes_fsb);
>  
>  	if (eof) {
> -		prealloc_blocks = xfs_iomap_prealloc_size(ip, offset, count, idx);
> +		prealloc_blocks = xfs_iomap_prealloc_size(ip, offset, count,
> +				&ext);
>  		if (prealloc_blocks) {
>  			xfs_extlen_t	align;
>  			xfs_off_t	end_offset;
> @@ -613,7 +614,7 @@ xfs_file_iomap_begin_delay(
>  
>  retry:
>  	error = xfs_bmapi_reserve_delalloc(ip, XFS_DATA_FORK, offset_fsb,
> -			end_fsb - offset_fsb, prealloc_blocks, &got, &idx, eof);
> +			end_fsb - offset_fsb, prealloc_blocks, &got, &ext, eof);
>  	switch (error) {
>  	case 0:
>  		break;
> diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
> index 1205747e1409..cadf0ff68003 100644
> --- a/fs/xfs/xfs_reflink.c
> +++ b/fs/xfs/xfs_reflink.c
> @@ -273,7 +273,7 @@ xfs_reflink_reserve_cow(
>  	struct xfs_bmbt_irec	got;
>  	int			error = 0;
>  	bool			eof = false, trimmed;
> -	xfs_extnum_t		idx;
> +	struct xfs_iext_cursor	ext;
>  
>  	/*
>  	 * Search the COW fork extent list first.  This serves two purposes:
> @@ -284,7 +284,7 @@ xfs_reflink_reserve_cow(
>  	 * tree.
>  	 */
>  
> -	if (!xfs_iext_lookup_extent(ip, ifp, imap->br_startoff, &idx, &got))
> +	if (!xfs_iext_lookup_extent(ip, ifp, imap->br_startoff, &ext, &got))
>  		eof = true;
>  	if (!eof && got.br_startoff <= imap->br_startoff) {
>  		trace_xfs_reflink_cow_found(ip, imap);
> @@ -312,7 +312,7 @@ xfs_reflink_reserve_cow(
>  		return error;
>  
>  	error = xfs_bmapi_reserve_delalloc(ip, XFS_COW_FORK, imap->br_startoff,
> -			imap->br_blockcount, 0, &got, &idx, eof);
> +			imap->br_blockcount, 0, &got, &ext, eof);
>  	if (error == -ENOSPC || error == -EDQUOT)
>  		trace_xfs_reflink_cow_enospc(ip, imap);
>  	if (error)
> @@ -359,16 +359,16 @@ xfs_reflink_convert_cow(
>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
>  	xfs_fileoff_t		offset_fsb = XFS_B_TO_FSBT(mp, offset);
>  	xfs_fileoff_t		end_fsb = XFS_B_TO_FSB(mp, offset + count);
> -	xfs_extnum_t		idx;
> +	struct xfs_iext_cursor	ext;
>  	bool			found;
>  	int			error = 0;
>  
>  	xfs_ilock(ip, XFS_ILOCK_EXCL);
>  
>  	/* Convert all the extents to real from unwritten. */
> -	for (found = xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got);
> +	for (found = xfs_iext_lookup_extent(ip, ifp, offset_fsb, &ext, &got);
>  	     found && got.br_startoff < end_fsb;
> -	     found = xfs_iext_get_extent(ifp, ++idx, &got)) {
> +	     found = xfs_iext_next_extent(ifp, &ext, &got)) {
>  		error = xfs_reflink_convert_cow_extent(ip, &got, offset_fsb,
>  				end_fsb - offset_fsb, &dfops);
>  		if (error)
> @@ -399,7 +399,7 @@ xfs_reflink_allocate_cow(
>  	bool			trimmed;
>  	xfs_filblks_t		resaligned;
>  	xfs_extlen_t		resblks = 0;
> -	xfs_extnum_t		idx;
> +	struct xfs_iext_cursor	ext;
>  
>  retry:
>  	ASSERT(xfs_is_reflink_inode(ip));
> @@ -409,7 +409,7 @@ xfs_reflink_allocate_cow(
>  	 * Even if the extent is not shared we might have a preallocation for
>  	 * it in the COW fork.  If so use it.
>  	 */
> -	if (xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &idx, &got) &&
> +	if (xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &ext, &got) &&
>  	    got.br_startoff <= offset_fsb) {
>  		*shared = true;
>  
> @@ -496,13 +496,13 @@ xfs_reflink_find_cow_mapping(
>  	struct xfs_ifork		*ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
>  	xfs_fileoff_t			offset_fsb;
>  	struct xfs_bmbt_irec		got;
> -	xfs_extnum_t			idx;
> +	struct xfs_iext_cursor		ext;
>  
>  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED));
>  	ASSERT(xfs_is_reflink_inode(ip));
>  
>  	offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset);
> -	if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got))
> +	if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &ext, &got))
>  		return false;
>  	if (got.br_startoff > offset_fsb)
>  		return false;
> @@ -524,18 +524,18 @@ xfs_reflink_trim_irec_to_next_cow(
>  {
>  	struct xfs_ifork		*ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
>  	struct xfs_bmbt_irec		got;
> -	xfs_extnum_t			idx;
> +	struct xfs_iext_cursor		ext;
>  
>  	if (!xfs_is_reflink_inode(ip))
>  		return;
>  
>  	/* Find the extent in the CoW fork. */
> -	if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got))
> +	if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &ext, &got))
>  		return;
>  
>  	/* This is the extent before; try sliding up one. */
>  	if (got.br_startoff < offset_fsb) {
> -		if (!xfs_iext_get_extent(ifp, idx + 1, &got))
> +		if (!xfs_iext_next_extent(ifp, &ext, &got))
>  			return;
>  	}
>  
> @@ -562,14 +562,14 @@ xfs_reflink_cancel_cow_blocks(
>  {
>  	struct xfs_ifork		*ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
>  	struct xfs_bmbt_irec		got, del;
> -	xfs_extnum_t			idx;
> +	struct xfs_iext_cursor		ext;
>  	xfs_fsblock_t			firstfsb;
>  	struct xfs_defer_ops		dfops;
>  	int				error = 0;
>  
>  	if (!xfs_is_reflink_inode(ip))
>  		return 0;
> -	if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got))
> +	if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &ext, &got))
>  		return 0;
>  
>  	while (got.br_startoff < end_fsb) {
> @@ -579,7 +579,7 @@ xfs_reflink_cancel_cow_blocks(
>  
>  		if (isnullstartblock(del.br_startblock)) {
>  			error = xfs_bmap_del_extent_delay(ip, XFS_COW_FORK,
> -					&idx, &got, &del);
> +					&ext, &got, &del);
>  			if (error)
>  				break;
>  		} else if (del.br_state == XFS_EXT_UNWRITTEN || cancel_real) {
> @@ -610,10 +610,10 @@ xfs_reflink_cancel_cow_blocks(
>  			}
>  
>  			/* Remove the mapping from the CoW fork. */
> -			xfs_bmap_del_extent_cow(ip, &idx, &got, &del);
> +			xfs_bmap_del_extent_cow(ip, &ext, &got, &del);
>  		}
>  
> -		if (!xfs_iext_get_extent(ifp, ++idx, &got))
> +		if (!xfs_iext_next_extent(ifp, &ext, &got))
>  			break;
>  	}
>  
> @@ -698,7 +698,7 @@ xfs_reflink_end_cow(
>  	int				error;
>  	unsigned int			resblks;
>  	xfs_filblks_t			rlen;
> -	xfs_extnum_t			idx;
> +	struct xfs_iext_cursor		ext;
>  
>  	trace_xfs_reflink_end_cow(ip, offset, count);
>  
> @@ -738,7 +738,7 @@ xfs_reflink_end_cow(
>  	 * left by the time I/O completes for the loser of the race.  In that
>  	 * case we are done.
>  	 */
> -	if (!xfs_iext_lookup_extent_before(ip, ifp, &end_fsb, &idx, &got))
> +	if (!xfs_iext_lookup_extent_before(ip, ifp, &end_fsb, &ext, &got))
>  		goto out_cancel;
>  
>  	/* Walk backwards until we're out of the I/O range... */
> @@ -746,9 +746,9 @@ xfs_reflink_end_cow(
>  		del = got;
>  		xfs_trim_extent(&del, offset_fsb, end_fsb - offset_fsb);
>  
> -		/* Extent delete may have bumped idx forward */
> +		/* Extent delete may have bumped ext forward */
>  		if (!del.br_blockcount) {
> -			idx--;
> +			xfs_iext_prev(ifp, &ext);
>  			goto next_extent;
>  		}
>  
> @@ -760,7 +760,7 @@ xfs_reflink_end_cow(
>  		 * allocated but have not yet been involved in a write.
>  		 */
>  		if (got.br_state == XFS_EXT_UNWRITTEN) {
> -			idx--;
> +			xfs_iext_prev(ifp, &ext);
>  			goto next_extent;
>  		}
>  
> @@ -791,14 +791,14 @@ xfs_reflink_end_cow(
>  			goto out_defer;
>  
>  		/* Remove the mapping from the CoW fork. */
> -		xfs_bmap_del_extent_cow(ip, &idx, &got, &del);
> +		xfs_bmap_del_extent_cow(ip, &ext, &got, &del);
>  
>  		xfs_defer_ijoin(&dfops, ip);
>  		error = xfs_defer_finish(&tp, &dfops);
>  		if (error)
>  			goto out_defer;
>  next_extent:
> -		if (!xfs_iext_get_extent(ifp, idx, &got))
> +		if (!xfs_iext_get_extent(ifp, &ext, &got))
>  			break;
>  	}
>  
> @@ -1428,7 +1428,7 @@ xfs_reflink_inode_has_shared_extents(
>  	xfs_extlen_t			aglen;
>  	xfs_agblock_t			rbno;
>  	xfs_extlen_t			rlen;
> -	xfs_extnum_t			idx;
> +	struct xfs_iext_cursor		ext;
>  	bool				found;
>  	int				error;
>  
> @@ -1440,7 +1440,7 @@ xfs_reflink_inode_has_shared_extents(
>  	}
>  
>  	*has_shared = false;
> -	found = xfs_iext_lookup_extent(ip, ifp, 0, &idx, &got);
> +	found = xfs_iext_lookup_extent(ip, ifp, 0, &ext, &got);
>  	while (found) {
>  		if (isnullstartblock(got.br_startblock) ||
>  		    got.br_state != XFS_EXT_NORM)
> @@ -1459,7 +1459,7 @@ xfs_reflink_inode_has_shared_extents(
>  			return 0;
>  		}
>  next:
> -		found = xfs_iext_get_extent(ifp, ++idx, &got);
> +		found = xfs_iext_next_extent(ifp, &ext, &got);
>  	}
>  
>  	return 0;
> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
> index 665ef6cca90c..667bfce802cd 100644
> --- a/fs/xfs/xfs_trace.h
> +++ b/fs/xfs/xfs_trace.h
> @@ -258,9 +258,9 @@ TRACE_EVENT(xfs_iext_insert,
>  );
>  
>  DECLARE_EVENT_CLASS(xfs_bmap_class,
> -	TP_PROTO(struct xfs_inode *ip, xfs_extnum_t idx, int state,
> +	TP_PROTO(struct xfs_inode *ip, struct xfs_iext_cursor *cur, int state,
>  		 unsigned long caller_ip),
> -	TP_ARGS(ip, idx, state, caller_ip),
> +	TP_ARGS(ip, cur, state, caller_ip),
>  	TP_STRUCT__entry(
>  		__field(dev_t, dev)
>  		__field(xfs_ino_t, ino)
> @@ -277,10 +277,10 @@ DECLARE_EVENT_CLASS(xfs_bmap_class,
>  		struct xfs_bmbt_irec	r;
>  
>  		ifp = xfs_iext_state_to_fork(ip, state);
> -		xfs_iext_get_extent(ifp, idx, &r);
> +		xfs_iext_get_extent(ifp, cur, &r);
>  		__entry->dev = VFS_I(ip)->i_sb->s_dev;
>  		__entry->ino = ip->i_ino;
> -		__entry->idx = idx;
> +		__entry->idx = cur->idx;
>  		__entry->startoff = r.br_startoff;
>  		__entry->startblock = r.br_startblock;
>  		__entry->blockcount = r.br_blockcount;
> @@ -303,9 +303,9 @@ DECLARE_EVENT_CLASS(xfs_bmap_class,
>  
>  #define DEFINE_BMAP_EVENT(name) \
>  DEFINE_EVENT(xfs_bmap_class, name, \
> -	TP_PROTO(struct xfs_inode *ip, xfs_extnum_t idx, int state, \
> +	TP_PROTO(struct xfs_inode *ip, struct xfs_iext_cursor *cur, int state, \
>  		 unsigned long caller_ip), \
> -	TP_ARGS(ip, idx, state, caller_ip))
> +	TP_ARGS(ip, cur, state, caller_ip))
>  DEFINE_BMAP_EVENT(xfs_iext_remove);
>  DEFINE_BMAP_EVENT(xfs_bmap_pre_update);
>  DEFINE_BMAP_EVENT(xfs_bmap_post_update);
> -- 
> 2.14.2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux