block: don't lose the status of a failed flush request

flush_end_io() stores the status in fq->rq_status for whoever drops the
last reference to finish the flush sequence. blk_mq_put_rq_ref() calls
it with BLK_STS_OK from tag iterators and the timeout handler and
overwrites an error the real completion stored. With two extra
references, reading /sys/block/<disk>/inflight is enough for that, a
failed flush completes everything waiting on it with success and fsync()
lies to the application.

Only store a status that is an error.

Fixes: 2e315dc07d ("blk-mq: grab rq->refcount before calling ->fn in blk_mq_tagset_busy_iter")
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20261028164415.1262013-6-axboe@kernel.dk
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Josef Bacik 2026-10-28 10:41:08 -06:00 committed by Jens Axboe
parent cebb1c2331
commit 67c43ceaa2

View File

@ -212,7 +212,13 @@ static enum rq_end_io_ret flush_end_io(struct request *flush_rq,
spin_lock_irqsave(&fq->mq_flush_lock, flags);
if (!req_ref_put_and_test(flush_rq)) {
fq->rq_status = error;
/*
* Remember the status of the flush for whoever drops the last
* reference. blk_mq_put_rq_ref() gets here with BLK_STS_OK and
* must not wipe it out.
*/
if (error != BLK_STS_OK)
fq->rq_status = error;
spin_unlock_irqrestore(&fq->mq_flush_lock, flags);
return RQ_END_IO_NONE;
}