diff options
-rw-r--r-- | block/blk-flush.c | 15 | ||||
-rw-r--r-- | block/blk-mq-tag.c | 4 | ||||
-rw-r--r-- | block/blk-mq-tag.h | 12 | ||||
-rw-r--r-- | block/blk-mq.c | 16 | ||||
-rw-r--r-- | block/blk.h | 6 |
5 files changed, 35 insertions, 18 deletions
diff --git a/block/blk-flush.c b/block/blk-flush.c index 20badd7b9d1b..9c423e53324a 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c | |||
@@ -73,6 +73,7 @@ | |||
73 | 73 | ||
74 | #include "blk.h" | 74 | #include "blk.h" |
75 | #include "blk-mq.h" | 75 | #include "blk-mq.h" |
76 | #include "blk-mq-tag.h" | ||
76 | 77 | ||
77 | /* FLUSH/FUA sequences */ | 78 | /* FLUSH/FUA sequences */ |
78 | enum { | 79 | enum { |
@@ -226,7 +227,12 @@ static void flush_end_io(struct request *flush_rq, int error) | |||
226 | struct blk_flush_queue *fq = blk_get_flush_queue(q, flush_rq->mq_ctx); | 227 | struct blk_flush_queue *fq = blk_get_flush_queue(q, flush_rq->mq_ctx); |
227 | 228 | ||
228 | if (q->mq_ops) { | 229 | if (q->mq_ops) { |
230 | struct blk_mq_hw_ctx *hctx; | ||
231 | |||
232 | /* release the tag's ownership to the req cloned from */ | ||
229 | spin_lock_irqsave(&fq->mq_flush_lock, flags); | 233 | spin_lock_irqsave(&fq->mq_flush_lock, flags); |
234 | hctx = q->mq_ops->map_queue(q, flush_rq->mq_ctx->cpu); | ||
235 | blk_mq_tag_set_rq(hctx, flush_rq->tag, fq->orig_rq); | ||
230 | flush_rq->tag = -1; | 236 | flush_rq->tag = -1; |
231 | } | 237 | } |
232 | 238 | ||
@@ -308,11 +314,18 @@ static bool blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq) | |||
308 | 314 | ||
309 | /* | 315 | /* |
310 | * Borrow tag from the first request since they can't | 316 | * Borrow tag from the first request since they can't |
311 | * be in flight at the same time. | 317 | * be in flight at the same time. And acquire the tag's |
318 | * ownership for flush req. | ||
312 | */ | 319 | */ |
313 | if (q->mq_ops) { | 320 | if (q->mq_ops) { |
321 | struct blk_mq_hw_ctx *hctx; | ||
322 | |||
314 | flush_rq->mq_ctx = first_rq->mq_ctx; | 323 | flush_rq->mq_ctx = first_rq->mq_ctx; |
315 | flush_rq->tag = first_rq->tag; | 324 | flush_rq->tag = first_rq->tag; |
325 | fq->orig_rq = first_rq; | ||
326 | |||
327 | hctx = q->mq_ops->map_queue(q, first_rq->mq_ctx->cpu); | ||
328 | blk_mq_tag_set_rq(hctx, first_rq->tag, flush_rq); | ||
316 | } | 329 | } |
317 | 330 | ||
318 | flush_rq->cmd_type = REQ_TYPE_FS; | 331 | flush_rq->cmd_type = REQ_TYPE_FS; |
diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index 9b6e28830b82..9115c6d59948 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c | |||
@@ -429,7 +429,7 @@ static void bt_for_each(struct blk_mq_hw_ctx *hctx, | |||
429 | for (bit = find_first_bit(&bm->word, bm->depth); | 429 | for (bit = find_first_bit(&bm->word, bm->depth); |
430 | bit < bm->depth; | 430 | bit < bm->depth; |
431 | bit = find_next_bit(&bm->word, bm->depth, bit + 1)) { | 431 | bit = find_next_bit(&bm->word, bm->depth, bit + 1)) { |
432 | rq = blk_mq_tag_to_rq(hctx->tags, off + bit); | 432 | rq = hctx->tags->rqs[off + bit]; |
433 | if (rq->q == hctx->queue) | 433 | if (rq->q == hctx->queue) |
434 | fn(hctx, rq, data, reserved); | 434 | fn(hctx, rq, data, reserved); |
435 | } | 435 | } |
@@ -453,7 +453,7 @@ static void bt_tags_for_each(struct blk_mq_tags *tags, | |||
453 | for (bit = find_first_bit(&bm->word, bm->depth); | 453 | for (bit = find_first_bit(&bm->word, bm->depth); |
454 | bit < bm->depth; | 454 | bit < bm->depth; |
455 | bit = find_next_bit(&bm->word, bm->depth, bit + 1)) { | 455 | bit = find_next_bit(&bm->word, bm->depth, bit + 1)) { |
456 | rq = blk_mq_tag_to_rq(tags, off + bit); | 456 | rq = tags->rqs[off + bit]; |
457 | fn(rq, data, reserved); | 457 | fn(rq, data, reserved); |
458 | } | 458 | } |
459 | 459 | ||
diff --git a/block/blk-mq-tag.h b/block/blk-mq-tag.h index 75893a34237d..9eb2cf4f01cb 100644 --- a/block/blk-mq-tag.h +++ b/block/blk-mq-tag.h | |||
@@ -89,4 +89,16 @@ static inline void blk_mq_tag_idle(struct blk_mq_hw_ctx *hctx) | |||
89 | __blk_mq_tag_idle(hctx); | 89 | __blk_mq_tag_idle(hctx); |
90 | } | 90 | } |
91 | 91 | ||
92 | /* | ||
93 | * This helper should only be used for flush request to share tag | ||
94 | * with the request cloned from, and both the two requests can't be | ||
95 | * in flight at the same time. The caller has to make sure the tag | ||
96 | * can't be freed. | ||
97 | */ | ||
98 | static inline void blk_mq_tag_set_rq(struct blk_mq_hw_ctx *hctx, | ||
99 | unsigned int tag, struct request *rq) | ||
100 | { | ||
101 | hctx->tags->rqs[tag] = rq; | ||
102 | } | ||
103 | |||
92 | #endif | 104 | #endif |
diff --git a/block/blk-mq.c b/block/blk-mq.c index 81edbd95bda8..f2d67b4047a0 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c | |||
@@ -559,23 +559,9 @@ void blk_mq_abort_requeue_list(struct request_queue *q) | |||
559 | } | 559 | } |
560 | EXPORT_SYMBOL(blk_mq_abort_requeue_list); | 560 | EXPORT_SYMBOL(blk_mq_abort_requeue_list); |
561 | 561 | ||
562 | static inline bool is_flush_request(struct request *rq, | ||
563 | struct blk_flush_queue *fq, unsigned int tag) | ||
564 | { | ||
565 | return ((rq->cmd_flags & REQ_FLUSH_SEQ) && | ||
566 | fq->flush_rq->tag == tag); | ||
567 | } | ||
568 | |||
569 | struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag) | 562 | struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag) |
570 | { | 563 | { |
571 | struct request *rq = tags->rqs[tag]; | 564 | return tags->rqs[tag]; |
572 | /* mq_ctx of flush rq is always cloned from the corresponding req */ | ||
573 | struct blk_flush_queue *fq = blk_get_flush_queue(rq->q, rq->mq_ctx); | ||
574 | |||
575 | if (!is_flush_request(rq, fq, tag)) | ||
576 | return rq; | ||
577 | |||
578 | return fq->flush_rq; | ||
579 | } | 565 | } |
580 | EXPORT_SYMBOL(blk_mq_tag_to_rq); | 566 | EXPORT_SYMBOL(blk_mq_tag_to_rq); |
581 | 567 | ||
diff --git a/block/blk.h b/block/blk.h index 026d9594142b..838188b35a83 100644 --- a/block/blk.h +++ b/block/blk.h | |||
@@ -22,6 +22,12 @@ struct blk_flush_queue { | |||
22 | struct list_head flush_queue[2]; | 22 | struct list_head flush_queue[2]; |
23 | struct list_head flush_data_in_flight; | 23 | struct list_head flush_data_in_flight; |
24 | struct request *flush_rq; | 24 | struct request *flush_rq; |
25 | |||
26 | /* | ||
27 | * flush_rq shares tag with this rq, both can't be active | ||
28 | * at the same time | ||
29 | */ | ||
30 | struct request *orig_rq; | ||
25 | spinlock_t mq_flush_lock; | 31 | spinlock_t mq_flush_lock; |
26 | }; | 32 | }; |
27 | 33 | ||