diff options
| author | Gilad Broner <gbroner@codeaurora.org> | 2014-12-28 16:50:10 +0200 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 11:01:56 -0700 |
| commit | ddb20cd6f07fd03283b2a28eba323bdb96a06d34 (patch) | |
| tree | 54ee1495a5d8d52ab0995cd34430cba231b2f78e /block | |
| parent | 2e5c505a5059f42b081bf6b6d22377c1eb2ab963 (diff) | |
block: test-iosched: fix spinlock recursion
blk_run_queue() takes the queue spinlock and disabled irqs.
Consider the following callstack:
blk_run_queue
->__blk_run_queue
-> scsi_request_fn
-> blk_peek_request
-> __elv_next_request
-> elevator_dispatch_fn
-> test_dispatch_requests
-> test_dispatch_from
test_dispatch_from() will release the test-iosched spinlock
using spin_unlock_irq which will enable interrupts, however,
caller is assuming interrupts are disabled.
An interrupt can occur now and scsi soft-irq may be scheduled
with the following call stack:
scsi_softirq_done
-> scsi_finish_command
-> scsi_device_unbusy
scsi_device_unbusy() tries to lock the queue spinlock which was
previously locked when blk_run_queue was called, resulting in a
spinlock recursion.
Change test_dispatch_from() to use the spinlock irq save/restore variants
to prevent enabling the irq in case they were previously disabled.
Change-Id: Icaea4f9ba54771edb0302c6005047fcc5478ce8d
Signed-off-by: Gilad Broner <gbroner@codeaurora.org>
Diffstat (limited to 'block')
| -rw-r--r-- | block/test-iosched.c | 9 |
1 files changed, 5 insertions, 4 deletions
diff --git a/block/test-iosched.c b/block/test-iosched.c index cc7d28c1ba81..9ac5d1441e0b 100644 --- a/block/test-iosched.c +++ b/block/test-iosched.c @@ -988,24 +988,25 @@ static int test_dispatch_from(struct request_queue *q, struct test_request *test_rq; struct request *rq; int ret = 0; + unsigned long flags; if (!ptd) goto err; - spin_lock_irq(&ptd->lock); + spin_lock_irqsave(&ptd->lock, flags); if (!list_empty(queue)) { test_rq = list_entry(queue->next, struct test_request, queuelist); rq = test_rq->rq; if (!rq) { pr_err("%s: null request,return", __func__); - spin_unlock_irq(&ptd->lock); + spin_unlock_irqrestore(&ptd->lock, flags); goto err; } list_move_tail(&test_rq->queuelist, &ptd->dispatched_queue); ptd->dispatched_count++; (*count)--; - spin_unlock_irq(&ptd->lock); + spin_unlock_irqrestore(&ptd->lock, flags); print_req(rq); elv_dispatch_sort(q, rq); @@ -1013,7 +1014,7 @@ static int test_dispatch_from(struct request_queue *q, ret = 1; goto err; } - spin_unlock_irq(&ptd->lock); + spin_unlock_irqrestore(&ptd->lock, flags); err: return ret; |
