Commit 9f16a667 authored by Ming Lei's avatar Ming Lei Committed by Jens Axboe

block: mark flush request as IDLE when it is really finished

For avoiding use-after-free on flush request, we call its .end_io() from
both timeout code path and __blk_mq_end_request().

When flush request's ref doesn't drop to zero, it is still used, we
can't mark it as IDLE, so fix it by marking IDLE when its refcount drops
to zero really.

Fixes: 65ff5cd0 ("blk-mq: mark flush request as IDLE in flush_end_io()")
Signed-off-by: default avatarMing Lei <ming.lei@redhat.com>
Cc: Yi Zhang <yi.zhang@redhat.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent c01a21b7
...@@ -225,13 +225,18 @@ static void flush_end_io(struct request *flush_rq, blk_status_t error) ...@@ -225,13 +225,18 @@ static void flush_end_io(struct request *flush_rq, blk_status_t error)
/* release the tag's ownership to the req cloned from */ /* release the tag's ownership to the req cloned from */
spin_lock_irqsave(&fq->mq_flush_lock, flags); spin_lock_irqsave(&fq->mq_flush_lock, flags);
WRITE_ONCE(flush_rq->state, MQ_RQ_IDLE);
if (!refcount_dec_and_test(&flush_rq->ref)) { if (!refcount_dec_and_test(&flush_rq->ref)) {
fq->rq_status = error; fq->rq_status = error;
spin_unlock_irqrestore(&fq->mq_flush_lock, flags); spin_unlock_irqrestore(&fq->mq_flush_lock, flags);
return; return;
} }
/*
* Flush request has to be marked as IDLE when it is really ended
* because its .end_io() is called from timeout code path too for
* avoiding use-after-free.
*/
WRITE_ONCE(flush_rq->state, MQ_RQ_IDLE);
if (fq->rq_status != BLK_STS_OK) if (fq->rq_status != BLK_STS_OK)
error = fq->rq_status; error = fq->rq_status;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment