Tag iterators such as blk_mq_queue_tag_busy_iter() take a reference on each busy request, the flush request included, and drop it with blk_mq_put_rq_ref(). For the flush request that calls flush_end_io() with a zero status. When that put is not the last one, flush_end_io() stores the status in fq->rq_status for the last put to report, so the iterator's zero overwrites an error the device completion stored there. With two iterators holding references, the device completes the flush with an error and flush_end_io() stores it, the first iterator drops its reference and stores 0, and the second drop reports success. The requests waiting on the flush complete without the error and fsync() returns 0. Only store a nonzero status in fq->rq_status, so dropping an iterator reference can't clear an error. Reproduced on v7.3 in an x86 QEMU guest with scsi_debug, failing every SYNCHRONIZE CACHE through its debugfs error injection while 16 processes read /sys/block/sda/inflight: modprobe scsi_debug dev_size_mb=64 ndelay=100000 echo "2 1 0x35 0x00 0x00 0x02 0x04 0x44 0x00" > \ /sys/kernel/debug/scsi_debug//error fsync() returned 0 for 35 of 18000 calls on /dev/sda and for 46 of 18000 calls on a file on ext4 without a journal, over six runs. With this change every call failed. Fixes: 8d6996630c03 ("block: fix null pointer dereference in blk_mq_rq_timed_out()") Cc: stable@vger.kernel.org Assisted-by: LLM Specula Signed-off-by: Nirmoy Das --- Ye Bin's "blk-flush: fix possibe deadlock when process nvme_timeout()" (not merged yet) adds lines right after the same assignment, so the second of the two to be applied needs a trivial rebase. block/blk-flush.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/block/blk-flush.c b/block/blk-flush.c index 403a46c8641172d..65697e2efad290b 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -212,7 +212,8 @@ 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; + if (error) + fq->rq_status = error; spin_unlock_irqrestore(&fq->mq_flush_lock, flags); return RQ_END_IO_NONE; } -- 2.43.0