scsi: sd: Rely on the driver core for asynchronous probing
As explained during the 2018 LSF/MM session about increasing SCSI disk
probing concurrency, the problems with the current probing approach are as
follows:
- The driver core is unaware of asynchronous SCSI LUN probing.
wait_for_device_probe() waits for all asynchronous probes except
asynchronous SCSI disk probes.
- There is unnecessary serialization between sd_probe() and sd_remove().
This can lead to a deadlock.
Hence this patch that modifies the sd driver such that it uses the driver
core framework for asynchronous probing. The async domains and
get_device()/put_device() pairs that became superfluous due to this change
are removed.
This patch does not affect the time needed for loading the scsi_debug
kernel module with parameters delay=0 and max_luns=256.
This patch depends on commit ef0ff68351
("driver core: Probe devices
asynchronously instead of the driver") that went upstream in kernel version
v5.1-rc1.
Cc: Lee Duncan <lduncan@suse.com>
Cc: Hannes Reinecke <hare@suse.com>
Cc: Luis Chamberlain <mcgrof@kernel.org>
Cc: Johannes Thumshirn <jthumshirn@suse.de>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Родитель
ea9006dfda
Коммит
21e6ba3f0e
|
@ -85,19 +85,6 @@ unsigned int scsi_logging_level;
|
|||
EXPORT_SYMBOL(scsi_logging_level);
|
||||
#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
|
||||
* @cmd: command block to free
|
||||
|
@ -820,7 +807,6 @@ static void __exit exit_scsi(void)
|
|||
scsi_exit_devinfo();
|
||||
scsi_exit_procfs();
|
||||
scsi_exit_queue();
|
||||
async_unregister_domain(&scsi_sd_probe_domain);
|
||||
}
|
||||
|
||||
subsys_initcall(init_scsi);
|
||||
|
|
|
@ -55,9 +55,6 @@ static int scsi_dev_type_suspend(struct device *dev,
|
|||
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
||||
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));
|
||||
if (err == 0) {
|
||||
err = cb(dev, pm);
|
||||
|
@ -154,18 +151,7 @@ static int scsi_bus_resume_common(struct device *dev,
|
|||
else
|
||||
fn = NULL;
|
||||
|
||||
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 {
|
||||
if (!fn) {
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
@ -175,11 +161,7 @@ static int scsi_bus_resume_common(struct device *dev,
|
|||
|
||||
static int scsi_bus_prepare(struct 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)) {
|
||||
if (scsi_is_host_device(dev)) {
|
||||
/* Wait until async scanning is finished */
|
||||
scsi_complete_async_scans();
|
||||
}
|
||||
|
|
|
@ -174,9 +174,6 @@ static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; }
|
|||
static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
extern struct async_domain scsi_sd_pm_domain;
|
||||
extern struct async_domain scsi_sd_probe_domain;
|
||||
|
||||
/* scsi_dh.c */
|
||||
#ifdef CONFIG_SCSI_DH
|
||||
void scsi_dh_add_device(struct scsi_device *sdev);
|
||||
|
|
|
@ -567,6 +567,7 @@ static struct scsi_driver sd_template = {
|
|||
.name = "sd",
|
||||
.owner = THIS_MODULE,
|
||||
.probe = sd_probe,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.remove = sd_remove,
|
||||
.shutdown = sd_shutdown,
|
||||
.pm = &sd_pm_ops,
|
||||
|
@ -3286,12 +3287,8 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The asynchronous part of sd_probe
|
||||
*/
|
||||
static void sd_probe_async(void *data, async_cookie_t cookie)
|
||||
static void sd_probe_part2(struct scsi_disk *sdkp)
|
||||
{
|
||||
struct scsi_disk *sdkp = data;
|
||||
struct scsi_device *sdp;
|
||||
struct gendisk *gd;
|
||||
u32 index;
|
||||
|
@ -3345,7 +3342,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
|
|||
sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
|
||||
sdp->removable ? "removable " : "");
|
||||
scsi_autopm_put_device(sdp);
|
||||
put_device(&sdkp->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3437,8 +3433,7 @@ static int sd_probe(struct device *dev)
|
|||
get_device(dev);
|
||||
dev_set_drvdata(dev, sdkp);
|
||||
|
||||
get_device(&sdkp->dev); /* prevent release before async_schedule */
|
||||
async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain);
|
||||
sd_probe_part2(sdkp);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -3473,8 +3468,6 @@ static int sd_remove(struct device *dev)
|
|||
devt = disk_devt(sdkp->disk);
|
||||
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);
|
||||
del_gendisk(sdkp->disk);
|
||||
sd_shutdown(dev);
|
||||
|
|
Загрузка…
Ссылка в новой задаче