Skip to content

Commit 27ec0bf

Browse files
author
Ming Lei
committed
block: don't update BLK_FEAT_POLL in __blk_mq_update_nr_hw_queues
JIRA: https://issues.redhat.com/browse/RHEL-71345 Upstream Status: for-6.4/block commit d432c81 Author: Christoph Hellwig <hch@lst.de> Date: Fri Jan 10 06:47:12 2025 +0100 block: don't update BLK_FEAT_POLL in __blk_mq_update_nr_hw_queues When __blk_mq_update_nr_hw_queues changes the number of tag sets, it might have to disable poll queues. Currently it does so by adjusting the BLK_FEAT_POLL, which is a bit against the intent of features that describe hardware / driver capabilities, but more importantly causes nasty lock order problems with the broadly held freeze when updating the number of hardware queues and the limits lock. Fix this by leaving BLK_FEAT_POLL alone, and instead check for the number of poll queues in the bio submission and poll handlers. While this adds extra work to the fast path, the variables are in cache lines used by these operations anyway, so it should be cheap enough. Fixes: 8023e14 ("block: move the poll flag to queue_limits") Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Ming Lei <ming.lei@redhat.com> Reviewed-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Reviewed-by: Nilay Shroff <nilay@linux.ibm.com> Link: https://lore.kernel.org/r/20250110054726.1499538-5-hch@lst.de Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Ming Lei <ming.lei@redhat.com>
1 parent dfed015 commit 27ec0bf

File tree

4 files changed

+22
-26
lines changed

4 files changed

+22
-26
lines changed

block/blk-core.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -934,14 +934,13 @@ int bio_poll(struct bio *bio, struct io_comp_batch *iob, unsigned int flags)
934934
*/
935935
if (!percpu_ref_tryget(&q->q_usage_counter))
936936
return 0;
937-
if (!(q->limits.features & BLK_FEAT_POLL)) {
938-
ret = 0;
939-
} else if (queue_is_mq(q)) {
937+
if (queue_is_mq(q)) {
940938
ret = blk_mq_poll(q, cookie, iob, flags);
941939
} else {
942940
struct gendisk *disk = q->disk;
943941

944-
if (disk && disk->fops->poll_bio)
942+
if ((q->limits.features & BLK_FEAT_POLL) && disk &&
943+
disk->fops->poll_bio)
945944
ret = disk->fops->poll_bio(bio, iob, flags);
946945
}
947946
blk_queue_exit(q);

block/blk-mq.c

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2985,8 +2985,7 @@ void blk_mq_submit_bio(struct bio *bio)
29852985
goto queue_exit;
29862986
}
29872987

2988-
if ((bio->bi_opf & REQ_POLLED) &&
2989-
!(q->limits.features & BLK_FEAT_POLL)) {
2988+
if ((bio->bi_opf & REQ_POLLED) && !blk_mq_can_poll(q)) {
29902989
bio->bi_status = BLK_STS_NOTSUPP;
29912990
bio_endio(bio);
29922991
goto queue_exit;
@@ -4138,12 +4137,6 @@ void blk_mq_release(struct request_queue *q)
41384137
blk_mq_sysfs_deinit(q);
41394138
}
41404139

4141-
static bool blk_mq_can_poll(struct blk_mq_tag_set *set)
4142-
{
4143-
return set->nr_maps > HCTX_TYPE_POLL &&
4144-
set->map[HCTX_TYPE_POLL].nr_queues;
4145-
}
4146-
41474140
struct request_queue *blk_mq_alloc_queue(struct blk_mq_tag_set *set,
41484141
struct queue_limits *lim, void *queuedata)
41494142
{
@@ -4154,7 +4147,7 @@ struct request_queue *blk_mq_alloc_queue(struct blk_mq_tag_set *set,
41544147
if (!lim)
41554148
lim = &default_lim;
41564149
lim->features |= BLK_FEAT_IO_STAT | BLK_FEAT_NOWAIT;
4157-
if (blk_mq_can_poll(set))
4150+
if (set->nr_maps > HCTX_TYPE_POLL)
41584151
lim->features |= BLK_FEAT_POLL;
41594152

41604153
q = blk_alloc_queue(lim, set->numa_node);
@@ -4827,8 +4820,6 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
48274820
fallback:
48284821
blk_mq_update_queue_map(set);
48294822
list_for_each_entry(q, &set->tag_list, tag_set_list) {
4830-
struct queue_limits lim;
4831-
48324823
blk_mq_realloc_hw_ctxs(set, q);
48334824

48344825
if (q->nr_hw_queues != set->nr_hw_queues) {
@@ -4842,13 +4833,6 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
48424833
set->nr_hw_queues = prev_nr_hw_queues;
48434834
goto fallback;
48444835
}
4845-
lim = queue_limits_start_update(q);
4846-
if (blk_mq_can_poll(set))
4847-
lim.features |= BLK_FEAT_POLL;
4848-
else
4849-
lim.features &= ~BLK_FEAT_POLL;
4850-
if (queue_limits_commit_update(q, &lim) < 0)
4851-
pr_warn("updating the poll flag failed\n");
48524836
blk_mq_map_swqueue(q);
48534837
}
48544838

@@ -4908,9 +4892,9 @@ static int blk_hctx_poll(struct request_queue *q, struct blk_mq_hw_ctx *hctx,
49084892
int blk_mq_poll(struct request_queue *q, blk_qc_t cookie,
49094893
struct io_comp_batch *iob, unsigned int flags)
49104894
{
4911-
struct blk_mq_hw_ctx *hctx = xa_load(&q->hctx_table, cookie);
4912-
4913-
return blk_hctx_poll(q, hctx, iob, flags);
4895+
if (!blk_mq_can_poll(q))
4896+
return 0;
4897+
return blk_hctx_poll(q, xa_load(&q->hctx_table, cookie), iob, flags);
49144898
}
49154899

49164900
int blk_rq_poll(struct request *rq, struct io_comp_batch *iob,

block/blk-mq.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,4 +438,10 @@ do { \
438438
#define blk_mq_run_dispatch_ops(q, dispatch_ops) \
439439
__blk_mq_run_dispatch_ops(q, true, dispatch_ops) \
440440

441+
static inline bool blk_mq_can_poll(struct request_queue *q)
442+
{
443+
return (q->limits.features & BLK_FEAT_POLL) &&
444+
q->tag_set->map[HCTX_TYPE_POLL].nr_queues;
445+
}
446+
441447
#endif

block/blk-sysfs.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,10 +256,17 @@ static ssize_t queue_##_name##_show(struct gendisk *disk, char *page) \
256256
!!(disk->queue->limits.features & _feature)); \
257257
}
258258

259-
QUEUE_SYSFS_FEATURE_SHOW(poll, BLK_FEAT_POLL);
260259
QUEUE_SYSFS_FEATURE_SHOW(fua, BLK_FEAT_FUA);
261260
QUEUE_SYSFS_FEATURE_SHOW(dax, BLK_FEAT_DAX);
262261

262+
static ssize_t queue_poll_show(struct gendisk *disk, char *page)
263+
{
264+
if (queue_is_mq(disk->queue))
265+
return sysfs_emit(page, "%u\n", blk_mq_can_poll(disk->queue));
266+
return sysfs_emit(page, "%u\n",
267+
!!(disk->queue->limits.features & BLK_FEAT_POLL));
268+
}
269+
263270
static ssize_t queue_zoned_show(struct gendisk *disk, char *page)
264271
{
265272
if (blk_queue_is_zoned(disk->queue))

0 commit comments

Comments
 (0)