hulk inclusion category: bugfix bugzilla: http://hulk.rnd.huawei.com/issue/info/34955 -------------------------------- A race condition in sbitmap_queue_wake_up() can cause an infinite loop when multiple CPUs concurrently decrement the same wait_cnt, resulting in a negative value that still satisfies the original condition check. The race scenario: CPU20 (in ioctl context): - Calls __sbq_wake_up() and selects ws based on wake_index CPU3 (in softirq): - Concurrently selects the same ws (wake_index unchanged) - Decrements wait_cnt from 1 to 0 CPU20 (interrupted by softirq): - Selects the same ws again (wake_index still unchanged) - Decrements wait_cnt from 0 to -1 - Returns true because (wait_cnt < 0) - Enters infinite loop in while(__sbq_wake_up(sbq)) The root cause is that sbq_wake_ptr() returns the wait_state when atomic_read(&ws->wait_cnt) is non-zero, which includes negative values. Since wake_index is never updated when the same ws is repeatedly selected, multiple CPUs can race on the same wait_state, driving wait_cnt increasingly negative and triggering the infinite loop condition. Fix this by explicitly checking that wait_cnt is positive (> 0) in sbq_wake_ptr(), preventing selection of wait_states with negative counts and breaking the infinite loop condition. Fixes: 084cd94d0b2a ("sbitmap: fix possible io hung due to lost wakeup") Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com> --- lib/sbitmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sbitmap.c b/lib/sbitmap.c index 9fe2aebc13da..dbe4e3bc6b33 100644 --- a/lib/sbitmap.c +++ b/lib/sbitmap.c @@ -554,7 +554,7 @@ static struct sbq_wait_state *sbq_wake_ptr(struct sbitmap_queue *sbq) for (i = 0; i < SBQ_WAIT_QUEUES; i++) { struct sbq_wait_state *ws = &sbq->ws[wake_index]; - if (waitqueue_active(&ws->wait) && atomic_read(&ws->wait_cnt)) { + if (waitqueue_active(&ws->wait) && (atomic_read(&ws->wait_cnt) > 0)) { if (wake_index != atomic_read(&sbq->wake_index)) atomic_set(&sbq->wake_index, wake_index); return ws; -- 2.46.1