From bec7d36a6514153ded6ffe1323ab14912ced42df Mon Sep 17 00:00:00 2001 From: Zhenxian Ma Date: Sat, 15 Aug 2026 17:06:52 +0800 Subject: [PATCH] block: skip redundant flush for O_DSYNC direct writes For an O_DIRECT | O_DSYNC write, dio_bio_write_op() adds REQ_FUA to the bio, so the data is durable once the direct I/O returns. The unconditional generic_write_sync() in blkdev_write_iter() then issues a REQ_PREFLUSH that is redundant. Skip it when the direct path already provided durability via FUA. A need_sync flag, clear by default, is set only for buffered writes and for the buffered fallback after a partial direct write. Measured on a Seagate ST20000NM007D (20 TB, 7200 rpm, fua=1, write_cache=write back), Linux v7.2.0-rc7, single-threaded pwrite() loop opening the raw block device with O_WRONLY | O_DIRECT | O_DSYNC, 4 KiB writes for 60 s: Sequential 4 KiB writes: baseline patched IOPS 119.7 7497.0 avg latency (us) 8357 133 p50 latency (us) 8346 127 p99 latency (us) 8368 395 p99.9 latency (us) 8728 569 Random 4 KiB writes (100 GiB span): baseline patched IOPS 156.1 666.4 avg latency (us) 6405 1500 p50 latency (us) 6186 1450 p99 latency (us) 16133 2285 p99.9 latency (us) 17250 9916 Signed-off-by: Zhenxian Ma Signed-off-by: Zhenxian Ma Reviewed-by: Christoph Hellwig Link: https://patch.msgid.link/f847707d772a9225460406b5aecba030d7209b05.1786782832.git.mzx199711@gmail.com Signed-off-by: Jens Axboe --- block/fops.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/block/fops.c b/block/fops.c index 2ce7c6c4714e..38959ebae80c 100644 --- a/block/fops.c +++ b/block/fops.c @@ -728,6 +728,7 @@ static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) bool atomic = iocb->ki_flags & IOCB_ATOMIC; loff_t size = bdev_nr_bytes(bdev); size_t shorted = 0; + bool need_sync = false; ssize_t ret; if (bdev_read_only(bdev)) @@ -765,9 +766,11 @@ static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) if (iocb->ki_flags & IOCB_DIRECT) { ret = blkdev_direct_write(iocb, from); - if (ret >= 0 && iov_iter_count(from)) + if (ret >= 0 && iov_iter_count(from)) { ret = direct_write_fallback(iocb, from, ret, blkdev_buffered_write(iocb, from)); + need_sync = true; + } } else { /* * Take i_rwsem and invalidate_lock to avoid racing with @@ -777,9 +780,10 @@ static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) inode_lock_shared(bd_inode); ret = blkdev_buffered_write(iocb, from); inode_unlock_shared(bd_inode); + need_sync = true; } - if (ret > 0) + if (ret > 0 && need_sync) ret = generic_write_sync(iocb, ret); iov_iter_reexpand(from, iov_iter_count(from) + shorted); return ret;