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

Chaohai Chen posted 1 patch 1 month, 1 week ago
drivers/scsi/scsi_scan.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
[PATCH v2] scsi: core: Fix missing lock when read async_scan in Scsi_Host
Posted by Chaohai Chen 1 month, 1 week ago
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@aliyun.com>
---

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@aliyun.com/

 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