-
Notifications
You must be signed in to change notification settings - Fork 168
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
memory/gmap: add test for shadow memory counters
KVM records shadow memory events for a nested guest. Confirm the counters go up. Signed-off-by: Sebastian Mitterle <[email protected]>
- Loading branch information
Showing
2 changed files
with
146 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
- gmap: | ||
type = gmap | ||
start_vm = no | ||
only s390-virtio | ||
variants: | ||
- l3_shadow_table_counters: | ||
l2_mem = 3906250 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
import logging as log | ||
import os | ||
from pathlib import Path | ||
|
||
from avocado.core.exceptions import TestError | ||
from virttest import virsh | ||
from virttest.libvirt_xml import vm_xml | ||
from virttest.utils_misc import cmd_status_output | ||
from virttest.utils_test.libvirt_device_utils import create_fs_xml | ||
|
||
|
||
logging = log.getLogger('avocado.' + __name__) | ||
cleanup_actions = [] | ||
|
||
|
||
def parent(file_path): | ||
""" | ||
Returns the parent directory of a file path | ||
:param file_path: absolute file path | ||
:return path: absolute path of parent directory | ||
""" | ||
return Path(file_path).parent.absolute() | ||
|
||
|
||
def get_source_disk_path(vmxml): | ||
""" | ||
Returns the absolute path to a disk image for import. | ||
Assume the boot image is the first disk and an image file. | ||
:param vmxml: VMXML instance | ||
:return: absolute path to the guest's first disk image file | ||
""" | ||
disks = vmxml.get_disk_all() | ||
disk_list = list(disks.values()) | ||
first_disk = disk_list[0] | ||
return first_disk.find('source').get('file') | ||
|
||
|
||
def update_l2_vm(vmxml, l2_mem, target_tag): | ||
""" | ||
Update the L2 VM to run L3 inside from virtiofs | ||
:param vmxml: The VMXML instance | ||
:param l2_mem: The new memory size | ||
:param target_tag: virtiofs mount tag | ||
""" | ||
vmxml.memory = l2_mem | ||
mb = vm_xml.VMMemBackingXML() | ||
mb.access_mode = "shared" | ||
vmxml.mb = mb | ||
vmxml.sync() | ||
fs = create_fs_xml({ | ||
"accessmode": "passthrough", | ||
"source": { | ||
"dir": parent(get_source_disk_path(vmxml)) | ||
}, | ||
"target": {"dir": target_tag}, | ||
"binary": {"flock": "off", "posix": "off"} | ||
}) | ||
virsh.attach_device(vmxml.vm_name, fs.xml, flagstr="--config", debug=True) | ||
|
||
|
||
def prepare_l3(vmxml): | ||
""" | ||
Prepares the disk for the L3 guest | ||
:param vmxml: The L2 VMXML instance | ||
""" | ||
l2_disk_path = get_source_disk_path(vmxml) | ||
l3_disk_path = os.path.join(parent(l2_disk_path), "test.qcow2") | ||
cmd = ("qemu-img convert -f qcow2 -O qcow2 -o lazy_refcounts=on" | ||
" {} {}".format(l2_disk_path, l3_disk_path)) | ||
cmd_status_output(cmd) | ||
cleanup_actions.append(lambda: os.unlink(l3_disk_path)) | ||
|
||
|
||
def start_l3(session, target_tag): | ||
""" | ||
Mount the shared directory with the image file and start | ||
the L3 guest with the qemu-kvm command | ||
:param session: VM session | ||
:param target_tag: virtiofs mount tag | ||
""" | ||
mount_dir = "/mnt" | ||
cmd = "mount -t virtiofs {} {}".format(target_tag, mount_dir) | ||
cmd_status_output(cmd, session=session) | ||
cmd = ("/usr/libexec/qemu-kvm -m 1024 -smp 1" | ||
" -daemonize {}".format(os.path.join(mount_dir, "test.qcow2"))) | ||
s, _ = cmd_status_output(cmd, session=session) | ||
if s: | ||
raise TestError("Couldn't start L3 guest.") | ||
|
||
|
||
def l1_counters_go_up(): | ||
""" | ||
Check that the shadow memory counters go up | ||
""" | ||
base_path = "/sys/kernel/debug/kvm/" | ||
for a in [ | ||
"gmap_shadow_reuse", | ||
"gmap_shadow_create", | ||
"gmap_shadow_sg_entry", | ||
"gmap_shadow_pg_entry" | ||
]: | ||
with open(os.path.join(base_path, a), "r") as f: | ||
if f.read().strip() == "0": | ||
return False | ||
return True | ||
|
||
|
||
def run(test, params, env): | ||
""" | ||
Test kvm counters for L3 shadow memory | ||
""" | ||
vm_name = params.get('main_vm') | ||
vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) | ||
bkxml = vmxml.copy() | ||
cleanup_actions.append(lambda: bkxml.sync()) | ||
vm = env.get_vm(vm_name) | ||
l2_mem = int(params.get("l2_mem", "4096")) | ||
target_tag = "mnt" | ||
|
||
try: | ||
update_l2_vm(vmxml, l2_mem, target_tag) | ||
prepare_l3(vmxml) | ||
logging.debug("VMXML: %s", vm_xml.VMXML.new_from_dumpxml(vm_name)) | ||
vm.start() | ||
cleanup_actions.append(lambda: vm.destroy()) | ||
session = vm.wait_for_login() | ||
cleanup_actions.append(lambda: session.close()) | ||
start_l3(session, target_tag) | ||
if not l1_counters_go_up(): | ||
test.fail("Gmap counters didn't go up.") | ||
finally: | ||
cleanup_actions.reverse() | ||
for a in cleanup_actions: | ||
a() |