]>
Commit | Line | Data |
---|---|---|
efa57d45 AM |
1 | commit f3da54ba140c6427fa4a32913e1bf406f41b5dda |
2 | Author: Jens Axboe <jens.axboe@oracle.com> | |
3 | Date: Thu Sep 13 14:26:53 2007 +0200 | |
4 | ||
5 | Fix race with shared tag queue maps | |
6 | ||
7 | There's a race condition in blk_queue_end_tag() for shared tag maps, | |
8 | users include stex (promise supertrak thingy) and qla2xxx. The former | |
9 | at least has reported bugs in this area, not sure why we haven't seen | |
10 | any for the latter. It could be because the window is narrow and that | |
11 | other conditions in the qla2xxx code hide this. It's a real bug, | |
12 | though, as the stex smp users can attest. | |
13 | ||
14 | We need to ensure two things - the tag bit clearing needs to happen | |
15 | AFTER we cleared the tag pointer, as the tag bit clearing/setting is | |
16 | what protects this map. Secondly, we need to ensure that the visibility | |
17 | of the tag pointer and tag bit clear are ordered properly. | |
18 | ||
19 | [ I removed the SMP barriers - "test_and_clear_bit()" already implies | |
20 | all the required barriers. -- Linus ] | |
21 | ||
22 | Also see http://bugzilla.kernel.org/show_bug.cgi?id=7842 | |
23 | ||
24 | Signed-off-by: Jens Axboe <jens.axboe@oracle.com> | |
25 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | |
26 | ||
27 | diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c | |
28 | index a15845c..cd20367 100644 | |
29 | --- a/block/ll_rw_blk.c | |
30 | +++ b/block/ll_rw_blk.c | |
31 | @@ -1075,12 +1075,6 @@ void blk_queue_end_tag(struct request_queue *q, struct request *rq) | |
32 | */ | |
33 | return; | |
34 | ||
35 | - if (unlikely(!__test_and_clear_bit(tag, bqt->tag_map))) { | |
36 | - printk(KERN_ERR "%s: attempt to clear non-busy tag (%d)\n", | |
37 | - __FUNCTION__, tag); | |
38 | - return; | |
39 | - } | |
40 | - | |
41 | list_del_init(&rq->queuelist); | |
42 | rq->cmd_flags &= ~REQ_QUEUED; | |
43 | rq->tag = -1; | |
44 | @@ -1090,6 +1084,13 @@ void blk_queue_end_tag(struct request_queue *q, struct request *rq) | |
45 | __FUNCTION__, tag); | |
46 | ||
47 | bqt->tag_index[tag] = NULL; | |
48 | + | |
49 | + if (unlikely(!test_and_clear_bit(tag, bqt->tag_map))) { | |
50 | + printk(KERN_ERR "%s: attempt to clear non-busy tag (%d)\n", | |
51 | + __FUNCTION__, tag); | |
52 | + return; | |
53 | + } | |
54 | + | |
55 | bqt->busy--; | |
56 | } | |
57 |