summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2022-07-14 11:05:33 -0700
committerDarrick J. Wong <djwong@kernel.org>2022-10-14 14:16:25 -0700
commitd5eae40277f697a55b50057f6d8301478dbf8d33 (patch)
tree182060028378099bd09349d0e61ece69e6588562
parent904ad989062d678ff24bb448226ba8b1ebbc02c7 (diff)
xfs: set the buffer type after holding the AG[IF] across trans_roll
Currently, the only way to lock an allocation group is to hold the AGI and AGF buffers. If repair needs to roll the transaction while repairing some AG metadata, it maintains that lock by holding the two buffers across the transaction roll and joins them afterwards. However, repair is not the same as the other parts of XFS that employ this bhold/bjoin sequence, because it's possible that the AGI or AGF buffers are not actually dirty before the roll. In this case, the buffer log item can detach from the buffer, which means that we have to re-set the buffer type in the bli after joining the buffer to the new transaction so that log recovery will know what to do if the fs fails. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
-rw-r--r--fs/xfs/scrub/repair.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
index 2ada7fc1c398..92c661b98892 100644
--- a/fs/xfs/scrub/repair.c
+++ b/fs/xfs/scrub/repair.c
@@ -138,11 +138,23 @@ xrep_roll_ag_trans(
if (error)
return error;
- /* Join AG headers to the new transaction. */
- if (sc->sa.agi_bp)
+ /*
+ * Join AG headers to the new transaction. The buffer log item can
+ * detach from the buffer across the transaction roll if the bli is
+ * clean, so ensure the buffer type is still set on the AG header
+ * buffers' blis before we return.
+ *
+ * Normal code would never hold a clean buffer across a roll, but scrub
+ * needs both buffers to maintain a total lock on the AG.
+ */
+ if (sc->sa.agi_bp) {
xfs_trans_bjoin(sc->tp, sc->sa.agi_bp);
- if (sc->sa.agf_bp)
+ xfs_trans_buf_set_type(sc->tp, sc->sa.agi_bp, XFS_BLFT_AGI_BUF);
+ }
+ if (sc->sa.agf_bp) {
xfs_trans_bjoin(sc->tp, sc->sa.agf_bp);
+ xfs_trans_buf_set_type(sc->tp, sc->sa.agf_bp, XFS_BLFT_AGF_BUF);
+ }
return 0;
}