From e3303f0dbd237934b21845a585de9f9e799cc351 Mon Sep 17 00:00:00 2001 From: Shreyansh Sancheti Date: Tue, 21 Jul 2026 14:19:56 +0530 Subject: [PATCH 1/2] fix(lcow/v2): gate vmmem lookup to VA-backed UVMs Signed-off-by: Shreyansh Sancheti --- internal/controller/vm/vm.go | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/internal/controller/vm/vm.go b/internal/controller/vm/vm.go index 4dd2cedf85..cd3f921ab4 100644 --- a/internal/controller/vm/vm.go +++ b/internal/controller/vm/vm.go @@ -530,15 +530,6 @@ func (c *Controller) Stats(ctx context.Context) (*stats.VirtualMachineStatistics return nil, fmt.Errorf("cannot get stats: VM is in incorrect state %s", c.vmState) } - // Initialization of vmmemProcess to calculate stats properly for VA-backed UVMs. - if c.vmmemProcess == 0 { - vmmemHandle, err := vmutils.LookupVMMEM(ctx, c.uvm.RuntimeID(), &iwin.WinAPI{}) - if err != nil { - return nil, fmt.Errorf("cannot get stats: %w", err) - } - c.vmmemProcess = vmmemHandle - } - s := &stats.VirtualMachineStatistics{} props, err := c.uvm.PropertiesV2(ctx, hcsschema.PTStatistics, hcsschema.PTMemory) if err != nil { @@ -553,6 +544,13 @@ func (c *Controller) Stats(ctx context.Context) (*stats.VirtualMachineStatistics // working set size for a VA-backed UVM. To work around this, we instead // locate the vmmem process for the VM, and query that process's working set // instead, which will be the working set for the VM. + if c.vmmemProcess == 0 { + vmmemHandle, err := vmutils.LookupVMMEM(ctx, c.uvm.RuntimeID(), &iwin.WinAPI{}) + if err != nil { + return nil, fmt.Errorf("cannot get stats: %w", err) + } + c.vmmemProcess = vmmemHandle + } memCounters, err := process.GetProcessMemoryInfo(c.vmmemProcess) if err != nil { return nil, err From e3e4cfb6d9d81644bd1c97ee2304dcfb6ac6278e Mon Sep 17 00:00:00 2001 From: Harsh Rawat Date: Wed, 22 Jul 2026 03:32:16 +0530 Subject: [PATCH 2/2] [lcowV2 specs] derive FullyPhysicallyBacked from memory backing In the v2 LCOW builder, SandboxOptions.FullyPhysicallyBacked was taken straight from the FullyPhysicallyBacked annotation. It feeds isPhysicallyBacked, which only drives VM memory/working-set stats, so setting AllowOvercommit=false alone left it false and a physically backed VM had its stats computed as if VA-backed. Set it to !AllowOvercommit so it reflects the VM's actual memory backing; the annotation still forces overcommit off. v2 has no VSMB/VPMem, so there is no separate devices-physically-backed notion. Also update the parity check to compare against !AllowOvercommit and add a regression test for overcommit-off alone. Signed-off-by: Harsh Rawat --- internal/builder/vm/lcow/sandbox_options.go | 5 ++++- internal/builder/vm/lcow/specs.go | 12 ++++++++--- internal/builder/vm/lcow/specs_test.go | 23 +++++++++++++++++++++ test/parity/vm/lcow_doc_test.go | 2 +- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/internal/builder/vm/lcow/sandbox_options.go b/internal/builder/vm/lcow/sandbox_options.go index 37c978a170..686ba6da9b 100644 --- a/internal/builder/vm/lcow/sandbox_options.go +++ b/internal/builder/vm/lcow/sandbox_options.go @@ -19,7 +19,10 @@ type SandboxOptions struct { // Architecture is the processor architecture (e.g., "amd64", "arm64"). Architecture string - // FullyPhysicallyBacked indicates all memory allocations are backed by physical memory. + // FullyPhysicallyBacked reports whether the VM's own memory is physically + // backed (equal to !AllowOvercommit). It does not cover additional devices + // added to the running VM (e.g. file shares or mounted layer disks), whose + // physical backing is determined directly by the FullyPhysicallyBacked annotation. FullyPhysicallyBacked bool // ConfidentialConfig carries confidential computing fields that are not diff --git a/internal/builder/vm/lcow/specs.go b/internal/builder/vm/lcow/specs.go index 18074e3bc4..55df766104 100644 --- a/internal/builder/vm/lcow/specs.go +++ b/internal/builder/vm/lcow/specs.go @@ -72,6 +72,9 @@ func BuildSandboxConfig( // When no-security-hardware is set, we still plumb the policy but use the standard HCS doc. isConfidentialSNP := sandboxOptions.ConfidentialConfig != nil && !noSecurityHardware + // The FullyPhysicallyBacked annotation forces memory overcommit off. + fullyPhysicallyBacked := oci.ParseAnnotationsBool(ctx, spec.Annotations, shimannotations.FullyPhysicallyBacked, false) + // ================== Parse Topology (CPU, Memory, NUMA) options ================= // =============================================================================== @@ -88,7 +91,7 @@ func BuildSandboxConfig( } // Parse memory configuration. - memoryConfig, err := parseMemoryOptions(ctx, opts, spec.Annotations, sandboxOptions.FullyPhysicallyBacked) + memoryConfig, err := parseMemoryOptions(ctx, opts, spec.Annotations, fullyPhysicallyBacked) if err != nil { return nil, nil, fmt.Errorf("failed to parse memory parameters: %w", err) } @@ -149,7 +152,7 @@ func BuildSandboxConfig( spec.Devices, rootFsFullPath, numa != nil && numaProcessors != nil, // isNumaEnabled - sandboxOptions.FullyPhysicallyBacked, // isFullyPhysicallyBacked + fullyPhysicallyBacked, // isFullyPhysicallyBacked isConfidentialSNP, // isConfidential ) if err != nil { @@ -207,6 +210,10 @@ func BuildSandboxConfig( memoryConfig.AllowOvercommit = false } + // Record whether the VM's own memory is physically backed (!AllowOvercommit). + // This is VM memory backing only, not additional-device backing. + sandboxOptions.FullyPhysicallyBacked = !memoryConfig.AllowOvercommit + // ================== Parse and set Kernel Args ================================== // =============================================================================== @@ -332,7 +339,6 @@ func parseSandboxOptions(ctx context.Context, platform string, annotations map[s sandboxOptions := &SandboxOptions{ // Extract architecture from platform string (e.g., "linux/amd64" -> "amd64") Architecture: platform[strings.IndexByte(platform, '/')+1:], - FullyPhysicallyBacked: oci.ParseAnnotationsBool(ctx, annotations, shimannotations.FullyPhysicallyBacked, false), PolicyBasedRouting: oci.ParseAnnotationsBool(ctx, annotations, iannotations.NetworkingPolicyBasedRouting, false), NoWritableFileShares: oci.ParseAnnotationsBool(ctx, annotations, shimannotations.DisableWritableFileShares, false), LiveMigrationSupportEnabled: oci.ParseAnnotationsBool(ctx, annotations, shimannotations.LiveMigrationSupportEnabled, false), diff --git a/internal/builder/vm/lcow/specs_test.go b/internal/builder/vm/lcow/specs_test.go index ac7d0b5842..088606228c 100644 --- a/internal/builder/vm/lcow/specs_test.go +++ b/internal/builder/vm/lcow/specs_test.go @@ -267,6 +267,29 @@ func TestBuildSandboxConfig(t *testing.T) { } }, }, + { + // FullyPhysicallyBacked tracks the VM's memory backing (!AllowOvercommit), + // so disabling overcommit alone (without the annotation) marks it true. + name: "overcommit off alone marks VM physically backed", + opts: &runhcsoptions.Options{ + SandboxPlatform: "linux/amd64", + BootFilesRootPath: validBootFilesPath, + }, + spec: &vm.Spec{ + Annotations: map[string]string{ + shimannotations.AllowOvercommit: "false", + }, + }, + validate: func(t *testing.T, doc *hcsschema.ComputeSystem, sandboxOpts *SandboxOptions) { + t.Helper() + if doc.VirtualMachine.ComputeTopology.Memory.AllowOvercommit != false { + t.Errorf("expected allow overcommit false, got %v", doc.VirtualMachine.ComputeTopology.Memory.AllowOvercommit) + } + if sandboxOpts.FullyPhysicallyBacked != true { + t.Errorf("expected fully physically backed true when overcommit off, got %v", sandboxOpts.FullyPhysicallyBacked) + } + }, + }, { name: "memory MMIO configuration", opts: &runhcsoptions.Options{ diff --git a/test/parity/vm/lcow_doc_test.go b/test/parity/vm/lcow_doc_test.go index f14ad2928b..e49302282b 100644 --- a/test/parity/vm/lcow_doc_test.go +++ b/test/parity/vm/lcow_doc_test.go @@ -204,7 +204,7 @@ func checkSandboxOptionsParity(t *testing.T, legacyOpts *uvm.OptionsLCOW, sandbo {"NoWritableFileShares", legacyOpts.NoWritableFileShares, sandboxOpts.NoWritableFileShares}, {"EnableScratchEncryption", legacyOpts.EnableScratchEncryption, sandboxOpts.EnableScratchEncryption}, {"PolicyBasedRouting", legacyOpts.PolicyBasedRouting, sandboxOpts.PolicyBasedRouting}, - {"FullyPhysicallyBacked", legacyOpts.FullyPhysicallyBacked, sandboxOpts.FullyPhysicallyBacked}, + {"PhysicallyBacked", !legacyOpts.AllowOvercommit, sandboxOpts.FullyPhysicallyBacked}, } for _, c := range checks {