summaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2012-07-04 10:54:50 -0400
committerBen Myers <bpm@sgi.com>2012-07-29 16:10:54 -0500
commitbe60fe54b216a62403b816d3930a66ad7c51cbc6 (patch)
tree20ae0c5de24e347a42f49a33802de67ff6ee4442 /fs/xfs
parent55d6af64cb8bf8c7e9a84b254d2c3479be8c067c (diff)
downloadlinux-be60fe54b216a62403b816d3930a66ad7c51cbc6.tar.gz
linux-be60fe54b216a62403b816d3930a66ad7c51cbc6.tar.bz2
linux-be60fe54b216a62403b816d3930a66ad7c51cbc6.zip
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: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Mark Tinguely <tinguely@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_ialloc.c127
1 files changed, 69 insertions, 58 deletions
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
index ecb9f22a7f35..21e37b55f7e5 100644
--- a/fs/xfs/xfs_ialloc.c
+++ b/fs/xfs/xfs_ialloc.c
@@ -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,67 +942,87 @@ xfs_dialloc(
* or in which we can allocate some inodes. Iterate through the
* allocation groups upward, wrapping at the end.
*/
- while (!agi->agi_freecount) {
- /*
- * Don't do anything if we're not supposed to allocate
- * any blocks, just go on to the next ag.
- */
- if (okalloc) {
- /*
- * Try to allocate some new inodes in the allocation
- * group.
- */
- if ((error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced))) {
- xfs_trans_brelse(tp, agbp);
- if (error == ENOSPC) {
- *inop = NULLFSINO;
- return 0;
- } else
- return error;
- }
- if (ialloced) {
- /*
- * We successfully allocated some inodes, return
- * the current context to the caller so that it
- * can commit the current transaction and call
- * us again where we left off.
- */
- ASSERT(be32_to_cpu(agi->agi_freecount) > 0);
- *IO_agbp = agbp;
- *inop = NULLFSINO;
- return 0;
- }
+ 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;
}
+
/*
- * If it failed, give up on this ag.
+ * Do a first racy fast path check if this AG is usable.
*/
- xfs_trans_brelse(tp, agbp);
+ if (!pag->pagi_freecount && !okalloc)
+ goto nextag;
+
+ error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
+ if (error)
+ goto out_error;
+
/*
- * Go on to the next ag: get its ag header.
+ * Once the AGI has been read in we have to recheck
+ * pagi_freecount with the AGI buffer lock held.
*/
-nextag:
- if (++tagno == mp->m_sb.sb_agcount)
- tagno = 0;
- if (tagno == agno) {
+ 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)
+ goto out_error;
+
+ xfs_perag_put(pag);
*inop = NULLFSINO;
- return noroom ? ENOSPC : 0;
+ return 0;
}
- pag = xfs_perag_get(mp, tagno);
- if (pag->pagi_inodeok == 0) {
+
+ if (ialloced) {
+ /*
+ * We successfully allocated some inodes, return
+ * the current context to the caller so that it
+ * can commit the current transaction and call
+ * us again where we left off.
+ */
+ ASSERT(pag->pagi_freecount > 0);
xfs_perag_put(pag);
- goto nextag;
+
+ *IO_agbp = agbp;
+ *inop = NULLFSINO;
+ return 0;
}
- error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp);
+
+nextag:
xfs_perag_put(pag);
- if (error)
- goto nextag;
- agi = XFS_BUF_TO_AGI(agbp);
- ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
+ if (++agno == mp->m_sb.sb_agcount)
+ agno = 0;
+ if (agno == start_agno) {
+ *inop = NULLFSINO;
+ return noroom ? ENOSPC : 0;
+ }
}
out_alloc:
*IO_agbp = NULL;
return xfs_dialloc_ag(tp, agbp, parent, inop);
+out_error:
+ xfs_perag_put(pag);
+ return XFS_ERROR(error);
}
/*