|
Jan Kara |
2ee3a6 |
From: Jan Kara <jack@suse.cz>
|
|
Jan Kara |
2ee3a6 |
Subject: [PATCH] sbitmap: Avoid lockups when waker gets preempted
|
|
Jan Kara |
2ee3a6 |
References: bsc#1209118
|
|
Jan Kara |
2ee3a6 |
Patch-mainline: Never, sbitmap code got rewritten
|
|
Jan Kara |
2ee3a6 |
|
|
Jan Kara |
2ee3a6 |
When the process performing wakeup on the wait queue gets preempted and this
|
|
Jan Kara |
2ee3a6 |
wait queue has the only waiter, we can loose many wakeups and in the end we
|
|
Jan Kara |
2ee3a6 |
may end up with waiter in the wait queue without anybody able to wake him up.
|
|
Jan Kara |
2ee3a6 |
|
|
Jan Kara |
2ee3a6 |
The scenario can by like: We have waitqueue 0 active.
|
|
Jan Kara |
2ee3a6 |
|
|
Jan Kara |
2ee3a6 |
CPU0 CPU1
|
|
Jan Kara |
2ee3a6 |
__sbq_wake_up()
|
|
Jan Kara |
2ee3a6 |
decrements wait_cnt to 0
|
|
Jan Kara |
2ee3a6 |
wake_up_nr() -> wakes waiters
|
|
Jan Kara |
2ee3a6 |
queues IOs until all tags are used
|
|
Jan Kara |
2ee3a6 |
blk_mq_get_tag() finds no tag ->
|
|
Jan Kara |
2ee3a6 |
adds waiter to waitqueue 0
|
|
Jan Kara |
2ee3a6 |
all IOs complete - wakeups discarded because
|
|
Jan Kara |
2ee3a6 |
waitqueue 0 still has wait_cnt == 0.
|
|
Jan Kara |
2ee3a6 |
set wait_cnt to 8
|
|
Jan Kara |
2ee3a6 |
|
|
Jan Kara |
2ee3a6 |
And waiter in waitqueue 0 sleeps indefinitely now because there's no IO to
|
|
Jan Kara |
2ee3a6 |
complete to wake him up.
|
|
Jan Kara |
2ee3a6 |
|
|
Jan Kara |
2ee3a6 |
Fix the problem by waking up some waiters if we don't find any valid wait queue
|
|
Jan Kara |
2ee3a6 |
to perform wake up on. This makes sure we don't loose all the wake ups.
|
|
Jan Kara |
2ee3a6 |
|
|
Jan Kara |
2ee3a6 |
Signed-off-by: Jan Kara <jack@suse.cz>
|
|
Jan Kara |
2ee3a6 |
|
|
Jan Kara |
2ee3a6 |
---
|
|
Jan Kara |
2ee3a6 |
lib/sbitmap.c | 22 ++++++++++++++++++----
|
|
Jan Kara |
2ee3a6 |
1 file changed, 18 insertions(+), 4 deletions(-)
|
|
Jan Kara |
2ee3a6 |
|
|
Jan Kara |
2ee3a6 |
--- a/lib/sbitmap.c
|
|
Jan Kara |
2ee3a6 |
+++ b/lib/sbitmap.c
|
|
Jan Kara |
2ee3a6 |
@@ -532,6 +532,7 @@ EXPORT_SYMBOL_GPL(sbitmap_queue_min_shal
|
|
Jan Kara |
2ee3a6 |
static struct sbq_wait_state *sbq_wake_ptr(struct sbitmap_queue *sbq)
|
|
Jan Kara |
2ee3a6 |
{
|
|
Jan Kara |
2ee3a6 |
int i, wake_index;
|
|
Jan Kara |
2ee3a6 |
+ struct sbq_wait_state *active_ws = NULL;
|
|
Jan Kara |
2ee3a6 |
|
|
Jan Kara |
2ee3a6 |
if (!atomic_read(&sbq->ws_active))
|
|
Jan Kara |
2ee3a6 |
return NULL;
|
|
Jan Kara |
2ee3a6 |
@@ -540,15 +541,28 @@ static struct sbq_wait_state *sbq_wake_p
|
|
Jan Kara |
2ee3a6 |
for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
|
|
Jan Kara |
2ee3a6 |
struct sbq_wait_state *ws = &sbq->ws[wake_index];
|
|
Jan Kara |
2ee3a6 |
|
|
Jan Kara |
2ee3a6 |
- if (waitqueue_active(&ws->wait) && atomic_read(&ws->wait_cnt) > 0) {
|
|
Jan Kara |
2ee3a6 |
- if (wake_index != atomic_read(&sbq->wake_index))
|
|
Jan Kara |
2ee3a6 |
- atomic_set(&sbq->wake_index, wake_index);
|
|
Jan Kara |
2ee3a6 |
- return ws;
|
|
Jan Kara |
2ee3a6 |
+ if (waitqueue_active(&ws->wait)) {
|
|
Jan Kara |
2ee3a6 |
+ if (atomic_read(&ws->wait_cnt) > 0) {
|
|
Jan Kara |
2ee3a6 |
+ if (wake_index != atomic_read(&sbq->wake_index))
|
|
Jan Kara |
2ee3a6 |
+ atomic_set(&sbq->wake_index, wake_index);
|
|
Jan Kara |
2ee3a6 |
+ return ws;
|
|
Jan Kara |
2ee3a6 |
+ }
|
|
Jan Kara |
2ee3a6 |
+ active_ws = ws;
|
|
Jan Kara |
2ee3a6 |
}
|
|
Jan Kara |
2ee3a6 |
|
|
Jan Kara |
2ee3a6 |
wake_index = sbq_index_inc(wake_index);
|
|
Jan Kara |
2ee3a6 |
}
|
|
Jan Kara |
2ee3a6 |
|
|
Jan Kara |
2ee3a6 |
+ /*
|
|
Jan Kara |
2ee3a6 |
+ * There are active waitqueues but all are in the process of being
|
|
Jan Kara |
2ee3a6 |
+ * woken. Perform wakeup on some waitqueue to avoid loosing the wakeup.
|
|
Jan Kara |
2ee3a6 |
+ * This is actually important in case task performing wakeup gets
|
|
Jan Kara |
2ee3a6 |
+ * preempted and lots of other wakeup events happen before it gets
|
|
Jan Kara |
2ee3a6 |
+ * scheduled again.
|
|
Jan Kara |
2ee3a6 |
+ */
|
|
Jan Kara |
2ee3a6 |
+ if (active_ws)
|
|
Jan Kara |
2ee3a6 |
+ wake_up_nr(&active_ws->wait, READ_ONCE(sbq->wake_batch));
|
|
Jan Kara |
2ee3a6 |
+
|
|
Jan Kara |
2ee3a6 |
return NULL;
|
|
Jan Kara |
2ee3a6 |
}
|
|
Jan Kara |
2ee3a6 |
|