Linux SCSI subsystem development
 help / color / mirror / Atom feed
* [PATCH] scsi: core: Make SCSI host scan interruptible
@ 2026-09-11 20:11 Bart Van Assche
  2026-09-11 20:23 ` sashiko-bot
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Bart Van Assche @ 2026-09-11 20:11 UTC (permalink / raw)
  To: Martin K . Petersen
  Cc: linux-scsi, John Garry, Bart Van Assche,
	syzbot+1f678bd2872aefb11d8a, James E.J. Bottomley,
	Martin K. Petersen

Writing to the sysfs "scan" attribute serializes SCSI host scans via
shost->scan_mutex. In virtualized environments such as virtio-scsi with
256 target IDs, scanning non-existent targets repeatedly allocates and
destroys temporary scsi_devices. Each iteration transitions the shared tag
queue state and freezes request queues, causing a full bus scan to take
tens of seconds.

When multiple processes initiate host scans concurrently, waiter tasks
sleep in TASK_UNINTERRUPTIBLE on shost->scan_mutex. If the waiting tasks
receive signals such as SIGKILL, they cannot wake up until the mutex is
acquired, easily exceeding the hung task timeout and triggering
khungtaskd warnings ("INFO: task hung in scsi_scan_host_selected").
Furthermore, once a task finally acquires the mutex, it continues to
perform the full scan even if a fatal signal is already pending.

Fix this by:
1. Use mutex_lock_interruptible() instead of mutex_lock() in
   scsi_scan_host_selected(), allowing waiting tasks to sleep in
   TASK_INTERRUPTIBLE and immediately wake up with -EINTR on signals.
2. Check signal_pending(current) in scsi_scan_host_selected(),
   scsi_scan_channel(), __scsi_scan_target(), scsi_report_lun_scan(),
   and scsi_sequential_lun_scan() to abort scanning early when a signal
   is delivered.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzbot+1f678bd2872aefb11d8a@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=1f678bd2872aefb11d8a
Assisted-by: Gemini
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
 drivers/scsi/scsi_scan.c | 32 ++++++++++++++++++++++++++------
 1 file changed, 26 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 96e4065ae8b5..ebe190f7e1c1 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -32,6 +32,7 @@
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
+#include <linux/sched/signal.h>
 #include <linux/spinlock.h>
 #include <linux/async.h>
 #include <linux/slab.h>
@@ -1415,11 +1416,14 @@ static void scsi_sequential_lun_scan(struct Scsi_Host *shost,
 	 * until we reach the max, or no LUN is found and we are not
 	 * sparse_lun.
 	 */
-	for (lun = 1; lun < max_dev_lun; ++lun)
+	for (lun = 1; lun < max_dev_lun; ++lun) {
+		if (signal_pending(current))
+			break;
 		if (scsi_probe_and_add_lun(shost, starget, lun, NULL, NULL,
 				rescan, NULL) != SCSI_SCAN_LUN_PRESENT &&
 		    !sparse_lun)
 			return;
+	}
 }
 
 /**
@@ -1591,6 +1595,9 @@ static int scsi_report_lun_scan(struct Scsi_Host *shost,
 	 * the header, so start at 1 and go up to and including num_luns.
 	 */
 	for (lunp = &lun_data[1]; lunp <= &lun_data[num_luns]; lunp++) {
+		if (signal_pending(current))
+			break;
+
 		lun = scsilun_to_int(lunp);
 
 		if (lun > sdev->host->max_lun) {
@@ -1804,6 +1811,8 @@ static void __scsi_scan_target(struct Scsi_Host *shost, struct device *parent,
 	 */
 	res = scsi_probe_and_add_lun(shost, starget, 0, &bflags, NULL, rescan,
 				     NULL);
+	if (signal_pending(current))
+		goto out_reap;
 	if (res == SCSI_SCAN_LUN_PRESENT || res == SCSI_SCAN_TARGET_PRESENT) {
 		if (scsi_report_lun_scan(shost, starget, bflags, rescan) != 0)
 			/*
@@ -1876,6 +1885,8 @@ static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel,
 
 	if (id == SCAN_WILD_CARD)
 		for (id = 0; id < shost->max_id; ++id) {
+			if (signal_pending(current))
+				break;
 			/*
 			 * XXX adapter drivers when possible (FCP, iSCSI)
 			 * could modify max_id to match the current max,
@@ -1895,7 +1906,7 @@ static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel,
 			__scsi_scan_target(shost, &shost->shost_gendev, channel,
 					order_id, lun, rescan);
 		}
-	else
+	else if (!signal_pending(current))
 		__scsi_scan_target(shost, &shost->shost_gendev, channel,
 				id, lun, rescan);
 }
@@ -1904,6 +1915,8 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
 			    unsigned int id, u64 lun,
 			    enum scsi_scan_mode rescan)
 {
+	int ret;
+
 	SCSI_LOG_SCAN_BUS(3, shost_printk (KERN_INFO, shost,
 		"%s: <%u:%u:%llu>\n",
 		__func__, channel, id, lun));
@@ -1913,23 +1926,30 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
 	    ((lun != SCAN_WILD_CARD) && (lun >= shost->max_lun)))
 		return -EINVAL;
 
-	mutex_lock(&shost->scan_mutex);
+	ret = mutex_lock_interruptible(&shost->scan_mutex);
+	if (ret)
+		return ret;
+
 	if (!shost->async_scan)
 		scsi_complete_async_scans();
 
-	if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
+	if (!signal_pending(current) && scsi_host_scan_allowed(shost) &&
+	    scsi_autopm_get_host(shost) == 0) {
 		if (channel == SCAN_WILD_CARD)
 			for (channel = 0; channel <= shost->max_channel;
-			     channel++)
+			     channel++) {
+				if (signal_pending(current))
+					break;
 				scsi_scan_channel(shost, channel, id, lun,
 						  rescan);
+			}
 		else
 			scsi_scan_channel(shost, channel, id, lun, rescan);
 		scsi_autopm_put_host(shost);
 	}
 	mutex_unlock(&shost->scan_mutex);
 
-	return 0;
+	return signal_pending(current) ? -EINTR : 0;
 }
 
 static void scsi_sysfs_add_devices(struct Scsi_Host *shost)

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-09-21  8:50 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-11 20:11 [PATCH] scsi: core: Make SCSI host scan interruptible Bart Van Assche
2026-09-11 20:23 ` sashiko-bot
2026-09-11 21:18   ` Bart Van Assche
2026-09-17  1:19 ` Stanley Jhu
2026-09-18 22:19   ` Bart Van Assche
2026-09-21  8:50 ` John Garry

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox