[PATCH] scsi: fix potential USB flash loss after reboot
From: Jiajia Liu
Date: Tue Apr 15 2025 - 05:48:05 EST
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@xxxxxxxxxx>
---
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 --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
--
2.25.1