Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5bfb9f8 authored by Gilad Broner's avatar Gilad Broner Committed by Matt Wagantall
Browse files

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: default avatarGilad Broner <gbroner@codeaurora.org>
parent 1f016896
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -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;