Skip to content

Commit c186fdc

Browse files
memory/memory_devices: nvdimm with access and discard settings (#6358)
including below actions with various memory backing access and discard config: 1. nvdimm defined in guest xml; 2. restart libvirt daemmon (test memory backing config is not lost after daemon restart); 3. nvdimm hot-plugged; Signed-off-by: liang-cong-red-hat <[email protected]>
1 parent 079f23f commit c186fdc

File tree

2 files changed

+222
-0
lines changed

2 files changed

+222
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
- memory.devices.nvdimm.access_and_discard:
2+
type = nvdimm_memory_with_access_and_discard
3+
no s390-virtio
4+
start_vm = no
5+
mem_model = "nvdimm"
6+
nvdimm_size = 524288
7+
nvdimm_num = 6
8+
nvdimm_path_prefix = "/tmp/nvdimm{}"
9+
nvdimm_dict_template = "{{'mem_model':'${mem_model}',{}'source': {{'path': '{}'}}, 'target': {{'size': ${nvdimm_size}, 'size_unit': 'KiB', 'node':{}}}}}"
10+
nvdimm_dynamic_access = {1: "'mem_access':'shared',", 3: "'mem_access':'private',", 5: "'mem_access':'shared',"}
11+
nvdimm_dynamic_node = {0: 0, 1: 0, 2: 1, 3: 1, 4: 2, 5: 2}
12+
nvdimm0_share = "'false'"
13+
max_mem = 20971520
14+
base_attrs = "'vcpu': 6, 'placement': 'static', 'memory_unit':'KiB','memory':3145728,'current_mem':3145728,'current_mem_unit':'KiB'"
15+
numa_attrs = "'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '1048576', 'unit': 'KiB'}, {'id': '1', 'cpus': '2-3', 'memory': '1048576', 'unit': 'KiB', 'memAccess':'shared','discard':'yes'},{'id':'2','cpus': '4-5','memory':'1048576','unit':'KiB', 'memAccess':'private','discard':'no'}]}"
16+
max_attrs = "'max_mem_rt': ${max_mem}, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'"
17+
variants memory_backing:
18+
- file:
19+
source_type = 'file'
20+
- anonymous:
21+
source_type = 'anonymous'
22+
- memfd:
23+
source_type = 'memfd'
24+
variants:
25+
- undefined:
26+
discard_attr = ""
27+
access_attr = ""
28+
- shared_and_discard:
29+
discard_attr = "'discard':'yes',"
30+
access_attr = "'access_mode':'shared',"
31+
nvdimm0_share = "'true'"
32+
- private_and_no_discard:
33+
discard_attr = ""
34+
access_attr = "'access_mode':'private',"
35+
variants operations:
36+
- define_nvdimm:
37+
init_nvdimms_id_range = 0-5
38+
- hot_plug_nvdimm:
39+
init_nvdimms_id_range = 0
40+
hotplug_nvdimms_id_range = 1-5
41+
share_cmd = "info memdev"
42+
share_cmd_protocal = "--hmp"
43+
share_pattern = "memory backend: (\w*nvdimm\w*).*?share: (true|false)"
44+
exp_share_list = [${nvdimm0_share}, 'true', 'true', 'false', 'false', 'true']
45+
discard_qom_cmd = '{{"execute":"qom-get", "arguments":{{"path":"/objects/{0}", "property":"discard-data"}}}}'
46+
exp_discard_list = [False, False, False, False, False, False]
47+
source_attr = "'source_type':'${source_type}'"
48+
memory_backing_attrs = "'mb':{${discard_attr} ${access_attr} ${source_attr}}"
49+
vm_attrs = {${memory_backing_attrs}, ${base_attrs}, ${numa_attrs}, ${max_attrs}}
50+
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2+
#
3+
# Copyright Red Hat
4+
#
5+
# SPDX-License-Identifier: GPL-2.0
6+
#
7+
# Author: Liang Cong <[email protected]>
8+
#
9+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10+
import json
11+
import os
12+
import re
13+
14+
from avocado.utils import process
15+
16+
from virttest import virsh
17+
from virttest.libvirt_xml import vm_xml
18+
from virttest.libvirt_xml.devices.memory import Memory
19+
from virttest.utils_libvirtd import Libvirtd
20+
21+
from provider.memory import memory_base
22+
23+
24+
def run(test, params, env):
25+
"""
26+
Verify nvdimm memory device behaviors with access and discard settings
27+
"""
28+
def setup_test():
29+
"""
30+
Construct nvdimms' variables and create nvdimms' backing files
31+
"""
32+
def is_in_range(num, range_str):
33+
"""
34+
Check if the number is in the given range string
35+
36+
:param num: int, target number
37+
:param range_str: string, range string to check
38+
:return: bool, True if number is in range string, False otherwise
39+
"""
40+
if '-' in range_str:
41+
start, end = map(int, range_str.split('-'))
42+
return start <= num <= end
43+
return num == int(range_str) if range_str else False
44+
45+
for i in range(nvdimm_num):
46+
n_path = nvdimm_path_prefix.format(i)
47+
n_access = nvdimm_dynamic_access.get(i, "")
48+
n_node = nvdimm_dynamic_node.get(i)
49+
50+
nvdimms_path_list.append(n_path)
51+
process.run(f"truncate -s {nvdimm_size}k {n_path}", verbose=True)
52+
53+
nvdimm_dict = eval(nvdimm_dict_template.format(n_access, n_path, n_node))
54+
if is_in_range(i, init_nvdimms_id_range):
55+
init_nvdimms.append(nvdimm_dict)
56+
if is_in_range(i, hotplug_nvdimms_id_range):
57+
hotplug_nvdimms.append(nvdimm_dict)
58+
59+
def check_nvdimm_share(exp_share_list):
60+
"""
61+
Verify nvdimm memory share status against expected values
62+
63+
:param exp_share_list: expected nvdimm memory share list
64+
"""
65+
share_cmd = params.get("share_cmd")
66+
share_cmd_protocal = params.get("share_cmd_protocal")
67+
pattern = params.get("share_pattern")
68+
69+
ret = virsh.qemu_monitor_command(vm_name, share_cmd,
70+
share_cmd_protocal, debug=True)
71+
test.log.debug(f"qemu-monitor-command '{share_cmd}' result: {ret.stdout_text}")
72+
matches = sorted(re.findall(fr'{pattern}', ret.stdout_text, re.DOTALL))
73+
actual_share_list = [share for _, share in matches]
74+
if actual_share_list != exp_share_list:
75+
test.fail(
76+
f"Expected share list is {exp_share_list}, but found {actual_share_list}")
77+
78+
nonlocal nvdimm_name_list
79+
nvdimm_name_list = [name for name, _ in matches]
80+
81+
def check_qemu_object_discard(name_list, exp_discard_list):
82+
"""
83+
Verify qemu object dicard property against expected values
84+
85+
:param name_list: list of qemu object names
86+
:param exp_list: expected list for discard property
87+
"""
88+
discard_qom_cmd = params.get("discard_qom_cmd")
89+
for index, name in enumerate(name_list):
90+
qom_cmd = discard_qom_cmd.format(name)
91+
ret = virsh.qemu_monitor_command(vm_name, qom_cmd, debug=True)
92+
data_dict = json.loads(ret.stdout_text)
93+
exp_value = exp_discard_list[index]
94+
95+
if "return" not in data_dict:
96+
test.fail(f"QOM command {qom_cmd} doesn't have return value: {ret.stdout_text}")
97+
98+
if data_dict["return"] != exp_value:
99+
test.fail(
100+
f"Expected nvdimm discard is {exp_value}, but found {data_dict['return']}")
101+
102+
def run_test():
103+
"""
104+
Test steps:
105+
1. Define the guest
106+
2. Start guest
107+
3. Restart libvirt daemon
108+
4: Hot plug nvdimms
109+
5: Check nvdimm memory device share access setting
110+
6: Check the all nvdimm memory device discard setting
111+
"""
112+
test.log.info("TEST_STEP1: Define the guest")
113+
memory_base.define_guest_with_memory_device(params, init_nvdimms, vm_attrs)
114+
115+
test.log.info("TEST_STEP2: Start guest")
116+
vm.start()
117+
118+
test.log.info("TEST_STEP3: Restart libvirt daemon")
119+
Libvirtd().restart()
120+
121+
if hotplug_nvdimms:
122+
test.log.info("TEST_STEP4: Hot plug nvdimms")
123+
for nvdimm in hotplug_nvdimms:
124+
nvdimm_device = Memory()
125+
nvdimm_device.setup_attrs(**nvdimm)
126+
virsh.attach_device(vm_name, nvdimm_device.xml, **virsh_args)
127+
128+
test.log.info("TEST_STEP5: Check nvdimm memory device share access setting")
129+
check_nvdimm_share(exp_share_list)
130+
131+
test.log.info("TEST_STEP6: Check the all nvdimm memory device discard setting")
132+
check_qemu_object_discard(nvdimm_name_list, exp_discard_list)
133+
134+
def teardown_test():
135+
"""
136+
Clean up environment after test
137+
1. Remove nvdimm memory backing files
138+
2. Restore domain xml
139+
"""
140+
for n_path in nvdimms_path_list:
141+
if os.path.exists(n_path):
142+
os.remove(n_path)
143+
bkxml.sync()
144+
145+
virsh_args = {'debug': True, 'ignore_status': False}
146+
vm_name = params.get("main_vm")
147+
vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
148+
bkxml = vmxml.copy()
149+
vm = env.get_vm(vm_name)
150+
151+
nvdimms_path_list = []
152+
nvdimm_name_list = []
153+
init_nvdimms = []
154+
hotplug_nvdimms = []
155+
nvdimm_size = int(params.get("nvdimm_size"))
156+
vm_attrs = eval(params.get("vm_attrs"))
157+
nvdimm_num = int(params.get("nvdimm_num"))
158+
nvdimm_path_prefix = params.get("nvdimm_path_prefix")
159+
nvdimm_dict_template = params.get("nvdimm_dict_template")
160+
nvdimm_dynamic_access = eval(params.get("nvdimm_dynamic_access"))
161+
nvdimm_dynamic_node = eval(params.get("nvdimm_dynamic_node"))
162+
init_nvdimms_id_range = params.get("init_nvdimms_id_range", "")
163+
hotplug_nvdimms_id_range = params.get("hotplug_nvdimms_id_range", "")
164+
exp_share_list = eval(params.get("exp_share_list"))
165+
exp_discard_list = eval(params.get("exp_discard_list"))
166+
167+
try:
168+
setup_test()
169+
run_test()
170+
171+
finally:
172+
teardown_test()

0 commit comments

Comments
 (0)