From 2bae5f981192d83a2805f74d9f6e6e71705a7085 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Mon, 10 Mar 2025 18:44:12 -0400 Subject: block: Allow REQ_FUA|REQ_READ FUA is also allowed with reads, not just writes. The specified behaviour is: - If the location being read from in the drive cache is dirty, it's flushed - Read is serviced from media, not cache It's documented in the NVME specification, and the nvme driver already passes through REQ_FUA for reads, not just writes, so there's no reason for the block layer to be disallowing it. To validate behaviour, a simple test was run on a variety of hardware that checks latency of repeated reads to the same location (cached reads), random reads (uncached), and FUA reads to the same location. Data: - Samsung consumer SSDs Reads appear to not be cached - Seagate SCSI hard drives (ST20000NM002D) Reads are cached, and FUA reads appear to work correctly Link: https://lore.kernel.org/linux-block/20250311133517.3095878-1-kent.overstreet@linux.dev/ Link: https://lore.kernel.org/linux-bcachefs/26585.34711.506258.318405@quad.stoffel.home/T/#m5fffbc0e1c68cf0479c94b9f4ac1bef297333782 Cc: Jens Axboe Cc: linux-block@vger.kernel.org Signed-off-by: Kent Overstreet --- block/blk-core.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index fdac48aec5ef..75fd237ce76c 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -800,20 +800,21 @@ void submit_bio_noacct(struct bio *bio) goto end_io; } + if (WARN_ON_ONCE((bio->bi_opf & REQ_PREFLUSH) && + bio_op(bio) != REQ_OP_WRITE && + bio_op(bio) != REQ_OP_ZONE_APPEND)) + goto end_io; + /* * Filter flush bio's early so that bio based drivers without flush * support don't have to worry about them. */ - if (op_is_flush(bio->bi_opf)) { - if (WARN_ON_ONCE(bio_op(bio) != REQ_OP_WRITE && - bio_op(bio) != REQ_OP_ZONE_APPEND)) + if (op_is_flush(bio->bi_opf) && + !bdev_write_cache(bdev)) { + bio->bi_opf &= ~(REQ_PREFLUSH | REQ_FUA); + if (!bio_sectors(bio)) { + status = BLK_STS_OK; goto end_io; - if (!bdev_write_cache(bdev)) { - bio->bi_opf &= ~(REQ_PREFLUSH | REQ_FUA); - if (!bio_sectors(bio)) { - status = BLK_STS_OK; - goto end_io; - } } } -- cgit v1.2.3