block: don't assume last put of shared tags is for the host
There is no inherent reason why the last put of a tag structure must be the one for the Scsi_Host, as device model objects can be held for arbitrary periods. Merge blk_free_tags and __blk_free_tags into a single funtion that just release a references and get rid of the BUG() when the host reference wasn't the last. Signed-off-by: Christoph Hellwig <hch@lst.de> Cc: stable@kernel.org Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
Родитель
448bfad8a1
Коммит
d45b3279a5
|
@ -27,18 +27,15 @@ struct request *blk_queue_find_tag(struct request_queue *q, int tag)
|
|||
EXPORT_SYMBOL(blk_queue_find_tag);
|
||||
|
||||
/**
|
||||
* __blk_free_tags - release a given set of tag maintenance info
|
||||
* blk_free_tags - release a given set of tag maintenance info
|
||||
* @bqt: the tag map to free
|
||||
*
|
||||
* Tries to free the specified @bqt. Returns true if it was
|
||||
* actually freed and false if there are still references using it
|
||||
* Drop the reference count on @bqt and frees it when the last reference
|
||||
* is dropped.
|
||||
*/
|
||||
static int __blk_free_tags(struct blk_queue_tag *bqt)
|
||||
void blk_free_tags(struct blk_queue_tag *bqt)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = atomic_dec_and_test(&bqt->refcnt);
|
||||
if (retval) {
|
||||
if (atomic_dec_and_test(&bqt->refcnt)) {
|
||||
BUG_ON(find_first_bit(bqt->tag_map, bqt->max_depth) <
|
||||
bqt->max_depth);
|
||||
|
||||
|
@ -50,9 +47,8 @@ static int __blk_free_tags(struct blk_queue_tag *bqt)
|
|||
|
||||
kfree(bqt);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_free_tags);
|
||||
|
||||
/**
|
||||
* __blk_queue_free_tags - release tag maintenance info
|
||||
|
@ -69,27 +65,12 @@ void __blk_queue_free_tags(struct request_queue *q)
|
|||
if (!bqt)
|
||||
return;
|
||||
|
||||
__blk_free_tags(bqt);
|
||||
blk_free_tags(bqt);
|
||||
|
||||
q->queue_tags = NULL;
|
||||
queue_flag_clear_unlocked(QUEUE_FLAG_QUEUED, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* blk_free_tags - release a given set of tag maintenance info
|
||||
* @bqt: the tag map to free
|
||||
*
|
||||
* For externally managed @bqt frees the map. Callers of this
|
||||
* function must guarantee to have released all the queues that
|
||||
* might have been using this tag map.
|
||||
*/
|
||||
void blk_free_tags(struct blk_queue_tag *bqt)
|
||||
{
|
||||
if (unlikely(!__blk_free_tags(bqt)))
|
||||
BUG();
|
||||
}
|
||||
EXPORT_SYMBOL(blk_free_tags);
|
||||
|
||||
/**
|
||||
* blk_queue_free_tags - release tag maintenance info
|
||||
* @q: the request queue for the device
|
||||
|
|
Загрузка…
Ссылка в новой задаче