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 /drivers/scsi | |
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>
Diffstat (limited to 'drivers/scsi')
-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); |