aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2014-02-20 17:21:01 -0500
committerJames Bottomley <JBottomley@Parallels.com>2014-03-27 11:26:33 -0400
commit89d9a567952baec13e26ada3e438f1b642d66b6e (patch)
treef6217370ee634dc3fa08228a0aa1073265aa13b7 /drivers
parent7c283341225d0ebeb7480a9e6560f599dcd0f417 (diff)
[SCSI] add support for per-host cmd pools
This allows drivers to specify the size of their per-command private data in the host template and then get extra memory allocated for each command instead of needing another allocation in ->queuecommand. With the current SCSI code that already does multiple allocations for each command this probably doesn't make a big performance impact, but it allows to clean up the drivers, and prepare them for using the blk-mq infrastructure where the common allocation will make a difference. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/scsi.c96
1 files changed, 77 insertions, 19 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 586c241c941e..c4d632c27a3e 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -331,46 +331,103 @@ void scsi_put_command(struct scsi_cmnd *cmd)
331} 331}
332EXPORT_SYMBOL(scsi_put_command); 332EXPORT_SYMBOL(scsi_put_command);
333 333
334static struct scsi_host_cmd_pool *scsi_get_host_cmd_pool(gfp_t gfp_mask) 334static struct scsi_host_cmd_pool *
335scsi_find_host_cmd_pool(struct Scsi_Host *shost)
335{ 336{
337 if (shost->hostt->cmd_size)
338 return shost->hostt->cmd_pool;
339 if (shost->unchecked_isa_dma)
340 return &scsi_cmd_dma_pool;
341 return &scsi_cmd_pool;
342}
343
344static void
345scsi_free_host_cmd_pool(struct scsi_host_cmd_pool *pool)
346{
347 kfree(pool->sense_name);
348 kfree(pool->cmd_name);
349 kfree(pool);
350}
351
352static struct scsi_host_cmd_pool *
353scsi_alloc_host_cmd_pool(struct Scsi_Host *shost)
354{
355 struct scsi_host_template *hostt = shost->hostt;
356 struct scsi_host_cmd_pool *pool;
357
358 pool = kzalloc(sizeof(*pool), GFP_KERNEL);
359 if (!pool)
360 return NULL;
361
362 pool->cmd_name = kasprintf(GFP_KERNEL, "%s_cmd", hostt->name);
363 pool->sense_name = kasprintf(GFP_KERNEL, "%s_sense", hostt->name);
364 if (!pool->cmd_name || !pool->sense_name) {
365 scsi_free_host_cmd_pool(pool);
366 return NULL;
367 }
368
369 pool->slab_flags = SLAB_HWCACHE_ALIGN;
370 if (shost->unchecked_isa_dma) {
371 pool->slab_flags |= SLAB_CACHE_DMA;
372 pool->gfp_mask = __GFP_DMA;
373 }
374 return pool;
375}
376
377static struct scsi_host_cmd_pool *
378scsi_get_host_cmd_pool(struct Scsi_Host *shost)
379{
380 struct scsi_host_template *hostt = shost->hostt;
336 struct scsi_host_cmd_pool *retval = NULL, *pool; 381 struct scsi_host_cmd_pool *retval = NULL, *pool;
382 size_t cmd_size = sizeof(struct scsi_cmnd) + hostt->cmd_size;
383
337 /* 384 /*
338 * Select a command slab for this host and create it if not 385 * Select a command slab for this host and create it if not
339 * yet existent. 386 * yet existent.
340 */ 387 */
341 mutex_lock(&host_cmd_pool_mutex); 388 mutex_lock(&host_cmd_pool_mutex);
342 pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool : 389 pool = scsi_find_host_cmd_pool(shost);
343 &scsi_cmd_pool; 390 if (!pool) {
391 pool = scsi_alloc_host_cmd_pool(shost);
392 if (!pool)
393 goto out;
394 }
395
344 if (!pool->users) { 396 if (!pool->users) {
345 pool->cmd_slab = kmem_cache_create(pool->cmd_name, 397 pool->cmd_slab = kmem_cache_create(pool->cmd_name, cmd_size, 0,
346 sizeof(struct scsi_cmnd), 0,
347 pool->slab_flags, NULL); 398 pool->slab_flags, NULL);
348 if (!pool->cmd_slab) 399 if (!pool->cmd_slab)
349 goto fail; 400 goto out_free_pool;
350 401
351 pool->sense_slab = kmem_cache_create(pool->sense_name, 402 pool->sense_slab = kmem_cache_create(pool->sense_name,
352 SCSI_SENSE_BUFFERSIZE, 0, 403 SCSI_SENSE_BUFFERSIZE, 0,
353 pool->slab_flags, NULL); 404 pool->slab_flags, NULL);
354 if (!pool->sense_slab) { 405 if (!pool->sense_slab)
355 kmem_cache_destroy(pool->cmd_slab); 406 goto out_free_slab;
356 goto fail;
357 }
358 } 407 }
359 408
360 pool->users++; 409 pool->users++;
361 retval = pool; 410 retval = pool;
362 fail: 411out:
363 mutex_unlock(&host_cmd_pool_mutex); 412 mutex_unlock(&host_cmd_pool_mutex);
364 return retval; 413 return retval;
414
415out_free_slab:
416 kmem_cache_destroy(pool->cmd_slab);
417out_free_pool:
418 if (hostt->cmd_size)
419 scsi_free_host_cmd_pool(pool);
420 goto out;
365} 421}
366 422
367static void scsi_put_host_cmd_pool(gfp_t gfp_mask) 423static void scsi_put_host_cmd_pool(struct Scsi_Host *shost)
368{ 424{
425 struct scsi_host_template *hostt = shost->hostt;
369 struct scsi_host_cmd_pool *pool; 426 struct scsi_host_cmd_pool *pool;
370 427
371 mutex_lock(&host_cmd_pool_mutex); 428 mutex_lock(&host_cmd_pool_mutex);
372 pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool : 429 pool = scsi_find_host_cmd_pool(shost);
373 &scsi_cmd_pool; 430
374 /* 431 /*
375 * This may happen if a driver has a mismatched get and put 432 * This may happen if a driver has a mismatched get and put
376 * of the command pool; the driver should be implicated in 433 * of the command pool; the driver should be implicated in
@@ -381,6 +438,8 @@ static void scsi_put_host_cmd_pool(gfp_t gfp_mask)
381 if (!--pool->users) { 438 if (!--pool->users) {
382 kmem_cache_destroy(pool->cmd_slab); 439 kmem_cache_destroy(pool->cmd_slab);
383 kmem_cache_destroy(pool->sense_slab); 440 kmem_cache_destroy(pool->sense_slab);
441 if (hostt->cmd_size)
442 scsi_free_host_cmd_pool(pool);
384 } 443 }
385 mutex_unlock(&host_cmd_pool_mutex); 444 mutex_unlock(&host_cmd_pool_mutex);
386} 445}
@@ -397,14 +456,13 @@ static void scsi_put_host_cmd_pool(gfp_t gfp_mask)
397 */ 456 */
398int scsi_setup_command_freelist(struct Scsi_Host *shost) 457int scsi_setup_command_freelist(struct Scsi_Host *shost)
399{ 458{
400 struct scsi_cmnd *cmd;
401 const gfp_t gfp_mask = shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL; 459 const gfp_t gfp_mask = shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL;
460 struct scsi_cmnd *cmd;
402 461
403 spin_lock_init(&shost->free_list_lock); 462 spin_lock_init(&shost->free_list_lock);
404 INIT_LIST_HEAD(&shost->free_list); 463 INIT_LIST_HEAD(&shost->free_list);
405 464
406 shost->cmd_pool = scsi_get_host_cmd_pool(gfp_mask); 465 shost->cmd_pool = scsi_get_host_cmd_pool(shost);
407
408 if (!shost->cmd_pool) 466 if (!shost->cmd_pool)
409 return -ENOMEM; 467 return -ENOMEM;
410 468
@@ -413,7 +471,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
413 */ 471 */
414 cmd = scsi_host_alloc_command(shost, gfp_mask); 472 cmd = scsi_host_alloc_command(shost, gfp_mask);
415 if (!cmd) { 473 if (!cmd) {
416 scsi_put_host_cmd_pool(gfp_mask); 474 scsi_put_host_cmd_pool(shost);
417 shost->cmd_pool = NULL; 475 shost->cmd_pool = NULL;
418 return -ENOMEM; 476 return -ENOMEM;
419 } 477 }
@@ -442,7 +500,7 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
442 scsi_host_free_command(shost, cmd); 500 scsi_host_free_command(shost, cmd);
443 } 501 }
444 shost->cmd_pool = NULL; 502 shost->cmd_pool = NULL;
445 scsi_put_host_cmd_pool(shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL); 503 scsi_put_host_cmd_pool(shost);
446} 504}
447 505
448#ifdef CONFIG_SCSI_LOGGING 506#ifdef CONFIG_SCSI_LOGGING