[PATCH v2 0/2] btrfs: drain in-flight direct IO before direct writes dirty the page cache
From: Breno Leitao
Date: Fri Nov 06 2026 - 10:32:45 EST
Atish reported that arm64 hosts with 64K pages and 4K btrfs blocks,
which keep VM disk images as NOCOW files opened with O_DIRECT, log
Page cache invalidation failure on direct I/O. Possible data corruption due to collision with buffered I/O!
and the next fsync() on the image fails with -EIO. Every write the VM
issues is O_DIRECT, the buffered writes come from btrfs itself.
Both patches close the same race: a direct write dirties a folio while
another task's direct write to a different block of that folio is in
flight, and the completion of the latter fails to invalidate it.
Patch 1 waits before the buffered fallback for unaligned writes. Patch 2
waits before btrfs_write_check() zeroes the block at an unaligned EOF,
which btrfs_direct_write() does before it decides to fall back.
Tested on a 64K page arm64 kernel, on a NOCOW file of a 4K block btrfs.
Async 4K O_DIRECT writes race 512 byte O_DIRECT writes inside EOF
(fallback), and O_DIRECT writes past an unaligned EOF, of 4K (eof-dio)
and of 512 bytes, which fall back (eof-fb). fdatasync() EIOs in 20
seconds per test:
base patch 1 patch 1+2
fallback 6 0 0
eof-dio 24 20 0
eof-fb 34 14 0
60 second runs got 56 and 38 EIOs in the eof tests with patch 1, and
none in any test with both patches, in two runs. The reproducer for
patch 1 is at [1].
[1] https://github.com/leitao/btrfs-dio-fallback
Signed-off-by: Breno Leitao <leitao@xxxxxxxxxx>
---
Changes in v2:
- New patch 2: drain in-flight direct IO before btrfs_write_check()
zeroes the block at an unaligned EOF (Qu, from a Sashiko review).
- Patch 1: no code change. Picked up Boris' Reviewed-by, and added a
stable Cc.
- Both patches: the Fixes: tags now name 95ea0486b20e, which first
allowed writes with more than one block per folio, 4K blocks on 64K
pages.
- Link to v1: https://lore.kernel.org/all/auxv7Tg0xSq5yHmb@xxxxxxxxx/
---
Breno Leitao (2):
btrfs: drain in-flight direct IO before buffered write fallback
btrfs: drain in-flight direct IO before zeroing an unaligned EOF block
fs/btrfs/file.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
---
base-commit: ddfe51b0a0f5dc9e415cc2c8ad8db17532dd426b
base-tree: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
change-id: 20261106-btrfs_page_cache-2ab11049c913
Best regards,
--
Breno Leitao <leitao@xxxxxxxxxx>