From 005d2ec5723cd4ac740de678274623f1fadd6a6e Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 12 Oct 2026 16:09:52 +0200 Subject: [PATCH] dm-bufio: fix a race leading to an unsigned integer underflow The function __scan tests "count - freed <= retain_target" and then sets "atomic_long_set(&c->need_shrink, 0);" It exits with the condition "if (!atomic_long_read(&c->need_shrink)) break;" It may be possible that between these two statements, another thread sets &c->need_shrink to a non-zero value. In this case, the function __scan continues and it may possibly the "freed" variable is larger than the "count" variable. The expression "count - freed" underflows and the function __scan will continue to free all the buffers, even those that are below retain_target. Fix this bug by immediatelly exiting if we set "atomic_long_set(&c->need_shrink, 0)"; and don't attempt to re-read c->need_shrink afterwards. Fixes: 450e8dee51aa ("dm bufio: improve concurrent IO performance") Cc: stable@vger.kernel.org Signed-off-by: Mikulas Patocka Assisted-by: Claude:claude-opus-5 --- drivers/md/dm-bufio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index edad64654ef6..5f0226270761 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -2426,8 +2426,10 @@ static void __scan(struct dm_bufio_client *c) for (l = 0; l < LIST_SIZE; l++) { while (true) { - if (count - freed <= retain_target) + if (count - freed <= retain_target) { atomic_long_set(&c->need_shrink, 0); + break; + } if (!atomic_long_read(&c->need_shrink)) break;