Skip to content
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
130 changes: 130 additions & 0 deletions qemu/tests/block_4k_discard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"""Attach the host 4k disk but QEMU is exposing a 512 to the Guest.
Test the unaligned discard operation on the disk."""

import re

from avocado.utils import process
from virttest import env_process, error_context
from virttest.utils_misc import get_linux_drive_path


@error_context.context_aware
def run(test, params, env):
"""
Qemu send unaligned discard test:
1) Load scsi_debug module with sector_size=4096
2) Boot guest with scsi_debug emulated disk as extra data disk
3) Login the guest and execute blkdiscard commands on the data disk
4) The unaligned discard command succeeds on the virtio or scsi-hd disk
Fails on the pass-through device

:param test: kvm test object
:param params: Dictionary with the test parameters
:param env: Dictionary with test environment.
"""

def _execute_io_in_guest(serial):
drive = get_linux_drive_path(session, serial)
if not drive:
test.fail("Can not find disk by {}".format(serial))

io_cmd_num = params.get_numeric("guest_io_cmd_number")
results_raw = params.get(
"expected_results", params.get("expected_resultes", "")
).split()
if len(results_raw) != io_cmd_num:
test.cancel(
"Mismatch: io_cmd_number={} but expected_results has {} items".format(
io_cmd_num, len(results_raw)
)
)
for i in range(io_cmd_num):
cmd = params["guest_io_cmd{}".format(i)].format(drive)
try:
expected = int(results_raw[i])
except ValueError:
test.fail(
"Non-integer expected_results[{}]={!r}".format(i, results_raw[i])
)
rc, out = session.cmd_status_output(cmd)
logger.debug(
"guest_io_cmd%d: rc=%s, cmd=%r, out=%s", i, rc, cmd, out.strip()
)
if rc != expected:
test.fail(
"Unexpected rc=%s:%s, cmd=%r, out=%s"
% (rc, expected, cmd, out.strip())
)

def _get_scsi_debug_disk():
cmd = "lsscsi -g -w -s | grep scsi_debug || true"
out = (
process.system_output(cmd, shell=True, ignore_status=True).decode().strip()
)
logger.info("Host cmd output '%s'", out)
if not out:
test.log.warning("Can not find scsi_debug disk")
return
disk_info = []
for line in out.splitlines():
tokens = line.split()
path = next((t for t in tokens if t.startswith("/dev/sd")), None)
sg = next((t for t in tokens if t.startswith("/dev/sg")), None)
size = next(
(t for t in tokens if re.search(r"(?i)\d+(?:\.\d+)?[KMGTPE]B$", t)),
None,
)
wwn_tok = next((t for t in tokens if t.startswith("0x")), None)
wwn = wwn_tok.split("0x", 1)[1]
if not (path and sg):
logger.warning("Unable to parse scsi_debug line: %s", line)
continue
disk_info.append(
{"path": path, "sg": sg, "wwn": wwn, "size": size, "all": line}
)
if not disk_info:
test.fail("Parsed no scsi_debug devices from lsscsi output")
return disk_info

logger = test.log
vm = None
disk_wwn = None
if params.get("get_scsi_device") == "yes":
scsi_debug_devs = _get_scsi_debug_disk()
if scsi_debug_devs:
dev = scsi_debug_devs[0]
disk_wwn = dev["wwn"]
print(disk_wwn)
if params["drive_format_stg1"] == "scsi-generic":
params["image_name_stg1"] = dev["sg"]
else:
params["image_name_stg1"] = dev["path"]
else:
test.fail("Can not find scsi_debug devices")
try:
if params.get("not_preprocess", "no") == "yes":
logger.debug("Ready boot VM : %s", params["images"])
env_process.process(
test,
params,
env,
env_process.preprocess_image,
env_process.preprocess_vm,
)

logger.info("Get the main VM")
vm = env.get_vm(params["main_vm"])
vm.verify_alive()
timeout = params.get_numeric("timeout", 300)
session = vm.wait_for_login(timeout=timeout)
serial = params.get("serial_stg1")
identifier = serial or disk_wwn
if not identifier:
test.fail("Missing serial and no WWN parsed; cannot locate drive in guest")
_execute_io_in_guest(identifier)

logger.info("Ready to destroy vm")
vm.destroy()
finally:
if vm and vm.is_alive():
vm.destroy(gracefully=False)
49 changes: 49 additions & 0 deletions qemu/tests/cfg/block_4k_discard.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
- block_4k_discard:
virt_test_type = qemu
type = block_4k_discard
only Linux
data_images = "stg1"
images += " ${data_images}"
drive_werror = stop
drive_rerror = stop
force_create_image_stg1 = no
force_remove_image_stg1 = no
not_preprocess = yes
get_scsi_device = yes
image_format_stg1 = raw
image_raw_device_stg1 = yes
image_name_stg1 = TBD
disk_size = 1024
pre_command = "modprobe scsi_debug sector_size=4096 dev_size_mb=${disk_size} lbpu=1 unmap_max_blocks=256 unmap_granularity=16"
post_command = "modprobe -r scsi_debug"
guest_io_cmd_number = 5
dd_cmd = "dd if=/dev/zero of={0} bs=1M count=100 oflag=direct "
lsblk_cmd = lsblk -d -o name,size,log-sec,phy-sec,disc-max,disc-gran,disc-aln,tran,alignment {0}
host_io_cmd = "${lsblk_cmd}|egrep '${sec_size}.*${sec_size}'"
guest_io_cmd1 = "${dd_cmd} && blkdiscard -l 512 {0} "
guest_io_cmd2 = "${dd_cmd} && blkdiscard -o 512 -l 512 {0} "
guest_io_cmd3 = "${dd_cmd} && blkdiscard -o 512 -l 4096 {0} "
guest_io_cmd4 = "${dd_cmd} && blkdiscard -l 4096 {0}"
variants:
- with_blk:
serial_stg1 = stg1
sec_size = 512
blk_extra_params_stg1 = "serial=${serial_stg1}"
drive_format_stg1 = virtio
expected_results = 0 0 0 0 0
- with_hd:
serial_stg1 = stg1
sec_size = 512
blk_extra_params_stg1 = "serial=${serial_stg1}"
drive_format_stg1 = scsi-hd
expected_results = 0 0 0 0 0
- with_block:
sec_size = 4096
drive_format_stg1 = scsi-block
expected_results = 0 1 1 1 0
- with_generic:
sec_size = 4096
drive_format_stg1 = scsi-generic
drive_cache_stg1 = writethrough
expected_results = 0 1 1 1 0
guest_io_cmd0 = "${lsblk_cmd}|egrep '${sec_size}.*${sec_size}'"