Commit ed24bee6 authored by Dave Chinner's avatar Dave Chinner
Browse files

Merge branch 'xfs-4.10-extent-lookup' into for-next

parents 0fc204e2 0e8d630b
Loading
Loading
Loading
Loading
+65 −169
Original line number Diff line number Diff line
@@ -1370,97 +1370,6 @@ error0:
	return -EFSCORRUPTED;
}


/*
 * Search the extent records for the entry containing block bno.
 * If bno lies in a hole, point to the next entry.  If bno lies
 * past eof, *eofp will be set, and *prevp will contain the last
 * entry (null if none).  Else, *lastxp will be set to the index
 * of the found entry; *gotp will contain the entry.
 */
STATIC xfs_bmbt_rec_host_t *		/* pointer to found extent entry */
xfs_bmap_search_multi_extents(
	xfs_ifork_t	*ifp,		/* inode fork pointer */
	xfs_fileoff_t	bno,		/* block number searched for */
	int		*eofp,		/* out: end of file found */
	xfs_extnum_t	*lastxp,	/* out: last extent index */
	xfs_bmbt_irec_t	*gotp,		/* out: extent entry found */
	xfs_bmbt_irec_t	*prevp)		/* out: previous extent entry found */
{
	xfs_bmbt_rec_host_t *ep;		/* extent record pointer */
	xfs_extnum_t	lastx;		/* last extent index */

	/*
	 * Initialize the extent entry structure to catch access to
	 * uninitialized br_startblock field.
	 */
	gotp->br_startoff = 0xffa5a5a5a5a5a5a5LL;
	gotp->br_blockcount = 0xa55a5a5a5a5a5a5aLL;
	gotp->br_state = XFS_EXT_INVALID;
	gotp->br_startblock = 0xffffa5a5a5a5a5a5LL;
	prevp->br_startoff = NULLFILEOFF;

	ep = xfs_iext_bno_to_ext(ifp, bno, &lastx);
	if (lastx > 0) {
		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx - 1), prevp);
	}
	if (lastx < xfs_iext_count(ifp)) {
		xfs_bmbt_get_all(ep, gotp);
		*eofp = 0;
	} else {
		if (lastx > 0) {
			*gotp = *prevp;
		}
		*eofp = 1;
		ep = NULL;
	}
	*lastxp = lastx;
	return ep;
}

/*
 * Search the extents list for the inode, for the extent containing bno.
 * If bno lies in a hole, point to the next entry.  If bno lies past eof,
 * *eofp will be set, and *prevp will contain the last entry (null if none).
 * Else, *lastxp will be set to the index of the found
 * entry; *gotp will contain the entry.
 */
xfs_bmbt_rec_host_t *                 /* pointer to found extent entry */
xfs_bmap_search_extents(
	xfs_inode_t     *ip,            /* incore inode pointer */
	xfs_fileoff_t   bno,            /* block number searched for */
	int             fork,      	/* data or attr fork */
	int             *eofp,          /* out: end of file found */
	xfs_extnum_t    *lastxp,        /* out: last extent index */
	xfs_bmbt_irec_t *gotp,          /* out: extent entry found */
	xfs_bmbt_irec_t *prevp)         /* out: previous extent entry found */
{
	xfs_ifork_t	*ifp;		/* inode fork pointer */
	xfs_bmbt_rec_host_t  *ep;            /* extent record pointer */

	XFS_STATS_INC(ip->i_mount, xs_look_exlist);
	ifp = XFS_IFORK_PTR(ip, fork);

	ep = xfs_bmap_search_multi_extents(ifp, bno, eofp, lastxp, gotp, prevp);

	if (unlikely(!(gotp->br_startblock) && (*lastxp != NULLEXTNUM) &&
		     !(XFS_IS_REALTIME_INODE(ip) && fork == XFS_DATA_FORK))) {
		xfs_alert_tag(ip->i_mount, XFS_PTAG_FSBLOCK_ZERO,
				"Access to block zero in inode %llu "
				"start_block: %llx start_off: %llx "
				"blkcnt: %llx extent-state: %x lastx: %x",
			(unsigned long long)ip->i_ino,
			(unsigned long long)gotp->br_startblock,
			(unsigned long long)gotp->br_startoff,
			(unsigned long long)gotp->br_blockcount,
			gotp->br_state, *lastxp);
		*lastxp = NULLEXTNUM;
		*eofp = 1;
		return NULL;
	}
	return ep;
}

/*
 * Returns the file-relative block number of the first unused block(s)
 * in the file with at least "len" logically contiguous blocks free.
@@ -1523,44 +1432,44 @@ xfs_bmap_first_unused(
 */
int						/* error */
xfs_bmap_last_before(
	xfs_trans_t	*tp,			/* transaction pointer */
	xfs_inode_t	*ip,			/* incore inode */
	struct xfs_trans	*tp,		/* transaction pointer */
	struct xfs_inode	*ip,		/* incore inode */
	xfs_fileoff_t		*last_block,	/* last block */
	int			whichfork)	/* data or attr fork */
{
	xfs_fileoff_t	bno;			/* input file offset */
	int		eof;			/* hit end of file */
	xfs_bmbt_rec_host_t *ep;		/* pointer to last extent */
	int		error;			/* error return value */
	xfs_bmbt_irec_t	got;			/* current extent value */
	xfs_ifork_t	*ifp;			/* inode fork pointer */
	xfs_extnum_t	lastx;			/* last extent used */
	xfs_bmbt_irec_t	prev;			/* previous extent value */
	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
	struct xfs_bmbt_irec	got;
	xfs_extnum_t		idx;
	int			error;

	if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL)
	       return -EIO;
	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
	switch (XFS_IFORK_FORMAT(ip, whichfork)) {
	case XFS_DINODE_FMT_LOCAL:
		*last_block = 0;
		return 0;
	case XFS_DINODE_FMT_BTREE:
	case XFS_DINODE_FMT_EXTENTS:
		break;
	default:
		return -EIO;
	}
	ifp = XFS_IFORK_PTR(ip, whichfork);
	if (!(ifp->if_flags & XFS_IFEXTENTS) &&
	    (error = xfs_iread_extents(tp, ip, whichfork)))

	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
		error = xfs_iread_extents(tp, ip, whichfork);
		if (error)
			return error;
	bno = *last_block - 1;
	ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
		&prev);
	if (eof || xfs_bmbt_get_startoff(ep) > bno) {
		if (prev.br_startoff == NULLFILEOFF)
			*last_block = 0;
		else
			*last_block = prev.br_startoff + prev.br_blockcount;
	}
	/*
	 * Otherwise *last_block is already the right answer.
	 */

	if (xfs_iext_lookup_extent(ip, ifp, *last_block - 1, &idx, &got)) {
		if (got.br_startoff <= *last_block - 1)
			return 0;
	}

	if (xfs_iext_get_extent(ifp, idx - 1, &got)) {
		*last_block = got.br_startoff + got.br_blockcount;
		return 0;
	}

	*last_block = 0;
	return 0;
}

@@ -4145,12 +4054,11 @@ xfs_bmapi_read(
	struct xfs_mount	*mp = ip->i_mount;
	struct xfs_ifork	*ifp;
	struct xfs_bmbt_irec	got;
	struct xfs_bmbt_irec	prev;
	xfs_fileoff_t		obno;
	xfs_fileoff_t		end;
	xfs_extnum_t		lastx;
	xfs_extnum_t		idx;
	int			error;
	int			eof;
	bool			eof = false;
	int			n = 0;
	int			whichfork = xfs_bmapi_whichfork(flags);

@@ -4190,7 +4098,8 @@ xfs_bmapi_read(
			return error;
	}

	xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev);
	if (!xfs_iext_lookup_extent(ip, ifp, bno, &idx, &got))
		eof = true;
	end = bno + len;
	obno = bno;

@@ -4221,10 +4130,8 @@ xfs_bmapi_read(
			break;

		/* Else go on to the next record. */
		if (++lastx < xfs_iext_count(ifp))
			xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx), &got);
		else
			eof = 1;
		if (!xfs_iext_get_extent(ifp, ++idx, &got))
			eof = true;
	}
	*nmap = n;
	return 0;
@@ -4237,7 +4144,6 @@ xfs_bmapi_reserve_delalloc(
	xfs_fileoff_t		aoff,
	xfs_filblks_t		len,
	struct xfs_bmbt_irec	*got,
	struct xfs_bmbt_irec	*prev,
	xfs_extnum_t		*lastx,
	int			eof)
{
@@ -4259,7 +4165,12 @@ xfs_bmapi_reserve_delalloc(
	else
		extsz = xfs_get_extsz_hint(ip);
	if (extsz) {
		error = xfs_bmap_extsize_align(mp, got, prev, extsz, rt, eof,
		struct xfs_bmbt_irec	prev;

		if (!xfs_iext_get_extent(ifp, *lastx - 1, &prev))
			prev.br_startoff = NULLFILEOFF;

		error = xfs_bmap_extsize_align(mp, got, &prev, extsz, rt, eof,
					       1, 0, &aoff, &alen);
		ASSERT(!error);
	}
@@ -4349,7 +4260,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 != NULLEXTNUM && bma->idx) {
		if (bma->idx) {
			xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1),
					 &bma->prev);
		}
@@ -4563,7 +4474,7 @@ xfs_bmapi_write(
	struct xfs_ifork	*ifp;
	struct xfs_bmalloca	bma = { NULL };	/* args for xfs_bmap_alloc */
	xfs_fileoff_t		end;		/* end of mapped file region */
	int			eof;		/* after the end of extents */
	bool			eof = false;	/* after the end of extents */
	int			error;		/* error return */
	int			n;		/* current extent index */
	xfs_fileoff_t		obno;		/* old block number (offset) */
@@ -4641,12 +4552,14 @@ xfs_bmapi_write(
			goto error0;
	}

	xfs_bmap_search_extents(ip, bno, whichfork, &eof, &bma.idx, &bma.got,
				&bma.prev);
	n = 0;
	end = bno + len;
	obno = bno;

	if (!xfs_iext_lookup_extent(ip, ifp, bno, &bma.idx, &bma.got))
		eof = true;
	if (!xfs_iext_get_extent(ifp, bma.idx - 1, &bma.prev))
		bma.prev.br_startoff = NULLFILEOFF;
	bma.tp = tp;
	bma.ip = ip;
	bma.total = total;
@@ -4733,11 +4646,8 @@ xfs_bmapi_write(

		/* Else go on to the next record. */
		bma.prev = bma.got;
		if (++bma.idx < xfs_iext_count(ifp)) {
			xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma.idx),
					 &bma.got);
		} else
			eof = 1;
		if (!xfs_iext_get_extent(ifp, ++bma.idx, &bma.got))
			eof = true;
	}
	*nmap = n;

@@ -5436,8 +5346,6 @@ __xfs_bunmapi(
{
	xfs_btree_cur_t		*cur;		/* bmap btree cursor */
	xfs_bmbt_irec_t		del;		/* extent being deleted */
	int			eof;		/* is deleting at eof */
	xfs_bmbt_rec_host_t	*ep;		/* extent record pointer */
	int			error;		/* error return value */
	xfs_extnum_t		extno;		/* extent number in list */
	xfs_bmbt_irec_t		got;		/* current extent record */
@@ -5447,7 +5355,6 @@ __xfs_bunmapi(
	int			logflags;	/* transaction logging flags */
	xfs_extlen_t		mod;		/* rt extent offset */
	xfs_mount_t		*mp;		/* mount structure */
	xfs_bmbt_irec_t		prev;		/* previous extent record */
	xfs_fileoff_t		start;		/* first file offset deleted */
	int			tmp_logflags;	/* partial logging flags */
	int			wasdel;		/* was a delayed alloc extent */
@@ -5486,18 +5393,17 @@ __xfs_bunmapi(
	isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
	start = bno;
	bno = start + len - 1;
	ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
		&prev);

	/*
	 * Check to see if the given block number is past the end of the
	 * file, back up to the last block if so...
	 */
	if (eof) {
		ep = xfs_iext_get_ext(ifp, --lastx);
		xfs_bmbt_get_all(ep, &got);
	if (!xfs_iext_lookup_extent(ip, ifp, bno, &lastx, &got)) {
		ASSERT(lastx > 0);
		xfs_iext_get_extent(ifp, --lastx, &got);
		bno = got.br_startoff + got.br_blockcount - 1;
	}

	logflags = 0;
	if (ifp->if_flags & XFS_IFBROOT) {
		ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE);
@@ -5528,8 +5434,7 @@ __xfs_bunmapi(
		if (got.br_startoff > bno) {
			if (--lastx < 0)
				break;
			ep = xfs_iext_get_ext(ifp, lastx);
			xfs_bmbt_get_all(ep, &got);
			xfs_iext_get_extent(ifp, lastx, &got);
		}
		/*
		 * Is the last block of this extent before the range
@@ -5543,7 +5448,6 @@ __xfs_bunmapi(
		 * Then deal with the (possibly delayed) allocated space
		 * we found.
		 */
		ASSERT(ep != NULL);
		del = got;
		wasdel = isnullstartblock(del.br_startblock);
		if (got.br_startoff < start) {
@@ -5624,15 +5528,12 @@ __xfs_bunmapi(
				 */
				ASSERT(bno >= del.br_blockcount);
				bno -= del.br_blockcount;
				if (got.br_startoff > bno) {
					if (--lastx >= 0) {
						ep = xfs_iext_get_ext(ifp,
								      lastx);
						xfs_bmbt_get_all(ep, &got);
					}
				}
				if (got.br_startoff > bno && --lastx >= 0)
					xfs_iext_get_extent(ifp, lastx, &got);
				continue;
			} else if (del.br_state == XFS_EXT_UNWRITTEN) {
				struct xfs_bmbt_irec	prev;

				/*
				 * This one is already unwritten.
				 * It must have a written left neighbor.
@@ -5640,8 +5541,7 @@ __xfs_bunmapi(
				 * try again.
				 */
				ASSERT(lastx > 0);
				xfs_bmbt_get_all(xfs_iext_get_ext(ifp,
						lastx - 1), &prev);
				xfs_iext_get_extent(ifp, lastx - 1, &prev);
				ASSERT(prev.br_state == XFS_EXT_NORM);
				ASSERT(!isnullstartblock(prev.br_startblock));
				ASSERT(del.br_startblock ==
@@ -5739,13 +5639,9 @@ nodelete:
		 */
		if (bno != (xfs_fileoff_t)-1 && bno >= start) {
			if (lastx >= 0) {
				ep = xfs_iext_get_ext(ifp, lastx);
				if (xfs_bmbt_get_startoff(ep) > bno) {
					if (--lastx >= 0)
						ep = xfs_iext_get_ext(ifp,
								      lastx);
				}
				xfs_bmbt_get_all(ep, &got);
				xfs_iext_get_extent(ifp, lastx, &got);
				if (got.br_startoff > bno && --lastx >= 0)
					xfs_iext_get_extent(ifp, lastx, &got);
			}
			extno++;
		}
+1 −6
Original line number Diff line number Diff line
@@ -237,14 +237,9 @@ int xfs_bmap_shift_extents(struct xfs_trans *tp, struct xfs_inode *ip,
		struct xfs_defer_ops *dfops, enum shift_direction direction,
		int num_exts);
int	xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset);
struct xfs_bmbt_rec_host *
	xfs_bmap_search_extents(struct xfs_inode *ip, xfs_fileoff_t bno,
		int fork, int *eofp, xfs_extnum_t *lastxp,
		struct xfs_bmbt_irec *gotp, struct xfs_bmbt_irec *prevp);
int	xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork,
		xfs_fileoff_t aoff, xfs_filblks_t len,
		struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *prev,
		xfs_extnum_t *lastx, int eof);
		struct xfs_bmbt_irec *got, xfs_extnum_t *lastx, int eof);

enum xfs_bmap_intent_type {
	XFS_BMAP_MAP = 1,
+46 −0
Original line number Diff line number Diff line
@@ -2003,3 +2003,49 @@ xfs_ifork_init_cow(
	ip->i_cformat = XFS_DINODE_FMT_EXTENTS;
	ip->i_cnextents = 0;
}

/*
 * 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.
 * 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
 * instead.
 * If bno is beyond the last extent return false, and return the index after
 * the last valid index in *idxp.
 */
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_bmbt_rec_host *ep;

	XFS_STATS_INC(ip->i_mount, xs_look_exlist);

	ep = xfs_iext_bno_to_ext(ifp, bno, idxp);
	if (!ep)
		return false;
	xfs_bmbt_get_all(ep, gotp);
	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.
 */
bool
xfs_iext_get_extent(
	struct xfs_ifork	*ifp,
	xfs_extnum_t		idx,
	struct xfs_bmbt_irec	*gotp)
{
	if (idx < 0 || idx >= xfs_iext_count(ifp))
		return false;
	xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), gotp);
	return true;
}
+6 −0
Original line number Diff line number Diff line
@@ -182,6 +182,12 @@ void xfs_iext_irec_compact_pages(struct xfs_ifork *);
void		xfs_iext_irec_compact_full(struct xfs_ifork *);
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);
bool		xfs_iext_get_extent(struct xfs_ifork *ifp, xfs_extnum_t idx,
			struct xfs_bmbt_irec *gotp);

extern struct kmem_zone	*xfs_ifork_zone;

extern void xfs_ifork_init_cow(struct xfs_inode *ip);
+0 −1
Original line number Diff line number Diff line
@@ -57,7 +57,6 @@ typedef __int64_t xfs_sfiloff_t; /* signed block number in a file */

#define	NULLAGBLOCK	((xfs_agblock_t)-1)
#define	NULLAGNUMBER	((xfs_agnumber_t)-1)
#define	NULLEXTNUM	((xfs_extnum_t)-1)

#define NULLCOMMITLSN	((xfs_lsn_t)-1)

Loading