Now that split bios are forced to preemt tag, however, they are unlikely to get tags continuously because 'wake_batch' threads are woke up each time while there are only 'wake_batch' tags available. Since it can be known in advance how many tags are required for huge io, it's safe to wake up based on required tags, because it can be sure that wakers will use up 'wake_batch' tags. Signed-off-by: Yu Kuai <yukuai3@xxxxxxxxxx> --- lib/sbitmap.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/sbitmap.c b/lib/sbitmap.c index 315e5619b384..5ac5ad1b4b1e 100644 --- a/lib/sbitmap.c +++ b/lib/sbitmap.c @@ -633,6 +633,32 @@ static inline void sbq_update_preemption(struct sbitmap_queue *sbq, true : false; } +static unsigned int get_wake_nr(struct sbq_wait_state *ws, unsigned int nr_tags) +{ + struct sbq_wait *wait; + struct wait_queue_entry *entry; + unsigned int nr = 1; + + spin_lock_irq(&ws->wait.lock); + list_for_each_entry(entry, &ws->wait.head, entry) { + wait = container_of(entry, struct sbq_wait, wait); + if (nr_tags <= wait->nr_tags) { + nr_tags = 0; + break; + } + + nr++; + nr_tags -= wait->nr_tags; + } + spin_unlock_irq(&ws->wait.lock); + + /* + * If nr_tags is not 0, additional wakeup is triggered to fix the race + * that new threads are waited before wake_up_nr() is called. + */ + return nr + nr_tags; +} + static bool __sbq_wake_up(struct sbitmap_queue *sbq) { struct sbq_wait_state *ws; @@ -672,7 +698,7 @@ static bool __sbq_wake_up(struct sbitmap_queue *sbq) smp_mb__before_atomic(); atomic_set(&ws->wait_cnt, wake_batch); sbq_update_preemption(sbq, wake_batch); - wake_up_nr(&ws->wait, wake_batch); + wake_up_nr(&ws->wait, get_wake_nr(ws, wake_batch)); return false; } -- 2.31.1