[PATCH 5/6] xfs: adjust datadev sector count to reflect internal rt volumes

"Darrick J. Wong" <[email protected]> Wed, 29 Jul 2026 22:27:20 -0700
Newsgroups org.kernel.vger.linux-xfs,org.kernel.vger.stable
Message-ID <178538912986.4070956.14205556423461124701.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <[email protected]>

A media scan of a filesystem containing an internal rt volume produced
an error in xfs_scrub phase 6 complaining about a truncated realtime
device.  The rt device wasn't truncated, but the media scan code thought
we were trying to start a scan past the end of m_rtdev_targp.  That in
turn is an alias for m_ddev_targp, but in xfs_configure_buftarg we set
nr_sectors to the size of the data section.  Oops.

On these filesystems, the internal rt section comes immediately after
the data section.  We need to set the sector count for the data device
buftarg to the size of both sections.  Without this, media scans don't
work and media failure notifications from the kernel will be discarded
silently.

We also need to fix the superblock buffer recovery code to do the same.

Cc: <[email protected]> # v6.15
Fixes: bdc03eb5f98f6f ("xfs: allow internal RT devices for zoned mode")
Signed-off-by: "Darrick J. Wong" <[email protected]>
---
 fs/xfs/xfs_buf_item_recover.c |   12 ++++++++++--
 fs/xfs/xfs_super.c            |   11 ++++++++++-
 2 files changed, 20 insertions(+), 3 deletions(-)


diff --git a/fs/xfs/xfs_buf_item_recover.c b/fs/xfs/xfs_buf_item_recover.c
index 02b95b89d1b597..140b1c16ea15c3 100644
--- a/fs/xfs/xfs_buf_item_recover.c
+++ b/fs/xfs/xfs_buf_item_recover.c
@@ -720,6 +720,7 @@ xlog_recover_do_primary_sb_buffer(
 	xfs_lsn_t			current_lsn)
 {
 	struct xfs_dsb			*dsb = bp->b_addr;
+	xfs_rfsblock_t			dblocks;
 	xfs_agnumber_t			orig_agcount = mp->m_sb.sb_agcount;
 	xfs_rgnumber_t			orig_rgcount = mp->m_sb.sb_rgcount;
 	int				error;
@@ -738,9 +739,16 @@ xlog_recover_do_primary_sb_buffer(
 
 	/*
 	 * Grow can change the device size.  Mirror that into the buftarg.
+	 *
+	 * Internal rt volumes are placed immediately after the data device,
+	 * so set the buftarg sector count to the end of the rt volume so that
+	 * we can do media scans and handle media failure reports.
 	 */
-	mp->m_ddev_targp->bt_nr_sectors =
-		XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
+	if (mp->m_sb.sb_rtstart)
+		dblocks = mp->m_sb.sb_rtstart + mp->m_sb.sb_rblocks;
+	else
+		dblocks = mp->m_sb.sb_dblocks;
+	mp->m_ddev_targp->bt_nr_sectors = XFS_FSB_TO_BB(mp, dblocks);
 	if (mp->m_rtdev_targp && mp->m_rtdev_targp != mp->m_ddev_targp) {
 		mp->m_rtdev_targp->bt_nr_sectors =
 			XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 8531d526fc4409..9898cd9db0ada6 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -555,10 +555,19 @@ STATIC int
 xfs_setup_devices(
 	struct xfs_mount	*mp)
 {
+	xfs_rfsblock_t		dblocks = mp->m_sb.sb_dblocks;
 	int			error;
 
+	/*
+	 * Internal rt volumes are placed immediately after the data device,
+	 * so set the buftarg sector count to the end of the rt volume so that
+	 * we can do media scans and handle media failure reports.
+	 */
+	if (mp->m_sb.sb_rtstart)
+		dblocks = mp->m_sb.sb_rtstart + mp->m_sb.sb_rblocks;
+
 	error = xfs_configure_buftarg(mp->m_ddev_targp, mp->m_sb.sb_sectsize,
-			mp->m_sb.sb_dblocks);
+			dblocks);
 	if (error)
 		return error;