Commit 8537b120 authored by Alexander Gordeev's avatar Alexander Gordeev Committed by Jens Axboe

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: default avatarAlexander Gordeev <agordeev@redhat.com>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent 736ed4de
...@@ -43,9 +43,16 @@ bool blk_mq_has_free_tags(struct blk_mq_tags *tags) ...@@ -43,9 +43,16 @@ bool blk_mq_has_free_tags(struct blk_mq_tags *tags)
return bt_has_free_tags(&tags->bitmap_tags); return bt_has_free_tags(&tags->bitmap_tags);
} }
static inline void bt_index_inc(unsigned int *index) static inline int bt_index_inc(int index)
{ {
*index = (*index + 1) & (BT_WAIT_QUEUES - 1); return (index + 1) & (BT_WAIT_QUEUES - 1);
}
static inline void bt_index_atomic_inc(atomic_t *index)
{
int old = atomic_read(index);
int new = bt_index_inc(old);
atomic_cmpxchg(index, old, new);
} }
/* /*
...@@ -69,14 +76,14 @@ static void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags) ...@@ -69,14 +76,14 @@ static void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags)
int i, wake_index; int i, wake_index;
bt = &tags->bitmap_tags; bt = &tags->bitmap_tags;
wake_index = bt->wake_index; wake_index = atomic_read(&bt->wake_index);
for (i = 0; i < BT_WAIT_QUEUES; i++) { for (i = 0; i < BT_WAIT_QUEUES; i++) {
struct bt_wait_state *bs = &bt->bs[wake_index]; struct bt_wait_state *bs = &bt->bs[wake_index];
if (waitqueue_active(&bs->wait)) if (waitqueue_active(&bs->wait))
wake_up(&bs->wait); wake_up(&bs->wait);
bt_index_inc(&wake_index); wake_index = bt_index_inc(wake_index);
} }
} }
...@@ -212,12 +219,14 @@ static struct bt_wait_state *bt_wait_ptr(struct blk_mq_bitmap_tags *bt, ...@@ -212,12 +219,14 @@ static struct bt_wait_state *bt_wait_ptr(struct blk_mq_bitmap_tags *bt,
struct blk_mq_hw_ctx *hctx) struct blk_mq_hw_ctx *hctx)
{ {
struct bt_wait_state *bs; struct bt_wait_state *bs;
int wait_index;
if (!hctx) if (!hctx)
return &bt->bs[0]; return &bt->bs[0];
bs = &bt->bs[hctx->wait_index]; wait_index = atomic_read(&hctx->wait_index);
bt_index_inc(&hctx->wait_index); bs = &bt->bs[wait_index];
bt_index_atomic_inc(&hctx->wait_index);
return bs; return bs;
} }
...@@ -313,18 +322,19 @@ static struct bt_wait_state *bt_wake_ptr(struct blk_mq_bitmap_tags *bt) ...@@ -313,18 +322,19 @@ static struct bt_wait_state *bt_wake_ptr(struct blk_mq_bitmap_tags *bt)
{ {
int i, wake_index; int i, wake_index;
wake_index = bt->wake_index; wake_index = atomic_read(&bt->wake_index);
for (i = 0; i < BT_WAIT_QUEUES; i++) { for (i = 0; i < BT_WAIT_QUEUES; i++) {
struct bt_wait_state *bs = &bt->bs[wake_index]; struct bt_wait_state *bs = &bt->bs[wake_index];
if (waitqueue_active(&bs->wait)) { if (waitqueue_active(&bs->wait)) {
if (wake_index != bt->wake_index) int o = atomic_read(&bt->wake_index);
bt->wake_index = wake_index; if (wake_index != o)
atomic_cmpxchg(&bt->wake_index, o, wake_index);
return bs; return bs;
} }
bt_index_inc(&wake_index); wake_index = bt_index_inc(wake_index);
} }
return NULL; return NULL;
...@@ -344,7 +354,7 @@ static void bt_clear_tag(struct blk_mq_bitmap_tags *bt, unsigned int tag) ...@@ -344,7 +354,7 @@ static void bt_clear_tag(struct blk_mq_bitmap_tags *bt, unsigned int tag)
bs = bt_wake_ptr(bt); bs = bt_wake_ptr(bt);
if (bs && atomic_dec_and_test(&bs->wait_cnt)) { if (bs && atomic_dec_and_test(&bs->wait_cnt)) {
atomic_set(&bs->wait_cnt, bt->wake_cnt); atomic_set(&bs->wait_cnt, bt->wake_cnt);
bt_index_inc(&bt->wake_index); bt_index_atomic_inc(&bt->wake_index);
wake_up(&bs->wait); wake_up(&bs->wait);
} }
} }
......
...@@ -24,7 +24,7 @@ struct blk_mq_bitmap_tags { ...@@ -24,7 +24,7 @@ struct blk_mq_bitmap_tags {
unsigned int map_nr; unsigned int map_nr;
struct blk_align_bitmap *map; struct blk_align_bitmap *map;
unsigned int wake_index; atomic_t wake_index;
struct bt_wait_state *bs; struct bt_wait_state *bs;
}; };
......
...@@ -42,7 +42,7 @@ struct blk_mq_hw_ctx { ...@@ -42,7 +42,7 @@ struct blk_mq_hw_ctx {
unsigned int nr_ctx; unsigned int nr_ctx;
struct blk_mq_ctx **ctxs; struct blk_mq_ctx **ctxs;
unsigned int wait_index; atomic_t wait_index;
struct blk_mq_tags *tags; struct blk_mq_tags *tags;
......
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