]> git.baikalelectronics.ru Git - kernel.git/commit
rq-qos: fix missed wake-ups in rq_qos_throttle try two
authorJan Kara <jack@suse.cz>
Mon, 7 Jun 2021 11:26:13 +0000 (13:26 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 19 Jul 2021 06:53:16 +0000 (08:53 +0200)
commiteb2bbe9cd4e4f415da4f62e1fbd603987a0192de
tree898fbf87dbc1e7544418ad5b669f8e5d49f78336
parentf70458c4a79f26aea89305c74bbecd523ab4296c
rq-qos: fix missed wake-ups in rq_qos_throttle try two

commit 11c7aa0ddea8611007768d3e6b58d45dc60a19e1 upstream.

Commit f3b0161f8012 ("rq-qos: fix missed wake-ups in rq_qos_throttle")
tried to fix a problem that a process could be sleeping in rq_qos_wait()
without anyone to wake it up. However the fix is not complete and the
following can still happen:

CPU1 (waiter1) CPU2 (waiter2) CPU3 (waker)
rq_qos_wait() rq_qos_wait()
  acquire_inflight_cb() -> fails
  acquire_inflight_cb() -> fails

completes IOs, inflight
  decreased
  prepare_to_wait_exclusive()
  prepare_to_wait_exclusive()
  has_sleeper = !wq_has_single_sleeper() -> true as there are two sleepers
  has_sleeper = !wq_has_single_sleeper() -> true
  io_schedule()   io_schedule()

Deadlock as now there's nobody to wakeup the two waiters. The logic
automatically blocking when there are already sleepers is really subtle
and the only way to make it work reliably is that we check whether there
are some waiters in the queue when adding ourselves there. That way, we
are guaranteed that at least the first process to enter the wait queue
will recheck the waiting condition before going to sleep and thus
guarantee forward progress.

Fixes: f3b0161f8012 ("rq-qos: fix missed wake-ups in rq_qos_throttle")
CC: stable@vger.kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20210607112613.25344-1-jack@suse.cz
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
block/blk-rq-qos.c
include/linux/wait.h
kernel/sched/wait.c