Skip to content

Add new case VIRT-299196 for nvdimm with access and discard settings #6358

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
- memory.devices.nvdimm.access_and_discard:
type = nvdimm_memory_with_access_and_discard
no s390-virtio
start_vm = no
mem_model = "nvdimm"
nvdimm_size = 524288
nvdimm_num = 6
nvdimm_path_prefix = "/tmp/nvdimm{}"
nvdimm_dict_template = "{{'mem_model':'${mem_model}',{}'source': {{'path': '{}'}}, 'target': {{'size': ${nvdimm_size}, 'size_unit': 'KiB', 'node':{}}}}}"
nvdimm_dynamic_access = {1: "'mem_access':'shared',", 3: "'mem_access':'private',", 5: "'mem_access':'shared',"}
nvdimm_dynamic_node = {0: 0, 1: 0, 2: 1, 3: 1, 4: 2, 5: 2}
nvdimm0_share = "'false'"
max_mem = 20971520
base_attrs = "'vcpu': 6, 'placement': 'static', 'memory_unit':'KiB','memory':3145728,'current_mem':3145728,'current_mem_unit':'KiB'"
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'}]}"
max_attrs = "'max_mem_rt': ${max_mem}, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'"
variants memory_backing:
- file:
source_type = 'file'
- anonymous:
source_type = 'anonymous'
- memfd:
source_type = 'memfd'
variants:
- undefined:
discard_attr = ""
access_attr = ""
- shared_and_discard:
discard_attr = "'discard':'yes',"
access_attr = "'access_mode':'shared',"
nvdimm0_share = "'true'"
- private_and_no_discard:
discard_attr = ""
access_attr = "'access_mode':'private',"
variants operations:
- define_nvdimm:
init_nvdimms_id_range = 0-5
- hot_plug_nvdimm:
init_nvdimms_id_range = 0
hotplug_nvdimms_id_range = 1-5
share_cmd = "info memdev"
share_cmd_protocal = "--hmp"
share_pattern = "memory backend: (\w*nvdimm\w*).*?share: (true|false)"
exp_share_list = [${nvdimm0_share}, 'true', 'true', 'false', 'false', 'true']
discard_qom_cmd = '{{"execute":"qom-get", "arguments":{{"path":"/objects/{0}", "property":"discard-data"}}}}'
exp_discard_list = [False, False, False, False, False, False]
source_attr = "'source_type':'${source_type}'"
memory_backing_attrs = "'mb':{${discard_attr} ${access_attr} ${source_attr}}"
vm_attrs = {${memory_backing_attrs}, ${base_attrs}, ${numa_attrs}, ${max_attrs}}

Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright Red Hat
#
# SPDX-License-Identifier: GPL-2.0
#
# Author: Liang Cong <[email protected]>
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import json
import os
import re

from avocado.utils import process

from virttest import virsh
from virttest.libvirt_xml import vm_xml
from virttest.libvirt_xml.devices.memory import Memory
from virttest.utils_libvirtd import Libvirtd

from provider.memory import memory_base


def run(test, params, env):
"""
Verify nvdimm memory device behaviors with access and discard settings
"""
def setup_test():
"""
Construct nvdimms' variables and create nvdimms' backing files
"""
def is_in_range(num, range_str):
"""
Check if the number is in the given range string

:param num: int, target number
:param range_str: string, range string to check
:return: bool, True if number is in range string, False otherwise
"""
if '-' in range_str:
start, end = map(int, range_str.split('-'))
return start <= num <= end
return num == int(range_str) if range_str else False

for i in range(nvdimm_num):
n_path = nvdimm_path_prefix.format(i)
n_access = nvdimm_dynamic_access.get(i, "")
n_node = nvdimm_dynamic_node.get(i)

nvdimms_path_list.append(n_path)
process.run(f"truncate -s {nvdimm_size}k {n_path}", verbose=True)

nvdimm_dict = eval(nvdimm_dict_template.format(n_access, n_path, n_node))
if is_in_range(i, init_nvdimms_id_range):
init_nvdimms.append(nvdimm_dict)
if is_in_range(i, hotplug_nvdimms_id_range):
hotplug_nvdimms.append(nvdimm_dict)

def check_nvdimm_share(exp_share_list):
"""
Verify nvdimm memory share status against expected values

:param exp_share_list: expected nvdimm memory share list
"""
share_cmd = params.get("share_cmd")
share_cmd_protocal = params.get("share_cmd_protocal")
pattern = params.get("share_pattern")

ret = virsh.qemu_monitor_command(vm_name, share_cmd,
share_cmd_protocal, debug=True)
test.log.debug(f"qemu-monitor-command '{share_cmd}' result: {ret.stdout_text}")
matches = sorted(re.findall(fr'{pattern}', ret.stdout_text, re.DOTALL))
actual_share_list = [share for _, share in matches]
if actual_share_list != exp_share_list:
test.fail(
f"Expected share list is {exp_share_list}, but found {actual_share_list}")

nonlocal nvdimm_name_list
nvdimm_name_list = [name for name, _ in matches]

def check_qemu_object_discard(name_list, exp_discard_list):
"""
Verify qemu object dicard property against expected values

:param name_list: list of qemu object names
:param exp_list: expected list for discard property
"""
discard_qom_cmd = params.get("discard_qom_cmd")
for index, name in enumerate(name_list):
qom_cmd = discard_qom_cmd.format(name)
ret = virsh.qemu_monitor_command(vm_name, qom_cmd, debug=True)
data_dict = json.loads(ret.stdout_text)
exp_value = exp_discard_list[index]

if "return" not in data_dict:
test.fail(f"QOM command {qom_cmd} doesn't have return value: {ret.stdout_text}")

if data_dict["return"] != exp_value:
test.fail(
f"Expected nvdimm discard is {exp_value}, but found {data_dict['return']}")

def run_test():
"""
Test steps:
1. Define the guest
2. Start guest
3. Restart libvirt daemon
4: Hot plug nvdimms
5: Check nvdimm memory device share access setting
6: Check the all nvdimm memory device discard setting
"""
test.log.info("TEST_STEP1: Define the guest")
memory_base.define_guest_with_memory_device(params, init_nvdimms, vm_attrs)

test.log.info("TEST_STEP2: Start guest")
vm.start()

test.log.info("TEST_STEP3: Restart libvirt daemon")
Libvirtd().restart()

if hotplug_nvdimms:
test.log.info("TEST_STEP4: Hot plug nvdimms")
for nvdimm in hotplug_nvdimms:
nvdimm_device = Memory()
nvdimm_device.setup_attrs(**nvdimm)
virsh.attach_device(vm_name, nvdimm_device.xml, **virsh_args)

test.log.info("TEST_STEP5: Check nvdimm memory device share access setting")
check_nvdimm_share(exp_share_list)

test.log.info("TEST_STEP6: Check the all nvdimm memory device discard setting")
check_qemu_object_discard(nvdimm_name_list, exp_discard_list)

def teardown_test():
"""
Clean up environment after test
1. Remove nvdimm memory backing files
2. Restore domain xml
"""
for n_path in nvdimms_path_list:
if os.path.exists(n_path):
os.remove(n_path)
bkxml.sync()

virsh_args = {'debug': True, 'ignore_status': False}
vm_name = params.get("main_vm")
vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
bkxml = vmxml.copy()
vm = env.get_vm(vm_name)

nvdimms_path_list = []
nvdimm_name_list = []
init_nvdimms = []
hotplug_nvdimms = []
nvdimm_size = int(params.get("nvdimm_size"))
vm_attrs = eval(params.get("vm_attrs"))
nvdimm_num = int(params.get("nvdimm_num"))
nvdimm_path_prefix = params.get("nvdimm_path_prefix")
nvdimm_dict_template = params.get("nvdimm_dict_template")
nvdimm_dynamic_access = eval(params.get("nvdimm_dynamic_access"))
nvdimm_dynamic_node = eval(params.get("nvdimm_dynamic_node"))
init_nvdimms_id_range = params.get("init_nvdimms_id_range", "")
hotplug_nvdimms_id_range = params.get("hotplug_nvdimms_id_range", "")
exp_share_list = eval(params.get("exp_share_list"))
exp_discard_list = eval(params.get("exp_discard_list"))

try:
setup_test()
run_test()

finally:
teardown_test()