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

Commit be60fe54 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Ben Myers
Browse files

xfs: do not read the AGI buffer in xfs_dialloc until nessecary



Refactor the AG selection loop in xfs_dialloc to operate on the in-memory
perag data as much as possible.  We only read the AGI buffer once we have
selected an AG to allocate inodes now instead of for every AG considered.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarMark Tinguely <tinguely@sgi.com>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent 55d6af64
Loading
Loading
Loading
Loading
+69 −58
Original line number Diff line number Diff line
@@ -900,11 +900,10 @@ xfs_dialloc(
	struct xfs_mount	*mp = tp->t_mountp;
	struct xfs_buf		*agbp;
	xfs_agnumber_t		agno;
	struct xfs_agi		*agi;
	int			error;
	int			ialloced;
	int			noroom = 0;
	xfs_agnumber_t		tagno;
	xfs_agnumber_t		start_agno;
	struct xfs_perag	*pag;

	if (*IO_agbp) {
@@ -921,25 +920,17 @@ xfs_dialloc(
	 * We do not have an agbp, so select an initial allocation
	 * group for inode allocation.
	 */
	agno = xfs_ialloc_ag_select(tp, parent, mode, okalloc);
	if (agno == NULLAGNUMBER) {
	start_agno = xfs_ialloc_ag_select(tp, parent, mode, okalloc);
	if (start_agno == NULLAGNUMBER) {
		*inop = NULLFSINO;
		return 0;
	}

	error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
	if (error)
		return XFS_ERROR(error);
	agi = XFS_BUF_TO_AGI(agbp);

	tagno = agno;

	/*
	 * If we have already hit the ceiling of inode blocks then clear
	 * okalloc so we scan all available agi structures for a free
	 * inode.
	 */

	if (mp->m_maxicount &&
	    mp->m_sb.sb_icount + XFS_IALLOC_INODES(mp) > mp->m_maxicount) {
		noroom = 1;
@@ -951,24 +942,56 @@ xfs_dialloc(
	 * or in which we can allocate some inodes.  Iterate through the
	 * allocation groups upward, wrapping at the end.
	 */
	while (!agi->agi_freecount) {
	agno = start_agno;
	for (;;) {
		pag = xfs_perag_get(mp, agno);
		if (!pag->pagi_inodeok) {
			xfs_ialloc_next_ag(mp);
			goto nextag;
		}

		if (!pag->pagi_init) {
			error = xfs_ialloc_pagi_init(mp, tp, agno);
			if (error)
				goto out_error;
		}

		/*
		 * Don't do anything if we're not supposed to allocate
		 * any blocks, just go on to the next ag.
		 * Do a first racy fast path check if this AG is usable.
		 */
		if (okalloc) {
		if (!pag->pagi_freecount && !okalloc)
			goto nextag;

		error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
		if (error)
			goto out_error;

		/*
			 * Try to allocate some new inodes in the allocation
			 * group.
		 * Once the AGI has been read in we have to recheck
		 * pagi_freecount with the AGI buffer lock held.
		 */
			if ((error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced))) {
		if (pag->pagi_freecount) {
			xfs_perag_put(pag);
			goto out_alloc;
		}

		if (!okalloc) {
			xfs_trans_brelse(tp, agbp);
			goto nextag;
		}

		error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced);
		if (error) {
			xfs_trans_brelse(tp, agbp);
				if (error == ENOSPC) {

			if (error != ENOSPC)
				goto out_error;

			xfs_perag_put(pag);
			*inop = NULLFSINO;
			return 0;
				} else
					return error;
		}

		if (ialloced) {
			/*
			 * We successfully allocated some inodes, return
@@ -976,42 +999,30 @@ xfs_dialloc(
			 * can commit the current transaction and call
			 * us again where we left off.
			 */
				ASSERT(be32_to_cpu(agi->agi_freecount) > 0);
			ASSERT(pag->pagi_freecount > 0);
			xfs_perag_put(pag);

			*IO_agbp = agbp;
			*inop = NULLFSINO;
			return 0;
		}
		}
		/*
		 * If it failed, give up on this ag.
		 */
		xfs_trans_brelse(tp, agbp);
		/*
		 * Go on to the next ag: get its ag header.
		 */

nextag:
		if (++tagno == mp->m_sb.sb_agcount)
			tagno = 0;
		if (tagno == agno) {
		xfs_perag_put(pag);
		if (++agno == mp->m_sb.sb_agcount)
			agno = 0;
		if (agno == start_agno) {
			*inop = NULLFSINO;
			return noroom ? ENOSPC : 0;
		}
		pag = xfs_perag_get(mp, tagno);
		if (pag->pagi_inodeok == 0) {
			xfs_perag_put(pag);
			goto nextag;
		}
		error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp);
		xfs_perag_put(pag);
		if (error)
			goto nextag;
		agi = XFS_BUF_TO_AGI(agbp);
		ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
	}

out_alloc:
	*IO_agbp = NULL;
	return xfs_dialloc_ag(tp, agbp, parent, inop);
out_error:
	xfs_perag_put(pag);
	return XFS_ERROR(error);
}

/*