|
Daniel Wagner |
4dedd6 |
From: Ming Lei <ming.lei@redhat.com>
|
|
Daniel Wagner |
4dedd6 |
Date: Tue, 9 Nov 2021 15:11:43 +0800
|
|
Daniel Wagner |
4dedd6 |
Subject: scsi: make sure that request queue queiesce and unquiesce balanced
|
|
Daniel Wagner |
4dedd6 |
Patch-mainline: v5.16-rc1
|
|
Daniel Wagner |
4dedd6 |
Git-commit: 93542fbfa7b726d053c01a9399577c03968c4f6b
|
|
Daniel Wagner |
4dedd6 |
References: bsc#1201651
|
|
Daniel Wagner |
4dedd6 |
|
|
Daniel Wagner |
4dedd6 |
For fixing queue quiesce race between driver and block layer(elevator
|
|
Daniel Wagner |
4dedd6 |
switch, update nr_requests, ...), we need to support concurrent quiesce
|
|
Daniel Wagner |
4dedd6 |
and unquiesce, which requires the two call balanced.
|
|
Daniel Wagner |
4dedd6 |
|
|
Daniel Wagner |
4dedd6 |
It isn't easy to audit that in all scsi drivers, especially the two may
|
|
Daniel Wagner |
4dedd6 |
be called from different contexts, so do it in scsi core with one
|
|
Daniel Wagner |
4dedd6 |
per-device atomic variable to balance quiesce and unquiesce.
|
|
Daniel Wagner |
4dedd6 |
|
|
Daniel Wagner |
4dedd6 |
Reported-by: Yi Zhang <yi.zhang@redhat.com>
|
|
Daniel Wagner |
4dedd6 |
Fixes: e70feb8b3e68 ("blk-mq: support concurrent queue quiesce/unquiesce")
|
|
Daniel Wagner |
4dedd6 |
Signed-off-by: Ming Lei <ming.lei@redhat.com>
|
|
Daniel Wagner |
4dedd6 |
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
|
|
Daniel Wagner |
4dedd6 |
Link: https://lore.kernel.org/r/20211109071144.181581-4-ming.lei@redhat.com
|
|
Daniel Wagner |
4dedd6 |
Signed-off-by: Jens Axboe <axboe@kernel.dk>
|
|
Daniel Wagner |
4dedd6 |
Acked-by: Daniel Wagner <dwagner@suse.de>
|
|
Daniel Wagner |
4dedd6 |
---
|
|
Daniel Wagner |
4dedd6 |
drivers/scsi/scsi_lib.c | 37 ++++++++++++++++++++++++++++---------
|
|
Daniel Wagner |
4dedd6 |
include/scsi/scsi_device.h | 1 +
|
|
Daniel Wagner |
4dedd6 |
2 files changed, 29 insertions(+), 9 deletions(-)
|
|
Daniel Wagner |
4dedd6 |
|
|
Daniel Wagner |
4dedd6 |
--- a/drivers/scsi/scsi_lib.c
|
|
Daniel Wagner |
4dedd6 |
+++ b/drivers/scsi/scsi_lib.c
|
|
Daniel Wagner |
4dedd6 |
@@ -2632,6 +2632,32 @@ static int __scsi_internal_device_block_
|
|
Daniel Wagner |
4dedd6 |
return 0;
|
|
Daniel Wagner |
4dedd6 |
}
|
|
Daniel Wagner |
4dedd6 |
|
|
Daniel Wagner |
4dedd6 |
+void scsi_start_queue(struct scsi_device *sdev)
|
|
Daniel Wagner |
4dedd6 |
+{
|
|
Daniel Wagner |
4dedd6 |
+ if (cmpxchg(&sdev->queue_stopped, 1, 0))
|
|
Daniel Wagner |
4dedd6 |
+ blk_mq_unquiesce_queue(sdev->request_queue);
|
|
Daniel Wagner |
4dedd6 |
+}
|
|
Daniel Wagner |
4dedd6 |
+
|
|
Daniel Wagner |
4dedd6 |
+static void scsi_stop_queue(struct scsi_device *sdev, bool nowait)
|
|
Daniel Wagner |
4dedd6 |
+{
|
|
Daniel Wagner |
4dedd6 |
+ /*
|
|
Daniel Wagner |
4dedd6 |
+ * The atomic variable of ->queue_stopped covers that
|
|
Daniel Wagner |
4dedd6 |
+ * blk_mq_quiesce_queue* is balanced with blk_mq_unquiesce_queue.
|
|
Daniel Wagner |
4dedd6 |
+ *
|
|
Daniel Wagner |
4dedd6 |
+ * However, we still need to wait until quiesce is done
|
|
Daniel Wagner |
4dedd6 |
+ * in case that queue has been stopped.
|
|
Daniel Wagner |
4dedd6 |
+ */
|
|
Daniel Wagner |
4dedd6 |
+ if (!cmpxchg(&sdev->queue_stopped, 0, 1)) {
|
|
Daniel Wagner |
4dedd6 |
+ if (nowait)
|
|
Daniel Wagner |
4dedd6 |
+ blk_mq_quiesce_queue_nowait(sdev->request_queue);
|
|
Daniel Wagner |
4dedd6 |
+ else
|
|
Daniel Wagner |
4dedd6 |
+ blk_mq_quiesce_queue(sdev->request_queue);
|
|
Daniel Wagner |
4dedd6 |
+ } else {
|
|
Daniel Wagner |
4dedd6 |
+ if (!nowait)
|
|
Daniel Wagner |
4dedd6 |
+ blk_mq_wait_quiesce_done(sdev->request_queue);
|
|
Daniel Wagner |
4dedd6 |
+ }
|
|
Daniel Wagner |
4dedd6 |
+}
|
|
Daniel Wagner |
4dedd6 |
+
|
|
Daniel Wagner |
4dedd6 |
/**
|
|
Daniel Wagner |
4dedd6 |
* scsi_internal_device_block_nowait - try to transition to the SDEV_BLOCK state
|
|
Daniel Wagner |
4dedd6 |
* @sdev: device to block
|
|
Daniel Wagner |
4dedd6 |
@@ -2656,7 +2682,7 @@ int scsi_internal_device_block_nowait(st
|
|
Daniel Wagner |
4dedd6 |
* request queue.
|
|
Daniel Wagner |
4dedd6 |
*/
|
|
Daniel Wagner |
4dedd6 |
if (!ret)
|
|
Daniel Wagner |
4dedd6 |
- blk_mq_quiesce_queue_nowait(sdev->request_queue);
|
|
Daniel Wagner |
4dedd6 |
+ scsi_stop_queue(sdev, true);
|
|
Daniel Wagner |
4dedd6 |
return ret;
|
|
Daniel Wagner |
4dedd6 |
}
|
|
Daniel Wagner |
4dedd6 |
EXPORT_SYMBOL_GPL(scsi_internal_device_block_nowait);
|
|
Daniel Wagner |
4dedd6 |
@@ -2683,19 +2709,12 @@ static int scsi_internal_device_block(st
|
|
Daniel Wagner |
4dedd6 |
mutex_lock(&sdev->state_mutex);
|
|
Daniel Wagner |
4dedd6 |
err = __scsi_internal_device_block_nowait(sdev);
|
|
Daniel Wagner |
4dedd6 |
if (err == 0)
|
|
Daniel Wagner |
4dedd6 |
- blk_mq_quiesce_queue(sdev->request_queue);
|
|
Daniel Wagner |
4dedd6 |
+ scsi_stop_queue(sdev, false);
|
|
Daniel Wagner |
4dedd6 |
mutex_unlock(&sdev->state_mutex);
|
|
Daniel Wagner |
4dedd6 |
|
|
Daniel Wagner |
4dedd6 |
return err;
|
|
Daniel Wagner |
4dedd6 |
}
|
|
Daniel Wagner |
4dedd6 |
|
|
Daniel Wagner |
4dedd6 |
-void scsi_start_queue(struct scsi_device *sdev)
|
|
Daniel Wagner |
4dedd6 |
-{
|
|
Daniel Wagner |
4dedd6 |
- struct request_queue *q = sdev->request_queue;
|
|
Daniel Wagner |
4dedd6 |
-
|
|
Daniel Wagner |
4dedd6 |
- blk_mq_unquiesce_queue(q);
|
|
Daniel Wagner |
4dedd6 |
-}
|
|
Daniel Wagner |
4dedd6 |
-
|
|
Daniel Wagner |
4dedd6 |
/**
|
|
Daniel Wagner |
4dedd6 |
* scsi_internal_device_unblock_nowait - resume a device after a block request
|
|
Daniel Wagner |
4dedd6 |
* @sdev: device to resume
|
|
Daniel Wagner |
4dedd6 |
--- a/include/scsi/scsi_device.h
|
|
Daniel Wagner |
4dedd6 |
+++ b/include/scsi/scsi_device.h
|
|
Daniel Wagner |
4dedd6 |
@@ -206,6 +206,7 @@ struct scsi_device {
|
|
Daniel Wagner |
4dedd6 |
unsigned rpm_autosuspend:1; /* Enable runtime autosuspend at device
|
|
Daniel Wagner |
4dedd6 |
* creation time */
|
|
Daniel Wagner |
4dedd6 |
|
|
Daniel Wagner |
4dedd6 |
+ unsigned int queue_stopped; /* request queue is quiesced */
|
|
Daniel Wagner |
4dedd6 |
bool offline_already; /* Device offline message logged */
|
|
Daniel Wagner |
4dedd6 |
|
|
Daniel Wagner |
4dedd6 |
atomic_t disk_events_disable_depth; /* disable depth for disk events */
|