Oh, wait, let's roll back! The case I'm interested in involves native booting of Windows Server 2022 from a VHDX instead of a partition!
Ah, native boot VHDX—that's a completely different beast and your frustration makes even MORE sense now. This is Windows Server 2022 booting directly from a VHDX file sitting on an NTFS partition, with no hypervisor involved at runtime. The bootloader (
bootmgr) uses a minihypervisor just to mount the VHDX, then the native kernel takes over.So your scenario is:
plain
复制
Physical Disk (C:)
└── \Boot\ (boot files)
└── \Server2022.vhdx (dynamic, say 100GB max, currently 30GB allocated)
└── Inside: Windows Server 2022 sees "100GB disk, 60GB free"
Host reality: C: drive only has 15GB free
Maximum possible growth: 30GB + 15GB = 45GBWhy This Is PARTICULARLY Stupid
In native boot, there is no hypervisor running to manage this. The VHDX driver is inside the Windows kernel itself (
vhdmp.sys). It could absolutely:- Query the host volume's free space before reporting virtual disk geometry
- Cap the reported size at
(current allocation + host free space) - Update this dynamically as the host volume changes
But it doesn't. It reports the static maximum size defined in the VHDX header, regardless of reality.
The Technical Excuse Falls Apart
| Hyper-V VM | Native Boot |
|---|---|
| Guest OS isolated by design | Same kernel! Same I/O stack! |
| No standard protocol for capacity query | Could use internal Windows APIs directly |
| Hypervisor manages multiple guests | Single system, single storage stack |
| "Someone else's problem" | YOUR problem, immediately |
In native boot, the VHDX driver and the host filesystem driver are literally in the same kernel. They could talk to each other. They don't.
What Actually Happens When You Run Out
plain
复制
Server 2022 tries to write to VHDX
↓
VHDX driver tries to expand file on C:
↓
NTFS returns STATUS_DISK_FULL
↓
VHDX driver returns I/O error to itself (same kernel!)
↓
Server 2022 bluescreens or corrupts dataIt's self-deception at the kernel level. The left hand genuinely doesn't know what the right hand is doing, despite being the same hand.
Why Microsoft Didn't Fix This
- VHDX native boot is a niche feature — Primarily used for:
- Dual-boot scenarios without repartitioning
- Easy deployment/rollback (replace VHDX file)
- Hyper-V "shielded VMs" preparation
Not enterprise-critical enough to invest in kernel changes. - Consistency with Hyper-V behavior — They wanted VHDX to behave identically whether virtual or native boot. "Principle of least surprise" (for admins, not for data integrity).
- The "use fixed-size VHDX" workaround — Microsoft's actual answer. If you care about reliability, pre-allocate.
What You CAN Do (Workarounds)
| Approach | How | Trade-off |
|---|---|---|
| Fixed VHDX | Convert-VHD -VHDType Fixed | Loses thin-provisioning benefit |
| Monitor aggressively | Script checking C: free space + VHDX current size | Reactive, not preventive |
| Separate partition | Put VHDX on dedicated volume | Easier to monitor, but still lies to guest |
| Storage Spaces | Use thin-provisioned storage pool with hard quotas | Overkill for single server |
The Real Fix (That Doesn't Exist)
What should happen is a dynamic capacity reporting option in
bcdedit or VHDX metadata:powershell
复制
# This doesn't exist
bcdedit /set {current} vhdx.dynamic-capacity-reporting true
# Result: Windows reports min(configured_max, current_size + host_free)Or even a VHDX format extension with a "host-aware" flag that the native boot driver understands.
Bottom Line
Native boot VHDX takes an already-broken thin-provisioning model and makes it worse by removing the hypervisor layer that could at least theoretically manage the deception. You're left with a single Windows instance lying to itself about its own storage, with no external referee. It's not even "distributed systems are hard"—it's local kernel coordination that was never implemented.
Your anger is 100% justified. This is technical debt from treating VHDX as "just a file" rather than "a volume with host-dependent capacity."