]> git.baikalelectronics.ru Git - kernel.git/commit
sbitmap: fix race in wait batch accounting
authorJens Axboe <axboe@kernel.dk>
Mon, 14 May 2018 18:17:31 +0000 (12:17 -0600)
committerJens Axboe <axboe@kernel.dk>
Mon, 14 May 2018 18:17:31 +0000 (12:17 -0600)
commit4a5d308aa37ba7e3e53d22a068c8c51cacb498ac
treef8736038b49c548fd13327a3d2db26804f027047
parentd2aaa96a80eca3d17a800e16eedb5fb87a66ef35
sbitmap: fix race in wait batch accounting

If we have multiple callers of sbq_wake_up(), we can end up in a
situation where the wait_cnt will continually go more and more
negative. Consider the case where our wake batch is 1, hence
wait_cnt will start out as 1.

wait_cnt == 1

CPU0 CPU1
atomic_dec_return(), cnt == 0
atomic_dec_return(), cnt == -1
cmpxchg(-1, 0) (succeeds)
[wait_cnt now 0]
cmpxchg(0, 1) (fails)

This ends up with wait_cnt being 0, we'll wakeup immediately
next time. Going through the same loop as above again, and
we'll have wait_cnt -1.

For the case where we have a larger wake batch, the only
difference is that the starting point will be higher. We'll
still end up with continually smaller batch wakeups, which
defeats the purpose of the rolling wakeups.

Always reset the wait_cnt to the batch value. Then it doesn't
matter who wins the race. But ensure that whomever does win
the race is the one that increments the ws index and wakes up
our batch count, loser gets to call __sbq_wake_up() again to
account his wakeups towards the next active wait state index.

Fixes: a40c17a9a492 ("sbitmap: fix wakeup hang after sbq resize")
Reviewed-by: Omar Sandoval <osandov@fb.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
lib/sbitmap.c