diff options
author | Stephen M. Cameron <stephenmcameron@gmail.com> | 2014-11-15 02:27:29 +0300 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-11-20 11:11:27 +0300 |
commit | 4c413128a6ff3af013bd1d82860a7ee60f93fb28 (patch) | |
tree | 24f139f6e806b5942134bf02a1b3fa43d0777c93 /drivers/scsi | |
parent | 4fa604e13bb2a6ef6e89224c80d96af385f533c3 (diff) | |
download | linux-4c413128a6ff3af013bd1d82860a7ee60f93fb28.tar.xz |
hpsa: remove spin lock around command allocation
It is already using atomic test_and_set_bit to do the
allocation.
There is some microscopic chance of starvation, but it is
so microscopic that it should never happen in reality.
Signed-off-by: Don Brace <don.brace@pmcs.com>
Reviewed-by: Webb Scales <webbnh@hp.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/hpsa.c | 36 |
1 files changed, 23 insertions, 13 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 36db63f63143..3569f4201942 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4607,19 +4607,32 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) int i; union u64bit temp64; dma_addr_t cmd_dma_handle, err_dma_handle; - unsigned long flags; + int loopcount; + + /* There is some *extremely* small but non-zero chance that that + * multiple threads could get in here, and one thread could + * be scanning through the list of bits looking for a free + * one, but the free ones are always behind him, and other + * threads sneak in behind him and eat them before he can + * get to them, so that while there is always a free one, a + * very unlucky thread might be starved anyway, never able to + * beat the other threads. In reality, this happens so + * infrequently as to be indistinguishable from never. + */ - spin_lock_irqsave(&h->lock, flags); + loopcount = 0; do { i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds); - if (i == h->nr_cmds) { - spin_unlock_irqrestore(&h->lock, flags); - return NULL; - } - } while (test_and_set_bit - (i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0); - spin_unlock_irqrestore(&h->lock, flags); + if (i == h->nr_cmds) + i = 0; + loopcount++; + } while (test_and_set_bit(i & (BITS_PER_LONG - 1), + h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0 && + loopcount < 10); + + /* Thread got starved? We do not expect this to ever happen. */ + if (loopcount >= 10) + return NULL; c = h->cmd_pool + i; memset(c, 0, sizeof(*c)); @@ -4679,13 +4692,10 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h) static void cmd_free(struct ctlr_info *h, struct CommandList *c) { int i; - unsigned long flags; i = c - h->cmd_pool; - spin_lock_irqsave(&h->lock, flags); clear_bit(i & (BITS_PER_LONG - 1), h->cmd_pool_bits + (i / BITS_PER_LONG)); - spin_unlock_irqrestore(&h->lock, flags); } static void cmd_special_free(struct ctlr_info *h, struct CommandList *c) |