From: Darrick J. Wong Date: Thu, 4 Jun 2026 06:06:25 +0000 (-0700) Subject: xfs_scrub: widen scrub and repair dependency mask X-Git-Tag: v7.1.0~59 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=064834b6a0a29ca456317b8b749af81f5905e2bb;p=xfsprogs-dev.git xfs_scrub: widen scrub and repair dependency mask Codex observes: "Since `XFS_SCRUB_TYPE_NR` is now 33 (`XFS_SCRUB_TYPE_RTREFCBT` is 32), any scheduled scrub item drives this loop to `j == 32`, where `1U << j` shifts a 32-bit unsigned value by its width. That is undefined behavior (and will trip UBSan or allow miscompilation of dependency scheduling); the dependency mask and shift need to use a type wide enough for all scrub types, e.g. `1ULL`/`uint64_t`." The presence of a shift overflow is correct, since there are now 33 scrub type codes. However, the local loop variable isn't the only problem here -- scrub_deps and repair_deps are masks, and they aren't wide enough. As a result, there's a lurking logic bomb because RTREFCBT will never get selected. Fortunately this is benign because no scrub/repair type depends on RTREFCBT, which is why we haven't seen any complaints. But let's eliminate an avenue for us to forget to fix the problem. Widen the masks and the local variable to fix the problem. Cc: linux-xfs@vger.kernel.org # v6.14.0 Fixes: b71fbe4c3da263 ("xfs: scrub the realtime refcount btree") Signed-off-by: "Darrick J. Wong" Reviewed-by: Andrey Albershteyn --- diff --git a/scrub/repair.c b/scrub/repair.c index c3a8b317..5d821655 100644 --- a/scrub/repair.c +++ b/scrub/repair.c @@ -28,8 +28,8 @@ * the filesystem if the btree root pointers in the AG headers are wrong. * Dependencies cannot cross scrub groups. */ -#define DEP(x) (1U << (x)) -static const unsigned int repair_deps[XFS_SCRUB_TYPE_NR] = { +#define DEP(x) (1ULL << (x)) +static const uint64_t repair_deps[XFS_SCRUB_TYPE_NR] = { [XFS_SCRUB_TYPE_BMBTD] = DEP(XFS_SCRUB_TYPE_INODE), [XFS_SCRUB_TYPE_BMBTA] = DEP(XFS_SCRUB_TYPE_INODE), [XFS_SCRUB_TYPE_BMBTC] = DEP(XFS_SCRUB_TYPE_INODE), @@ -250,7 +250,7 @@ repair_item_dependencies_ok( const struct scrub_item *sri, unsigned int scrub_type) { - unsigned int dep_mask = repair_deps[scrub_type]; + uint64_t dep_mask = repair_deps[scrub_type]; unsigned int b; for (b = 0; dep_mask && b < XFS_SCRUB_TYPE_NR; b++, dep_mask >>= 1) { @@ -434,7 +434,7 @@ repair_item_boost_priorities( unsigned int scrub_type; foreach_scrub_type(scrub_type) { - unsigned int dep_mask = repair_deps[scrub_type]; + uint64_t dep_mask = repair_deps[scrub_type]; unsigned int b; if (repair_item_count_needsrepair(sri) == 0 || !dep_mask) diff --git a/scrub/scrub.c b/scrub/scrub.c index de687af6..12ed87f0 100644 --- a/scrub/scrub.c +++ b/scrub/scrub.c @@ -28,8 +28,8 @@ * Bitmap showing the correctness dependencies between scrub types for scrubs. * Dependencies cannot cross scrub groups. */ -#define DEP(x) (1U << (x)) -static const unsigned int scrub_deps[XFS_SCRUB_TYPE_NR] = { +#define DEP(x) (1ULL << (x)) +static const uint64_t scrub_deps[XFS_SCRUB_TYPE_NR] = { [XFS_SCRUB_TYPE_AGF] = DEP(XFS_SCRUB_TYPE_SB), [XFS_SCRUB_TYPE_AGFL] = DEP(XFS_SCRUB_TYPE_SB) | DEP(XFS_SCRUB_TYPE_AGF), @@ -472,7 +472,7 @@ bool scrub_item_schedule_work( struct scrub_item *sri, uint8_t state_flags, - const unsigned int *schedule_deps) + const uint64_t *schedule_deps) { unsigned int scrub_type; unsigned int nr = 0; @@ -486,7 +486,7 @@ scrub_item_schedule_work( continue; foreach_scrub_type(j) { - if (schedule_deps[scrub_type] & (1U << j)) + if (schedule_deps[scrub_type] & (1ULL << j)) sri->sri_state[j] |= SCRUB_ITEM_BARRIER; } diff --git a/scrub/scrub_private.h b/scrub/scrub_private.h index c5e0a7c0..629ef440 100644 --- a/scrub/scrub_private.h +++ b/scrub/scrub_private.h @@ -118,6 +118,6 @@ scrub_item_schedule_retry(struct scrub_item *sri, unsigned int scrub_type) bool scrub_item_call_kernel_again(struct scrub_item *sri, uint8_t work_mask, const struct scrub_item *old); bool scrub_item_schedule_work(struct scrub_item *sri, uint8_t state_flags, - const unsigned int *schedule_deps); + const uint64_t *schedule_deps); #endif /* XFS_SCRUB_SCRUB_PRIVATE_H_ */