forked from mirrors/linux
		
	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:
		
							parent
							
								
									ea9006dfda
								
							
						
					
					
						commit
						21e6ba3f0e
					
				
					 4 changed files with 5 additions and 47 deletions
				
			
		|  | @ -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); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Bart Van Assche
						Bart Van Assche