diff mbox series

scsi: fix potential USB flash loss after reboot

Message ID 20250415094737.1394310-1-liujiajia@kylinos.cn
State New
Headers show
Series scsi: fix potential USB flash loss after reboot | expand

Commit Message

Jiajia Liu April 15, 2025, 9:47 a.m. UTC
If device shutdown is blocking for a few seconds after xhci_pci_shutdown,
disk_check_events will get scheduled becase block.events_dfl_poll_msecs
is set to 2000 by user space. usb-storage can get USB access error and
then call usb_reset_device.

Some SanDisk USB flashes, 0781:5567 and 0781:5581, are lost after reboot.

This can be simulated by injecting mdelay(5000) at the end of
i915_driver_shutdown. Add event block in sd_shutdown to prevent
disk_check_events scheduled during the potential blocking.

[   27.324042][    T1] shutdown[1]: Rebooting.
[   27.548410][    T1] sd 1:0:0:0: [sda] Synchronizing SCSI cache
[   30.060554][  T225] usb 4-4: device not accepting address 2, error -108
[   32.838110][    T1] ACPI: PM: Preparing to enter system sleep state S5
[   32.851746][    T1] reboot: Restarting system
[   32.856127][    T1] reboot: machine restart

Before bd738d859e71 ("drm/i915: Prevent modesets during driver init/ shutdown"),
plymouthd can commit modeset during i915 shutdown process, this brings
ten seconds delay.

[   36.519606][    T1] shutdown[1]: Rebooting.
[   36.763427][    T1] sd 1:0:0:0: [sda] Synchronizing SCSI cache
[   37.229513][ T7030] i915 0000:00:02.0: drm_WARN_ON(!intel_irqs_enabled(dev_priv))
...
[   39.008748][ T4356] usb 4-4: device not accepting address 2, error -108
[   43.116781][ T4356] usb usb4-port4: Cannot enable. Maybe the USB cable is bad?
[   47.196768][  T185] usb usb4-port4: Cannot enable. Maybe the USB cable is bad?
[   47.204511][  T185] usb 4-4: USB disconnect, device number 2
[   48.438385][    T1] i915 0000:00:02.0: i915 raw-wakerefs=6 wakelocks=6 on cleanup

Signed-off-by: Jiajia Liu <liujiajia@kylinos.cn>
---
 block/disk-events.c    | 1 +
 drivers/scsi/sd.c      | 4 ++++
 drivers/scsi/sd.h      | 1 +
 include/linux/blkdev.h | 1 +
 4 files changed, 7 insertions(+)
diff mbox series

Patch

diff --git a/block/disk-events.c b/block/disk-events.c
index 2f697224386a..2c998fb360a5 100644
--- a/block/disk-events.c
+++ b/block/disk-events.c
@@ -94,6 +94,7 @@  void disk_block_events(struct gendisk *disk)
 
 	mutex_unlock(&ev->block_mutex);
 }
+EXPORT_SYMBOL_GPL(disk_block_events);
 
 static void __disk_unblock_events(struct gendisk *disk, bool check_now)
 {
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 950d8c9fb884..86199991f2e3 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -4064,6 +4064,7 @@  static int sd_remove(struct device *dev)
 
 	device_del(&sdkp->disk_dev);
 	del_gendisk(sdkp->disk);
+	sdkp->remove = 1;
 	if (!sdkp->suspended)
 		sd_shutdown(dev);
 
@@ -4162,6 +4163,9 @@  static void sd_shutdown(struct device *dev)
 	if (!sdkp)
 		return;         /* this can happen */
 
+	if (sdkp->device->removable && !sdkp->remove)
+		disk_block_events(sdkp->disk);
+
 	if (pm_runtime_suspended(dev))
 		return;
 
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 36382eca941c..ff7004681267 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -156,6 +156,7 @@  struct scsi_disk {
 	unsigned	ignore_medium_access_errors : 1;
 	unsigned	rscs : 1; /* reduced stream control support */
 	unsigned	use_atomic_write_boundary : 1;
+	unsigned	remove : 1;
 };
 #define to_scsi_disk(obj) container_of(obj, struct scsi_disk, disk_dev)
 
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index e39c45bc0a97..7739713c5202 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -879,6 +879,7 @@  int __register_blkdev(unsigned int major, const char *name,
 void unregister_blkdev(unsigned int major, const char *name);
 
 bool disk_check_media_change(struct gendisk *disk);
+void disk_block_events(struct gendisk *disk);
 void set_capacity(struct gendisk *disk, sector_t size);
 
 #ifdef CONFIG_BLOCK_HOLDER_DEPRECATED