提交 be60fe54 编写于 作者: C Christoph Hellwig 提交者: Ben Myers

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: NChristoph Hellwig <hch@lst.de>
Reviewed-by: NDave Chinner <dchinner@redhat.com>
Reviewed-by: NMark Tinguely <tinguely@sgi.com>
Signed-off-by: NBen Myers <bpm@sgi.com>
上级 55d6af64
...@@ -900,11 +900,10 @@ xfs_dialloc( ...@@ -900,11 +900,10 @@ xfs_dialloc(
struct xfs_mount *mp = tp->t_mountp; struct xfs_mount *mp = tp->t_mountp;
struct xfs_buf *agbp; struct xfs_buf *agbp;
xfs_agnumber_t agno; xfs_agnumber_t agno;
struct xfs_agi *agi;
int error; int error;
int ialloced; int ialloced;
int noroom = 0; int noroom = 0;
xfs_agnumber_t tagno; xfs_agnumber_t start_agno;
struct xfs_perag *pag; struct xfs_perag *pag;
if (*IO_agbp) { if (*IO_agbp) {
...@@ -921,25 +920,17 @@ xfs_dialloc( ...@@ -921,25 +920,17 @@ xfs_dialloc(
* We do not have an agbp, so select an initial allocation * We do not have an agbp, so select an initial allocation
* group for inode allocation. * group for inode allocation.
*/ */
agno = xfs_ialloc_ag_select(tp, parent, mode, okalloc); start_agno = xfs_ialloc_ag_select(tp, parent, mode, okalloc);
if (agno == NULLAGNUMBER) { if (start_agno == NULLAGNUMBER) {
*inop = NULLFSINO; *inop = NULLFSINO;
return 0; 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 * If we have already hit the ceiling of inode blocks then clear
* okalloc so we scan all available agi structures for a free * okalloc so we scan all available agi structures for a free
* inode. * inode.
*/ */
if (mp->m_maxicount && if (mp->m_maxicount &&
mp->m_sb.sb_icount + XFS_IALLOC_INODES(mp) > mp->m_maxicount) { mp->m_sb.sb_icount + XFS_IALLOC_INODES(mp) > mp->m_maxicount) {
noroom = 1; noroom = 1;
...@@ -951,24 +942,56 @@ xfs_dialloc( ...@@ -951,24 +942,56 @@ xfs_dialloc(
* or in which we can allocate some inodes. Iterate through the * or in which we can allocate some inodes. Iterate through the
* allocation groups upward, wrapping at the end. * 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 * Do a first racy fast path check if this AG is usable.
* any blocks, just go on to the next ag.
*/ */
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 * Once the AGI has been read in we have to recheck
* group. * 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); xfs_trans_brelse(tp, agbp);
if (error == ENOSPC) {
if (error != ENOSPC)
goto out_error;
xfs_perag_put(pag);
*inop = NULLFSINO; *inop = NULLFSINO;
return 0; return 0;
} else
return error;
} }
if (ialloced) { if (ialloced) {
/* /*
* We successfully allocated some inodes, return * We successfully allocated some inodes, return
...@@ -976,42 +999,30 @@ xfs_dialloc( ...@@ -976,42 +999,30 @@ xfs_dialloc(
* can commit the current transaction and call * can commit the current transaction and call
* us again where we left off. * 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; *IO_agbp = agbp;
*inop = NULLFSINO; *inop = NULLFSINO;
return 0; 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: nextag:
if (++tagno == mp->m_sb.sb_agcount) xfs_perag_put(pag);
tagno = 0; if (++agno == mp->m_sb.sb_agcount)
if (tagno == agno) { agno = 0;
if (agno == start_agno) {
*inop = NULLFSINO; *inop = NULLFSINO;
return noroom ? ENOSPC : 0; 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: out_alloc:
*IO_agbp = NULL; *IO_agbp = NULL;
return xfs_dialloc_ag(tp, agbp, parent, inop); return xfs_dialloc_ag(tp, agbp, parent, inop);
out_error:
xfs_perag_put(pag);
return XFS_ERROR(error);
} }
/* /*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册