|
@@ -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);
|
|
|
|
|
|
/*
|