diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2025-03-10 18:44:12 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2025-06-30 17:52:47 -0400 |
commit | 2bae5f981192d83a2805f74d9f6e6e71705a7085 (patch) | |
tree | 878d95db58a3fe2d03992a3f29a82bd4adb59de7 | |
parent | 03d70d5d61909e3db9b4e924074fa6cc9fba38f2 (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.c | 19 |
1 files 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; - } } } |