Skip to content

Commit 4f1731d

Browse files
YuKuai-huaweiaxboe
authored andcommitted
blk-mq: fix potential io hang by wrong 'wake_batch'
In __blk_mq_tag_busy/idle(), updating 'active_queues' and calculating 'wake_batch' is not atomic: t1: t2: _blk_mq_tag_busy blk_mq_tag_busy inc active_queues // assume 1->2 inc active_queues // 2 -> 3 blk_mq_update_wake_batch // calculate based on 3 blk_mq_update_wake_batch /* calculate based on 2, while active_queues is actually 3. */ Fix this problem by protecting them wih 'tags->lock', this is not a hot path, so performance should not be concerned. And now that all writers are inside the lock, switch 'actives_queues' from atomic to unsigned int. Fixes: 180dccb ("blk-mq: fix tag_get wait task can't be awakened") Signed-off-by: Yu Kuai <[email protected]> Reviewed-by: Jan Kara <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 0733ad8 commit 4f1731d

File tree

4 files changed

+13
-10
lines changed

4 files changed

+13
-10
lines changed

block/blk-mq-debugfs.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ static void blk_mq_debugfs_tags_show(struct seq_file *m,
401401
seq_printf(m, "nr_tags=%u\n", tags->nr_tags);
402402
seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags);
403403
seq_printf(m, "active_queues=%d\n",
404-
atomic_read(&tags->active_queues));
404+
READ_ONCE(tags->active_queues));
405405

406406
seq_puts(m, "\nbitmap_tags:\n");
407407
sbitmap_queue_show(&tags->bitmap_tags, m);

block/blk-mq-tag.c

+10-5
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ static void blk_mq_update_wake_batch(struct blk_mq_tags *tags,
3838
void __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx)
3939
{
4040
unsigned int users;
41+
struct blk_mq_tags *tags = hctx->tags;
4142

4243
if (blk_mq_is_shared_tags(hctx->flags)) {
4344
struct request_queue *q = hctx->queue;
@@ -51,9 +52,11 @@ void __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx)
5152
set_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state);
5253
}
5354

54-
users = atomic_inc_return(&hctx->tags->active_queues);
55-
56-
blk_mq_update_wake_batch(hctx->tags, users);
55+
spin_lock_irq(&tags->lock);
56+
users = tags->active_queues + 1;
57+
WRITE_ONCE(tags->active_queues, users);
58+
blk_mq_update_wake_batch(tags, users);
59+
spin_unlock_irq(&tags->lock);
5760
}
5861

5962
/*
@@ -86,9 +89,11 @@ void __blk_mq_tag_idle(struct blk_mq_hw_ctx *hctx)
8689
return;
8790
}
8891

89-
users = atomic_dec_return(&tags->active_queues);
90-
92+
spin_lock_irq(&tags->lock);
93+
users = tags->active_queues - 1;
94+
WRITE_ONCE(tags->active_queues, users);
9195
blk_mq_update_wake_batch(tags, users);
96+
spin_unlock_irq(&tags->lock);
9297

9398
blk_mq_tag_wakeup_all(tags, false);
9499
}

block/blk-mq.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,7 @@ static inline bool hctx_may_queue(struct blk_mq_hw_ctx *hctx,
412412
return true;
413413
}
414414

415-
users = atomic_read(&hctx->tags->active_queues);
416-
415+
users = READ_ONCE(hctx->tags->active_queues);
417416
if (!users)
418417
return true;
419418

include/linux/blk-mq.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -739,8 +739,7 @@ struct request *blk_mq_alloc_request_hctx(struct request_queue *q,
739739
struct blk_mq_tags {
740740
unsigned int nr_tags;
741741
unsigned int nr_reserved_tags;
742-
743-
atomic_t active_queues;
742+
unsigned int active_queues;
744743

745744
struct sbitmap_queue bitmap_tags;
746745
struct sbitmap_queue breserved_tags;

0 commit comments

Comments
 (0)