Skip to content

Commit 331a6ed

Browse files
committed
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()
2 parents 8ecfa36 + 1e0d4e6 commit 331a6ed

File tree

1 file changed

+26
-21
lines changed

1 file changed

+26
-21
lines changed

drivers/scsi/hosts.c

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -254,12 +254,11 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
254254

255255
device_enable_async_suspend(&shost->shost_dev);
256256

257+
get_device(&shost->shost_gendev);
257258
error = device_add(&shost->shost_dev);
258259
if (error)
259260
goto out_del_gendev;
260261

261-
get_device(&shost->shost_gendev);
262-
263262
if (shost->transportt->host_size) {
264263
shost->shost_data = kzalloc(shost->transportt->host_size,
265264
GFP_KERNEL);
@@ -278,33 +277,36 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
278277

279278
if (!shost->work_q) {
280279
error = -EINVAL;
281-
goto out_free_shost_data;
280+
goto out_del_dev;
282281
}
283282
}
284283

285284
error = scsi_sysfs_add_host(shost);
286285
if (error)
287-
goto out_destroy_host;
286+
goto out_del_dev;
288287

289288
scsi_proc_host_add(shost);
290289
scsi_autopm_put_host(shost);
291290
return error;
292291

293-
out_destroy_host:
294-
if (shost->work_q)
295-
destroy_workqueue(shost->work_q);
296-
out_free_shost_data:
297-
kfree(shost->shost_data);
292+
/*
293+
* Any host allocation in this function will be freed in
294+
* scsi_host_dev_release().
295+
*/
298296
out_del_dev:
299297
device_del(&shost->shost_dev);
300298
out_del_gendev:
299+
/*
300+
* Host state is SHOST_RUNNING so we have to explicitly release
301+
* ->shost_dev.
302+
*/
303+
put_device(&shost->shost_dev);
301304
device_del(&shost->shost_gendev);
302305
out_disable_runtime_pm:
303306
device_disable_async_suspend(&shost->shost_gendev);
304307
pm_runtime_disable(&shost->shost_gendev);
305308
pm_runtime_set_suspended(&shost->shost_gendev);
306309
pm_runtime_put_noidle(&shost->shost_gendev);
307-
scsi_mq_destroy_tags(shost);
308310
fail:
309311
return error;
310312
}
@@ -345,7 +347,7 @@ static void scsi_host_dev_release(struct device *dev)
345347

346348
ida_simple_remove(&host_index_ida, shost->host_no);
347349

348-
if (parent)
350+
if (shost->shost_state != SHOST_CREATED)
349351
put_device(parent);
350352
kfree(shost);
351353
}
@@ -388,8 +390,10 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
388390
mutex_init(&shost->scan_mutex);
389391

390392
index = ida_simple_get(&host_index_ida, 0, 0, GFP_KERNEL);
391-
if (index < 0)
392-
goto fail_kfree;
393+
if (index < 0) {
394+
kfree(shost);
395+
return NULL;
396+
}
393397
shost->host_no = index;
394398

395399
shost->dma_channel = 0xff;
@@ -481,7 +485,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
481485
shost_printk(KERN_WARNING, shost,
482486
"error handler thread failed to spawn, error = %ld\n",
483487
PTR_ERR(shost->ehandler));
484-
goto fail_index_remove;
488+
goto fail;
485489
}
486490

487491
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)
490494
if (!shost->tmf_work_q) {
491495
shost_printk(KERN_WARNING, shost,
492496
"failed to create tmf workq\n");
493-
goto fail_kthread;
497+
goto fail;
494498
}
495499
scsi_proc_hostdir_add(shost->hostt);
496500
return shost;
501+
fail:
502+
/*
503+
* Host state is still SHOST_CREATED and that is enough to release
504+
* ->shost_gendev. scsi_host_dev_release() will free
505+
* dev_name(&shost->shost_dev).
506+
*/
507+
put_device(&shost->shost_gendev);
497508

498-
fail_kthread:
499-
kthread_stop(shost->ehandler);
500-
fail_index_remove:
501-
ida_simple_remove(&host_index_ida, shost->host_no);
502-
fail_kfree:
503-
kfree(shost);
504509
return NULL;
505510
}
506511
EXPORT_SYMBOL(scsi_host_alloc);

0 commit comments

Comments
 (0)