diff options
author | Bart Van Assche <bart.vanassche@sandisk.com> | 2017-04-07 14:40:09 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2017-04-07 14:40:09 -0400 |
commit | 6d8c6c0f97ad8a3517c42b179c1dc8e77397d0e2 (patch) | |
tree | 9400809275952c263a8512447cf625b3c490fa61 | |
parent | 6077c2d706097c00d8f2fed57d3f3c45cd228ee8 (diff) |
blk-mq: Restart a single queue if tag sets are shared
To improve scalability, if hardware queues are shared, restart
a single hardware queue in round-robin fashion. Rename
blk_mq_sched_restart_queues() to reflect the new semantics.
Remove blk_mq_sched_mark_restart_queue() because this function
has no callers. Remove flag QUEUE_FLAG_RESTART because this
patch removes the code that uses this flag.
Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r-- | block/blk-mq-sched.c | 63 | ||||
-rw-r--r-- | block/blk-mq-sched.h | 16 | ||||
-rw-r--r-- | block/blk-mq.c | 2 | ||||
-rw-r--r-- | include/linux/blkdev.h | 1 |
4 files changed, 55 insertions, 27 deletions
diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c index e8c2ed654ef0..c974a1bbf4cb 100644 --- a/block/blk-mq-sched.c +++ b/block/blk-mq-sched.c | |||
@@ -318,25 +318,68 @@ static bool blk_mq_sched_bypass_insert(struct blk_mq_hw_ctx *hctx, | |||
318 | return true; | 318 | return true; |
319 | } | 319 | } |
320 | 320 | ||
321 | static void blk_mq_sched_restart_hctx(struct blk_mq_hw_ctx *hctx) | 321 | static bool blk_mq_sched_restart_hctx(struct blk_mq_hw_ctx *hctx) |
322 | { | 322 | { |
323 | if (test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state)) { | 323 | if (test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state)) { |
324 | clear_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state); | 324 | clear_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state); |
325 | if (blk_mq_hctx_has_pending(hctx)) | 325 | if (blk_mq_hctx_has_pending(hctx)) { |
326 | blk_mq_run_hw_queue(hctx, true); | 326 | blk_mq_run_hw_queue(hctx, true); |
327 | return true; | ||
328 | } | ||
327 | } | 329 | } |
330 | return false; | ||
328 | } | 331 | } |
329 | 332 | ||
330 | void blk_mq_sched_restart_queues(struct blk_mq_hw_ctx *hctx) | 333 | /** |
331 | { | 334 | * list_for_each_entry_rcu_rr - iterate in a round-robin fashion over rcu list |
332 | struct request_queue *q = hctx->queue; | 335 | * @pos: loop cursor. |
333 | unsigned int i; | 336 | * @skip: the list element that will not be examined. Iteration starts at |
337 | * @skip->next. | ||
338 | * @head: head of the list to examine. This list must have at least one | ||
339 | * element, namely @skip. | ||
340 | * @member: name of the list_head structure within typeof(*pos). | ||
341 | */ | ||
342 | #define list_for_each_entry_rcu_rr(pos, skip, head, member) \ | ||
343 | for ((pos) = (skip); \ | ||
344 | (pos = (pos)->member.next != (head) ? list_entry_rcu( \ | ||
345 | (pos)->member.next, typeof(*pos), member) : \ | ||
346 | list_entry_rcu((pos)->member.next->next, typeof(*pos), member)), \ | ||
347 | (pos) != (skip); ) | ||
334 | 348 | ||
335 | if (test_bit(QUEUE_FLAG_RESTART, &q->queue_flags)) { | 349 | /* |
336 | if (test_and_clear_bit(QUEUE_FLAG_RESTART, &q->queue_flags)) { | 350 | * Called after a driver tag has been freed to check whether a hctx needs to |
337 | queue_for_each_hw_ctx(q, hctx, i) | 351 | * be restarted. Restarts @hctx if its tag set is not shared. Restarts hardware |
338 | blk_mq_sched_restart_hctx(hctx); | 352 | * queues in a round-robin fashion if the tag set of @hctx is shared with other |
353 | * hardware queues. | ||
354 | */ | ||
355 | void blk_mq_sched_restart(struct blk_mq_hw_ctx *const hctx) | ||
356 | { | ||
357 | struct blk_mq_tags *const tags = hctx->tags; | ||
358 | struct blk_mq_tag_set *const set = hctx->queue->tag_set; | ||
359 | struct request_queue *const queue = hctx->queue, *q; | ||
360 | struct blk_mq_hw_ctx *hctx2; | ||
361 | unsigned int i, j; | ||
362 | |||
363 | if (set->flags & BLK_MQ_F_TAG_SHARED) { | ||
364 | rcu_read_lock(); | ||
365 | list_for_each_entry_rcu_rr(q, queue, &set->tag_list, | ||
366 | tag_set_list) { | ||
367 | queue_for_each_hw_ctx(q, hctx2, i) | ||
368 | if (hctx2->tags == tags && | ||
369 | blk_mq_sched_restart_hctx(hctx2)) | ||
370 | goto done; | ||
371 | } | ||
372 | j = hctx->queue_num + 1; | ||
373 | for (i = 0; i < queue->nr_hw_queues; i++, j++) { | ||
374 | if (j == queue->nr_hw_queues) | ||
375 | j = 0; | ||
376 | hctx2 = queue->queue_hw_ctx[j]; | ||
377 | if (hctx2->tags == tags && | ||
378 | blk_mq_sched_restart_hctx(hctx2)) | ||
379 | break; | ||
339 | } | 380 | } |
381 | done: | ||
382 | rcu_read_unlock(); | ||
340 | } else { | 383 | } else { |
341 | blk_mq_sched_restart_hctx(hctx); | 384 | blk_mq_sched_restart_hctx(hctx); |
342 | } | 385 | } |
diff --git a/block/blk-mq-sched.h b/block/blk-mq-sched.h index e704956e0862..3a9e6e40558b 100644 --- a/block/blk-mq-sched.h +++ b/block/blk-mq-sched.h | |||
@@ -19,7 +19,7 @@ bool blk_mq_sched_try_merge(struct request_queue *q, struct bio *bio, | |||
19 | struct request **merged_request); | 19 | struct request **merged_request); |
20 | bool __blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio); | 20 | bool __blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio); |
21 | bool blk_mq_sched_try_insert_merge(struct request_queue *q, struct request *rq); | 21 | bool blk_mq_sched_try_insert_merge(struct request_queue *q, struct request *rq); |
22 | void blk_mq_sched_restart_queues(struct blk_mq_hw_ctx *hctx); | 22 | void blk_mq_sched_restart(struct blk_mq_hw_ctx *hctx); |
23 | 23 | ||
24 | void blk_mq_sched_insert_request(struct request *rq, bool at_head, | 24 | void blk_mq_sched_insert_request(struct request *rq, bool at_head, |
25 | bool run_queue, bool async, bool can_block); | 25 | bool run_queue, bool async, bool can_block); |
@@ -136,20 +136,6 @@ static inline void blk_mq_sched_mark_restart_hctx(struct blk_mq_hw_ctx *hctx) | |||
136 | set_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state); | 136 | set_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state); |
137 | } | 137 | } |
138 | 138 | ||
139 | /* | ||
140 | * Mark a hardware queue and the request queue it belongs to as needing a | ||
141 | * restart. | ||
142 | */ | ||
143 | static inline void blk_mq_sched_mark_restart_queue(struct blk_mq_hw_ctx *hctx) | ||
144 | { | ||
145 | struct request_queue *q = hctx->queue; | ||
146 | |||
147 | if (!test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state)) | ||
148 | set_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state); | ||
149 | if (!test_bit(QUEUE_FLAG_RESTART, &q->queue_flags)) | ||
150 | set_bit(QUEUE_FLAG_RESTART, &q->queue_flags); | ||
151 | } | ||
152 | |||
153 | static inline bool blk_mq_sched_needs_restart(struct blk_mq_hw_ctx *hctx) | 139 | static inline bool blk_mq_sched_needs_restart(struct blk_mq_hw_ctx *hctx) |
154 | { | 140 | { |
155 | return test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state); | 141 | return test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state); |
diff --git a/block/blk-mq.c b/block/blk-mq.c index ad45ae743186..572966f49596 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c | |||
@@ -348,7 +348,7 @@ void __blk_mq_finish_request(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx, | |||
348 | blk_mq_put_tag(hctx, hctx->tags, ctx, rq->tag); | 348 | blk_mq_put_tag(hctx, hctx->tags, ctx, rq->tag); |
349 | if (sched_tag != -1) | 349 | if (sched_tag != -1) |
350 | blk_mq_sched_completed_request(hctx, rq); | 350 | blk_mq_sched_completed_request(hctx, rq); |
351 | blk_mq_sched_restart_queues(hctx); | 351 | blk_mq_sched_restart(hctx); |
352 | blk_queue_exit(q); | 352 | blk_queue_exit(q); |
353 | } | 353 | } |
354 | 354 | ||
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 5a7da607ca04..7548f332121a 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -610,7 +610,6 @@ struct request_queue { | |||
610 | #define QUEUE_FLAG_FLUSH_NQ 25 /* flush not queueuable */ | 610 | #define QUEUE_FLAG_FLUSH_NQ 25 /* flush not queueuable */ |
611 | #define QUEUE_FLAG_DAX 26 /* device supports DAX */ | 611 | #define QUEUE_FLAG_DAX 26 /* device supports DAX */ |
612 | #define QUEUE_FLAG_STATS 27 /* track rq completion times */ | 612 | #define QUEUE_FLAG_STATS 27 /* track rq completion times */ |
613 | #define QUEUE_FLAG_RESTART 28 /* queue needs restart at completion */ | ||
614 | 613 | ||
615 | #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ | 614 | #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ |
616 | (1 << QUEUE_FLAG_STACKABLE) | \ | 615 | (1 << QUEUE_FLAG_STACKABLE) | \ |