Skip to content

disk_vhdmp: use overlapped scatter/gather IO instead of FileDisk#3327

Open
jstarks wants to merge 3 commits intomicrosoft:mainfrom
jstarks:fast_vhdmp
Open

disk_vhdmp: use overlapped scatter/gather IO instead of FileDisk#3327
jstarks wants to merge 3 commits intomicrosoft:mainfrom
jstarks:fast_vhdmp

Conversation

@jstarks
Copy link
Copy Markdown
Member

@jstarks jstarks commented Apr 20, 2026

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.

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.
Copilot AI review requested due to automatic review settings April 20, 2026 06:13
@github-actions
Copy link
Copy Markdown

⚠️ Unsafe Code Detected

This PR modifies files containing unsafe Rust code. Extra scrutiny is required during review.

For more on why we check whole files, instead of just diffs, check out the Rustonomicon

@github-actions github-actions Bot added the unsafe Related to unsafe code label Apr 20, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_vhdmp read/write paths to pal_async::windows::overlapped::OverlappedFile, using ReadFileScatter / WriteFileGather for aligned buffers and a fallback path for unaligned buffers.
  • Extend pal_async’s OverlappedFile with read_scatter_at / write_gather_at wrappers 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.

Comment thread vm/devices/storage/disk_vhdmp/src/lib.rs Outdated
Comment thread vm/devices/storage/disk_vhdmp/src/lib.rs Outdated
Comment thread vm/devices/storage/disk_vhdmp/src/lib.rs
Comment thread vm/devices/storage/disk_vhdmp/src/lib.rs
@jstarks jstarks marked this pull request as ready for review April 20, 2026 16:00
@jstarks jstarks requested a review from a team as a code owner April 20, 2026 16:00
Copilot AI review requested due to automatic review settings April 20, 2026 16:00
@jstarks jstarks requested a review from a team as a code owner April 20, 2026 16:00
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 4 comments.

Comment thread vm/devices/storage/disk_vhdmp/src/lib.rs
Comment thread vm/devices/storage/disk_vhdmp/src/lib.rs
Comment thread vm/devices/storage/disk_vhdmp/src/lib.rs
Comment thread vm/devices/storage/disk_vhdmp/src/lib.rs
) -> Self {
let segments_ptr = segments.as_ptr();
Self::issue(file, offset, (), |handle, _, overlapped| {
// SAFETY: caller of read_scatter_at ensures segments are valid.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the caller does this? if it's not, we just fail?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

unsafe Related to unsafe code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants