xfs: track the number of blocks in each buftarg

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: 10616b806d ("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>
This commit is contained in:
Christoph Hellwig 2025-09-19 06:12:08 -07:00 committed by Carlos Maiolino
parent 3c54e6027f
commit 42852fe57c
5 changed files with 52 additions and 34 deletions

View File

@ -387,8 +387,6 @@ xfs_buf_map_verify(
struct xfs_buftarg *btp, struct xfs_buftarg *btp,
struct xfs_buf_map *map) struct xfs_buf_map *map)
{ {
xfs_daddr_t eofs;
/* Check for IOs smaller than the sector size / not sector aligned */ /* Check for IOs smaller than the sector size / not sector aligned */
ASSERT(!(BBTOB(map->bm_len) < btp->bt_meta_sectorsize)); ASSERT(!(BBTOB(map->bm_len) < btp->bt_meta_sectorsize));
ASSERT(!(BBTOB(map->bm_bn) & (xfs_off_t)btp->bt_meta_sectormask)); 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 * Corrupted block numbers can get through to here, unfortunately, so we
* have to check that the buffer falls within the filesystem bounds. * 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 >= btp->bt_nr_sectors) {
if (map->bm_bn < 0 || map->bm_bn >= eofs) {
xfs_alert(btp->bt_mount, xfs_alert(btp->bt_mount,
"%s: daddr 0x%llx out of range, EOFS 0x%llx", "%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); WARN_ON(1);
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
@ -1720,26 +1717,30 @@ xfs_configure_buftarg_atomic_writes(
int int
xfs_configure_buftarg( xfs_configure_buftarg(
struct xfs_buftarg *btp, 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 */ error = bdev_validate_blocksize(btp->bt_bdev, sectorsize);
btp->bt_meta_sectorsize = sectorsize; if (error) {
btp->bt_meta_sectormask = sectorsize - 1; 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 (bdev_can_atomic_write(btp->bt_bdev))
if (error) { xfs_configure_buftarg_atomic_writes(btp);
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)) btp->bt_meta_sectorsize = sectorsize;
xfs_configure_buftarg_atomic_writes(btp); 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; return 0;
} }
@ -1749,6 +1750,9 @@ xfs_init_buftarg(
size_t logical_sectorsize, size_t logical_sectorsize,
const char *descr) 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 */ /* Set up device logical sector size mask */
btp->bt_logical_sectorsize = logical_sectorsize; btp->bt_logical_sectorsize = logical_sectorsize;
btp->bt_logical_sectormask = logical_sectorsize - 1; btp->bt_logical_sectormask = logical_sectorsize - 1;

View File

@ -103,6 +103,7 @@ struct xfs_buftarg {
size_t bt_meta_sectormask; size_t bt_meta_sectormask;
size_t bt_logical_sectorsize; size_t bt_logical_sectorsize;
size_t bt_logical_sectormask; size_t bt_logical_sectormask;
xfs_daddr_t bt_nr_sectors;
/* LRU control structures */ /* LRU control structures */
struct shrinker *bt_shrinker; 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_free_buftarg(struct xfs_buftarg *);
extern void xfs_buftarg_wait(struct xfs_buftarg *); extern void xfs_buftarg_wait(struct xfs_buftarg *);
extern void xfs_buftarg_drain(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) #define xfs_readonly_buftarg(buftarg) bdev_read_only((buftarg)->bt_bdev)

View File

@ -736,6 +736,16 @@ xlog_recover_do_primary_sb_buffer(
*/ */
xfs_sb_from_disk(&mp->m_sb, dsb); 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) { if (mp->m_sb.sb_agcount < orig_agcount) {
xfs_alert(mp, "Shrinking AG count in log recovery not supported"); xfs_alert(mp, "Shrinking AG count in log recovery not supported");
return -EFSCORRUPTED; return -EFSCORRUPTED;

View File

@ -535,7 +535,8 @@ xfs_setup_devices(
{ {
int error; 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) if (error)
return error; return error;
@ -545,7 +546,7 @@ xfs_setup_devices(
if (xfs_has_sector(mp)) if (xfs_has_sector(mp))
log_sector_size = mp->m_sb.sb_logsectsize; log_sector_size = mp->m_sb.sb_logsectsize;
error = xfs_configure_buftarg(mp->m_logdev_targp, error = xfs_configure_buftarg(mp->m_logdev_targp,
log_sector_size); log_sector_size, mp->m_sb.sb_logblocks);
if (error) if (error)
return error; return error;
} }
@ -559,7 +560,7 @@ xfs_setup_devices(
mp->m_rtdev_targp = mp->m_ddev_targp; mp->m_rtdev_targp = mp->m_ddev_targp;
} else if (mp->m_rtname) { } else if (mp->m_rtname) {
error = xfs_configure_buftarg(mp->m_rtdev_targp, 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) if (error)
return error; return error;
} }

View File

@ -452,19 +452,17 @@ xfs_trans_mod_sb(
*/ */
STATIC void STATIC void
xfs_trans_apply_sb_deltas( xfs_trans_apply_sb_deltas(
xfs_trans_t *tp) struct xfs_trans *tp)
{ {
struct xfs_dsb *sbp; struct xfs_mount *mp = tp->t_mountp;
struct xfs_buf *bp; struct xfs_buf *bp = xfs_trans_getsb(tp);
int whole = 0; struct xfs_dsb *sbp = bp->b_addr;
int whole = 0;
bp = xfs_trans_getsb(tp);
sbp = bp->b_addr;
/* /*
* Only update the superblock counters if we are logging them * 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) if (tp->t_icount_delta)
be64_add_cpu(&sbp->sb_icount, tp->t_icount_delta); be64_add_cpu(&sbp->sb_icount, tp->t_icount_delta);
if (tp->t_ifree_delta) if (tp->t_ifree_delta)
@ -491,8 +489,7 @@ xfs_trans_apply_sb_deltas(
* write the correct value ondisk. * write the correct value ondisk.
*/ */
if ((tp->t_frextents_delta || tp->t_res_frextents_delta) && if ((tp->t_frextents_delta || tp->t_res_frextents_delta) &&
!xfs_has_rtgroups(tp->t_mountp)) { !xfs_has_rtgroups(mp)) {
struct xfs_mount *mp = tp->t_mountp;
int64_t rtxdelta; int64_t rtxdelta;
rtxdelta = tp->t_frextents_delta + tp->t_res_frextents_delta; rtxdelta = tp->t_frextents_delta + tp->t_res_frextents_delta;
@ -505,6 +502,8 @@ xfs_trans_apply_sb_deltas(
if (tp->t_dblocks_delta) { if (tp->t_dblocks_delta) {
be64_add_cpu(&sbp->sb_dblocks, 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; whole = 1;
} }
if (tp->t_agcount_delta) { if (tp->t_agcount_delta) {
@ -524,7 +523,7 @@ xfs_trans_apply_sb_deltas(
* recompute the ondisk rtgroup block log. The incore values * recompute the ondisk rtgroup block log. The incore values
* will be recomputed in xfs_trans_unreserve_and_mod_sb. * 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( sbp->sb_rgblklog = xfs_compute_rgblklog(
be32_to_cpu(sbp->sb_rgextents), be32_to_cpu(sbp->sb_rgextents),
be32_to_cpu(sbp->sb_rextsize)); be32_to_cpu(sbp->sb_rextsize));
@ -537,6 +536,8 @@ xfs_trans_apply_sb_deltas(
} }
if (tp->t_rblocks_delta) { if (tp->t_rblocks_delta) {
be64_add_cpu(&sbp->sb_rblocks, 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; whole = 1;
} }
if (tp->t_rextents_delta) { if (tp->t_rextents_delta) {