]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
xfs: track the number of blocks in each buftarg
authorChristoph Hellwig <hch@lst.de>
Fri, 19 Sep 2025 13:12:08 +0000 (06:12 -0700)
committerCarlos Maiolino <cem@kernel.org>
Mon, 22 Sep 2025 10:55:20 +0000 (12:55 +0200)
Add a bt_nr_sectors to track the number of sector in each buftarg, and
replace the check that hard codes sb_dblock in xfs_buf_map_verify with
this new value so that it is correct for non-ddev buftargs.  The
RT buftarg only has a superblock in the first block, so it is unlikely
to trigger this, or are we likely to ever have enough blocks in the
in-memory buftargs, but we might as well get the check right.

Fixes: 10616b806d1d ("xfs: fix _xfs_buf_find oops on blocks beyond the filesystem end")
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_buf_item_recover.c
fs/xfs/xfs_super.c
fs/xfs/xfs_trans.c

index 8360e77b3215ddc8e073cff8c37b8ca95eed19f0..773d959965dc29420c71147538b82dd6f69eaa83 100644 (file)
@@ -387,8 +387,6 @@ xfs_buf_map_verify(
        struct xfs_buftarg      *btp,
        struct xfs_buf_map      *map)
 {
-       xfs_daddr_t             eofs;
-
        /* Check for IOs smaller than the sector size / not sector aligned */
        ASSERT(!(BBTOB(map->bm_len) < btp->bt_meta_sectorsize));
        ASSERT(!(BBTOB(map->bm_bn) & (xfs_off_t)btp->bt_meta_sectormask));
@@ -397,11 +395,10 @@ xfs_buf_map_verify(
         * Corrupted block numbers can get through to here, unfortunately, so we
         * have to check that the buffer falls within the filesystem bounds.
         */
-       eofs = XFS_FSB_TO_BB(btp->bt_mount, btp->bt_mount->m_sb.sb_dblocks);
-       if (map->bm_bn < 0 || map->bm_bn >= eofs) {
+       if (map->bm_bn < 0 || map->bm_bn >= btp->bt_nr_sectors) {
                xfs_alert(btp->bt_mount,
                          "%s: daddr 0x%llx out of range, EOFS 0x%llx",
-                         __func__, map->bm_bn, eofs);
+                         __func__, map->bm_bn, btp->bt_nr_sectors);
                WARN_ON(1);
                return -EFSCORRUPTED;
        }
@@ -1720,26 +1717,30 @@ xfs_configure_buftarg_atomic_writes(
 int
 xfs_configure_buftarg(
        struct xfs_buftarg      *btp,
-       unsigned int            sectorsize)
+       unsigned int            sectorsize,
+       xfs_rfsblock_t          nr_blocks)
 {
-       int                     error;
+       struct xfs_mount        *mp = btp->bt_mount;
 
-       ASSERT(btp->bt_bdev != NULL);
+       if (btp->bt_bdev) {
+               int             error;
 
-       /* Set up metadata sector size info */
-       btp->bt_meta_sectorsize = sectorsize;
-       btp->bt_meta_sectormask = sectorsize - 1;
+               error = bdev_validate_blocksize(btp->bt_bdev, sectorsize);
+               if (error) {
+                       xfs_warn(mp,
+                               "Cannot use blocksize %u on device %pg, err %d",
+                               sectorsize, btp->bt_bdev, error);
+                       return -EINVAL;
+               }
 
-       error = bdev_validate_blocksize(btp->bt_bdev, sectorsize);
-       if (error) {
-               xfs_warn(btp->bt_mount,
-                       "Cannot use blocksize %u on device %pg, err %d",
-                       sectorsize, btp->bt_bdev, error);
-               return -EINVAL;
+               if (bdev_can_atomic_write(btp->bt_bdev))
+                       xfs_configure_buftarg_atomic_writes(btp);
        }
 
-       if (bdev_can_atomic_write(btp->bt_bdev))
-               xfs_configure_buftarg_atomic_writes(btp);
+       btp->bt_meta_sectorsize = sectorsize;
+       btp->bt_meta_sectormask = sectorsize - 1;
+       /* m_blkbb_log is not set up yet */
+       btp->bt_nr_sectors = nr_blocks << (mp->m_sb.sb_blocklog - BBSHIFT);
        return 0;
 }
 
@@ -1749,6 +1750,9 @@ xfs_init_buftarg(
        size_t                          logical_sectorsize,
        const char                      *descr)
 {
+       /* The maximum size of the buftarg is only known once the sb is read. */
+       btp->bt_nr_sectors = (xfs_daddr_t)-1;
+
        /* Set up device logical sector size mask */
        btp->bt_logical_sectorsize = logical_sectorsize;
        btp->bt_logical_sectormask = logical_sectorsize - 1;
index b269e115d9ace0f3c08ed30952b1d039a4d8536f..8fa7bdf59c911015f7879673d1bbe2e21f40fb0d 100644 (file)
@@ -103,6 +103,7 @@ struct xfs_buftarg {
        size_t                  bt_meta_sectormask;
        size_t                  bt_logical_sectorsize;
        size_t                  bt_logical_sectormask;
+       xfs_daddr_t             bt_nr_sectors;
 
        /* LRU control structures */
        struct shrinker         *bt_shrinker;
@@ -372,7 +373,8 @@ struct xfs_buftarg *xfs_alloc_buftarg(struct xfs_mount *mp,
 extern void xfs_free_buftarg(struct xfs_buftarg *);
 extern void xfs_buftarg_wait(struct xfs_buftarg *);
 extern void xfs_buftarg_drain(struct xfs_buftarg *);
-int xfs_configure_buftarg(struct xfs_buftarg *btp, unsigned int sectorsize);
+int xfs_configure_buftarg(struct xfs_buftarg *btp, unsigned int sectorsize,
+               xfs_fsblock_t nr_blocks);
 
 #define xfs_readonly_buftarg(buftarg)  bdev_read_only((buftarg)->bt_bdev)
 
index 5d58e2ae4972da2bfdbdc1b4f34645ff5cb1b264..e4c8af873632436470b13bab0cb7be25251ad35b 100644 (file)
@@ -736,6 +736,16 @@ xlog_recover_do_primary_sb_buffer(
         */
        xfs_sb_from_disk(&mp->m_sb, dsb);
 
+       /*
+        * Grow can change the device size.  Mirror that into the buftarg.
+        */
+       mp->m_ddev_targp->bt_nr_sectors =
+               XFS_FSB_TO_BB(mp, mp->m_sb.sb_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);
+       }
+
        if (mp->m_sb.sb_agcount < orig_agcount) {
                xfs_alert(mp, "Shrinking AG count in log recovery not supported");
                return -EFSCORRUPTED;
index 77acb3e5a4eca18b1e6cfdc4cffd94c935faea3c..9e759c5b1096ff5e62be9614509ca195139f9b47 100644 (file)
@@ -535,7 +535,8 @@ xfs_setup_devices(
 {
        int                     error;
 
-       error = xfs_configure_buftarg(mp->m_ddev_targp, mp->m_sb.sb_sectsize);
+       error = xfs_configure_buftarg(mp->m_ddev_targp, mp->m_sb.sb_sectsize,
+                       mp->m_sb.sb_dblocks);
        if (error)
                return error;
 
@@ -545,7 +546,7 @@ xfs_setup_devices(
                if (xfs_has_sector(mp))
                        log_sector_size = mp->m_sb.sb_logsectsize;
                error = xfs_configure_buftarg(mp->m_logdev_targp,
-                                           log_sector_size);
+                               log_sector_size, mp->m_sb.sb_logblocks);
                if (error)
                        return error;
        }
@@ -559,7 +560,7 @@ xfs_setup_devices(
                mp->m_rtdev_targp = mp->m_ddev_targp;
        } else if (mp->m_rtname) {
                error = xfs_configure_buftarg(mp->m_rtdev_targp,
-                                           mp->m_sb.sb_sectsize);
+                               mp->m_sb.sb_sectsize, mp->m_sb.sb_rblocks);
                if (error)
                        return error;
        }
index 575e7028f423a8892d458f607d6d64fd6b1bb8e9..474f5a04ec6367dc4094f433d0b5bd602a7ff8ff 100644 (file)
@@ -452,19 +452,17 @@ xfs_trans_mod_sb(
  */
 STATIC void
 xfs_trans_apply_sb_deltas(
-       xfs_trans_t     *tp)
+       struct xfs_trans        *tp)
 {
-       struct xfs_dsb  *sbp;
-       struct xfs_buf  *bp;
-       int             whole = 0;
-
-       bp = xfs_trans_getsb(tp);
-       sbp = bp->b_addr;
+       struct xfs_mount        *mp = tp->t_mountp;
+       struct xfs_buf          *bp = xfs_trans_getsb(tp);
+       struct xfs_dsb          *sbp = bp->b_addr;
+       int                     whole = 0;
 
        /*
         * Only update the superblock counters if we are logging them
         */
-       if (!xfs_has_lazysbcount((tp->t_mountp))) {
+       if (!xfs_has_lazysbcount(mp)) {
                if (tp->t_icount_delta)
                        be64_add_cpu(&sbp->sb_icount, tp->t_icount_delta);
                if (tp->t_ifree_delta)
@@ -491,8 +489,7 @@ xfs_trans_apply_sb_deltas(
         * write the correct value ondisk.
         */
        if ((tp->t_frextents_delta || tp->t_res_frextents_delta) &&
-           !xfs_has_rtgroups(tp->t_mountp)) {
-               struct xfs_mount        *mp = tp->t_mountp;
+           !xfs_has_rtgroups(mp)) {
                int64_t                 rtxdelta;
 
                rtxdelta = tp->t_frextents_delta + tp->t_res_frextents_delta;
@@ -505,6 +502,8 @@ xfs_trans_apply_sb_deltas(
 
        if (tp->t_dblocks_delta) {
                be64_add_cpu(&sbp->sb_dblocks, tp->t_dblocks_delta);
+               mp->m_ddev_targp->bt_nr_sectors +=
+                       XFS_FSB_TO_BB(mp, tp->t_dblocks_delta);
                whole = 1;
        }
        if (tp->t_agcount_delta) {
@@ -524,7 +523,7 @@ xfs_trans_apply_sb_deltas(
                 * recompute the ondisk rtgroup block log.  The incore values
                 * will be recomputed in xfs_trans_unreserve_and_mod_sb.
                 */
-               if (xfs_has_rtgroups(tp->t_mountp)) {
+               if (xfs_has_rtgroups(mp)) {
                        sbp->sb_rgblklog = xfs_compute_rgblklog(
                                                be32_to_cpu(sbp->sb_rgextents),
                                                be32_to_cpu(sbp->sb_rextsize));
@@ -537,6 +536,8 @@ xfs_trans_apply_sb_deltas(
        }
        if (tp->t_rblocks_delta) {
                be64_add_cpu(&sbp->sb_rblocks, tp->t_rblocks_delta);
+               mp->m_rtdev_targp->bt_nr_sectors +=
+                       XFS_FSB_TO_BB(mp, tp->t_rblocks_delta);
                whole = 1;
        }
        if (tp->t_rextents_delta) {