Skip to content

Commit 7bf9cdf

Browse files
author
gitlab
committed
Merge branch 'fix/5.5.12/ZSTAC-76375@@3' into '5.5.12'
fix(kvm): disable PMU on aarch64 for Kunpeng-920 panic See merge request zstackio/zstack!9508
2 parents d2941ba + 61174c8 commit 7bf9cdf

4 files changed

Lines changed: 217 additions & 0 deletions

File tree

compute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ public class VmGlobalConfig {
5252
@GlobalConfigValidation(validValues = {"true", "false"})
5353
@BindResourceConfig(value = {VmInstanceVO.class})
5454
public static GlobalConfig VM_PORT_OFF = new GlobalConfig(CATEGORY, "vmPortOff");
55+
@GlobalConfigDef(defaultValue = "false", type = Boolean.class, description = "enable PMU for VM, disabled by default on aarch64 to avoid Kunpeng-920 kernel panic")
56+
@GlobalConfigValidation(validValues = {"true", "false"})
57+
@BindResourceConfig(value = {VmInstanceVO.class, ClusterVO.class})
58+
public static GlobalConfig VM_PMU = new GlobalConfig(CATEGORY, "vm.pmu");
5559
@GlobalConfigValidation(validValues = {"true", "false"})
5660
@BindResourceConfig(value = {VmInstanceVO.class, ClusterVO.class})
5761
public static GlobalConfig EMULATE_HYPERV = new GlobalConfig(CATEGORY, "emulateHyperV");

plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2312,6 +2312,8 @@ public static class StartVmCmd extends vdiCmd implements VmAddOnsCmd {
23122312
private boolean consoleLogToFile;
23132313
@GrayVersion(value = "5.0.0")
23142314
private boolean acpi;
2315+
@GrayVersion(value = "5.5.12")
2316+
private boolean pmu = true;
23152317
@GrayVersion(value = "5.0.0")
23162318
private boolean x2apic = true;
23172319
// cpuid hypervisor feature
@@ -2835,6 +2837,14 @@ public void setAcpi(boolean acpi) {
28352837
this.acpi = acpi;
28362838
}
28372839

2840+
public boolean isPmu() {
2841+
return pmu;
2842+
}
2843+
2844+
public void setPmu(boolean pmu) {
2845+
this.pmu = pmu;
2846+
}
2847+
28382848
public boolean getX2apic() {
28392849
return x2apic;
28402850
}

plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import org.zstack.header.message.MessageReply;
6767
import org.zstack.header.message.NeedReplyMessage;
6868
import org.zstack.header.network.l2.*;
69+
import org.zstack.header.os.OSArchitecture;
6970
import org.zstack.header.network.l3.L3NetworkInventory;
7071
import org.zstack.header.network.l3.L3NetworkVO;
7172
import org.zstack.header.rest.JsonAsyncRESTCallback;
@@ -4573,6 +4574,14 @@ protected void startVm(final VmInstanceSpec spec, final NeedReplyMessage msg, fi
45734574
cmd.setCreatePaused(true);
45744575
}
45754576
cmd.setAcpi(true);
4577+
// aarch64: disable PMU by default to avoid kernel panic on new Kunpeng-920 (7270Z/5230Z)
4578+
// where PMMIR_EL1 register is not supported by KVM. See ZSTAC-76375
4579+
// GlobalConfig vm.pmu defaults to false; users can re-enable via ResourceConfig.
4580+
if (OSArchitecture.AARCH64.normalizedArchName().equals(architecture)) {
4581+
Boolean pmuEnabled = rcf.getResourceConfigValue(
4582+
VmGlobalConfig.VM_PMU, spec.getVmInventory().getUuid(), Boolean.class);
4583+
cmd.setPmu(Boolean.TRUE.equals(pmuEnabled));
4584+
}
45764585

45774586
GuestOsCharacter.Config config = GuestOsHelper.getInstance().getGuestOsCharacter(
45784587
spec.getVmInventory().getArchitecture(),
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package org.zstack.test.integration.kvm.vm
2+
3+
import org.springframework.http.HttpEntity
4+
import org.zstack.compute.vm.VmGlobalConfig
5+
import org.zstack.kvm.KVMAgentCommands
6+
import org.zstack.kvm.KVMConstant
7+
import org.zstack.sdk.GlobalConfigInventory
8+
import org.zstack.sdk.VmInstanceInventory
9+
import org.zstack.test.integration.kvm.KvmTest
10+
import org.zstack.testlib.EnvSpec
11+
import org.zstack.testlib.SubCase
12+
import org.zstack.utils.data.SizeUnit
13+
import org.zstack.utils.gson.JSONObjectUtil
14+
15+
/**
16+
* Test VM PMU configuration.
17+
* See ZSTAC-76375: Kunpeng-920 7270Z kernel panic due to PMMIR_EL1.
18+
*/
19+
class VmPmuConfigCase extends SubCase {
20+
EnvSpec env
21+
22+
@Override
23+
void clean() {
24+
env.delete()
25+
}
26+
27+
@Override
28+
void setup() {
29+
useSpring(KvmTest.springSpec)
30+
}
31+
32+
@Override
33+
void environment() {
34+
env = env {
35+
instanceOffering {
36+
name = "instanceOffering"
37+
memory = SizeUnit.GIGABYTE.toByte(2)
38+
cpu = 1
39+
}
40+
41+
sftpBackupStorage {
42+
name = "sftp"
43+
url = "/sftp"
44+
username = "root"
45+
password = "password"
46+
hostname = "localhost"
47+
48+
image {
49+
name = "image1"
50+
url = "http://zstack.org/download/test.qcow2"
51+
}
52+
}
53+
54+
zone {
55+
name = "zone"
56+
description = "test"
57+
58+
cluster {
59+
name = "cluster"
60+
hypervisorType = "KVM"
61+
62+
kvm {
63+
name = "kvm"
64+
managementIp = "localhost"
65+
username = "root"
66+
password = "password"
67+
}
68+
69+
attachPrimaryStorage("local")
70+
attachL2Network("l2")
71+
}
72+
73+
attachBackupStorage("sftp")
74+
75+
localPrimaryStorage {
76+
name = "local"
77+
url = "/local_ps"
78+
}
79+
80+
l2NoVlanNetwork {
81+
name = "l2"
82+
physicalInterface = "eth0"
83+
84+
l3Network {
85+
name = "l3"
86+
87+
ip {
88+
startIp = "192.168.100.10"
89+
endIp = "192.168.100.100"
90+
netmask = "255.255.255.0"
91+
gateway = "192.168.100.1"
92+
}
93+
}
94+
}
95+
}
96+
}
97+
}
98+
99+
@Override
100+
void test() {
101+
env.create()
102+
testPmuGlobalConfigExists()
103+
testPmuDefaultOnX86()
104+
testPmuResourceConfigOverride()
105+
}
106+
107+
void testPmuGlobalConfigExists() {
108+
def configs = queryGlobalConfig {
109+
conditions = ["category=${VmGlobalConfig.CATEGORY}", "name=${VmGlobalConfig.VM_PMU.name}"]
110+
}
111+
112+
assert configs.size() == 1 : "vm.pmu GlobalConfig should exist"
113+
def config = configs[0] as GlobalConfigInventory
114+
assert config.defaultValue == "false" : "vm.pmu should default to false"
115+
}
116+
117+
void testPmuDefaultOnX86() {
118+
def image = env.inventoryByName("image1")
119+
def l3 = env.inventoryByName("l3")
120+
def instance = env.inventoryByName("instanceOffering")
121+
122+
KVMAgentCommands.StartVmCmd startCmd = null
123+
env.afterSimulator(KVMConstant.KVM_START_VM_PATH) { KVMAgentCommands.StartVmResponse rsp, HttpEntity<String> e ->
124+
startCmd = JSONObjectUtil.toObject(e.body, KVMAgentCommands.StartVmCmd.class)
125+
return rsp
126+
}
127+
128+
def vm = createVmInstance {
129+
name = "test-pmu-x86"
130+
imageUuid = image.uuid
131+
l3NetworkUuids = [l3.uuid]
132+
instanceOfferingUuid = instance.uuid
133+
} as VmInstanceInventory
134+
135+
assert startCmd != null
136+
// On x86 (non-aarch64), PMU code path is not triggered,
137+
// so StartVmCmd.pmu stays at its field default (true)
138+
if ("x86_64".equals(vm.architecture) || vm.architecture == null) {
139+
assert startCmd.pmu == true : "x86 VM should have PMU enabled by default"
140+
} else if ("aarch64".equals(vm.architecture)) {
141+
assert startCmd.pmu == false : "aarch64 VM should have PMU disabled by default"
142+
}
143+
144+
destroyVmInstance { uuid = vm.uuid }
145+
expungeVmInstance { uuid = vm.uuid }
146+
}
147+
148+
void testPmuResourceConfigOverride() {
149+
def image = env.inventoryByName("image1")
150+
def l3 = env.inventoryByName("l3")
151+
def instance = env.inventoryByName("instanceOffering")
152+
153+
def vm = createVmInstance {
154+
name = "test-pmu-override"
155+
imageUuid = image.uuid
156+
l3NetworkUuids = [l3.uuid]
157+
instanceOfferingUuid = instance.uuid
158+
} as VmInstanceInventory
159+
160+
// Set vm.pmu=true via ResourceConfig (different from default false)
161+
updateResourceConfig {
162+
category = VmGlobalConfig.CATEGORY
163+
name = VmGlobalConfig.VM_PMU.name
164+
value = "true"
165+
resourceUuid = vm.uuid
166+
}
167+
168+
KVMAgentCommands.StartVmCmd startCmd = null
169+
env.afterSimulator(KVMConstant.KVM_START_VM_PATH) { KVMAgentCommands.StartVmResponse rsp, HttpEntity<String> e ->
170+
startCmd = JSONObjectUtil.toObject(e.body, KVMAgentCommands.StartVmCmd.class)
171+
return rsp
172+
}
173+
174+
rebootVmInstance { uuid = vm.uuid }
175+
176+
assert startCmd != null
177+
// On x86, PMU stays true regardless of ResourceConfig (code only reads for aarch64)
178+
// This verifies the ResourceConfig record exists and reboot doesn't crash
179+
assert startCmd.pmu == true : "PMU should be true after reboot on x86"
180+
181+
// Verify ResourceConfig was persisted
182+
def configs = queryResourceConfig {
183+
conditions = [
184+
"category=${VmGlobalConfig.CATEGORY}",
185+
"name=${VmGlobalConfig.VM_PMU.name}",
186+
"resourceUuid=${vm.uuid}"
187+
]
188+
}
189+
assert configs.size() == 1 : "ResourceConfig should be persisted"
190+
191+
destroyVmInstance { uuid = vm.uuid }
192+
expungeVmInstance { uuid = vm.uuid }
193+
}
194+
}

0 commit comments

Comments
 (0)