Skip to content

Commit 81f06b3

Browse files
committed
Add block 4k device unaligned discard test
Signed-off-by: qingwangrh <[email protected]>
1 parent 39966b3 commit 81f06b3

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed

qemu/tests/block_4k_discard.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
"""Attach the host 4k disk but QEMU is exposing a 512 to the Guest.
2+
Test the unaligned discard operation on the disk."""
3+
4+
import re
5+
6+
from avocado.utils import process
7+
from virttest import env_process, error_context
8+
from virttest.utils_misc import get_linux_drive_path
9+
10+
11+
@error_context.context_aware
12+
def run(test, params, env):
13+
"""
14+
Qemu send unaligned discard test:
15+
1) Load scsi_debug module with sector_size=4096
16+
2) Boot guest with scsi_debug emulated disk as extra data disk
17+
3) Login the guest and execute blkdiscard commands on the data disk
18+
4) The unaligned discard command succeeds on the virtio or scsi-hd disk
19+
Fails on the pass-through device
20+
21+
:param test: kvm test object
22+
:param params: Dictionary with the test parameters
23+
:param env: Dictionary with test environment.
24+
"""
25+
26+
def _execute_io_in_guest(serial=None):
27+
drive = get_linux_drive_path(session, serial)
28+
if not drive:
29+
test.fail("Can not find disk by {}".format(serial))
30+
31+
io_cmd_num = params.get_numeric("guest_io_cmd_number")
32+
results_raw = params.get(
33+
"expected_results", params.get("expected_resultes", "")
34+
).split()
35+
if len(results_raw) != io_cmd_num:
36+
test.cancel(
37+
"Mismatch: io_cmd_number={} but has {} items".format(
38+
io_cmd_num, len(results_raw)
39+
)
40+
)
41+
for i in range(io_cmd_num):
42+
cmd = params["guest_io_cmd{}".format(i)].format(drive)
43+
expected = int(results_raw[i])
44+
rc, out = session.cmd_status_output(cmd)
45+
logger.debug(
46+
"guest_io_cmd%d: rc=%s, cmd=%r, out=%s", i, rc, cmd, out.strip()
47+
)
48+
if rc != expected:
49+
test.fail(
50+
"Unexpected rc=%s:%s, cmd=%r, out=%s"
51+
% (rc, expected, cmd, out.strip())
52+
)
53+
54+
def _get_scsi_debug_disk():
55+
cmd = "lsscsi -g -w -s | grep scsi_debug || true"
56+
out = (
57+
process.system_output(cmd, shell=True, ignore_status=True).decode().strip()
58+
)
59+
logger.info("Host cmd output '%s'", out)
60+
if not out:
61+
test.log.warning("Can not find scsi_debug disk")
62+
return
63+
disk_info = []
64+
for line in out.splitlines():
65+
tokens = line.split()
66+
path = next((t for t in tokens if t.startswith("/dev/sd")), None)
67+
sg = next((t for t in tokens if t.startswith("/dev/sg")), None)
68+
size = next(
69+
(t for t in tokens if re.search(r"(?i)\d+(?:\.\d+)?[KMGTPE]B$", t)),
70+
None,
71+
)
72+
wwn_tok = next((t for t in tokens if t.startswith("0x")), None)
73+
wwn = wwn_tok.split("0x", 1)[1]
74+
if not (path and sg):
75+
logger.warning("Unable to parse scsi_debug line: %s", line)
76+
continue
77+
disk_info.append(
78+
{"path": path, "sg": sg, "wwn": wwn, "size": size, "all": line}
79+
)
80+
if not disk_info:
81+
test.fail("Parsed no scsi_debug devices from lsscsi output")
82+
return disk_info
83+
84+
logger = test.log
85+
vm = None
86+
disk_wwn = None
87+
if params.get("get_scsi_device") == "yes":
88+
scsi_debug_devs = _get_scsi_debug_disk()
89+
if scsi_debug_devs:
90+
dev = scsi_debug_devs[0]
91+
disk_wwn = dev["wwn"]
92+
print(disk_wwn)
93+
if params["drive_format_stg1"] == "scsi-generic":
94+
params["image_name_stg1"] = dev["sg"]
95+
else:
96+
params["image_name_stg1"] = dev["path"]
97+
else:
98+
test.fail("Can not find scsi_debug devices")
99+
try:
100+
if params.get("not_preprocess", "no") == "yes":
101+
logger.debug("Ready boot VM : %s", params["images"])
102+
env_process.process(
103+
test,
104+
params,
105+
env,
106+
env_process.preprocess_image,
107+
env_process.preprocess_vm,
108+
)
109+
110+
logger.info("Get the main VM")
111+
vm = env.get_vm(params["main_vm"])
112+
vm.verify_alive()
113+
timeout = params.get_numeric("timeout", 300)
114+
session = vm.wait_for_login(timeout=timeout)
115+
serial = params.get("serial_stg1")
116+
_execute_io_in_guest(serial if serial else disk_wwn)
117+
118+
logger.info("Ready to destroy vm")
119+
vm.destroy()
120+
finally:
121+
if vm and vm.is_alive():
122+
vm.destroy(gracefully=False)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
- block_4k_discard:
2+
virt_test_type = qemu
3+
type = block_4k_discard
4+
only Linux
5+
data_images = "stg1"
6+
images += " ${data_images}"
7+
drive_werror = stop
8+
drive_rerror = stop
9+
force_create_image_stg1 = no
10+
force_remove_image_stg1 = no
11+
not_preprocess = yes
12+
get_scsi_device = yes
13+
image_format_stg1 = raw
14+
image_raw_device_stg1 = yes
15+
image_name_stg1 = TBD
16+
disk_size = 1024
17+
pre_command = "modprobe scsi_debug sector_size=4096 dev_size_mb=${disk_size} lbpu=1 unmap_max_blocks=256 unmap_granularity=16"
18+
post_command = "modprobe -r scsi_debug"
19+
guest_io_cmd_number = 5
20+
dd_cmd = "dd if=/dev/zero of={0} bs=1M count=100 oflag=direct "
21+
lsblk_cmd = lsblk -d -o name,size,log-sec,phy-sec,disc-max,disc-gran,disc-aln,tran,alignment {0}
22+
host_io_cmd = "${lsblk_cmd}|egrep '${sec_size}.*${sec_size}'"
23+
guest_io_cmd1 = "${dd_cmd} && blkdiscard -l 512 {0} "
24+
guest_io_cmd2 = "${dd_cmd} && blkdiscard -o 512 -l 512 {0} "
25+
guest_io_cmd3 = "${dd_cmd} && blkdiscard -o 512 -l 4096 {0} "
26+
guest_io_cmd4 = "${dd_cmd} && blkdiscard -l 4096 {0}"
27+
variants:
28+
- with_blk:
29+
serial_stg1 = stg1
30+
sec_size = 512
31+
blk_extra_params_stg1 = "serial=${serial_stg1}"
32+
drive_format_stg1 = virtio
33+
expected_results = 0 0 0 0 0
34+
- with_hd:
35+
serial_stg1 = stg1
36+
sec_size = 512
37+
blk_extra_params_stg1 = "serial=${serial_stg1}"
38+
drive_format_stg1 = scsi-hd
39+
expected_results = 0 0 0 0 0
40+
- with_block:
41+
sec_size = 4096
42+
drive_format_stg1 = scsi-block
43+
expected_results = 0 1 1 1 0
44+
- with_generic:
45+
sec_size = 4096
46+
drive_format_stg1 = scsi-generic
47+
drive_cache_stg1 = writethrough
48+
expected_results = 0 1 1 1 0
49+
guest_io_cmd0 = "${lsblk_cmd}|egrep '${sec_size}.*${sec_size}'"

0 commit comments

Comments
 (0)