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>
This commit is contained in:
parent
8806bc6d8d
commit
60cbc8e7fd
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue