scsi: ufs & esp_scsi: fix module reference counting
Subsystems (2)
PATCH v7 1/1 scsi: ufs & esp_scsi: fix module reference counting
While accessing a scsi_device, the use count of the underlying LLDD module is incremented. The module reference is retrieved through .module field of struct scsi_host_template.
This mapping between scsi_device and underlying LLDD module works well except ufs and esp scsi drivers. These drivers consist with core driver and actual LLDDs, and scsi_host_template is defined in the core driver. Since the module reference count isn't incremented, the actual LLDDs can be unloaded while the scsi_device is being accessed.
This fixes it by preparing scsi host template for each LLDDs, which is initialized at module_init().
* v7:
- Patch series is almost rewritten again and no scsi mid layer change anymore. This fixes the issue by preparing scsi host template for each LLDDs, which is initialized at module_init().
The idea is provided by James Bottomley
- The patch for usb-storage was removed as it was added to usb-testing
* v6:
- Rebased as v5 doesn't apply cleanly to the latest tree anymore.
* v5:
- Discard v4 changes and restore to v3. Because v4 shows that moving owner module field from scsi_host_template to Scsi_Host requires a lot of changes and introduces complication to existing drivers which don't have the module reference mismatch issue.
- Rebased to the 4.0-rc1
* v4:
- Patch series is almost rewritten as module reference field in struct scsi_host_template has been unused anymore. So Acked-by: and
Reviewed-by: tags that have been received are deleted.
* v3:
- Add fix for ESP SCSI drivers
* v2:
- Pass correct module reference to usb_stor_probe1() instead of touching all ums-* drivers, suggested by Alan Stern
Akinobu Mita (2):
scsi: ufs: fix module reference for scsi host
scsi: esp_scsi: fix module reference for scsi host
drivers/scsi/am53c974.c | 7 +++++-- drivers/scsi/esp_scsi.c | 13 +++++++++++-- drivers/scsi/esp_scsi.h | 9 +++++++-- drivers/scsi/jazz_esp.c | 7 +++++-- drivers/scsi/mac_esp.c | 7 +++++-- drivers/scsi/sun3x_esp.c | 7 +++++-- drivers/scsi/sun_esp.c | 7 +++++-- drivers/scsi/ufs/ufshcd-pci.c | 19 +++++++++++++++++-- drivers/scsi/ufs/ufshcd-pltfrm.c | 19 +++++++++++++++++-- drivers/scsi/ufs/ufshcd.c | 19 +++++++++++++++---- drivers/scsi/ufs/ufshcd.h | 5 ++++- 11 files changed, 96 insertions(+), 23 deletions(-)
Signature · 1 line
1.9.1
PATCH v7 1/1 scsi: ufs: fix module reference for scsi host
While accessing a UFS device, the module reference count for core driver (ufshcd) is incremented but not incremented for the actual glue driver (ufshcd-pci or ufshcd-pltfrm). Because these drivers allocate scsi hosts with scsi_host_template defined in ufshcd module. So these drivers always can be unloaded.
This fixes it by preparing scsi host template which is initialized at module_init() for each ufs glue driver.
--- drivers/scsi/ufs/ufshcd-pci.c | 19 +++++++++++++++++-- drivers/scsi/ufs/ufshcd-pltfrm.c | 19 +++++++++++++++++-- drivers/scsi/ufs/ufshcd.c | 19 +++++++++++++++---- drivers/scsi/ufs/ufshcd.h | 5 ++++- 4 files changed, 53 insertions(+), 9 deletions(-)
drivers/scsi/ufs/ufshcd-pci.c +17 -2
@@ -106,6 +106,8 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)ufshcd_remove (hba); } +static struct scsi_host_template ufshcd_pci_host_template; +/** * ufshcd_pci_probe - probe routine of the driver * @pdev: pointer to PCI device handle
@@ -136,7 +138,7 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mmio_base =pcim_iomap_table (pdev)[0 ]; - err =ufshcd_alloc_host (&pdev->dev, &hba); + err =ufshcd_alloc_host (&pdev->dev, &ufshcd_pci_host_template, &hba);if (err) {dev_err (&pdev->dev,"Allocation failed\n" );return err;
@@ -183,7 +185,20 @@ static struct pci_driver ufshcd_pci_driver = { }, }; -module_pci_driver (ufshcd_pci_driver); +static int __init ufshcd_pci_driver_init (void ) +{ +ufshcd_host_template_init (&ufshcd_pci_host_template,"ufshcd-pci" , +THIS_MODULE ); + +return pci_register_driver (&ufshcd_pci_driver); +} +module_init (ufshcd_pci_driver_init); + +static void __exit ufshcd_pci_driver_exit(void) +{ +pci_unregister_driver (&ufshcd_pci_driver); +} +module_exit (ufshcd_pci_driver_exit);MODULE_AUTHOR ("Santosh Yaragnavi <[email protected]>" );MODULE_AUTHOR ("Vinayak Holikatti <[email protected]>" );
drivers/scsi/ufs/ufshcd-pltfrm.c +17 -2
@@ -288,6 +288,8 @@ static void ufshcd_pltfrm_shutdown(struct platform_device *pdev)ufshcd_shutdown ((struct ufs_hba *)platform_get_drvdata (pdev)); } +static struct scsi_host_template ufshcd_pltfrm_host_template; +/** * ufshcd_pltfrm_probe - probe routine of the driver * @pdev: pointer to Platform device handle
@@ -316,7 +318,7 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev) goto out; } - err =ufshcd_alloc_host (dev, &hba); + err =ufshcd_alloc_host (dev, &ufshcd_pltfrm_host_template, &hba);if (err) {dev_err (&pdev->dev,"Allocation failed\n" ); goto out;
@@ -404,7 +406,20 @@ static struct platform_driver ufshcd_pltfrm_driver = { }, }; -module_platform_driver (ufshcd_pltfrm_driver); +static int __init ufshcd_pltfrm_driver_init (void ) +{ +ufshcd_host_template_init (&ufshcd_pltfrm_host_template,"ufshcd-pltfrm" , +THIS_MODULE ); + +return platform_driver_register (&ufshcd_pltfrm_driver); +} +module_init (ufshcd_pltfrm_driver_init); + +static void __exit ufshcd_pltfrm_driver_exit(void) +{ +platform_driver_unregister (&ufshcd_pltfrm_driver); +} +module_exit (ufshcd_pltfrm_driver_exit);MODULE_AUTHOR ("Santosh Yaragnavi <[email protected]>" );MODULE_AUTHOR ("Vinayak Holikatti <[email protected]>" );
drivers/scsi/ufs/ufshcd.c +15 -4
@@ -4234,7 +4234,7 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)ufshcd_probe_hba (hba); } -static struct scsi_host_template ufshcd_driver_template = { +static const struct scsi_host_template ufshcd_driver_template = { .module =THIS_MODULE , .name =UFSHCD , .proc_name =UFSHCD ,
@@ -4255,6 +4255,16 @@ static struct scsi_host_template ufshcd_driver_template = { .track_queue_depth = 1, }; +void ufshcd_host_template_init (struct scsi_host_template *sht,const char *name, +struct module *owner) +{ + *sht = ufshcd_driver_template; + sht->name = name; + sht->proc_name = name; + sht->module = owner; +} +EXPORT_SYMBOL_GPL (ufshcd_host_template_init); +static int ufshcd_config_vreg_load (struct device *dev,struct ufs_vreg *vreg,int ua) {
@@ -5272,10 +5282,12 @@ static int ufshcd_set_dma_mask(struct ufs_hba *hba)/** * ufshcd_alloc_host - allocate Host Bus Adapter (HBA) * @dev: pointer to device handle +* @sht: scsi_host_template to use when registering the host * @hba_handle: driver private handle * Returns 0 on success, non-zero value on failure */ -int ufshcd_alloc_host (struct device *dev,struct ufs_hba **hba_handle) +int ufshcd_alloc_host (struct device *dev,struct scsi_host_template *sht, +struct ufs_hba **hba_handle) {struct Scsi_Host *host;struct ufs_hba *hba;
@@ -5288,8 +5300,7 @@ int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle) goto out_error; } - host =scsi_host_alloc (&ufshcd_driver_template, -sizeof (struct ufs_hba )); + host =scsi_host_alloc (sht,sizeof (struct ufs_hba ));if (!host) {dev_err (dev,"scsi_host_alloc failed\n" ); err = -ENOMEM ;
drivers/scsi/ufs/ufshcd.h +4 -1
@@ -524,7 +524,10 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)ufshcd_writel (hba, tmp, reg); } -int ufshcd_alloc_host (struct device *,struct ufs_hba **); +void ufshcd_host_template_init (struct scsi_host_template *sht,const char *name, +struct module *owner); +int ufshcd_alloc_host (struct device *,struct scsi_host_template *, +struct ufs_hba **);int ufshcd_init (struct ufs_hba * ,void __iomem * ,unsigned int );void ufshcd_remove (struct ufs_hba *);
Signature · 1 line
1.9.1
PATCH v7 1/1 scsi: esp_scsi: fix module reference for scsi host
In reply to Akinobu MitaWhile accessing a scsi device on host adapter supported by sub driver for the ESP chip (mac_esp, am53c974, sun_esp, jazz_esp, sun3x_esp), the module reference count for ESP SCSI driver core module (esp_scsi) is incremented but not incremented for actual sub drivers. Because these drivers allocate scsi hosts with scsi_esp_template defined in the core module. So these drivers always can be unloaded.
This fixes it by preparing scsi host template which is initialized at module_init() for each esp sub driver.
--- drivers/scsi/am53c974.c | 7 +++++-- drivers/scsi/esp_scsi.c | 13 +++++++++++-- drivers/scsi/esp_scsi.h | 9 +++++++-- drivers/scsi/jazz_esp.c | 7 +++++-- drivers/scsi/mac_esp.c | 7 +++++-- drivers/scsi/sun3x_esp.c | 7 +++++-- drivers/scsi/sun_esp.c | 7 +++++-- 7 files changed, 43 insertions(+), 14 deletions(-)
drivers/scsi/am53c974.c +5 -2
@@ -397,10 +397,11 @@ static void dc390_check_eeprom(struct esp *esp) esp->config4 |=ESP_CONFIG4_RADE |ESP_CONFIG4_RAE ; } +static struct scsi_host_template pci_esp_template; +static int pci_esp_probe_one (struct pci_dev *pdev,const struct pci_device_id *id) { -struct scsi_host_template *hostt = &scsi_esp_template;int err = -ENODEV ;struct Scsi_Host *shost;struct esp *esp;
@@ -417,7 +418,7 @@ static int pci_esp_probe_one(struct pci_dev *pdev, goto fail_disable_device; } - shost =scsi_host_alloc (hostt,sizeof (struct esp )); + shost =scsi_host_alloc (&pci_esp_template,sizeof (struct esp ));if (!shost) {dev_printk (KERN_INFO , &pdev->dev,"failed to allocate scsi host\n" );
@@ -558,6 +559,8 @@ static struct pci_driver am53c974_driver = {static int __init am53c974_module_init (void ) { +scsi_esp_template_init (&pci_esp_template,DRV_MODULE_NAME ); +return pci_register_driver (&am53c974_driver); }
drivers/scsi/esp_scsi.c +11 -2
@@ -2675,7 +2675,7 @@ static const char *esp_info(struct Scsi_Host *host)return "esp" ; } -struct scsi_host_template scsi_esp_template = { +static const struct scsi_host_template scsi_esp_template = { .module =THIS_MODULE , .name ="esp" , .info = esp_info,
@@ -2696,7 +2696,16 @@ struct scsi_host_template scsi_esp_template = { .skip_settle_delay = 1, .use_blk_tags = 1, }; -EXPORT_SYMBOL (scsi_esp_template); + +void __scsi_esp_template_init (struct scsi_host_template *sht,const char *name, +struct module *owner) +{ + *sht = scsi_esp_template; + sht->name = name; + sht->proc_name = name; + sht->module = owner; +} +EXPORT_SYMBOL (__scsi_esp_template_init);static void esp_get_signalling (struct Scsi_Host *host) {
drivers/scsi/esp_scsi.h +7 -2
@@ -544,9 +544,11 @@ struct esp {/* A front-end driver for the ESP chip should do the following in * it's device probe routine: +* 0) Declare the scsi_host_template and initialize it using +* scsi_esp_template_init() with the driver name in module_init(). * 1) Allocate the host and private area using scsi_host_alloc() * with size 'sizeof(struct esp)'. The first argument to -* scsi_host_alloc() should be &scsi_esp_template. +* scsi_host_alloc() should be the scsi_host_template initialized in 0) * 2) Set host->max_id as appropriate. * 3) Set esp->host to the scsi_host itself, and esp->dev * to the device object pointer.
@@ -573,7 +575,10 @@ struct esp {* 13) Check scsi_esp_register() return value, release all resources * if an error was returned. */ -extern struct scsi_host_template scsi_esp_template; +extern void __scsi_esp_template_init (struct scsi_host_template *sht, +const char *name,struct module *owner); +#define scsi_esp_template_init (sht, name) \ + __scsi_esp_template_init(sht, name, THIS_MODULE)extern int scsi_esp_register (struct esp *,struct device *);extern void scsi_esp_unregister (struct esp *);
drivers/scsi/jazz_esp.c +5 -2
@@ -129,15 +129,16 @@ static const struct esp_driver_ops jazz_esp_ops = { .dma_error = jazz_esp_dma_error, }; +static struct scsi_host_template esp_jazz_template; +static int esp_jazz_probe (struct platform_device *dev) { -struct scsi_host_template *tpnt = &scsi_esp_template;struct Scsi_Host *host;struct esp *esp;struct resource *res;int err; - host =scsi_host_alloc (tpnt,sizeof (struct esp )); + host =scsi_host_alloc (&esp_jazz_template,sizeof (struct esp )); err = -ENOMEM ;if (!host)
@@ -231,6 +232,8 @@ static struct platform_driver esp_jazz_driver = {static int __init jazz_esp_init (void ) { +scsi_esp_template_init (&esp_jazz_template,DRV_MODULE_NAME ); +return platform_driver_register (&esp_jazz_driver); }
drivers/scsi/mac_esp.c +5 -2
@@ -481,9 +481,10 @@ static struct esp_driver_ops mac_esp_ops = { .dma_error = mac_esp_dma_error, }; +static struct scsi_host_template esp_mac_template; +static int esp_mac_probe (struct platform_device *dev) { -struct scsi_host_template *tpnt = &scsi_esp_template;struct Scsi_Host *host;struct esp *esp;int err;
@@ -495,7 +496,7 @@ static int esp_mac_probe(struct platform_device *dev)if (dev->id >1 )return -ENODEV ; - host =scsi_host_alloc (tpnt,sizeof (struct esp )); + host =scsi_host_alloc (&esp_mac_template,sizeof (struct esp )); err = -ENOMEM ;if (!host)
@@ -622,6 +623,8 @@ static struct platform_driver esp_mac_driver = {static int __init mac_esp_init (void ) { +scsi_esp_template_init (&esp_mac_template,DRV_MODULE_NAME ); +return platform_driver_register (&esp_mac_driver); }
drivers/scsi/sun3x_esp.c +5 -2
@@ -194,15 +194,16 @@ static const struct esp_driver_ops sun3x_esp_ops = { .dma_error = sun3x_esp_dma_error, }; +static struct scsi_host_template esp_sun3x_template; +static int esp_sun3x_probe (struct platform_device *dev) { -struct scsi_host_template *tpnt = &scsi_esp_template;struct Scsi_Host *host;struct esp *esp;struct resource *res;int err = -ENOMEM ; - host =scsi_host_alloc (tpnt,sizeof (struct esp )); + host =scsi_host_alloc (&esp_sun3x_template,sizeof (struct esp ));if (!host) goto fail;
@@ -300,6 +301,8 @@ static struct platform_driver esp_sun3x_driver = {static int __init sun3x_esp_init (void ) { +scsi_esp_template_init (&esp_sun3x_template,DRV_MODULE_NAME ); +return platform_driver_register (&esp_sun3x_driver); }
drivers/scsi/sun_esp.c +5 -2
@@ -486,15 +486,16 @@ static const struct esp_driver_ops sbus_esp_ops = { .dma_error = sbus_esp_dma_error, }; +static struct scsi_host_template esp_sbus_template; +static int esp_sbus_probe_one (struct platform_device *op,struct platform_device *espdma,int hme) { -struct scsi_host_template *tpnt = &scsi_esp_template;struct Scsi_Host *host;struct esp *esp;int err; - host =scsi_host_alloc (tpnt,sizeof (struct esp )); + host =scsi_host_alloc (&esp_sbus_template,sizeof (struct esp )); err = -ENOMEM ;if (!host)
@@ -641,6 +642,8 @@ static struct platform_driver esp_sbus_driver = {static int __init sunesp_init (void ) { +scsi_esp_template_init (&esp_sbus_template,DRV_MODULE_NAME ); +return platform_driver_register (&esp_sbus_driver); }
Signature · 1 line
1.9.1