diff options
author | Hannes Reinecke <hare@suse.de> | 2013-05-10 11:06:16 +0200 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-06-04 11:16:23 -0700 |
commit | 0761df9c4b2d966da3af2ac4ee7372afa681ce63 (patch) | |
tree | 270b55e300537889e9eb2254f04f824abb964cbd /drivers/scsi/sd.c | |
parent | 70288b4c8fd35340b79b25b2ac9c86a79d105e60 (diff) | |
download | op-kernel-dev-0761df9c4b2d966da3af2ac4ee7372afa681ce63.zip op-kernel-dev-0761df9c4b2d966da3af2ac4ee7372afa681ce63.tar.gz |
[SCSI] sd: avoid deadlocks when running under multipath
When multipathed systems run into an all-paths-down scenario
all devices might be dropped, too. This causes 'del_gendisk'
to be called, which will unregister the kobj_map->probe()
function for all disk device numbers.
When the device comes back the default ->probe() function
is run which will call __request_module(), which will
deadlock.
As 'del_gendisk' typically does _not_ trigger a module unload
the default ->probe() function is pointless anyway.
This patch implements a dummy ->probe() function, which will
just return NULL if the disk is not registered.
This will avoid the deadlock. Plus it'll speed up device
scanning.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 29 |
1 files changed, 25 insertions, 4 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index c1c5552..a37eda9 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -504,6 +504,16 @@ static struct scsi_driver sd_template = { }; /* + * Dummy kobj_map->probe function. + * The default ->probe function will call modprobe, which is + * pointless as this module is already loaded. + */ +static struct kobject *sd_default_probe(dev_t devt, int *partno, void *data) +{ + return NULL; +} + +/* * Device no to disk mapping: * * major disc2 disc p1 @@ -2970,8 +2980,10 @@ static int sd_probe(struct device *dev) static int sd_remove(struct device *dev) { struct scsi_disk *sdkp; + dev_t devt; sdkp = dev_get_drvdata(dev); + devt = disk_devt(sdkp->disk); scsi_autopm_get_device(sdkp->device); async_synchronize_full_domain(&scsi_sd_probe_domain); @@ -2981,6 +2993,9 @@ static int sd_remove(struct device *dev) del_gendisk(sdkp->disk); sd_shutdown(dev); + blk_register_region(devt, SD_MINORS, NULL, + sd_default_probe, NULL, NULL); + mutex_lock(&sd_ref_mutex); dev_set_drvdata(dev, NULL); put_device(&sdkp->dev); @@ -3124,9 +3139,13 @@ static int __init init_sd(void) SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n")); - for (i = 0; i < SD_MAJORS; i++) - if (register_blkdev(sd_major(i), "sd") == 0) - majors++; + for (i = 0; i < SD_MAJORS; i++) { + if (register_blkdev(sd_major(i), "sd") != 0) + continue; + majors++; + blk_register_region(sd_major(i), SD_MINORS, NULL, + sd_default_probe, NULL, NULL); + } if (!majors) return -ENODEV; @@ -3185,8 +3204,10 @@ static void __exit exit_sd(void) class_unregister(&sd_disk_class); - for (i = 0; i < SD_MAJORS; i++) + for (i = 0; i < SD_MAJORS; i++) { + blk_unregister_region(sd_major(i), SD_MINORS); unregister_blkdev(sd_major(i), "sd"); + } } module_init(init_sd); |