scsi_host_block() calls scsi_internal_device_block() for each scsi_device, and scsi_internal_device_block() calls blk_mq_quiesce_queue() for each LUN. However synchronize_rcu is run from blk_mq_quiesce_queue(). This way may become unnecessary slow in case of lots of LUNs. So use scsi_internal_device_block() to implement scsi_host_block(), and just run once synchronize_rcu() because scsi never supports tagset of BLK_MQ_F_BLOCKING. Cc: Bart Van Assche <bvanassche@xxxxxxx> Cc: Christoph Hellwig <hch@xxxxxx> Cc: Dexuan Cui <decui@xxxxxxxxxxxxx> Cc: Hannes Reinecke <hare@xxxxxxx> Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxx> --- drivers/scsi/scsi_lib.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 47835c4b4ee0..089ac92ac6c3 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2841,11 +2841,22 @@ scsi_host_block(struct Scsi_Host *shost) struct scsi_device *sdev; int ret = 0; + /* + * Call scsi_internal_device_block_nowait then we can avoid to + * run synchronize_rcu() one time for every LUN. + */ shost_for_each_device(sdev, shost) { - ret = scsi_internal_device_block(sdev); + mutex_lock(&sdev->state_mutex); + ret = scsi_internal_device_block_nowait(sdev); + mutex_unlock(&sdev->state_mutex); if (ret) break; } + + WARN_ON_ONCE(shost->tag_set.flags & BLK_MQ_F_BLOCKING); + + if (!ret) + synchronize_rcu(); return ret; } EXPORT_SYMBOL_GPL(scsi_host_block); -- 2.25.2