]> git-server-git.apps.pok.os.sepia.ceph.com Git - xfsprogs-dev.git/commitdiff
xfs_scrub: widen scrub and repair dependency mask
authorDarrick J. Wong <djwong@kernel.org>
Thu, 4 Jun 2026 06:06:25 +0000 (23:06 -0700)
committerAndrey Albershteyn <aalbersh@kernel.org>
Thu, 11 Jun 2026 10:26:04 +0000 (12:26 +0200)
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" <djwong@kernel.org>
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
scrub/repair.c
scrub/scrub.c
scrub/scrub_private.h

index c3a8b3179600a68b6b4380f66e915abde5900a09..5d821655877b8079e728c432f635ec4d9c154988 100644 (file)
@@ -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)
index de687af687d32d9030ea7683380da7b7bdcd199a..12ed87f07d9f6c6654b223321c1ad3c802e85907 100644 (file)
@@ -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;
                }
 
index c5e0a7c08be05650ca31774ae838faec38bb6e8e..629ef4405225ebd5a994a4c589100a5a7baeac82 100644 (file)
@@ -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_ */