Commit 6eca9004 authored by Jens Axboe's avatar Jens Axboe

[BLOCK] Fix bad sharing of tag busy list on queues with shared tag maps

For the locking to work, only the tag map and tag bit map may be shared
(incidentally, I was just explaining this to Nick yesterday, but I
apparently didn't review the code well enough myself). But we also share
the busy list!  The busy_list must be queue private, or we need a
block_queue_tag covering lock as well.

So we have to move the busy_list to the queue. This'll work fine, and
it'll actually also fix a problem with blk_queue_invalidate_tags() which
will invalidate tags across all shared queues. This is a bit confusing,
the low level driver should call it for each queue seperately since
otherwise you cannot kill tags on just a single queue for eg a hard
drive that stops responding. Since the function has no callers
currently, it's not an issue.
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 3a424f2d
...@@ -791,7 +791,6 @@ static int __blk_free_tags(struct blk_queue_tag *bqt) ...@@ -791,7 +791,6 @@ static int __blk_free_tags(struct blk_queue_tag *bqt)
retval = atomic_dec_and_test(&bqt->refcnt); retval = atomic_dec_and_test(&bqt->refcnt);
if (retval) { if (retval) {
BUG_ON(bqt->busy); BUG_ON(bqt->busy);
BUG_ON(!list_empty(&bqt->busy_list));
kfree(bqt->tag_index); kfree(bqt->tag_index);
bqt->tag_index = NULL; bqt->tag_index = NULL;
...@@ -903,7 +902,6 @@ static struct blk_queue_tag *__blk_queue_init_tags(struct request_queue *q, ...@@ -903,7 +902,6 @@ static struct blk_queue_tag *__blk_queue_init_tags(struct request_queue *q,
if (init_tag_map(q, tags, depth)) if (init_tag_map(q, tags, depth))
goto fail; goto fail;
INIT_LIST_HEAD(&tags->busy_list);
tags->busy = 0; tags->busy = 0;
atomic_set(&tags->refcnt, 1); atomic_set(&tags->refcnt, 1);
return tags; return tags;
...@@ -954,6 +952,7 @@ int blk_queue_init_tags(struct request_queue *q, int depth, ...@@ -954,6 +952,7 @@ int blk_queue_init_tags(struct request_queue *q, int depth,
*/ */
q->queue_tags = tags; q->queue_tags = tags;
q->queue_flags |= (1 << QUEUE_FLAG_QUEUED); q->queue_flags |= (1 << QUEUE_FLAG_QUEUED);
INIT_LIST_HEAD(&q->tag_busy_list);
return 0; return 0;
fail: fail:
kfree(tags); kfree(tags);
...@@ -1122,7 +1121,7 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq) ...@@ -1122,7 +1121,7 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq)
rq->tag = tag; rq->tag = tag;
bqt->tag_index[tag] = rq; bqt->tag_index[tag] = rq;
blkdev_dequeue_request(rq); blkdev_dequeue_request(rq);
list_add(&rq->queuelist, &bqt->busy_list); list_add(&rq->queuelist, &q->tag_busy_list);
bqt->busy++; bqt->busy++;
return 0; return 0;
} }
...@@ -1143,11 +1142,10 @@ EXPORT_SYMBOL(blk_queue_start_tag); ...@@ -1143,11 +1142,10 @@ EXPORT_SYMBOL(blk_queue_start_tag);
**/ **/
void blk_queue_invalidate_tags(struct request_queue *q) void blk_queue_invalidate_tags(struct request_queue *q)
{ {
struct blk_queue_tag *bqt = q->queue_tags;
struct list_head *tmp, *n; struct list_head *tmp, *n;
struct request *rq; struct request *rq;
list_for_each_safe(tmp, n, &bqt->busy_list) { list_for_each_safe(tmp, n, &q->tag_busy_list) {
rq = list_entry_rq(tmp); rq = list_entry_rq(tmp);
if (rq->tag == -1) { if (rq->tag == -1) {
......
...@@ -341,7 +341,6 @@ enum blk_queue_state { ...@@ -341,7 +341,6 @@ enum blk_queue_state {
struct blk_queue_tag { struct blk_queue_tag {
struct request **tag_index; /* map of busy tags */ struct request **tag_index; /* map of busy tags */
unsigned long *tag_map; /* bit map of free/busy tags */ unsigned long *tag_map; /* bit map of free/busy tags */
struct list_head busy_list; /* fifo list of busy tags */
int busy; /* current depth */ int busy; /* current depth */
int max_depth; /* what we will send to device */ int max_depth; /* what we will send to device */
int real_max_depth; /* what the array can hold */ int real_max_depth; /* what the array can hold */
...@@ -435,6 +434,7 @@ struct request_queue ...@@ -435,6 +434,7 @@ struct request_queue
unsigned int dma_alignment; unsigned int dma_alignment;
struct blk_queue_tag *queue_tags; struct blk_queue_tag *queue_tags;
struct list_head tag_busy_list;
unsigned int nr_sorted; unsigned int nr_sorted;
unsigned int in_flight; unsigned int in_flight;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment