From 1fc6a13662d36cae8cb212a51e43666216a17e7e Mon Sep 17 00:00:00 2001 From: Shreyansh Sancheti Date: Tue, 21 Jul 2026 14:19:56 +0530 Subject: [PATCH] fix(lcow/v2): report physically backed VM stats Signed-off-by: Shreyansh Sancheti --- internal/controller/vm/save_lcow.go | 4 +- internal/controller/vm/vm.go | 16 ++++---- internal/controller/vm/vm_lcow.go | 10 ++++- internal/controller/vm/vm_lcow_test.go | 53 ++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 13 deletions(-) create mode 100644 internal/controller/vm/vm_lcow_test.go diff --git a/internal/controller/vm/save_lcow.go b/internal/controller/vm/save_lcow.go index 29f330c74a..46243967a8 100644 --- a/internal/controller/vm/save_lcow.go +++ b/internal/controller/vm/save_lcow.go @@ -138,9 +138,6 @@ func (c *Controller) Import(ctx context.Context, env *anypb.Any) error { // the controller migrating so only migration APIs are permitted. c.vmID = state.GetVmID() c.sandboxOptions = sandboxOptionsFromProto(state.GetSandboxOptions()) - if c.sandboxOptions != nil { - c.isPhysicallyBacked = c.sandboxOptions.FullyPhysicallyBacked - } c.nextGuestPort = state.GetGcsNextPort() c.nextBridgeID = state.GetBridgeNextID() c.compatInfo = state.GetCompatInfo() @@ -155,6 +152,7 @@ func (c *Controller) Import(ctx context.Context, env *anypb.Any) error { } c.hcsDocument = doc + c.isPhysicallyBacked = isMemoryPhysicallyBacked(doc) } // Import the SCSI sub-controller. 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 diff --git a/internal/controller/vm/vm_lcow.go b/internal/controller/vm/vm_lcow.go index 3c548df04c..720b3c4170 100644 --- a/internal/controller/vm/vm_lcow.go +++ b/internal/controller/vm/vm_lcow.go @@ -56,11 +56,19 @@ func (c *Controller) buildHCSConfig(ctx context.Context, opts *CreateOptions) (* } c.sandboxOptions = sandboxOptions - c.isPhysicallyBacked = sandboxOptions.FullyPhysicallyBacked + c.isPhysicallyBacked = isMemoryPhysicallyBacked(hcsDocument) return hcsDocument, nil } +func isMemoryPhysicallyBacked(doc *hcsschema.ComputeSystem) bool { + return doc != nil && + doc.VirtualMachine != nil && + doc.VirtualMachine.ComputeTopology != nil && + doc.VirtualMachine.ComputeTopology.Memory != nil && + !doc.VirtualMachine.ComputeTopology.Memory.AllowOvercommit +} + // buildConfidentialOptions builds confidential options from the stored sandbox options. func (c *Controller) buildConfidentialOptions(ctx context.Context) (*guestresource.ConfidentialOptions, error) { if c.sandboxOptions == nil || c.sandboxOptions.ConfidentialConfig == nil { diff --git a/internal/controller/vm/vm_lcow_test.go b/internal/controller/vm/vm_lcow_test.go new file mode 100644 index 0000000000..9c97f63c33 --- /dev/null +++ b/internal/controller/vm/vm_lcow_test.go @@ -0,0 +1,53 @@ +//go:build windows && lcow + +package vm + +import ( + "testing" + + hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" +) + +func TestIsMemoryPhysicallyBacked(t *testing.T) { + tests := []struct { + name string + doc *hcsschema.ComputeSystem + want bool + }{ + { + name: "missing memory topology", + doc: &hcsschema.ComputeSystem{}, + }, + { + name: "overcommitted memory", + doc: computeSystemWithMemory(&hcsschema.VirtualMachineMemory{ + AllowOvercommit: true, + }), + }, + { + name: "non-overcommitted memory", + doc: computeSystemWithMemory(&hcsschema.VirtualMachineMemory{ + AllowOvercommit: false, + }), + want: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := isMemoryPhysicallyBacked(test.doc); got != test.want { + t.Fatalf("isMemoryPhysicallyBacked() = %t, want %t", got, test.want) + } + }) + } +} + +func computeSystemWithMemory(memory *hcsschema.VirtualMachineMemory) *hcsschema.ComputeSystem { + return &hcsschema.ComputeSystem{ + VirtualMachine: &hcsschema.VirtualMachine{ + ComputeTopology: &hcsschema.Topology{ + Memory: memory, + }, + }, + } +}