@@ -551,8 +551,25 @@ static void scsi_run_queue_async(struct scsi_device *sdev)
if (scsi_target(sdev)->single_lun ||
!list_empty(&sdev->host->starved_list))
kblockd_schedule_work(&sdev->requeue_work);
- else
- blk_mq_run_hw_queues(sdev->request_queue, true);
+ else {
+ /*
+ * smp_mb() implied in either rq->end_io or blk_mq_free_request
+ * is for ordering writing .device_busy in scsi_device_unbusy()
+ * and reading sdev->restarts.
+ */
+ int old = atomic_read(&sdev->restarts);
+
+ /*
+ * ->restarts has to be kept as non-zero if there new budget
+ * contention comes.
+ *
+ * No need to run queue when either another re-run
+ * queue wins in updating ->restarts or one new budget
+ * contention comes.
+ */
+ if (old && (atomic_cmpxchg(&sdev->restarts, old, 0) == old))
+ blk_mq_run_hw_queues(sdev->request_queue, true);
+ }
}
/* Returns false when no more bytes to process, true if there are more */
@@ -1611,8 +1628,33 @@ static void scsi_mq_put_budget(struct request_queue *q)
static bool scsi_mq_get_budget(struct request_queue *q)
{
struct scsi_device *sdev = q->queuedata;
+ int ret = scsi_dev_queue_ready(q, sdev);
- return scsi_dev_queue_ready(q, sdev);
+ if (ret)
+ return true;
+
+ atomic_inc(&sdev->restarts);
+
+ /*
+ * Order writing .restarts and reading .device_busy. Its pair is
+ * implied by __blk_mq_end_request() in scsi_end_request() for
+ * ordering writing .device_busy in scsi_device_unbusy() and
+ * reading .restarts.
+ */
+ smp_mb__after_atomic();
+
+ /*
+ * If all in-flight requests originated from this LUN are completed
+ * before setting .restarts, sdev->device_busy will be observed as
+ * zero, then blk_mq_delay_run_hw_queues() will dispatch this request
+ * soon. Otherwise, completion of one of these request will observe
+ * the .restarts flag, and the request queue will be run for handling
+ * this request, see scsi_end_request().
+ */
+ if (unlikely(atomic_read(&sdev->device_busy) == 0 &&
+ !scsi_device_blocked(sdev)))
+ blk_mq_delay_run_hw_queues(sdev->request_queue, SCSI_QUEUE_DELAY);
+ return false;
}
static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
@@ -109,6 +109,7 @@ struct scsi_device {
atomic_t device_busy; /* commands actually active on LLDD */
atomic_t device_blocked; /* Device returned QUEUE_FULL. */
+ atomic_t restarts;
spinlock_t list_lock;
struct list_head starved_entry;
unsigned short queue_depth; /* How deep of a queue we want */