Commit 395b9bca authored by Bart Van Assche's avatar Bart Van Assche Committed by Martin K. Petersen

scsi: sd: Revert "Rely on the driver core for asynchronous probing"

Hibernation hangs as follows due to commit 21e6ba3f when using SATA:

Call Trace:
 __schedule+0x464/0xe70
 schedule+0x4e/0xd0
 blk_queue_enter+0x5fe/0x7e0
 generic_make_request+0x313/0x950
 submit_bio+0x9b/0x250
 submit_bio_wait+0xc9/0x110
 hib_submit_io+0x17d/0x1c0
 write_page+0x61/0xa0
 swap_write_page+0x4b/0x1f0
 swsusp_write+0x2f9/0x3d0
 hibernate.cold.10+0x108/0x231
 state_store+0xf7/0x100
 kobj_attr_store+0x37/0x50
 sysfs_kf_write+0x87/0xa0
 kernfs_fop_write+0x186/0x240
 __vfs_write+0x4d/0x90
 vfs_write+0xfa/0x260
 ksys_write+0xb9/0x1a0
 __x64_sys_write+0x43/0x50
 do_syscall_64+0x71/0x210
 entry_SYSCALL_64_after_hwframe+0x49/0xbe

Hence revert commit 21e6ba3f.

Cc: Pavel Machek <pavel@ucw.cz>
Reported-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarBart Van Assche <bvanassche@acm.org>
Acked-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 9a058e88
...@@ -85,6 +85,19 @@ unsigned int scsi_logging_level; ...@@ -85,6 +85,19 @@ unsigned int scsi_logging_level;
EXPORT_SYMBOL(scsi_logging_level); EXPORT_SYMBOL(scsi_logging_level);
#endif #endif
/* sd, scsi core and power management need to coordinate flushing async actions */
ASYNC_DOMAIN(scsi_sd_probe_domain);
EXPORT_SYMBOL(scsi_sd_probe_domain);
/*
* Separate domain (from scsi_sd_probe_domain) to maximize the benefit of
* asynchronous system resume operations. It is marked 'exclusive' to avoid
* being included in the async_synchronize_full() that is invoked by
* dpm_resume()
*/
ASYNC_DOMAIN_EXCLUSIVE(scsi_sd_pm_domain);
EXPORT_SYMBOL(scsi_sd_pm_domain);
/** /**
* scsi_put_command - Free a scsi command block * scsi_put_command - Free a scsi command block
* @cmd: command block to free * @cmd: command block to free
...@@ -807,6 +820,7 @@ static void __exit exit_scsi(void) ...@@ -807,6 +820,7 @@ static void __exit exit_scsi(void)
scsi_exit_devinfo(); scsi_exit_devinfo();
scsi_exit_procfs(); scsi_exit_procfs();
scsi_exit_queue(); scsi_exit_queue();
async_unregister_domain(&scsi_sd_probe_domain);
} }
subsys_initcall(init_scsi); subsys_initcall(init_scsi);
......
...@@ -55,6 +55,9 @@ static int scsi_dev_type_suspend(struct device *dev, ...@@ -55,6 +55,9 @@ static int scsi_dev_type_suspend(struct device *dev,
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int err; int err;
/* flush pending in-flight resume operations, suspend is synchronous */
async_synchronize_full_domain(&scsi_sd_pm_domain);
err = scsi_device_quiesce(to_scsi_device(dev)); err = scsi_device_quiesce(to_scsi_device(dev));
if (err == 0) { if (err == 0) {
err = cb(dev, pm); err = cb(dev, pm);
...@@ -151,7 +154,18 @@ static int scsi_bus_resume_common(struct device *dev, ...@@ -151,7 +154,18 @@ static int scsi_bus_resume_common(struct device *dev,
else else
fn = NULL; fn = NULL;
if (!fn) { if (fn) {
async_schedule_domain(fn, dev, &scsi_sd_pm_domain);
/*
* If a user has disabled async probing a likely reason
* is due to a storage enclosure that does not inject
* staggered spin-ups. For safety, make resume
* synchronous as well in that case.
*/
if (strncmp(scsi_scan_type, "async", 5) != 0)
async_synchronize_full_domain(&scsi_sd_pm_domain);
} else {
pm_runtime_disable(dev); pm_runtime_disable(dev);
pm_runtime_set_active(dev); pm_runtime_set_active(dev);
pm_runtime_enable(dev); pm_runtime_enable(dev);
...@@ -161,7 +175,11 @@ static int scsi_bus_resume_common(struct device *dev, ...@@ -161,7 +175,11 @@ static int scsi_bus_resume_common(struct device *dev,
static int scsi_bus_prepare(struct device *dev) static int scsi_bus_prepare(struct device *dev)
{ {
if (scsi_is_host_device(dev)) { if (scsi_is_sdev_device(dev)) {
/* sd probing uses async_schedule. Wait until it finishes. */
async_synchronize_full_domain(&scsi_sd_probe_domain);
} else if (scsi_is_host_device(dev)) {
/* Wait until async scanning is finished */ /* Wait until async scanning is finished */
scsi_complete_async_scans(); scsi_complete_async_scans();
} }
......
...@@ -174,6 +174,9 @@ static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; } ...@@ -174,6 +174,9 @@ static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; }
static inline void scsi_autopm_put_host(struct Scsi_Host *h) {} static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
extern struct async_domain scsi_sd_pm_domain;
extern struct async_domain scsi_sd_probe_domain;
/* scsi_dh.c */ /* scsi_dh.c */
#ifdef CONFIG_SCSI_DH #ifdef CONFIG_SCSI_DH
void scsi_dh_add_device(struct scsi_device *sdev); void scsi_dh_add_device(struct scsi_device *sdev);
......
...@@ -567,7 +567,6 @@ static struct scsi_driver sd_template = { ...@@ -567,7 +567,6 @@ static struct scsi_driver sd_template = {
.name = "sd", .name = "sd",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.probe = sd_probe, .probe = sd_probe,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.remove = sd_remove, .remove = sd_remove,
.shutdown = sd_shutdown, .shutdown = sd_shutdown,
.pm = &sd_pm_ops, .pm = &sd_pm_ops,
...@@ -3285,8 +3284,12 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) ...@@ -3285,8 +3284,12 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen)
return 0; return 0;
} }
static void sd_probe_part2(struct scsi_disk *sdkp) /*
* The asynchronous part of sd_probe
*/
static void sd_probe_async(void *data, async_cookie_t cookie)
{ {
struct scsi_disk *sdkp = data;
struct scsi_device *sdp; struct scsi_device *sdp;
struct gendisk *gd; struct gendisk *gd;
u32 index; u32 index;
...@@ -3340,6 +3343,7 @@ static void sd_probe_part2(struct scsi_disk *sdkp) ...@@ -3340,6 +3343,7 @@ static void sd_probe_part2(struct scsi_disk *sdkp)
sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
sdp->removable ? "removable " : ""); sdp->removable ? "removable " : "");
scsi_autopm_put_device(sdp); scsi_autopm_put_device(sdp);
put_device(&sdkp->dev);
} }
/** /**
...@@ -3431,7 +3435,8 @@ static int sd_probe(struct device *dev) ...@@ -3431,7 +3435,8 @@ static int sd_probe(struct device *dev)
get_device(dev); get_device(dev);
dev_set_drvdata(dev, sdkp); dev_set_drvdata(dev, sdkp);
sd_probe_part2(sdkp); get_device(&sdkp->dev); /* prevent release before async_schedule */
async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain);
return 0; return 0;
...@@ -3466,6 +3471,8 @@ static int sd_remove(struct device *dev) ...@@ -3466,6 +3471,8 @@ static int sd_remove(struct device *dev)
devt = disk_devt(sdkp->disk); devt = disk_devt(sdkp->disk);
scsi_autopm_get_device(sdkp->device); scsi_autopm_get_device(sdkp->device);
async_synchronize_full_domain(&scsi_sd_pm_domain);
async_synchronize_full_domain(&scsi_sd_probe_domain);
device_del(&sdkp->dev); device_del(&sdkp->dev);
del_gendisk(sdkp->disk); del_gendisk(sdkp->disk);
sd_shutdown(dev); sd_shutdown(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment