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

Commit 7e47a4ef authored by Dave Chinner's avatar Dave Chinner Committed by Alex Elder
Browse files

xfs: factor extent allocation out of xfs_bmapi



To further improve the readability of xfs_bmapi(), factor the extent
allocation out into a separate function. This removes a large block
of logic from the xfs_bmapi() code loop and makes it easier to see
the operational logic flow for xfs_bmapi().

Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAlex Elder <aelder@sgi.com>
parent 1fd044d9
Loading
Loading
Loading
Loading
+162 −140
Original line number Diff line number Diff line
@@ -4605,6 +4605,147 @@ xfs_bmapi_delay(
}


STATIC int
xfs_bmapi_allocate(
	struct xfs_bmalloca	*bma,
	xfs_extnum_t		*lastx,
	struct xfs_btree_cur	**cur,
	xfs_fsblock_t		*firstblock,
	struct xfs_bmap_free	*flist,
	int			flags,
	int			*nallocs,
	int			*logflags)
{
	struct xfs_mount	*mp = bma->ip->i_mount;
	int			whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
						XFS_ATTR_FORK : XFS_DATA_FORK;
	struct xfs_ifork	*ifp = XFS_IFORK_PTR(bma->ip, whichfork);
	xfs_fsblock_t		abno;
	xfs_extlen_t		alen;
	xfs_fileoff_t		aoff;
	int			error;
	int			rt;

	rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(bma->ip);

	/*
	 * For the wasdelay case, we could also just allocate the stuff asked
	 * for in this bmap call but that wouldn't be as good.
	 */
	if (bma->wasdel) {
		alen = (xfs_extlen_t)bma->gotp->br_blockcount;
		aoff = bma->gotp->br_startoff;
		if (*lastx != NULLEXTNUM && *lastx) {
			xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx - 1),
					 bma->prevp);
		}
	} else {
		alen = (xfs_extlen_t)XFS_FILBLKS_MIN(bma->alen, MAXEXTLEN);
		if (!bma->eof)
			alen = (xfs_extlen_t)XFS_FILBLKS_MIN(alen,
					bma->gotp->br_startoff - bma->off);
		aoff = bma->off;
	}

	/*
	 * Indicate if this is the first user data in the file, or just any
	 * user data.
	 */
	if (!(flags & XFS_BMAPI_METADATA)) {
		bma->userdata = (aoff == 0) ?
			XFS_ALLOC_INITIAL_USER_DATA : XFS_ALLOC_USERDATA;
	}

	/*
	 * Fill in changeable bma fields.
	 */
	bma->alen = alen;
	bma->off = aoff;
	bma->firstblock = *firstblock;
	bma->minlen = (flags & XFS_BMAPI_CONTIG) ? alen : 1;
	bma->low = flist->xbf_low;
	bma->aeof = 0;

	/*
	 * Only want to do the alignment at the eof if it is userdata and
	 * allocation length is larger than a stripe unit.
	 */
	if (mp->m_dalign && alen >= mp->m_dalign &&
	    !(flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) {
		error = xfs_bmap_isaeof(bma->ip, aoff, whichfork, &bma->aeof);
		if (error)
			return error;
	}

	error = xfs_bmap_alloc(bma);
	if (error)
		return error;

	/*
	 * Copy out result fields.
	 */
	abno = bma->rval;
	flist->xbf_low = bma->low;
	alen = bma->alen;
	aoff = bma->off;
	ASSERT(*firstblock == NULLFSBLOCK ||
	       XFS_FSB_TO_AGNO(mp, *firstblock) ==
	       XFS_FSB_TO_AGNO(mp, bma->firstblock) ||
	       (flist->xbf_low &&
		XFS_FSB_TO_AGNO(mp, *firstblock) <
			XFS_FSB_TO_AGNO(mp, bma->firstblock)));
	*firstblock = bma->firstblock;
	if (*cur)
		(*cur)->bc_private.b.firstblock = *firstblock;
	if (abno == NULLFSBLOCK)
		return 0;
	if ((ifp->if_flags & XFS_IFBROOT) && !*cur) {
		(*cur) = xfs_bmbt_init_cursor(mp, bma->tp, bma->ip, whichfork);
		(*cur)->bc_private.b.firstblock = *firstblock;
		(*cur)->bc_private.b.flist = flist;
	}
	/*
	 * Bump the number of extents we've allocated
	 * in this call.
	 */
	(*nallocs)++;

	if (*cur)
		(*cur)->bc_private.b.flags =
			bma->wasdel ? XFS_BTCUR_BPRV_WASDEL : 0;

	bma->gotp->br_startoff = aoff;
	bma->gotp->br_startblock = abno;
	bma->gotp->br_blockcount = alen;
	bma->gotp->br_state = XFS_EXT_NORM;

	/*
	 * A wasdelay extent has been initialized, so shouldn't be flagged
	 * as unwritten.
	 */
	if (!bma->wasdel && (flags & XFS_BMAPI_PREALLOC) &&
	    xfs_sb_version_hasextflgbit(&mp->m_sb))
		bma->gotp->br_state = XFS_EXT_UNWRITTEN;

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

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

	ASSERT(bma->gotp->br_startoff <= aoff);
	ASSERT(bma->gotp->br_startoff + bma->gotp->br_blockcount >=
		aoff + alen);
	ASSERT(bma->gotp->br_state == XFS_EXT_NORM ||
	       bma->gotp->br_state == XFS_EXT_UNWRITTEN);
	return 0;
}

/*
 * Map file blocks to filesystem blocks.
 * File range is given by the bno/len pair.
@@ -4632,9 +4773,6 @@ xfs_bmapi(
	int		*nmap,		/* i/o: mval size/count */
	xfs_bmap_free_t	*flist)		/* i/o: list extents to free */
{
	xfs_fsblock_t	abno;		/* allocated block number */
	xfs_extlen_t	alen;		/* allocated extent length */
	xfs_fileoff_t	aoff;		/* allocated file offset */
	xfs_bmalloca_t	bma = { 0 };	/* args for xfs_bmap_alloc */
	xfs_btree_cur_t	*cur;		/* bmap btree cursor */
	xfs_fileoff_t	end;		/* end of mapped file region */
@@ -4646,7 +4784,6 @@ xfs_bmapi(
	xfs_extnum_t	lastx;		/* last useful extent number */
	int		logflags;	/* flags for transaction logging */
	xfs_extlen_t	minleft;	/* min blocks left after allocation */
	xfs_extlen_t	minlen;		/* min allocation size */
	xfs_mount_t	*mp;		/* xfs mount structure */
	int		n;		/* current extent index */
	int		nallocs;	/* number of extents alloc'd */
@@ -4737,7 +4874,13 @@ xfs_bmapi(
	n = 0;
	end = bno + len;
	obno = bno;
	bma.ip = NULL;

	bma.tp = tp;
	bma.ip = ip;
	bma.prevp = &prev;
	bma.gotp = &got;
	bma.total = total;
	bma.userdata = 0;

	while (bno < end && n < *nmap) {
		/*
@@ -4753,144 +4896,23 @@ xfs_bmapi(
		 * that we found, if any.
		 */
		if (wr && (inhole || wasdelay)) {
			/*
			 * For the wasdelay case, we could also just
			 * allocate the stuff asked for in this bmap call
			 * but that wouldn't be as good.
			 */
			if (wasdelay) {
				alen = (xfs_extlen_t)got.br_blockcount;
				aoff = got.br_startoff;
				if (lastx != NULLEXTNUM && lastx) {
					ep = xfs_iext_get_ext(ifp, lastx - 1);
					xfs_bmbt_get_all(ep, &prev);
				}
			} else {
				alen = (xfs_extlen_t)
					XFS_FILBLKS_MIN(len, MAXEXTLEN);
				if (!eof)
					alen = (xfs_extlen_t)
						XFS_FILBLKS_MIN(alen,
							got.br_startoff - bno);
				aoff = bno;
			}
			minlen = (flags & XFS_BMAPI_CONTIG) ? alen : 1;
			{
				/*
				 * If first time, allocate and fill in
				 * once-only bma fields.
				 */
				if (bma.ip == NULL) {
					bma.tp = tp;
					bma.ip = ip;
					bma.prevp = &prev;
					bma.gotp = &got;
					bma.total = total;
					bma.userdata = 0;
				}
				/* Indicate if this is the first user data
				 * in the file, or just any user data.
				 */
				if (!(flags & XFS_BMAPI_METADATA)) {
					bma.userdata = (aoff == 0) ?
						XFS_ALLOC_INITIAL_USER_DATA :
						XFS_ALLOC_USERDATA;
				}
				/*
				 * Fill in changeable bma fields.
				 */
			bma.eof = eof;
				bma.firstblock = *firstblock;
				bma.alen = alen;
				bma.off = aoff;
			bma.conv = !!(flags & XFS_BMAPI_CONVERT);
			bma.wasdel = wasdelay;
				bma.minlen = minlen;
				bma.low = flist->xbf_low;
			bma.alen = len;
			bma.off = bno;
			bma.minleft = minleft;
				/*
				 * Only want to do the alignment at the
				 * eof if it is userdata and allocation length
				 * is larger than a stripe unit.
				 */
				if (mp->m_dalign && alen >= mp->m_dalign &&
				    (!(flags & XFS_BMAPI_METADATA)) &&
				    (whichfork == XFS_DATA_FORK)) {
					if ((error = xfs_bmap_isaeof(ip, aoff,
							whichfork, &bma.aeof)))
						goto error0;
				} else
					bma.aeof = 0;
				/*
				 * Call allocator.
				 */
				if ((error = xfs_bmap_alloc(&bma)))
					goto error0;
				/*
				 * Copy out result fields.
				 */
				abno = bma.rval;
				if ((flist->xbf_low = bma.low))
					minleft = 0;
				alen = bma.alen;
				aoff = bma.off;
				ASSERT(*firstblock == NULLFSBLOCK ||
				       XFS_FSB_TO_AGNO(mp, *firstblock) ==
				       XFS_FSB_TO_AGNO(mp, bma.firstblock) ||
				       (flist->xbf_low &&
					XFS_FSB_TO_AGNO(mp, *firstblock) <
					XFS_FSB_TO_AGNO(mp, bma.firstblock)));
				*firstblock = bma.firstblock;
				if (cur)
					cur->bc_private.b.firstblock =
						*firstblock;
				if (abno == NULLFSBLOCK)
					break;
				if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
					cur = xfs_bmbt_init_cursor(mp, tp,
						ip, whichfork);
					cur->bc_private.b.firstblock =
						*firstblock;
					cur->bc_private.b.flist = flist;
				}
				/*
				 * Bump the number of extents we've allocated
				 * in this call.
				 */
				nallocs++;
			}
			if (cur)
				cur->bc_private.b.flags =
					wasdelay ? XFS_BTCUR_BPRV_WASDEL : 0;
			got.br_startoff = aoff;
			got.br_startblock = abno;
			got.br_blockcount = alen;
			got.br_state = XFS_EXT_NORM;	/* assume normal */
			/*
			 * Determine state of extent, and the filesystem.
			 * A wasdelay extent has been initialized, so
			 * shouldn't be flagged as unwritten.
			 */
			if (wr && xfs_sb_version_hasextflgbit(&mp->m_sb)) {
				if (!wasdelay && (flags & XFS_BMAPI_PREALLOC))
					got.br_state = XFS_EXT_UNWRITTEN;
			}
			error = xfs_bmap_add_extent(tp, ip, &lastx, &cur, &got,
				firstblock, flist, &tmp_logflags,
				whichfork);

			error = xfs_bmapi_allocate(&bma, &lastx, &cur,
					firstblock, flist, flags, &nallocs,
					&tmp_logflags);
			logflags |= tmp_logflags;
			if (error)
				goto error0;
			ep = xfs_iext_get_ext(ifp, lastx);
			xfs_bmbt_get_all(ep, &got);
			ASSERT(got.br_startoff <= aoff);
			ASSERT(got.br_startoff + got.br_blockcount >=
				aoff + alen);
			ASSERT(got.br_state == XFS_EXT_NORM ||
			       got.br_state == XFS_EXT_UNWRITTEN);
			/*
			 * Fall down into the found allocated space case.
			 */
			if (flist && flist->xbf_low)
				minleft = 0;
			if (bma.rval == NULLFSBLOCK)
				break;
		} else if (inhole) {
			/*
			 * Reading in a hole.