From 2f4911566e9701c4f207864ebc564471812439e2 Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Wed, 15 Jan 2020 12:01:28 +0100 Subject: [PATCH] agent: Fix mem-hotplug on x86 when ARCH_MEMORY_PROBE is set Don't use the /sys/devices/system/memory/probe interface on architectures where the firmware (ACPI) is notifying the system of hotplugged memory. This fixes an issue with the agent erroring out when the guest-kernel is compiled with CONFIG_ARCH_MEMORY_PROBE=y. Fixes: #712 Signed-off-by: Ralf Haferkamp --- grpc.go | 19 ++++++++++++++++++- grpc_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/grpc.go b/grpc.go index ea0d7afa9..4c0dea39e 100644 --- a/grpc.go +++ b/grpc.go @@ -54,6 +54,7 @@ var ( sysfsMemOnlinePath = "/sys/devices/system/memory" sysfsMemoryBlockSizePath = "/sys/devices/system/memory/block_size_bytes" sysfsMemoryHotplugProbePath = "/sys/devices/system/memory/probe" + sysfsAcpiMemoryHotplugPath = "/sys/firmware/acpi/hotplug/memory/enabled" sysfsConnectedCPUsPath = filepath.Join(sysfsCPUOnlinePath, "online") containersRootfsPath = "/run" @@ -1576,6 +1577,16 @@ func (a *agentGRPC) ReseedRandomDev(ctx context.Context, req *pb.ReseedRandomDev return emptyResp, reseedRNG(req.Data) } +func (a *agentGRPC) haveAcpiMemoryHotplug() bool { + enabled, err := ioutil.ReadFile(sysfsAcpiMemoryHotplugPath) + if err != nil { + return false + } else if strings.TrimSpace(string(enabled)) == "1" { + return true + } + return false +} + func (a *agentGRPC) GetGuestDetails(ctx context.Context, req *pb.GuestDetailsRequest) (*pb.GuestDetailsResponse, error) { var details pb.GuestDetailsResponse if req.MemBlockSize { @@ -1603,7 +1614,13 @@ func (a *agentGRPC) GetGuestDetails(ctx context.Context, req *pb.GuestDetailsReq } else if err != nil { return nil, err } else { - details.SupportMemHotplugProbe = true + // Avoid triggering memory hotplugging notifications when ACPI + // hotplugging is enabled + if a.haveAcpiMemoryHotplug() { + details.SupportMemHotplugProbe = false + } else { + details.SupportMemHotplugProbe = true + } } } diff --git a/grpc_test.go b/grpc_test.go index 768cd1959..4bddb0535 100644 --- a/grpc_test.go +++ b/grpc_test.go @@ -843,12 +843,38 @@ func TestGetGuestDetails(t *testing.T) { probeFile, err := ioutil.TempFile("", "probe") assert.NoError(err) + // sysfsAcpiMemoryHotplugPath exist and is 1 + hotplugEnabledFile, err := ioutil.TempFile("", "enabled") + assert.NoError(err) + _, err = hotplugEnabledFile.WriteString("1") + assert.NoError(err) + hotplugEnabledFile.Sync() + oldSysfsMemoryHotplugProbePath := sysfsMemoryHotplugProbePath + oldSysfsAcpiMemoryHotplugPath := sysfsAcpiMemoryHotplugPath defer func() { sysfsMemoryHotplugProbePath = oldSysfsMemoryHotplugProbePath + sysfsAcpiMemoryHotplugPath = oldSysfsAcpiMemoryHotplugPath }() sysfsMemoryHotplugProbePath = probeFile.Name() + sysfsAcpiMemoryHotplugPath = hotplugEnabledFile.Name() + resp, err = a.GetGuestDetails(context.TODO(), req) + assert.NoError(err) + assert.Equal(resp.SupportMemHotplugProbe, false) + + // sysfsAcpiMemoryHotplugPath exist and is 0 + _, err = hotplugEnabledFile.Seek(0, 0) + assert.NoError(err) + _, err = hotplugEnabledFile.WriteString("0") + assert.NoError(err) + hotplugEnabledFile.Sync() + resp, err = a.GetGuestDetails(context.TODO(), req) + assert.NoError(err) + assert.Equal(resp.SupportMemHotplugProbe, true) + + // sysfsAcpiMemoryHotplugPath does not exist + os.Remove(sysfsAcpiMemoryHotplugPath) resp, err = a.GetGuestDetails(context.TODO(), req) assert.NoError(err) assert.Equal(resp.SupportMemHotplugProbe, true)