disk_vhdmp: use overlapped scatter/gather IO instead of FileDisk#3327
disk_vhdmp: use overlapped scatter/gather IO instead of FileDisk#3327jstarks wants to merge 3 commits intomicrosoft:mainfrom
Conversation
The previous VhdmpDisk implementation wrapped the VHDMP handle in a FileDisk and serialized all IOs through a futures::Mutex. This meant that even though the underlying handle supported overlapped IO, every read, write, and flush had to wait for the previous one to complete. Replace FileDisk with direct use of OverlappedFile, issuing reads and writes via ReadFileScatter/WriteFileGather when guest buffers are page-aligned, and falling back to a bounce buffer for unaligned requests. This removes the serialization bottleneck and allows true concurrent IO. To support this, add read_scatter_at and write_gather_at methods to pal_async's OverlappedFile, wrapping the Win32 scatter/gather APIs. Flush is dispatched to the system thread pool (TpPool) because NtFlushBuffersFileEx always blocks synchronously even on async handles. This replaces the previous blocking crate dependency. The petri Hyper-V backend is updated to pass a Driver (via TpPool::system()) when constructing VhdmpDisk, and no longer needs the disk_file crate.
|
This PR modifies files containing For more on why we check whole files, instead of just diffs, check out the Rustonomicon |
There was a problem hiding this comment.
Pull request overview
This PR removes the FileDisk-based VHDMP implementation that serialized all IO behind a mutex and replaces it with true concurrent Windows overlapped IO, using scatter/gather APIs when guest buffers are page-aligned.
Changes:
- Switch
disk_vhdmpread/write paths topal_async::windows::overlapped::OverlappedFile, usingReadFileScatter/WriteFileGatherfor aligned buffers and a fallback path for unaligned buffers. - Extend
pal_async’sOverlappedFilewithread_scatter_at/write_gather_atwrappers for Win32 scatter/gather. - Update the Petri Hyper-V backend to pass a Windows threadpool-based driver when constructing
VhdmpDisk, and remove now-unused deps.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| vm/devices/storage/disk_vhdmp/src/lib.rs | Replace FileDisk + mutex with overlapped scatter/gather IO, add flush via TpPool, update tests to use a driver. |
| vm/devices/storage/disk_vhdmp/Cargo.toml | Drop disk_file/futures, move guestmem + pal_async into main Windows deps. |
| support/pal/pal_async/src/windows/overlapped.rs | Add scatter/gather IO primitives and re-export FILE_SEGMENT_ELEMENT. |
| petri/src/vm/hyperv/mod.rs | Construct VhdmpDisk with a TpPool::system() driver. |
| Cargo.lock | Reflect dependency removals for disk_vhdmp. |
| ) -> Self { | ||
| let segments_ptr = segments.as_ptr(); | ||
| Self::issue(file, offset, (), |handle, _, overlapped| { | ||
| // SAFETY: caller of read_scatter_at ensures segments are valid. |
There was a problem hiding this comment.
maybe a dumb question, but how can this fn be safe if we have caller preconditions? is it because only things within this file can construct an Io struct?
| }; | ||
| let vhd = FileDisk::with_metadata(vhd.0, metadata); | ||
| let physical_sector_size = vhd.get_physical_sector_size().map_err(Error::Query)?; | ||
| // SAFETY: VHDMP handles are opened with FILE_FLAG_OVERLAPPED. |
There was a problem hiding this comment.
the caller does this? if it's not, we just fail?
The previous VhdmpDisk implementation wrapped the VHDMP handle in a FileDisk and serialized all IOs through a futures::Mutex. This meant that even though the underlying handle supported overlapped IO, every read, write, and flush had to wait for the previous one to complete.
Replace FileDisk with direct use of OverlappedFile, issuing reads and writes via ReadFileScatter/WriteFileGather when guest buffers are page-aligned, and falling back to a bounce buffer for unaligned requests. This removes the serialization bottleneck and allows true concurrent IO.
To support this, add read_scatter_at and write_gather_at methods to pal_async's OverlappedFile, wrapping the Win32 scatter/gather APIs.
Flush is dispatched to the system thread pool (TpPool) because NtFlushBuffersFileEx always blocks synchronously even on async handles. This replaces the previous blocking crate dependency.
The petri Hyper-V backend is updated to pass a Driver (via TpPool::system()) when constructing VhdmpDisk, and no longer needs the disk_file crate.