diff options
author | Alexander Gordeev <agordeev@redhat.com> | 2014-06-18 01:12:35 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2014-06-18 01:12:35 -0400 |
commit | 8537b12034cf1fd3fab3da2c859d71f76846fae9 (patch) | |
tree | eef471e49e99b4e78d180f1158258ef1d5eb0aca /block | |
parent | 736ed4de766d4f0e8e6142dd4f9d73ef61835ed9 (diff) |
blk-mq: bitmap tag: fix races on shared ::wake_index fields
Fix racy updates of shared blk_mq_bitmap_tags::wake_index
and blk_mq_hw_ctx::wake_index fields.
Cc: Ming Lei <tom.leiming@gmail.com>
Signed-off-by: Alexander Gordeev <agordeev@redhat.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-mq-tag.c | 32 | ||||
-rw-r--r-- | block/blk-mq-tag.h | 2 |
2 files changed, 22 insertions, 12 deletions
diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index 1aab39f71d95..6deb13055490 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c | |||
@@ -43,9 +43,16 @@ bool blk_mq_has_free_tags(struct blk_mq_tags *tags) | |||
43 | return bt_has_free_tags(&tags->bitmap_tags); | 43 | return bt_has_free_tags(&tags->bitmap_tags); |
44 | } | 44 | } |
45 | 45 | ||
46 | static inline void bt_index_inc(unsigned int *index) | 46 | static inline int bt_index_inc(int index) |
47 | { | 47 | { |
48 | *index = (*index + 1) & (BT_WAIT_QUEUES - 1); | 48 | return (index + 1) & (BT_WAIT_QUEUES - 1); |
49 | } | ||
50 | |||
51 | static inline void bt_index_atomic_inc(atomic_t *index) | ||
52 | { | ||
53 | int old = atomic_read(index); | ||
54 | int new = bt_index_inc(old); | ||
55 | atomic_cmpxchg(index, old, new); | ||
49 | } | 56 | } |
50 | 57 | ||
51 | /* | 58 | /* |
@@ -69,14 +76,14 @@ static void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags) | |||
69 | int i, wake_index; | 76 | int i, wake_index; |
70 | 77 | ||
71 | bt = &tags->bitmap_tags; | 78 | bt = &tags->bitmap_tags; |
72 | wake_index = bt->wake_index; | 79 | wake_index = atomic_read(&bt->wake_index); |
73 | for (i = 0; i < BT_WAIT_QUEUES; i++) { | 80 | for (i = 0; i < BT_WAIT_QUEUES; i++) { |
74 | struct bt_wait_state *bs = &bt->bs[wake_index]; | 81 | struct bt_wait_state *bs = &bt->bs[wake_index]; |
75 | 82 | ||
76 | if (waitqueue_active(&bs->wait)) | 83 | if (waitqueue_active(&bs->wait)) |
77 | wake_up(&bs->wait); | 84 | wake_up(&bs->wait); |
78 | 85 | ||
79 | bt_index_inc(&wake_index); | 86 | wake_index = bt_index_inc(wake_index); |
80 | } | 87 | } |
81 | } | 88 | } |
82 | 89 | ||
@@ -212,12 +219,14 @@ static struct bt_wait_state *bt_wait_ptr(struct blk_mq_bitmap_tags *bt, | |||
212 | struct blk_mq_hw_ctx *hctx) | 219 | struct blk_mq_hw_ctx *hctx) |
213 | { | 220 | { |
214 | struct bt_wait_state *bs; | 221 | struct bt_wait_state *bs; |
222 | int wait_index; | ||
215 | 223 | ||
216 | if (!hctx) | 224 | if (!hctx) |
217 | return &bt->bs[0]; | 225 | return &bt->bs[0]; |
218 | 226 | ||
219 | bs = &bt->bs[hctx->wait_index]; | 227 | wait_index = atomic_read(&hctx->wait_index); |
220 | bt_index_inc(&hctx->wait_index); | 228 | bs = &bt->bs[wait_index]; |
229 | bt_index_atomic_inc(&hctx->wait_index); | ||
221 | return bs; | 230 | return bs; |
222 | } | 231 | } |
223 | 232 | ||
@@ -313,18 +322,19 @@ static struct bt_wait_state *bt_wake_ptr(struct blk_mq_bitmap_tags *bt) | |||
313 | { | 322 | { |
314 | int i, wake_index; | 323 | int i, wake_index; |
315 | 324 | ||
316 | wake_index = bt->wake_index; | 325 | wake_index = atomic_read(&bt->wake_index); |
317 | for (i = 0; i < BT_WAIT_QUEUES; i++) { | 326 | for (i = 0; i < BT_WAIT_QUEUES; i++) { |
318 | struct bt_wait_state *bs = &bt->bs[wake_index]; | 327 | struct bt_wait_state *bs = &bt->bs[wake_index]; |
319 | 328 | ||
320 | if (waitqueue_active(&bs->wait)) { | 329 | if (waitqueue_active(&bs->wait)) { |
321 | if (wake_index != bt->wake_index) | 330 | int o = atomic_read(&bt->wake_index); |
322 | bt->wake_index = wake_index; | 331 | if (wake_index != o) |
332 | atomic_cmpxchg(&bt->wake_index, o, wake_index); | ||
323 | 333 | ||
324 | return bs; | 334 | return bs; |
325 | } | 335 | } |
326 | 336 | ||
327 | bt_index_inc(&wake_index); | 337 | wake_index = bt_index_inc(wake_index); |
328 | } | 338 | } |
329 | 339 | ||
330 | return NULL; | 340 | return NULL; |
@@ -344,7 +354,7 @@ static void bt_clear_tag(struct blk_mq_bitmap_tags *bt, unsigned int tag) | |||
344 | bs = bt_wake_ptr(bt); | 354 | bs = bt_wake_ptr(bt); |
345 | if (bs && atomic_dec_and_test(&bs->wait_cnt)) { | 355 | if (bs && atomic_dec_and_test(&bs->wait_cnt)) { |
346 | atomic_set(&bs->wait_cnt, bt->wake_cnt); | 356 | atomic_set(&bs->wait_cnt, bt->wake_cnt); |
347 | bt_index_inc(&bt->wake_index); | 357 | bt_index_atomic_inc(&bt->wake_index); |
348 | wake_up(&bs->wait); | 358 | wake_up(&bs->wait); |
349 | } | 359 | } |
350 | } | 360 | } |
diff --git a/block/blk-mq-tag.h b/block/blk-mq-tag.h index 98696a65d4d4..6206ed17ef76 100644 --- a/block/blk-mq-tag.h +++ b/block/blk-mq-tag.h | |||
@@ -24,7 +24,7 @@ struct blk_mq_bitmap_tags { | |||
24 | unsigned int map_nr; | 24 | unsigned int map_nr; |
25 | struct blk_align_bitmap *map; | 25 | struct blk_align_bitmap *map; |
26 | 26 | ||
27 | unsigned int wake_index; | 27 | atomic_t wake_index; |
28 | struct bt_wait_state *bs; | 28 | struct bt_wait_state *bs; |
29 | }; | 29 | }; |
30 | 30 | ||