scsi: sd: Revert "Rely on the driver core for asynchronous probing"
Hibernation hangs as follows due to commit21e6ba3f0e
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 commit21e6ba3f0e
. Cc: Pavel Machek <pavel@ucw.cz> Reported-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Bart Van Assche <bvanassche@acm.org> Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:

committed by
Martin K. Petersen

parent
9a058e88fd
commit
395b9bca6b
@@ -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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
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; }
|
|||||||
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 = {
|
|||||||
.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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user