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

xfs: merge filestream AG lookup into xfs_filestream_select_ag()



The lookup currently either returns the cached filestream AG or it
calls xfs_filestreams_select_lengths() to looks up a new AG. This
has verify the AG that is selected, so we end up doing "select a new
AG loop in a couple of places when only one really is needed.  Merge
the initial lookup functionality with the length selection so that
we only need to do a single pick loop on lookup or verification
failure.

This undoes a lot of the factoring that enabled the selection to be
moved over to the filestreams code. It makes
xfs_filestream_select_ag() an awful messier, but it has to be made
worse before it can get better in future patches...

Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
parent 8f7747ad
Loading
Loading
Loading
Loading
+70 −114
Original line number Diff line number Diff line
@@ -258,55 +258,6 @@ xfs_filestream_get_parent(
	return dir ? XFS_I(dir) : NULL;
}

/*
 * Find the right allocation group for a file, either by finding an
 * existing file stream or creating a new one.
 *
 * Returns NULLAGNUMBER in case of an error.
 */
static xfs_agnumber_t
xfs_filestream_lookup_ag(
	struct xfs_inode	*ip)
{
	struct xfs_mount	*mp = ip->i_mount;
	struct xfs_inode	*pip = NULL;
	xfs_agnumber_t		startag, ag = NULLAGNUMBER;
	struct xfs_mru_cache_elem *mru;

	ASSERT(S_ISREG(VFS_I(ip)->i_mode));

	pip = xfs_filestream_get_parent(ip);
	if (!pip)
		return NULLAGNUMBER;

	mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
	if (mru) {
		ag = container_of(mru, struct xfs_fstrm_item, mru)->ag;
		xfs_mru_cache_done(mp->m_filestream);

		trace_xfs_filestream_lookup(mp, ip->i_ino, ag);
		goto out;
	}

	/*
	 * Set the starting AG using the rotor for inode32, otherwise
	 * use the directory inode's AG.
	 */
	if (xfs_is_inode32(mp)) {
		xfs_agnumber_t	 rotorstep = xfs_rotorstep;
		startag = (mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount;
		mp->m_agfrotor = (mp->m_agfrotor + 1) %
		                 (mp->m_sb.sb_agcount * rotorstep);
	} else
		startag = XFS_INO_TO_AGNO(mp, pip->i_ino);

	if (xfs_filestream_pick_ag(pip, startag, &ag, 0, 0))
		ag = NULLAGNUMBER;
out:
	xfs_irele(pip);
	return ag;
}

/*
 * Pick a new allocation group for the current file and its file stream.
 *
@@ -359,24 +310,45 @@ xfs_filestream_new_ag(
	return err;
}

static int
xfs_filestreams_select_lengths(
/*
 * Search for an allocation group with a single extent large enough for
 * the request.  If one isn't found, then the largest available free extent is
 * returned as the best length possible.
 */
int
xfs_filestream_select_ag(
	struct xfs_bmalloca	*ap,
	struct xfs_alloc_arg	*args,
	xfs_extlen_t		*blen)
{
	struct xfs_mount	*mp = ap->ip->i_mount;
	struct xfs_perag	*pag;
	xfs_agnumber_t		start_agno;
	struct xfs_inode	*pip = NULL;
	xfs_agnumber_t		agno = NULLAGNUMBER;
	struct xfs_mru_cache_elem *mru;
	int			error;

	args->total = ap->total;
	*blen = 0;

	pip = xfs_filestream_get_parent(ap->ip);
	if (!pip) {
		agno = 0;
		goto new_ag;
	}

	start_agno = XFS_FSB_TO_AGNO(mp, ap->blkno);
	if (start_agno == NULLAGNUMBER)
		start_agno = 0;
	mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
	if (mru) {
		agno = container_of(mru, struct xfs_fstrm_item, mru)->ag;
		xfs_mru_cache_done(mp->m_filestream);

	pag = xfs_perag_grab(mp, start_agno);
		trace_xfs_filestream_lookup(mp, ap->ip->i_ino, agno);
		xfs_irele(pip);

		ap->blkno = XFS_AGB_TO_FSB(args->mp, agno, 0);
		xfs_bmap_adjacent(ap);

		pag = xfs_perag_grab(mp, agno);
		if (pag) {
			error = xfs_bmap_longest_free_extent(pag, args->tp, blen);
			xfs_perag_rele(pag);
@@ -386,15 +358,39 @@ xfs_filestreams_select_lengths(
				*blen = 0;
			}
		}
		if (*blen >= args->maxlen)
			goto out_select;
	} else if (xfs_is_inode32(mp)) {
		xfs_agnumber_t	 rotorstep = xfs_rotorstep;
		agno = (mp->m_agfrotor / rotorstep) %
				mp->m_sb.sb_agcount;
		mp->m_agfrotor = (mp->m_agfrotor + 1) %
				 (mp->m_sb.sb_agcount * rotorstep);
		xfs_irele(pip);
	} else {
		agno = XFS_INO_TO_AGNO(mp, pip->i_ino);
		xfs_irele(pip);
	}

	if (*blen < args->maxlen) {
		xfs_agnumber_t	agno = start_agno;
new_ag:
	ap->blkno = XFS_AGB_TO_FSB(args->mp, agno, 0);
	xfs_bmap_adjacent(ap);

	/*
	 * If there is very little free space before we start a filestreams
	 * allocation, we're almost guaranteed to fail to find a better AG with
	 * larger free space available so we don't even try.
	 */
	if (ap->tp->t_flags & XFS_TRANS_LOWMODE)
		return 0;

	error = xfs_filestream_new_ag(ap, &agno);
	if (error)
		return error;
		if (agno == NULLAGNUMBER)
	if (agno == NULLAGNUMBER) {
		agno = 0;
		goto out_select;
	}

	pag = xfs_perag_grab(mp, agno);
	if (!pag)
@@ -407,52 +403,12 @@ xfs_filestreams_select_lengths(
			return error;
		*blen = 0;
	}
		start_agno = agno;
	}

out_select:
	/*
	 * Set the failure fallback case to look in the selected AG as stream
	 * may have moved.
	 */
	ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, start_agno, 0);
	ap->blkno = XFS_AGB_TO_FSB(mp, agno, 0);
	return 0;
}

/*
 * Search for an allocation group with a single extent large enough for
 * the request.  If one isn't found, then the largest available free extent is
 * returned as the best length possible.
 */
int
xfs_filestream_select_ag(
	struct xfs_bmalloca	*ap,
	struct xfs_alloc_arg	*args,
	xfs_extlen_t		*blen)
{
	xfs_agnumber_t		start_agno = xfs_filestream_lookup_ag(ap->ip);

	/* Determine the initial block number we will target for allocation. */
	if (start_agno == NULLAGNUMBER)
		start_agno = 0;
	ap->blkno = XFS_AGB_TO_FSB(args->mp, start_agno, 0);
	xfs_bmap_adjacent(ap);

	/*
	 * If there is very little free space before we start a filestreams
	 * allocation, we're almost guaranteed to fail to find a better AG with
	 * larger free space available so we don't even try.
	 */
	if (ap->tp->t_flags & XFS_TRANS_LOWMODE)
		return 0;

	/*
	 * Search for an allocation group with a single extent large enough for
	 * the request.  If one isn't found, then adjust the minimum allocation
	 * size to the largest space found.
	 */
	return xfs_filestreams_select_lengths(ap, args, blen);
}

void
xfs_filestream_deassociate(