aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Gordeev <agordeev@redhat.com>2014-06-18 01:12:35 -0400
committerJens Axboe <axboe@fb.com>2014-06-18 01:12:35 -0400
commit8537b12034cf1fd3fab3da2c859d71f76846fae9 (patch)
treeeef471e49e99b4e78d180f1158258ef1d5eb0aca
parent736ed4de766d4f0e8e6142dd4f9d73ef61835ed9 (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>
-rw-r--r--block/blk-mq-tag.c32
-rw-r--r--block/blk-mq-tag.h2
-rw-r--r--include/linux/blk-mq.h2
3 files changed, 23 insertions, 13 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
46static inline void bt_index_inc(unsigned int *index) 46static 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
51static 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
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index a002cf191427..eb726b9c5762 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -42,7 +42,7 @@ struct blk_mq_hw_ctx {
42 unsigned int nr_ctx; 42 unsigned int nr_ctx;
43 struct blk_mq_ctx **ctxs; 43 struct blk_mq_ctx **ctxs;
44 44
45 unsigned int wait_index; 45 atomic_t wait_index;
46 46
47 struct blk_mq_tags *tags; 47 struct blk_mq_tags *tags;
48 48