blk-mq-sched: don't hold queue_lock when calling exit_icq

None of the other blk-mq elevator hooks are called with this lock held.
Additionally, it can lead to circular locking dependencies between
queue_lock and the private scheduler lock.

Reported-by: Paolo Valente <paolo.valente@linaro.org>
Signed-off-by: Omar Sandoval <osandov@fb.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
Omar Sandoval 2017-02-10 10:32:34 -08:00 committed by Jens Axboe
parent f6f94300cd
commit 3d492c2e01
1 changed files with 16 additions and 6 deletions

View File

@ -35,7 +35,10 @@ static void icq_free_icq_rcu(struct rcu_head *head)
kmem_cache_free(icq->__rcu_icq_cache, icq); kmem_cache_free(icq->__rcu_icq_cache, icq);
} }
/* Exit an icq. Called with both ioc and q locked. */ /*
* Exit an icq. Called with both ioc and q locked for sq, only ioc locked for
* mq.
*/
static void ioc_exit_icq(struct io_cq *icq) static void ioc_exit_icq(struct io_cq *icq)
{ {
struct elevator_type *et = icq->q->elevator->type; struct elevator_type *et = icq->q->elevator->type;
@ -166,6 +169,7 @@ EXPORT_SYMBOL(put_io_context);
*/ */
void put_io_context_active(struct io_context *ioc) void put_io_context_active(struct io_context *ioc)
{ {
struct elevator_type *et;
unsigned long flags; unsigned long flags;
struct io_cq *icq; struct io_cq *icq;
@ -184,13 +188,19 @@ retry:
hlist_for_each_entry(icq, &ioc->icq_list, ioc_node) { hlist_for_each_entry(icq, &ioc->icq_list, ioc_node) {
if (icq->flags & ICQ_EXITED) if (icq->flags & ICQ_EXITED)
continue; continue;
if (spin_trylock(icq->q->queue_lock)) {
et = icq->q->elevator->type;
if (et->uses_mq) {
ioc_exit_icq(icq); ioc_exit_icq(icq);
spin_unlock(icq->q->queue_lock);
} else { } else {
spin_unlock_irqrestore(&ioc->lock, flags); if (spin_trylock(icq->q->queue_lock)) {
cpu_relax(); ioc_exit_icq(icq);
goto retry; spin_unlock(icq->q->queue_lock);
} else {
spin_unlock_irqrestore(&ioc->lock, flags);
cpu_relax();
goto retry;
}
} }
} }
spin_unlock_irqrestore(&ioc->lock, flags); spin_unlock_irqrestore(&ioc->lock, flags);