From ddb20cd6f07fd03283b2a28eba323bdb96a06d34 Mon Sep 17 00:00:00 2001 From: Gilad Broner Date: Sun, 28 Dec 2014 16:50:10 +0200 Subject: 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 --- block/test-iosched.c | 9 +++++---- 1 file 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; -- cgit v1.2.3