I think this can be done much simpler. The only place in blk_insert_flush that actually needs to run the queue is the case where no flushes are needed, as all the others are handled via the flush state machine and the requeue list. So something like this should work: diff --git a/block/blk-flush.c b/block/blk-flush.c index 4201728bf3a5a..1fce6d16e6d3a 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -421,7 +421,7 @@ void blk_insert_flush(struct request *rq) */ if ((policy & REQ_FSEQ_DATA) && !(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) { - blk_mq_request_bypass_insert(rq, false, false); + blk_mq_request_bypass_insert(rq, false, true); return; } diff --git a/block/blk-mq.c b/block/blk-mq.c index f296edff47246..89a142b61f456 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -2314,7 +2314,6 @@ void blk_mq_submit_bio(struct bio *bio) if (unlikely(is_flush_fua)) { /* Bypass scheduler for flush requests */ blk_insert_flush(rq); - blk_mq_run_hw_queue(rq->mq_hctx, true); } else if (plug && (q->nr_hw_queues == 1 || blk_mq_is_shared_tags(rq->mq_hctx->flags) || q->mq_ops->commit_rqs || !blk_queue_nonrot(q))) {