diff options
-rw-r--r-- | drivers/scsi/scsi.c | 149 | ||||
-rw-r--r-- | include/scsi/scsi_cmnd.h | 3 |
2 files changed, 115 insertions, 37 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 2cf9a625f227..f6980bd9d8f9 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
@@ -330,30 +330,16 @@ void scsi_put_command(struct scsi_cmnd *cmd) | |||
330 | } | 330 | } |
331 | EXPORT_SYMBOL(scsi_put_command); | 331 | EXPORT_SYMBOL(scsi_put_command); |
332 | 332 | ||
333 | /** | 333 | static struct scsi_host_cmd_pool *scsi_get_host_cmd_pool(gfp_t gfp_mask) |
334 | * scsi_setup_command_freelist - Setup the command freelist for a scsi host. | ||
335 | * @shost: host to allocate the freelist for. | ||
336 | * | ||
337 | * Description: The command freelist protects against system-wide out of memory | ||
338 | * deadlock by preallocating one SCSI command structure for each host, so the | ||
339 | * system can always write to a swap file on a device associated with that host. | ||
340 | * | ||
341 | * Returns: Nothing. | ||
342 | */ | ||
343 | int scsi_setup_command_freelist(struct Scsi_Host *shost) | ||
344 | { | 334 | { |
345 | struct scsi_host_cmd_pool *pool; | 335 | struct scsi_host_cmd_pool *retval = NULL, *pool; |
346 | struct scsi_cmnd *cmd; | ||
347 | |||
348 | spin_lock_init(&shost->free_list_lock); | ||
349 | INIT_LIST_HEAD(&shost->free_list); | ||
350 | |||
351 | /* | 336 | /* |
352 | * Select a command slab for this host and create it if not | 337 | * Select a command slab for this host and create it if not |
353 | * yet existent. | 338 | * yet existent. |
354 | */ | 339 | */ |
355 | mutex_lock(&host_cmd_pool_mutex); | 340 | mutex_lock(&host_cmd_pool_mutex); |
356 | pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool); | 341 | pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool : |
342 | &scsi_cmd_pool; | ||
357 | if (!pool->users) { | 343 | if (!pool->users) { |
358 | pool->cmd_slab = kmem_cache_create(pool->cmd_name, | 344 | pool->cmd_slab = kmem_cache_create(pool->cmd_name, |
359 | sizeof(struct scsi_cmnd), 0, | 345 | sizeof(struct scsi_cmnd), 0, |
@@ -371,28 +357,122 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost) | |||
371 | } | 357 | } |
372 | 358 | ||
373 | pool->users++; | 359 | pool->users++; |
374 | shost->cmd_pool = pool; | 360 | retval = pool; |
361 | fail: | ||
375 | mutex_unlock(&host_cmd_pool_mutex); | 362 | mutex_unlock(&host_cmd_pool_mutex); |
363 | return retval; | ||
364 | } | ||
365 | |||
366 | static void scsi_put_host_cmd_pool(gfp_t gfp_mask) | ||
367 | { | ||
368 | struct scsi_host_cmd_pool *pool; | ||
376 | 369 | ||
370 | mutex_lock(&host_cmd_pool_mutex); | ||
371 | pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool : | ||
372 | &scsi_cmd_pool; | ||
377 | /* | 373 | /* |
378 | * Get one backup command for this host. | 374 | * This may happen if a driver has a mismatched get and put |
375 | * of the command pool; the driver should be implicated in | ||
376 | * the stack trace | ||
379 | */ | 377 | */ |
380 | cmd = scsi_pool_alloc_command(shost->cmd_pool, GFP_KERNEL); | 378 | BUG_ON(pool->users == 0); |
381 | if (!cmd) | ||
382 | goto fail2; | ||
383 | 379 | ||
384 | list_add(&cmd->list, &shost->free_list); | ||
385 | return 0; | ||
386 | |||
387 | fail2: | ||
388 | mutex_lock(&host_cmd_pool_mutex); | ||
389 | if (!--pool->users) { | 380 | if (!--pool->users) { |
390 | kmem_cache_destroy(pool->cmd_slab); | 381 | kmem_cache_destroy(pool->cmd_slab); |
391 | kmem_cache_destroy(pool->sense_slab); | 382 | kmem_cache_destroy(pool->sense_slab); |
392 | } | 383 | } |
393 | fail: | ||
394 | mutex_unlock(&host_cmd_pool_mutex); | 384 | mutex_unlock(&host_cmd_pool_mutex); |
395 | return -ENOMEM; | 385 | } |
386 | |||
387 | /** | ||
388 | * scsi_allocate_command - get a fully allocated SCSI command | ||
389 | * @gfp_mask: allocation mask | ||
390 | * | ||
391 | * This function is for use outside of the normal host based pools. | ||
392 | * It allocates the relevant command and takes an additional reference | ||
393 | * on the pool it used. This function *must* be paired with | ||
394 | * scsi_free_command which also has the identical mask, otherwise the | ||
395 | * free pool counts will eventually go wrong and you'll trigger a bug. | ||
396 | * | ||
397 | * This function should *only* be used by drivers that need a static | ||
398 | * command allocation at start of day for internal functions. | ||
399 | */ | ||
400 | struct scsi_cmnd *scsi_allocate_command(gfp_t gfp_mask) | ||
401 | { | ||
402 | struct scsi_host_cmd_pool *pool = scsi_get_host_cmd_pool(gfp_mask); | ||
403 | |||
404 | if (!pool) | ||
405 | return NULL; | ||
406 | |||
407 | return scsi_pool_alloc_command(pool, gfp_mask); | ||
408 | } | ||
409 | EXPORT_SYMBOL(scsi_allocate_command); | ||
410 | |||
411 | /** | ||
412 | * scsi_free_command - free a command allocated by scsi_allocate_command | ||
413 | * @gfp_mask: mask used in the original allocation | ||
414 | * @cmd: command to free | ||
415 | * | ||
416 | * Note: using the original allocation mask is vital because that's | ||
417 | * what determines which command pool we use to free the command. Any | ||
418 | * mismatch will cause the system to BUG eventually. | ||
419 | */ | ||
420 | void scsi_free_command(gfp_t gfp_mask, struct scsi_cmnd *cmd) | ||
421 | { | ||
422 | struct scsi_host_cmd_pool *pool = scsi_get_host_cmd_pool(gfp_mask); | ||
423 | |||
424 | /* | ||
425 | * this could trigger if the mask to scsi_allocate_command | ||
426 | * doesn't match this mask. Otherwise we're guaranteed that this | ||
427 | * succeeds because scsi_allocate_command must have taken a reference | ||
428 | * on the pool | ||
429 | */ | ||
430 | BUG_ON(!pool); | ||
431 | |||
432 | scsi_pool_free_command(pool, cmd); | ||
433 | /* | ||
434 | * scsi_put_host_cmd_pool is called twice; once to release the | ||
435 | * reference we took above, and once to release the reference | ||
436 | * originally taken by scsi_allocate_command | ||
437 | */ | ||
438 | scsi_put_host_cmd_pool(gfp_mask); | ||
439 | scsi_put_host_cmd_pool(gfp_mask); | ||
440 | } | ||
441 | EXPORT_SYMBOL(scsi_free_command); | ||
442 | |||
443 | /** | ||
444 | * scsi_setup_command_freelist - Setup the command freelist for a scsi host. | ||
445 | * @shost: host to allocate the freelist for. | ||
446 | * | ||
447 | * Description: The command freelist protects against system-wide out of memory | ||
448 | * deadlock by preallocating one SCSI command structure for each host, so the | ||
449 | * system can always write to a swap file on a device associated with that host. | ||
450 | * | ||
451 | * Returns: Nothing. | ||
452 | */ | ||
453 | int scsi_setup_command_freelist(struct Scsi_Host *shost) | ||
454 | { | ||
455 | struct scsi_cmnd *cmd; | ||
456 | const gfp_t gfp_mask = shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL; | ||
457 | |||
458 | spin_lock_init(&shost->free_list_lock); | ||
459 | INIT_LIST_HEAD(&shost->free_list); | ||
460 | |||
461 | shost->cmd_pool = scsi_get_host_cmd_pool(gfp_mask); | ||
462 | |||
463 | if (!shost->cmd_pool) | ||
464 | return -ENOMEM; | ||
465 | |||
466 | /* | ||
467 | * Get one backup command for this host. | ||
468 | */ | ||
469 | cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask); | ||
470 | if (!cmd) { | ||
471 | scsi_put_host_cmd_pool(gfp_mask); | ||
472 | return -ENOMEM; | ||
473 | } | ||
474 | list_add(&cmd->list, &shost->free_list); | ||
475 | return 0; | ||
396 | } | 476 | } |
397 | 477 | ||
398 | /** | 478 | /** |
@@ -408,13 +488,8 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost) | |||
408 | list_del_init(&cmd->list); | 488 | list_del_init(&cmd->list); |
409 | scsi_pool_free_command(shost->cmd_pool, cmd); | 489 | scsi_pool_free_command(shost->cmd_pool, cmd); |
410 | } | 490 | } |
411 | 491 | shost->cmd_pool = NULL; | |
412 | mutex_lock(&host_cmd_pool_mutex); | 492 | scsi_put_host_cmd_pool(shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL); |
413 | if (!--shost->cmd_pool->users) { | ||
414 | kmem_cache_destroy(shost->cmd_pool->cmd_slab); | ||
415 | kmem_cache_destroy(shost->cmd_pool->sense_slab); | ||
416 | } | ||
417 | mutex_unlock(&host_cmd_pool_mutex); | ||
418 | } | 493 | } |
419 | 494 | ||
420 | #ifdef CONFIG_SCSI_LOGGING | 495 | #ifdef CONFIG_SCSI_LOGGING |
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index b260be6d0d73..8d20e60a94b7 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h | |||
@@ -130,6 +130,9 @@ extern void scsi_release_buffers(struct scsi_cmnd *cmd); | |||
130 | extern int scsi_dma_map(struct scsi_cmnd *cmd); | 130 | extern int scsi_dma_map(struct scsi_cmnd *cmd); |
131 | extern void scsi_dma_unmap(struct scsi_cmnd *cmd); | 131 | extern void scsi_dma_unmap(struct scsi_cmnd *cmd); |
132 | 132 | ||
133 | struct scsi_cmnd *scsi_allocate_command(gfp_t gfp_mask); | ||
134 | void scsi_free_command(gfp_t gfp_mask, struct scsi_cmnd *cmd); | ||
135 | |||
133 | static inline unsigned scsi_sg_count(struct scsi_cmnd *cmd) | 136 | static inline unsigned scsi_sg_count(struct scsi_cmnd *cmd) |
134 | { | 137 | { |
135 | return cmd->sdb.table.nents; | 138 | return cmd->sdb.table.nents; |