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;
 


Reply via email to