Skip to content
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

add case for dimm memory with access and discard setting #5328

Merged
Merged
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,70 @@
- memory.devices.dimm.access_and_discard:
type = dimm_memory_with_access_and_discard
start_vm = yes
mem_model = "dimm"
dimm_mem_num = 6
share_0 = 'false'
discard_0 = 'False'
check_path = "ls -l /var/lib/libvirt/qemu/ram/%s"
target_size = 131072
requested_size = 131072
block_size = 2048
aarch64:
target_size = 1048576
requested_size = 524288
block_size = 524288
dimm_basic = {'mem_model': '${mem_model}', 'target': {'requested_unit': 'KiB', 'size': ${target_size}, 'size_unit': 'KiB', 'requested_size': ${requested_size}, 'block_unit': 'KiB', 'block_size': ${block_size}}}
kernel_params_add = "memhp_default_state=online_movable"
variants memory_backing:
- file:
source_type = 'file'
- anonymous:
source_type = 'anonymous'
- memfd:
source_type = 'memfd'
discard_error = 'yes'
discard_error_msg = "Property 'memory-backend-memfd.discard-data' not found"
variants:
- undefined:
memfd:
share_0 = 'true'
file:
discard_0 = 'False'
anonymous:
discard_error = 'yes'
discard_error_msg = "Property 'memory-backend-ram.discard-data' not found"
- shared_and_discard:
discard_attr = "'discard':'yes'"
access_attr = "'access_mode':'shared'"
share_0 = 'true'
file:
discard_0 = 'True'
anonymous:
discard_0 = 'True'
- private_and_no_discard:
access_attr = "'access_mode':'private'"
file:
discard_0 = 'False'
anonymous:
discard_0 = 'False'
source_attr = "'source_type':'${source_type}'"
expected_share = ['${share_0}', 'true', 'true', 'false', 'false', 'true']
check_discard = '{"execute":"qom-get", "arguments":{"path":"/objects/%s", "property":"discard-data"}}'
expected_discard = ['${discard_0}', 'True', 'True', 'False', 'False', 'True']
variants:
- with_numa:
no s390-virtio
mem_value = 3145728
current_mem = 3145728
max_mem = 10485760
numa_mem = 1048576
aarch64:
max_mem = 20971520
mem_access_1 = "shared"
discard_1 = "yes"
mem_access_2 = "private"
discard_2 = "no"
base_attrs = "'vcpu': 6, 'placement': 'static', 'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'KiB'"
numa_attrs = "'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem}', 'unit': 'KiB'}, {'id': '1', 'cpus': '2-3', 'memory': '${numa_mem}', 'unit': 'KiB', 'memAccess':'${mem_access_1}','discard':'${discard_1}'},{'id':'2','cpus': '4-5','memory':'${numa_mem}','unit':'KiB', 'memAccess':'${mem_access_2}','discard':'${discard_2}'}]}"
max_attrs = "'max_mem_rt': ${max_mem}, 'max_mem_rt_slots': 16, 'max_mem_rt_unit': 'KiB'"
vm_attrs = {${base_attrs}, ${numa_attrs}, ${max_attrs}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright Redhat
#
# SPDX-License-Identifier: GPL-2.0

# Author: Nannan Li <[email protected]>
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import re
import json

from avocado.utils import process

from virttest import utils_test
from virttest import virsh
from virttest.libvirt_xml import vm_xml
from virttest.utils_libvirtd import Libvirtd
from virttest.utils_libvirt import libvirt_vmxml


def get_vm_attrs(test, params):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same function is in #5290. Maybe we can move this function to provide/memory/memory_base.py. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks liping , Good idea. Currently , It's not very common for all the cases , only suitable for these two prs, Could I move it if exists more usage ?

"""
Get vm attrs.

:param test: test object
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a blank line above this line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks dzheng, Done

:param params: dictionary with the test parameters
:return vm_attrs: get updated vm attrs dict.
"""
vm_attrs = eval(params.get("vm_attrs", "{}"))
source_attr = params.get("source_attr", "")
discard_attr = params.get("discard_attr", "")
access_attr = params.get("access_attr", "")

mb_value = ""
for item in [source_attr, discard_attr, access_attr]:
if item != "":
mb_value += item + ","
mb_attrs = eval("{'mb':{%s}}" % mb_value[:-1])

vm_attrs.update(mb_attrs)
test.log.debug("Get current vm attrs is :%s", vm_attrs)

return vm_attrs


def create_dimm_mem_list(test, params):
"""
Get 6 basic different dimm memory devices.

:param test: test object.
:param params: dictionary with the test parameters.
:return mem_list: dimm memory attr dict list.
"""
mem_list = []
for item in [(None, None, 0), ('shared', 'yes', 0),
(None, None, 1), ('private', 'no', 1),
(None, None, 2), ('shared', 'yes', 2)]:

single_mem = eval(params.get("dimm_basic"))
target = single_mem['target']
target.update({'node': item[2]})

if item[0] is not None:
single_mem.update({'mem_access': item[0]})
if item[1] is not None:
single_mem.update({'mem_discard': item[1]})
mem_list.append(single_mem)

test.log.debug("Get all dimm list:'%s'", mem_list)
return mem_list


def check_access_and_discard(test, params, vm,
expected_share, expected_discard):
"""
Check access and discard setting.

:param test: test object.
:param params: dictionary with the test parameters.
:param vm: vm object.
:param expected_share: expected access shared value list.
:param expected_discard: expected discard value list.
"""
dimm_mem_num = int(params.get("dimm_mem_num"))
check_discard = params.get("check_discard")
discard_error_msg = params.get("discard_error_msg")
mem_name_list = []

# Check access share setting
ret = virsh.qemu_monitor_command(vm.name, "info memdev", "--hmp",
debug=True).stdout_text.replace("\r\n", "")
for index in range(dimm_mem_num):
mem_name = "memdimm%d" % index
pattern = "memory backend: %s.*share: %s " % (mem_name, expected_share[index])
if not re.search(pattern, ret):
test.fail("Expect '%s' exist, but not found" % pattern)
else:
test.log.debug("Check access shared value is '%s': PASS", pattern)
mem_name_list.append(mem_name)

# Check discard setting
for index, mem_name in enumerate(mem_name_list):
res = virsh.qemu_monitor_command(
vm.name, check_discard % mem_name, debug=True).stdout_text

if 'return' in json.loads(res):
actual_discard = str(json.loads(res)['return'])
if actual_discard != expected_discard[index]:
test.fail("Expect discard is '%s', but got '%s'" % (
expected_discard[index], actual_discard))
else:
test.log.debug("Check discard value is '%s' PASS", actual_discard)
else:
actual_error = json.loads(res)['error']['desc']
if not re.search(discard_error_msg, actual_error):
test.fail("Expected to get '%s' in '%s'" % (discard_error_msg,
actual_error))
else:
test.log.debug("Check '%s' PASS ", actual_error)


def run(test, params, env):
"""
Verify dimm memory device works with access and discard settings.
"""
def setup_test():
"""
Set kernel parameter memhp_default_state to online_movable(
this would make hotunplug more reliable)
"""
utils_test.update_boot_option(vm, args_added=kernel_params_add,
need_reboot=True)
vm.destroy()

def run_test():
"""
1.Define vm with dimm memory device.
2.Check the dimm memory device access and discard setting.
3.Define vm without dimm memory device and restart service, and hotplug
dimm device.
"""
test.log.info("TEST_STEP1: Define vm with dimm memory")
vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is duplicated with line 207 original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi dzheng,Thanks for your comment. L144 is used for step1, original_xml is used for step8

vmxml.remove_all_device_by_type("memory")

vm_attrs = get_vm_attrs(test, params)
vmxml.setup_attrs(**vm_attrs)

all_dimms = create_dimm_mem_list(test, params)
dimm_objs = []
for mem in all_dimms:
dimm = libvirt_vmxml.create_vm_device_by_type('memory', mem)
vmxml.devices = vmxml.devices.append(dimm)
dimm_objs.append(dimm)
vmxml.sync()

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

test.log.info("TEST_STEP3,4: Check dimm memory access and discard")
check_access_and_discard(test, params, vm, expected_share,
expected_discard)

test.log.info("TEST_STEP5: Hot unplug all dimm memory device")
for dimm in dimm_objs:
virsh.detach_device(vm_name, dimm.xml,
debug=True, ignore_status=False)

test.log.info("TEST_STEP6: Destroy vm")
vm.destroy()

test.log.info("TEST_STEP7: Check the host path for memory file backing")
res = process.run(check_path % vm_name, shell=True, ignore_status=True).stderr_text
if not re.search(path_error, res):
test.fail("Expected '%s', but got '%s'" % (path_error, res))

test.log.info("TEST_STEP8: Define guest without any dimm memory")
original_xml.setup_attrs(**vm_attrs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand why we use vm_attrs to configure vm xml?
Is it required attributes?
And could we make sure original_xml has no dimm memory device? If not, we need explicitly to remove existing dimm device if any.

Copy link
Contributor Author

@nanli1 nanli1 Feb 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi dzheng, Thanks your comment. For these two questions:

  1. vm_attrs should be used to define required attributes as the polarion case
  2. Done , Removed dimm

original_xml.sync()
vm.start()

test.log.info("TEST_STEP8: Restart service")
Libvirtd().restart()

test.log.info("TEST_STEP9: Hot plug all dimm memory device")
for dimm in dimm_objs:
virsh.attach_device(vm_name, dimm.xml,
debug=True, ignore_status=False)

test.log.info("TEST_STEP10: Check dimm discard and access again.")
check_access_and_discard(test, params, vm,
expected_share, expected_discard)

def teardown_test():
"""
Clean data.
"""
test.log.info("TEST_TEARDOWN: Clean up env.")
utils_test.update_boot_option(vm, args_removed=kernel_params_add,
need_reboot=True)
bkxml.sync()

vm_name = params.get("main_vm")
original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
bkxml = original_xml.copy()
vm = env.get_vm(vm_name)

kernel_params_add = params.get("kernel_params_add")
expected_share = eval(params.get("expected_share"))
expected_discard = eval(params.get("expected_discard"))
check_path = params.get("check_path")
path_error = params.get("path_error", "No such file or directory")

try:
setup_test()
run_test()

finally:
teardown_test()
Loading