summaryrefslogtreecommitdiff
path: root/drivers/scsi
diff options
context:
space:
mode:
authorMartin Wilck <mwilck@suse.com>2023-06-14 13:36:13 +0300
committerMartin K. Petersen <martin.petersen@oracle.com>2023-06-16 19:19:59 +0300
commitd7035b73a73a79a1dc991fad0ee5f784559e81ed (patch)
treea5bfdcf61a78cfaa4ac8f6621c84a45a1972d417 /drivers/scsi
parentc5e46f7ad43b0519980020378a2b00b339359968 (diff)
downloadlinux-d7035b73a73a79a1dc991fad0ee5f784559e81ed.tar.xz
scsi: core: Don't wait for quiesce in scsi_stop_queue()
scsi_stop_queue() has just two callers, one with and one without "nowait". As blk_mq_quiesce_queue() comes down to blk_mq_quiesce_queue_nowait() followed by blk_mq_wait_quiesce_done(), we might as well open-code this in scsi_device_block(). Also, add a comment explaining why blk_mq_quiesce_queue_nowait() must be called with the state_mutex held, see https://lore.kernel.org/linux-scsi/3b8b13bf-a458-827a-b916-07d7eee8ae00@acm.org/. Signed-off-by: Martin Wilck <mwilck@suse.com> Link: https://lore.kernel.org/r/20230614103616.31857-5-mwilck@suse.com Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/scsi_lib.c32
1 files changed, 16 insertions, 16 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 357eb0ab6f21..4b46dcba7649 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2725,24 +2725,16 @@ void scsi_start_queue(struct scsi_device *sdev)
blk_mq_unquiesce_queue(sdev->request_queue);
}
-static void scsi_stop_queue(struct scsi_device *sdev, bool nowait)
+static void scsi_stop_queue(struct scsi_device *sdev)
{
/*
* The atomic variable of ->queue_stopped covers that
* blk_mq_quiesce_queue* is balanced with blk_mq_unquiesce_queue.
*
- * However, we still need to wait until quiesce is done
- * in case that queue has been stopped.
+ * The caller needs to wait until quiesce is done.
*/
- if (!cmpxchg(&sdev->queue_stopped, 0, 1)) {
- if (nowait)
- blk_mq_quiesce_queue_nowait(sdev->request_queue);
- else
- blk_mq_quiesce_queue(sdev->request_queue);
- } else {
- if (!nowait)
- blk_mq_wait_quiesce_done(sdev->request_queue->tag_set);
- }
+ if (!cmpxchg(&sdev->queue_stopped, 0, 1))
+ blk_mq_quiesce_queue_nowait(sdev->request_queue);
}
/**
@@ -2769,7 +2761,7 @@ int scsi_internal_device_block_nowait(struct scsi_device *sdev)
* request queue.
*/
if (!ret)
- scsi_stop_queue(sdev, true);
+ scsi_stop_queue(sdev);
return ret;
}
EXPORT_SYMBOL_GPL(scsi_internal_device_block_nowait);
@@ -2794,9 +2786,17 @@ static void scsi_device_block(struct scsi_device *sdev, void *data)
mutex_lock(&sdev->state_mutex);
err = __scsi_internal_device_block_nowait(sdev);
- if (err == 0)
- scsi_stop_queue(sdev, false);
- mutex_unlock(&sdev->state_mutex);
+ if (err == 0) {
+ /*
+ * scsi_stop_queue() must be called with the state_mutex
+ * held. Otherwise a simultaneous scsi_start_queue() call
+ * might unquiesce the queue before we quiesce it.
+ */
+ scsi_stop_queue(sdev);
+ mutex_unlock(&sdev->state_mutex);
+ blk_mq_wait_quiesce_done(sdev->request_queue->tag_set);
+ } else
+ mutex_unlock(&sdev->state_mutex);
WARN_ONCE(err, "__scsi_internal_device_block_nowait(%s) failed: err = %d\n",
dev_name(&sdev->sdev_gendev), err);