summaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_fsops.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_fsops.c')
-rw-r--r--fs/xfs/xfs_fsops.c74
1 files changed, 33 insertions, 41 deletions
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 391d1938a6c8..4b560caaf397 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -81,7 +81,8 @@ xfs_grow_ag_headers(
struct xfs_mount *mp,
xfs_agnumber_t agno,
xfs_extlen_t agsize,
- xfs_rfsblock_t *nfree)
+ xfs_rfsblock_t *nfree,
+ struct list_head *buffer_list)
{
struct xfs_agf *agf;
struct xfs_agi *agi;
@@ -135,11 +136,8 @@ xfs_grow_ag_headers(
agf->agf_refcount_level = cpu_to_be32(1);
agf->agf_refcount_blocks = cpu_to_be32(1);
}
-
- error = xfs_bwrite(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
- if (error)
- goto out_error;
/*
* AG freelist header block
@@ -164,10 +162,8 @@ xfs_grow_ag_headers(
for (bucket = 0; bucket < xfs_agfl_size(mp); bucket++)
agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK);
- error = xfs_bwrite(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
- if (error)
- goto out_error;
/*
* AG inode header block
@@ -201,10 +197,8 @@ xfs_grow_ag_headers(
for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
- error = xfs_bwrite(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
- if (error)
- goto out_error;
/*
* BNO btree root block
@@ -226,10 +220,8 @@ xfs_grow_ag_headers(
arec->ar_blockcount = cpu_to_be32(
agsize - be32_to_cpu(arec->ar_startblock));
- error = xfs_bwrite(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
- if (error)
- goto out_error;
/*
* CNT btree root block
@@ -251,10 +243,8 @@ xfs_grow_ag_headers(
agsize - be32_to_cpu(arec->ar_startblock));
*nfree += be32_to_cpu(arec->ar_blockcount);
- error = xfs_bwrite(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
- if (error)
- goto out_error;
/* RMAP btree root block */
if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
@@ -326,10 +316,8 @@ xfs_grow_ag_headers(
be16_add_cpu(&block->bb_numrecs, 1);
}
- error = xfs_bwrite(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
- if (error)
- goto out_error;
}
/*
@@ -345,11 +333,8 @@ xfs_grow_ag_headers(
}
xfs_btree_init_block(mp, bp, XFS_BTNUM_INO , 0, 0, agno, 0);
-
- error = xfs_bwrite(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
- if (error)
- goto out_error;
/*
* FINO btree root block
@@ -364,13 +349,9 @@ xfs_grow_ag_headers(
goto out_error;
}
- xfs_btree_init_block(mp, bp, XFS_BTNUM_FINO,
- 0, 0, agno, 0);
-
- error = xfs_bwrite(bp);
+ xfs_btree_init_block(mp, bp, XFS_BTNUM_FINO, 0, 0, agno, 0);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
- if (error)
- goto out_error;
}
/*
@@ -386,13 +367,9 @@ xfs_grow_ag_headers(
goto out_error;
}
- xfs_btree_init_block(mp, bp, XFS_BTNUM_REFC,
- 0, 0, agno, 0);
-
- error = xfs_bwrite(bp);
+ xfs_btree_init_block(mp, bp, XFS_BTNUM_REFC, 0, 0, agno, 0);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
- if (error)
- goto out_error;
}
out_error:
@@ -419,6 +396,7 @@ xfs_growfs_data_private(
xfs_agnumber_t oagcount;
int pct;
xfs_trans_t *tp;
+ LIST_HEAD (buffer_list);
nb = in->newblocks;
pct = in->imaxpct;
@@ -459,9 +437,16 @@ xfs_growfs_data_private(
return error;
/*
- * Write new AG headers to disk. Non-transactional, but written
- * synchronously so they are completed prior to the growfs transaction
- * being logged.
+ * Write new AG headers to disk. Non-transactional, but need to be
+ * written and completed prior to the growfs transaction being logged.
+ * To do this, we use a delayed write buffer list and wait for
+ * submission and IO completion of the list as a whole. This allows the
+ * IO subsystem to merge all the AG headers in a single AG into a single
+ * IO and hide most of the latency of the IO from us.
+ *
+ * This also means that if we get an error whilst building the buffer
+ * list to write, we can cancel the entire list without having written
+ * anything.
*/
nfree = 0;
for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) {
@@ -472,10 +457,17 @@ xfs_growfs_data_private(
else
agsize = mp->m_sb.sb_agblocks;
- error = xfs_grow_ag_headers(mp, agno, agsize, &nfree);
- if (error)
+ error = xfs_grow_ag_headers(mp, agno, agsize, &nfree,
+ &buffer_list);
+ if (error) {
+ xfs_buf_delwri_cancel(&buffer_list);
goto error0;
+ }
}
+ error = xfs_buf_delwri_submit(&buffer_list);
+ if (error)
+ goto error0;
+
xfs_trans_agblocks_delta(tp, nfree);
/*