summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2025-03-10 18:44:12 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2025-04-06 19:13:47 -0400
commit0fbdfdac9e8d11be09d53af33f1a125a8df4819b (patch)
treefa2f07f9cbc3fcb6b03e80e529369aba3004fee7
parent5e952a5da7d5ab05748dda0f8a93fb6f85981c95 (diff)
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 <axboe@kernel.dk> Cc: linux-block@vger.kernel.org Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--block/blk-core.c19
1 files changed, 10 insertions, 9 deletions
diff --git a/block/blk-core.c b/block/blk-core.c
index e8cc270a453f..7d3ea8f91988 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;
- }
}
}