SCSI fixes on 20210613
Four reasonably small fixes to the core for scsi host allocation failure paths. The root problem is that we're not freeing the memory allocated by dev_set_name(), which involves a rejig of may of the free on error paths to do put_device() instead of kfree which, in turn, has several other knock on ramifications and inspection turned up a few other lurking bugs. Signed-off-by: James E.J. Bottomley <jejb@linux.ibm.com> -----BEGIN PGP SIGNATURE----- iJwEABMIAEQWIQTnYEDbdso9F2cI+arnQslM7pishQUCYMYEVCYcamFtZXMuYm90 dG9tbGV5QGhhbnNlbnBhcnRuZXJzaGlwLmNvbQAKCRDnQslM7pishbP/AP4oyLA5 h7T5v7z29prQWn0P3TApcDVvXjOnqPNUzZlvkAEAifnVHLMehlzrJDeaSR0OUf8u U+SKrsxkiov5XYvwGGU= =0Vfx -----END PGP SIGNATURE----- Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi Pull SCSI fixes from James Bottomley: "Four reasonably small fixes to the core for scsi host allocation failure paths. The root problem is that we're not freeing the memory allocated by dev_set_name(), which involves a rejig of may of the free on error paths to do put_device() instead of kfree which, in turn, has several other knock on ramifications and inspection turned up a few other lurking bugs" * tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: scsi: core: Only put parent device if host state differs from SHOST_CREATED scsi: core: Put .shost_dev in failure path if host state changes to RUNNING scsi: core: Fix failure handling of scsi_add_host_with_dma() scsi: core: Fix error handling of scsi_host_alloc()
This commit is contained in:
commit
331a6edb30
@ -254,12 +254,11 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
|
||||
|
||||
device_enable_async_suspend(&shost->shost_dev);
|
||||
|
||||
get_device(&shost->shost_gendev);
|
||||
error = device_add(&shost->shost_dev);
|
||||
if (error)
|
||||
goto out_del_gendev;
|
||||
|
||||
get_device(&shost->shost_gendev);
|
||||
|
||||
if (shost->transportt->host_size) {
|
||||
shost->shost_data = kzalloc(shost->transportt->host_size,
|
||||
GFP_KERNEL);
|
||||
@ -278,33 +277,36 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
|
||||
|
||||
if (!shost->work_q) {
|
||||
error = -EINVAL;
|
||||
goto out_free_shost_data;
|
||||
goto out_del_dev;
|
||||
}
|
||||
}
|
||||
|
||||
error = scsi_sysfs_add_host(shost);
|
||||
if (error)
|
||||
goto out_destroy_host;
|
||||
goto out_del_dev;
|
||||
|
||||
scsi_proc_host_add(shost);
|
||||
scsi_autopm_put_host(shost);
|
||||
return error;
|
||||
|
||||
out_destroy_host:
|
||||
if (shost->work_q)
|
||||
destroy_workqueue(shost->work_q);
|
||||
out_free_shost_data:
|
||||
kfree(shost->shost_data);
|
||||
/*
|
||||
* Any host allocation in this function will be freed in
|
||||
* scsi_host_dev_release().
|
||||
*/
|
||||
out_del_dev:
|
||||
device_del(&shost->shost_dev);
|
||||
out_del_gendev:
|
||||
/*
|
||||
* Host state is SHOST_RUNNING so we have to explicitly release
|
||||
* ->shost_dev.
|
||||
*/
|
||||
put_device(&shost->shost_dev);
|
||||
device_del(&shost->shost_gendev);
|
||||
out_disable_runtime_pm:
|
||||
device_disable_async_suspend(&shost->shost_gendev);
|
||||
pm_runtime_disable(&shost->shost_gendev);
|
||||
pm_runtime_set_suspended(&shost->shost_gendev);
|
||||
pm_runtime_put_noidle(&shost->shost_gendev);
|
||||
scsi_mq_destroy_tags(shost);
|
||||
fail:
|
||||
return error;
|
||||
}
|
||||
@ -345,7 +347,7 @@ static void scsi_host_dev_release(struct device *dev)
|
||||
|
||||
ida_simple_remove(&host_index_ida, shost->host_no);
|
||||
|
||||
if (parent)
|
||||
if (shost->shost_state != SHOST_CREATED)
|
||||
put_device(parent);
|
||||
kfree(shost);
|
||||
}
|
||||
@ -388,8 +390,10 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
|
||||
mutex_init(&shost->scan_mutex);
|
||||
|
||||
index = ida_simple_get(&host_index_ida, 0, 0, GFP_KERNEL);
|
||||
if (index < 0)
|
||||
goto fail_kfree;
|
||||
if (index < 0) {
|
||||
kfree(shost);
|
||||
return NULL;
|
||||
}
|
||||
shost->host_no = index;
|
||||
|
||||
shost->dma_channel = 0xff;
|
||||
@ -481,7 +485,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
|
||||
shost_printk(KERN_WARNING, shost,
|
||||
"error handler thread failed to spawn, error = %ld\n",
|
||||
PTR_ERR(shost->ehandler));
|
||||
goto fail_index_remove;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
shost->tmf_work_q = alloc_workqueue("scsi_tmf_%d",
|
||||
@ -490,17 +494,18 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
|
||||
if (!shost->tmf_work_q) {
|
||||
shost_printk(KERN_WARNING, shost,
|
||||
"failed to create tmf workq\n");
|
||||
goto fail_kthread;
|
||||
goto fail;
|
||||
}
|
||||
scsi_proc_hostdir_add(shost->hostt);
|
||||
return shost;
|
||||
fail:
|
||||
/*
|
||||
* Host state is still SHOST_CREATED and that is enough to release
|
||||
* ->shost_gendev. scsi_host_dev_release() will free
|
||||
* dev_name(&shost->shost_dev).
|
||||
*/
|
||||
put_device(&shost->shost_gendev);
|
||||
|
||||
fail_kthread:
|
||||
kthread_stop(shost->ehandler);
|
||||
fail_index_remove:
|
||||
ida_simple_remove(&host_index_ida, shost->host_no);
|
||||
fail_kfree:
|
||||
kfree(shost);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_host_alloc);
|
||||
|
Loading…
Reference in New Issue
Block a user