diff options
| author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-20 10:28:24 -0500 |
|---|---|---|
| committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-23 12:37:44 -0500 |
| commit | 5b7f16804ad90e7f7a10c05b6a2e782598d9745a (patch) | |
| tree | 2228c575b0b001eaf76f48216fee2f066065681a | |
| parent | de25deb18016f66dcdede165d07654559bb332bc (diff) | |
[SCSI] don't use __GFP_DMA for sense buffers if not required
Only hosts which actually have ISA DMA requirements need sense buffers
coming out of ZONE_DMA, so only use the __GFP_DMA flag for that case
to avoid allocating this scarce resource if it's not necessary.
[tomo: fixed slab leak in failure case]
Acked-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
| -rw-r--r-- | drivers/scsi/hosts.c | 9 | ||||
| -rw-r--r-- | drivers/scsi/scsi.c | 111 | ||||
| -rw-r--r-- | drivers/scsi/scsi_priv.h | 2 |
3 files changed, 51 insertions, 71 deletions
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index f5d3fbb55717..9a10b4335e76 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c | |||
| @@ -268,7 +268,6 @@ static void scsi_host_dev_release(struct device *dev) | |||
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | scsi_destroy_command_freelist(shost); | 270 | scsi_destroy_command_freelist(shost); |
| 271 | scsi_destroy_command_sense_buffer(shost); | ||
| 272 | if (shost->bqt) | 271 | if (shost->bqt) |
| 273 | blk_free_tags(shost->bqt); | 272 | blk_free_tags(shost->bqt); |
| 274 | 273 | ||
| @@ -373,13 +372,9 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) | |||
| 373 | else | 372 | else |
| 374 | shost->dma_boundary = 0xffffffff; | 373 | shost->dma_boundary = 0xffffffff; |
| 375 | 374 | ||
| 376 | rval = scsi_setup_command_sense_buffer(shost); | ||
| 377 | if (rval) | ||
| 378 | goto fail_kfree; | ||
| 379 | |||
| 380 | rval = scsi_setup_command_freelist(shost); | 375 | rval = scsi_setup_command_freelist(shost); |
| 381 | if (rval) | 376 | if (rval) |
| 382 | goto fail_destroy_sense; | 377 | goto fail_kfree; |
| 383 | 378 | ||
| 384 | device_initialize(&shost->shost_gendev); | 379 | device_initialize(&shost->shost_gendev); |
| 385 | snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d", | 380 | snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d", |
| @@ -404,8 +399,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) | |||
| 404 | 399 | ||
| 405 | fail_destroy_freelist: | 400 | fail_destroy_freelist: |
| 406 | scsi_destroy_command_freelist(shost); | 401 | scsi_destroy_command_freelist(shost); |
| 407 | fail_destroy_sense: | ||
| 408 | scsi_destroy_command_sense_buffer(shost); | ||
| 409 | fail_kfree: | 402 | fail_kfree: |
| 410 | kfree(shost); | 403 | kfree(shost); |
| 411 | return NULL; | 404 | return NULL; |
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 0a4a5b8b87c6..1a9fba6a9f92 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
| @@ -141,29 +141,30 @@ const char * scsi_device_type(unsigned type) | |||
| 141 | EXPORT_SYMBOL(scsi_device_type); | 141 | EXPORT_SYMBOL(scsi_device_type); |
| 142 | 142 | ||
| 143 | struct scsi_host_cmd_pool { | 143 | struct scsi_host_cmd_pool { |
| 144 | struct kmem_cache *slab; | 144 | struct kmem_cache *cmd_slab; |
| 145 | unsigned int users; | 145 | struct kmem_cache *sense_slab; |
| 146 | char *name; | 146 | unsigned int users; |
| 147 | unsigned int slab_flags; | 147 | char *cmd_name; |
| 148 | gfp_t gfp_mask; | 148 | char *sense_name; |
| 149 | unsigned int slab_flags; | ||
| 150 | gfp_t gfp_mask; | ||
| 149 | }; | 151 | }; |
| 150 | 152 | ||
| 151 | static struct scsi_host_cmd_pool scsi_cmd_pool = { | 153 | static struct scsi_host_cmd_pool scsi_cmd_pool = { |
| 152 | .name = "scsi_cmd_cache", | 154 | .cmd_name = "scsi_cmd_cache", |
| 155 | .sense_name = "scsi_sense_cache", | ||
| 153 | .slab_flags = SLAB_HWCACHE_ALIGN, | 156 | .slab_flags = SLAB_HWCACHE_ALIGN, |
| 154 | }; | 157 | }; |
| 155 | 158 | ||
| 156 | static struct scsi_host_cmd_pool scsi_cmd_dma_pool = { | 159 | static struct scsi_host_cmd_pool scsi_cmd_dma_pool = { |
| 157 | .name = "scsi_cmd_cache(DMA)", | 160 | .cmd_name = "scsi_cmd_cache(DMA)", |
| 161 | .sense_name = "scsi_sense_cache(DMA)", | ||
| 158 | .slab_flags = SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA, | 162 | .slab_flags = SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA, |
| 159 | .gfp_mask = __GFP_DMA, | 163 | .gfp_mask = __GFP_DMA, |
| 160 | }; | 164 | }; |
| 161 | 165 | ||
| 162 | static DEFINE_MUTEX(host_cmd_pool_mutex); | 166 | static DEFINE_MUTEX(host_cmd_pool_mutex); |
| 163 | 167 | ||
| 164 | static struct kmem_cache *sense_buffer_slab; | ||
| 165 | static int sense_buffer_slab_users; | ||
| 166 | |||
| 167 | /** | 168 | /** |
| 168 | * __scsi_get_command - Allocate a struct scsi_cmnd | 169 | * __scsi_get_command - Allocate a struct scsi_cmnd |
| 169 | * @shost: host to transmit command | 170 | * @shost: host to transmit command |
| @@ -177,8 +178,8 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) | |||
| 177 | struct scsi_cmnd *cmd; | 178 | struct scsi_cmnd *cmd; |
| 178 | unsigned char *buf; | 179 | unsigned char *buf; |
| 179 | 180 | ||
| 180 | cmd = kmem_cache_alloc(shost->cmd_pool->slab, | 181 | cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab, |
| 181 | gfp_mask | shost->cmd_pool->gfp_mask); | 182 | gfp_mask | shost->cmd_pool->gfp_mask); |
| 182 | 183 | ||
| 183 | if (unlikely(!cmd)) { | 184 | if (unlikely(!cmd)) { |
| 184 | unsigned long flags; | 185 | unsigned long flags; |
| @@ -197,12 +198,13 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) | |||
| 197 | cmd->sense_buffer = buf; | 198 | cmd->sense_buffer = buf; |
| 198 | } | 199 | } |
| 199 | } else { | 200 | } else { |
| 200 | buf = kmem_cache_alloc(sense_buffer_slab, __GFP_DMA|gfp_mask); | 201 | buf = kmem_cache_alloc(shost->cmd_pool->sense_slab, |
| 202 | gfp_mask | shost->cmd_pool->gfp_mask); | ||
| 201 | if (likely(buf)) { | 203 | if (likely(buf)) { |
| 202 | memset(cmd, 0, sizeof(*cmd)); | 204 | memset(cmd, 0, sizeof(*cmd)); |
| 203 | cmd->sense_buffer = buf; | 205 | cmd->sense_buffer = buf; |
| 204 | } else { | 206 | } else { |
| 205 | kmem_cache_free(shost->cmd_pool->slab, cmd); | 207 | kmem_cache_free(shost->cmd_pool->cmd_slab, cmd); |
| 206 | cmd = NULL; | 208 | cmd = NULL; |
| 207 | } | 209 | } |
| 208 | } | 210 | } |
| @@ -265,8 +267,9 @@ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd, | |||
| 265 | spin_unlock_irqrestore(&shost->free_list_lock, flags); | 267 | spin_unlock_irqrestore(&shost->free_list_lock, flags); |
| 266 | 268 | ||
| 267 | if (likely(cmd != NULL)) { | 269 | if (likely(cmd != NULL)) { |
| 268 | kmem_cache_free(sense_buffer_slab, cmd->sense_buffer); | 270 | kmem_cache_free(shost->cmd_pool->sense_slab, |
| 269 | kmem_cache_free(shost->cmd_pool->slab, cmd); | 271 | cmd->sense_buffer); |
| 272 | kmem_cache_free(shost->cmd_pool->cmd_slab, cmd); | ||
| 270 | } | 273 | } |
| 271 | 274 | ||
| 272 | put_device(dev); | 275 | put_device(dev); |
| @@ -310,7 +313,6 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost) | |||
| 310 | { | 313 | { |
| 311 | struct scsi_host_cmd_pool *pool; | 314 | struct scsi_host_cmd_pool *pool; |
| 312 | struct scsi_cmnd *cmd; | 315 | struct scsi_cmnd *cmd; |
| 313 | unsigned char *sense_buffer; | ||
| 314 | 316 | ||
| 315 | spin_lock_init(&shost->free_list_lock); | 317 | spin_lock_init(&shost->free_list_lock); |
| 316 | INIT_LIST_HEAD(&shost->free_list); | 318 | INIT_LIST_HEAD(&shost->free_list); |
| @@ -322,11 +324,19 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost) | |||
| 322 | mutex_lock(&host_cmd_pool_mutex); | 324 | mutex_lock(&host_cmd_pool_mutex); |
| 323 | pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool); | 325 | pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool); |
| 324 | if (!pool->users) { | 326 | if (!pool->users) { |
| 325 | pool->slab = kmem_cache_create(pool->name, | 327 | pool->cmd_slab = kmem_cache_create(pool->cmd_name, |
| 326 | sizeof(struct scsi_cmnd), 0, | 328 | sizeof(struct scsi_cmnd), 0, |
| 327 | pool->slab_flags, NULL); | 329 | pool->slab_flags, NULL); |
| 328 | if (!pool->slab) | 330 | if (!pool->cmd_slab) |
| 331 | goto fail; | ||
| 332 | |||
| 333 | pool->sense_slab = kmem_cache_create(pool->sense_name, | ||
| 334 | SCSI_SENSE_BUFFERSIZE, 0, | ||
| 335 | pool->slab_flags, NULL); | ||
| 336 | if (!pool->sense_slab) { | ||
| 337 | kmem_cache_destroy(pool->cmd_slab); | ||
| 329 | goto fail; | 338 | goto fail; |
| 339 | } | ||
| 330 | } | 340 | } |
| 331 | 341 | ||
| 332 | pool->users++; | 342 | pool->users++; |
| @@ -336,26 +346,28 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost) | |||
| 336 | /* | 346 | /* |
| 337 | * Get one backup command for this host. | 347 | * Get one backup command for this host. |
| 338 | */ | 348 | */ |
| 339 | cmd = kmem_cache_alloc(shost->cmd_pool->slab, | 349 | cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab, |
| 340 | GFP_KERNEL | shost->cmd_pool->gfp_mask); | 350 | GFP_KERNEL | shost->cmd_pool->gfp_mask); |
| 341 | if (!cmd) | 351 | if (!cmd) |
| 342 | goto fail2; | 352 | goto fail2; |
| 343 | 353 | ||
| 344 | sense_buffer = kmem_cache_alloc(sense_buffer_slab, | 354 | cmd->sense_buffer = kmem_cache_alloc(shost->cmd_pool->sense_slab, |
| 345 | GFP_KERNEL | __GFP_DMA); | 355 | GFP_KERNEL | |
| 346 | if (!sense_buffer) | 356 | shost->cmd_pool->gfp_mask); |
| 347 | goto destroy_backup; | 357 | if (!cmd->sense_buffer) |
| 358 | goto fail2; | ||
| 348 | 359 | ||
| 349 | cmd->sense_buffer = sense_buffer; | ||
| 350 | list_add(&cmd->list, &shost->free_list); | 360 | list_add(&cmd->list, &shost->free_list); |
| 351 | return 0; | 361 | return 0; |
| 352 | 362 | ||
| 353 | destroy_backup: | ||
| 354 | kmem_cache_free(shost->cmd_pool->slab, cmd); | ||
| 355 | fail2: | 363 | fail2: |
| 364 | if (cmd) | ||
| 365 | kmem_cache_free(shost->cmd_pool->cmd_slab, cmd); | ||
| 356 | mutex_lock(&host_cmd_pool_mutex); | 366 | mutex_lock(&host_cmd_pool_mutex); |
| 357 | if (!--pool->users) | 367 | if (!--pool->users) { |
| 358 | kmem_cache_destroy(pool->slab); | 368 | kmem_cache_destroy(pool->cmd_slab); |
| 369 | kmem_cache_destroy(pool->sense_slab); | ||
| 370 | } | ||
| 359 | fail: | 371 | fail: |
| 360 | mutex_unlock(&host_cmd_pool_mutex); | 372 | mutex_unlock(&host_cmd_pool_mutex); |
| 361 | return -ENOMEM; | 373 | return -ENOMEM; |
| @@ -372,39 +384,16 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost) | |||
| 372 | 384 | ||
| 373 | cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list); | 385 | cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list); |
| 374 | list_del_init(&cmd->list); | 386 | list_del_init(&cmd->list); |
| 375 | kmem_cache_free(sense_buffer_slab, cmd->sense_buffer); | 387 | kmem_cache_free(shost->cmd_pool->sense_slab, |
| 376 | kmem_cache_free(shost->cmd_pool->slab, cmd); | 388 | cmd->sense_buffer); |
| 389 | kmem_cache_free(shost->cmd_pool->cmd_slab, cmd); | ||
| 377 | } | 390 | } |
| 378 | 391 | ||
| 379 | mutex_lock(&host_cmd_pool_mutex); | 392 | mutex_lock(&host_cmd_pool_mutex); |
| 380 | if (!--shost->cmd_pool->users) | 393 | if (!--shost->cmd_pool->users) { |
| 381 | kmem_cache_destroy(shost->cmd_pool->slab); | 394 | kmem_cache_destroy(shost->cmd_pool->cmd_slab); |
| 382 | mutex_unlock(&host_cmd_pool_mutex); | 395 | kmem_cache_destroy(shost->cmd_pool->sense_slab); |
| 383 | } | ||
| 384 | |||
| 385 | int scsi_setup_command_sense_buffer(struct Scsi_Host *shost) | ||
| 386 | { | ||
| 387 | mutex_lock(&host_cmd_pool_mutex); | ||
| 388 | if (!sense_buffer_slab_users) { | ||
| 389 | sense_buffer_slab = kmem_cache_create("scsi_sense_buffer", | ||
| 390 | SCSI_SENSE_BUFFERSIZE, | ||
| 391 | 0, SLAB_CACHE_DMA, NULL); | ||
| 392 | if (!sense_buffer_slab) { | ||
| 393 | mutex_unlock(&host_cmd_pool_mutex); | ||
| 394 | return -ENOMEM; | ||
| 395 | } | ||
| 396 | } | 396 | } |
| 397 | sense_buffer_slab_users++; | ||
| 398 | mutex_unlock(&host_cmd_pool_mutex); | ||
| 399 | |||
| 400 | return 0; | ||
| 401 | } | ||
| 402 | |||
| 403 | void scsi_destroy_command_sense_buffer(struct Scsi_Host *shost) | ||
| 404 | { | ||
| 405 | mutex_lock(&host_cmd_pool_mutex); | ||
| 406 | if (!--sense_buffer_slab_users) | ||
| 407 | kmem_cache_destroy(sense_buffer_slab); | ||
| 408 | mutex_unlock(&host_cmd_pool_mutex); | 397 | mutex_unlock(&host_cmd_pool_mutex); |
| 409 | } | 398 | } |
| 410 | 399 | ||
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 55c6f71a9aee..3f34e9376b0a 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h | |||
| @@ -27,8 +27,6 @@ extern void scsi_exit_hosts(void); | |||
| 27 | extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd); | 27 | extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd); |
| 28 | extern int scsi_setup_command_freelist(struct Scsi_Host *shost); | 28 | extern int scsi_setup_command_freelist(struct Scsi_Host *shost); |
| 29 | extern void scsi_destroy_command_freelist(struct Scsi_Host *shost); | 29 | extern void scsi_destroy_command_freelist(struct Scsi_Host *shost); |
| 30 | extern int scsi_setup_command_sense_buffer(struct Scsi_Host *shost); | ||
| 31 | extern void scsi_destroy_command_sense_buffer(struct Scsi_Host *shost); | ||
| 32 | extern void __scsi_done(struct scsi_cmnd *cmd); | 30 | extern void __scsi_done(struct scsi_cmnd *cmd); |
| 33 | #ifdef CONFIG_SCSI_LOGGING | 31 | #ifdef CONFIG_SCSI_LOGGING |
| 34 | void scsi_log_send(struct scsi_cmnd *cmd); | 32 | void scsi_log_send(struct scsi_cmnd *cmd); |
