diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2025-03-10 18:44:12 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2025-04-06 19:13:47 -0400 |
commit | 0fbdfdac9e8d11be09d53af33f1a125a8df4819b (patch) | |
tree | fa2f07f9cbc3fcb6b03e80e529369aba3004fee7 | |
parent | 5e952a5da7d5ab05748dda0f8a93fb6f85981c95 (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 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; - } } } |