From: Dave Chinner <dgc@kernel.org>
To: linux-xfs@vger.kernel.org
Cc: cem@kernel.org
Subject: [PATCH 14/48] xfs: validate the unmount record during recovery
Date: Tue, 13 Oct 2026 17:01:04 +1100 [thread overview]
Message-ID: <20261013060204.3138690-15-dgc@kernel.org> (raw)
In-Reply-To: <20261013060204.3138690-1-dgc@kernel.org>
The unmount record is the only record the log writes itself rather than
through a transaction, and the log item processing loop skips it, so its
contents were never validated on recovery even though a clean unmount is
detected by inspecting it during the head and tail scan.
Add xlog_recover_validate_unmount_record() to check the record is written by
the log, is the expected length, and carries the expected magic and zeroed
padding. Call it from the operation header validation, and route the head and
tail scan through the operation header validation as well so a corrupt
unmount record is detected there rather than being mistaken for a clean
unmount.
The unmount record length was incorrectly written as zero for a period of time.
A zero length record has no payload to check, so accept it with a warning so
that filesystems written by those kernels still recover.
Assisted-by: LLM
Signed-off-by: Dave Chinner <dgc@kernel.org>
---
fs/xfs/xfs_log_recover.c | 70 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 67 insertions(+), 3 deletions(-)
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 0ba3f4409d28..37b5dbc3b239 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -42,6 +42,8 @@ xlog_clear_stale_blocks(
STATIC int
xlog_do_recovery_pass(
struct xlog *, xfs_daddr_t, xfs_daddr_t, int, xfs_daddr_t *);
+STATIC struct xlog_op_header *
+xlog_recover_validate_ophdr(struct xlog *log, char *dp, char *end);
/*
* Sector aligned buffer routines for buffer create/read/write/access
@@ -1169,8 +1171,11 @@ xlog_check_unmount_rec(
if (error)
return error;
- op_head = (struct xlog_op_header *)offset;
- if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) {
+ op_head = xlog_recover_validate_ophdr(log, offset,
+ offset + BBSIZE);
+ if (IS_ERR(op_head))
+ return PTR_ERR(op_head);
+ if (op_head->oh_flags == XLOG_UNMOUNT_TRANS) {
/*
* Set tail and last sync so that newly written log
* records will point recovery to after the current
@@ -2636,6 +2641,60 @@ xlog_recover_ophdr_to_trans(
return NULL;
}
+/*
+ * Validate an unmount record. The unmount record is the only record written by
+ * the log itself rather than by a transaction, and the log item processing loop
+ * skips it, so it can only be validated here. It is a single fixed size region,
+ * written by the log with the XFS_LOG clientid, containing an unmount format
+ * structure with a known magic number and zeroed padding.
+ *
+ * The ophdr has already been validated, so oh_len is known to be within the
+ * record. The unmount format length was incorrectly written for a period of
+ * time as zero rather than the region length. Such a record has no payload to
+ * read, so accept it with a warning and stop, so that filesystems written by
+ * those kernels still recover.
+ */
+STATIC int
+xlog_recover_validate_unmount_record(
+ struct xlog *log,
+ struct xlog_op_header *ohead)
+{
+ struct xfs_unmount_log_format *ulf;
+ unsigned int len = be32_to_cpu(ohead->oh_len);
+
+ if (ohead->oh_clientid != XFS_LOG) {
+ xfs_warn(log->l_mp, "%s: bad unmount clientid 0x%x",
+ __func__, ohead->oh_clientid);
+ return -EFSCORRUPTED;
+ }
+
+ if (len == 0) {
+ xfs_warn(log->l_mp,
+ "%s: zero length unmount record recovered.", __func__);
+ return 0;
+ }
+
+ if (len != sizeof(*ulf)) {
+ xfs_warn(log->l_mp, "%s: bad unmount record length 0x%x",
+ __func__, len);
+ return -EFSCORRUPTED;
+ }
+
+ ulf = (struct xfs_unmount_log_format *)(ohead + 1);
+ if (ulf->magic != XLOG_UNMOUNT_TYPE) {
+ xfs_warn(log->l_mp, "%s: bad unmount magic 0x%x, expected 0x%x",
+ __func__, ulf->magic, XLOG_UNMOUNT_TYPE);
+ return -EFSCORRUPTED;
+ }
+
+ if (ulf->pad1 != 0 || ulf->pad2 != 0) {
+ xfs_warn(log->l_mp, "%s: bad unmount padding", __func__);
+ return -EFSCORRUPTED;
+ }
+
+ return 0;
+}
+
/*
* Decode and validate an operation header from the journal. dp points at the
* ophdr within the log record and end is the end of the record data. The ophdr
@@ -2653,6 +2712,7 @@ xlog_recover_validate_ophdr(
{
struct xlog_op_header *ohead;
unsigned int len;
+ int error;
/*
* All log regions are 32 bit aligned, so the ophdr must be too. A
@@ -2736,11 +2796,15 @@ xlog_recover_validate_ophdr(
return ERR_PTR(-EFSCORRUPTED);
}
break;
+ case XLOG_UNMOUNT_TRANS:
+ error = xlog_recover_validate_unmount_record(log, ohead);
+ if (error)
+ return ERR_PTR(error);
+ break;
case 0:
case XLOG_CONTINUE_TRANS:
case XLOG_WAS_CONT_TRANS | XLOG_CONTINUE_TRANS:
case XLOG_WAS_CONT_TRANS | XLOG_END_TRANS:
- case XLOG_UNMOUNT_TRANS:
break;
default:
xfs_warn(log->l_mp, "%s: bad flags 0x%x",
--
2.55.0
next prev parent reply other threads:[~2026-10-13 6:02 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-13 6:00 [RFC] [PATCH 00/48] Validate journal log items during log recovery Dave Chinner
2026-10-13 6:00 ` [PATCH 01/48] xfs: set the unmount record operation header length Dave Chinner
2026-10-13 6:00 ` [PATCH 02/48] xfs: add log recovery item validation design document Dave Chinner
2026-10-13 6:00 ` [PATCH 03/48] xfs: lift transaction header parsing out of the region assembly Dave Chinner
2026-10-13 6:00 ` [PATCH 04/48] xfs: track transaction header decode state explicitly Dave Chinner
2026-10-13 6:00 ` [PATCH 05/48] xfs: track the log item being rebuilt with an explicit pointer Dave Chinner
2026-10-13 6:00 ` [PATCH 06/48] xfs: complete log items explicitly during recovery Dave Chinner
2026-10-13 6:00 ` [PATCH 07/48] xfs: add log item validation infrastructure to log recovery Dave Chinner
2026-10-13 6:00 ` [PATCH 08/48] xfs: recover the transaction header as a validated item type Dave Chinner
2026-10-13 6:00 ` [PATCH 09/48] xfs: factor out xlog_recover_validate_ophdr() Dave Chinner
2026-10-13 6:01 ` [PATCH 10/48] xfs: validate operation header length and alignment during recovery Dave Chinner
2026-10-13 6:01 ` [PATCH 11/48] xfs: validate the operation header padding " Dave Chinner
2026-10-13 6:01 ` [PATCH 12/48] xfs: validate the operation header flags " Dave Chinner
2026-10-13 6:01 ` [PATCH 13/48] xfs: enforce zero length control records " Dave Chinner
2026-10-13 6:01 ` Dave Chinner [this message]
2026-10-13 6:01 ` [PATCH 15/48] xfs: handle zero length continuation op headers " Dave Chinner
2026-10-13 6:01 ` [PATCH 16/48] xfs: bound the assembled region size " Dave Chinner
2026-10-13 6:01 ` [PATCH 17/48] xfs: dump the corrupt region when log item validation fails Dave Chinner
2026-10-13 6:01 ` [PATCH 18/48] xfs: validate fixed size log items during recovery Dave Chinner
2026-10-13 6:01 ` [PATCH 19/48] xfs: validate extent free " Dave Chinner
2026-10-13 6:01 ` [PATCH 20/48] xfs: validate and convert extent free intents " Dave Chinner
2026-10-13 6:01 ` [PATCH 21/48] xfs: validate and convert extent free done items " Dave Chinner
2026-10-13 6:01 ` [PATCH 22/48] xfs: validate rmap update intents " Dave Chinner
2026-10-13 6:01 ` [PATCH 23/48] xfs: validate rmap update done items " Dave Chinner
2026-10-13 6:01 ` [PATCH 24/48] xfs: validate refcount update intents " Dave Chinner
2026-10-13 6:01 ` [PATCH 25/48] xfs: validate refcount update done items " Dave Chinner
2026-10-13 6:01 ` [PATCH 26/48] xfs: validate bmap update intents " Dave Chinner
2026-10-13 6:01 ` [PATCH 27/48] xfs: validate bmap update done items " Dave Chinner
2026-10-13 6:01 ` [PATCH 28/48] xfs: validate mapping exchange intents " Dave Chinner
2026-10-13 6:01 ` [PATCH 29/48] xfs: validate mapping exchange done items " Dave Chinner
2026-10-13 6:01 ` [PATCH 30/48] xfs: validate dquot " Dave Chinner
2026-10-13 6:01 ` [PATCH 31/48] xfs: validate attr done " Dave Chinner
2026-10-13 6:01 ` [PATCH 32/48] xfs: validate attr intents " Dave Chinner
2026-10-13 6:01 ` [PATCH 33/48] xfs: convert inode items to host format " Dave Chinner
2026-10-13 6:01 ` [PATCH 34/48] xfs: allow xfs_imap() to map without an inode btree lookup Dave Chinner
2026-10-13 6:01 ` [PATCH 35/48] xfs: validate the inode item format header during recovery Dave Chinner
2026-10-13 6:01 ` [PATCH 36/48] xfs: validate the logged inode core " Dave Chinner
2026-10-13 6:01 ` [PATCH 37/48] xfs: validate the logged inode forks " Dave Chinner
2026-10-13 6:01 ` [PATCH 38/48] xfs: validate logged local fork contents " Dave Chinner
2026-10-13 6:01 ` [PATCH 39/48] xfs: validate logged extent " Dave Chinner
2026-10-13 6:01 ` [PATCH 40/48] xfs: allow a long format btree root to be checked without a cursor Dave Chinner
2026-10-13 6:01 ` [PATCH 41/48] xfs: validate logged btree fork roots during recovery Dave Chinner
2026-10-13 6:01 ` [PATCH 42/48] xfs: validate logged metadata " Dave Chinner
2026-10-13 6:01 ` [PATCH 43/48] xfs: validate buffer item region count " Dave Chinner
2026-10-13 6:01 ` [PATCH 44/48] xfs: validate buffer item regions " Dave Chinner
2026-10-13 6:01 ` [PATCH 45/48] xfs: validate the whole buffer item " Dave Chinner
2026-10-13 6:01 ` [PATCH 46/48] xfs: remove redundant buffer checks from recovery replay Dave Chinner
2026-10-13 6:01 ` [PATCH 47/48] xfs: fail recovery on a buffer type mismatch Dave Chinner
2026-10-13 6:01 ` [PATCH 48/48] xfs: validate logged dquot buffers during recovery Dave Chinner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261013060204.3138690-15-dgc@kernel.org \
--to=dgc@kernel.org \
--cc=cem@kernel.org \
--cc=linux-xfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.