block: qcow: Fix O_DIRECT EINVAL in async io_uring read path - #8051
Merged
rbradford merged 7 commits intoApr 17, 2026
Merged
Conversation
weltling
force-pushed
the
qcow-odirect-async-alignment
branch
from
April 17, 2026 06:54
5a5a253 to
08d551a
Compare
rbradford
approved these changes
Apr 17, 2026
| "truncate failed" | ||
| ); | ||
|
|
||
| let loop_dev = exec_host_command_output(&format!( |
Member
There was a problem hiding this comment.
Claude tells me there is a create_loop_device function that does this using ioctls rather than needing to shell out. Maybe you could use that (and change the existing use too.)
Member
Author
There was a problem hiding this comment.
Yep. Switched to create_loop_device now and fixed the other test. I was considering it but the other use is what actually misled me.
Thanks
Boot a UEFI guest from a QCOW2 image with direct=on to exercise the aligned I/O write path during early firmware operations. Signed-off-by: Anatol Belski <[email protected]>
Verify that QcowAsync reports the default SECTOR_SIZE alignment when O_DIRECT is not active. Signed-off-by: Anatol Belski <[email protected]>
Verify that QcowAsync reports at least SECTOR_SIZE alignment when O_DIRECT is active. Skipped on filesystems that do not support O_DIRECT (e.g. tmpfs). Signed-off-by: Anatol Belski <[email protected]>
Verify that a 512 byte read from an allocated cluster succeeds with O_DIRECT. This exercises the synchronous fallback path in resolve_read() that is taken when alignment is nonzero. Signed-off-by: Anatol Belski <[email protected]>
Write 128K of patterned data and read it back with O_DIRECT active to verify the aligned I/O paths produce correct results. Signed-off-by: Anatol Belski <[email protected]>
Override AsyncIo::alignment() to report the actual device sector size so that execute_async() correctly bounces misaligned guest memory pointers. Guard the io_uring fast path in resolve_read() with an alignment check. When O_DIRECT is active, guest requests can have I/O sizes smaller than the device sector size (e.g. 512 byte UEFI reads on a 4096 byte sector device). The kernel rejects these with EINVAL. Route such reads through scatter_read_sync() which uses AlignedBuf and aligned_pread to satisfy O_DIRECT size and offset requirements. Signed-off-by: Anatol Belski <[email protected]>
Use the ioctl based create_loop_device() helper instead of shelling out to losetup in the file backed 4K alignment test. Signed-off-by: Anatol Belski <[email protected]>
weltling
force-pushed
the
qcow-odirect-async-alignment
branch
from
April 17, 2026 07:29
08d551a to
250cd64
Compare
rbradford
approved these changes
Apr 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes
EINVALerrors when booting UEFI guests from QCOW2 images withdirect=onon devices where O_DIRECT requires alignment larger than 512 bytes.QcowAsync::resolve_read()has a fast path that submits guest iovecs directly to io_uring. When O_DIRECT is active on a device with 4096 byte sectors, guest reads smaller than the sector size (for example, 512 byte UEFI firmware reads) are rejected by the kernel because the I/O length is not a multiple of the required alignment.The
AsyncIo::alignment()trait method was also not overridden, soexecute_async()in the virtio block layer used the default 512, which is not enough to correctly bounce misaligned guest memory pointers on 4K sector devices.Fix:
AsyncIo::alignment()onQcowAsyncto report the actual device alignment (max(file_alignment, SECTOR_SIZE)), so thatexecute_async()correctly handles pointer alignment.resolve_read()with an alignment check. When O_DIRECT is active, reads are routed throughscatter_read_sync()which usesAlignedBufandaligned_preadto satisfy all three O_DIRECT constraints (buffer address, offset, and length alignment).Tests:
direct=onRef #8007.
See #8050 for a broader discussion on centralizing alignment handling across all block backends.