[PATCH v2] scsi: core: Fix missing lock when read async_scan in Scsi_Host

From: Chaohai Chen

Date: Mon Mar 02 2026 - 22:27:27 EST


When setting the async_scan flag in host, the host lock was locked,
but it is not locked during reading. Encapsulate the corresponding
API to fix this issue.

Signed-off-by: Chaohai Chen <wdhh6@xxxxxxxxxx>
---

v1->v2:
- Use scoped_guard() in scsi_scan_async(). (Bart Van Assche)
- Drop the scsi_set_async_scan() and scsi_clear_async_scan. (Bart Van Assche)

v1: https://lore.kernel.org/all/20260302121343.1630837-1-wdhh6@xxxxxxxxxx/

drivers/scsi/scsi_scan.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 60c06fa4ec32..d09b896d07d1 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -122,6 +122,14 @@ struct async_scan_data {
struct completion prev_finished;
};

+static bool scsi_test_async_scan(struct Scsi_Host *shost)
+{
+ lockdep_assert_not_held(shost->host_lock);
+
+ scoped_guard(spinlock_irqsave, shost->host_lock)
+ return shost->async_scan;
+}
+
/*
* scsi_enable_async_suspend - Enable async suspend and resume
*/
@@ -1298,7 +1306,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
goto out_free_result;
}

- res = scsi_add_lun(sdev, result, &bflags, shost->async_scan);
+ res = scsi_add_lun(sdev, result, &bflags, scsi_test_async_scan(shost));
if (res == SCSI_SCAN_LUN_PRESENT) {
if (bflags & BLIST_KEY) {
sdev->lockable = 0;
@@ -1629,7 +1637,7 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
scsi_autopm_get_target(starget);

mutex_lock(&shost->scan_mutex);
- if (!shost->async_scan)
+ if (!scsi_test_async_scan(shost))
scsi_complete_async_scans();

if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
@@ -1839,7 +1847,7 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
return;

mutex_lock(&shost->scan_mutex);
- if (!shost->async_scan)
+ if (!scsi_test_async_scan(shost))
scsi_complete_async_scans();

if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
@@ -1896,7 +1904,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
return -EINVAL;

mutex_lock(&shost->scan_mutex);
- if (!shost->async_scan)
+ if (!scsi_test_async_scan(shost))
scsi_complete_async_scans();

if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
@@ -1949,7 +1957,7 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
return NULL;

mutex_lock(&shost->scan_mutex);
- if (shost->async_scan) {
+ if (scsi_test_async_scan(shost)) {
shost_printk(KERN_DEBUG, shost, "%s called twice\n", __func__);
goto err;
}
@@ -2001,7 +2009,7 @@ static void scsi_finish_async_scan(struct async_scan_data *data)

mutex_lock(&shost->scan_mutex);

- if (!shost->async_scan) {
+ if (!scsi_test_async_scan(shost)) {
shost_printk(KERN_INFO, shost, "%s called twice\n", __func__);
dump_stack();
mutex_unlock(&shost->scan_mutex);
--
2.43.7