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: [email protected]
Signed-off-by: Mikulas Patocka <[email protected]>
Assisted-by: Claude:claude-opus-5
---
drivers/md/dm-bufio.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
Index: linux-2.6/drivers/md/dm-bufio.c
===================================================================
--- linux-2.6.orig/drivers/md/dm-bufio.c
+++ linux-2.6/drivers/md/dm-bufio.c
@@ -2426,8 +2426,10 @@ static void __scan(struct dm_bufio_clien
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;