rounddown() and roundup() do not modify their first argument in place; they return the rounded value. _badblocks_set(), _badblocks_clear() and badblocks_check() were calling them as bare statements and discarding the result, so 's' (and 'next'/ 'target') were never actually rounded. Depending on the caller's alignment this can leave 'sectors' unchanged or, in the reported case, produce a range whose end never advances, causing _badblocks_check()/badblocks_check() to loop with a non-advancing cursor and stall the CPU (RCU stall) when called through the nvdimm ioctl path via nvdimm_clear_badblocks_region(). rounddown()/roundup() also do division/modulo on the sector_t (u64) operand, which requires libgcc helpers (__aeabi_uldivmod, __umoddi3) that are not linked into the kernel on 32-bit builds, breaking the build on arm/i386 (reported by kernel test robot). Switch to round_down()/round_up() (include/linux/math.h), which are mask-based, assign their result back to the variable being rounded, and require no 64-bit division, fixing both the non-rounding bug and the 32-bit build breakage. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202604301231.IpPh4AiH-lkp@intel.com/ Fixes: aa511ff8218b ("badblocks: switch to the improved badblock handling code") Cc: stable@vger.kernel.org Signed-off-by: Ramesh Adhikari Reviewed-by: Coly Li --- block/badblocks.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/block/badblocks.c b/block/badblocks.c index ece64e76fe8..1f786b193fb 100644 --- a/block/badblocks.c +++ b/block/badblocks.c @@ -857,8 +857,8 @@ static bool _badblocks_set(struct badblocks *bb, sector_t s, sector_t sectors, /* round the start down, and the end up */ sector_t next = s + sectors; - rounddown(s, 1 << bb->shift); - roundup(next, 1 << bb->shift); + s = round_down(s, 1 << bb->shift); + next = round_up(next, 1 << bb->shift); sectors = next - s; } @@ -1071,8 +1071,8 @@ static bool _badblocks_clear(struct badblocks *bb, sector_t s, sector_t sectors) * isn't than to think a block is not bad when it is. */ target = s + sectors; - roundup(s, 1 << bb->shift); - rounddown(target, 1 << bb->shift); + s = round_up(s, 1 << bb->shift); + target = round_down(target, 1 << bb->shift); sectors = target - s; } @@ -1307,8 +1307,8 @@ int badblocks_check(struct badblocks *bb, sector_t s, sector_t sectors, /* round the start down, and the end up */ sector_t target = s + sectors; - rounddown(s, 1 << bb->shift); - roundup(target, 1 << bb->shift); + s = round_down(s, 1 << bb->shift); + target = round_up(target, 1 << bb->shift); sectors = target - s; } -- 2.43.0