Skip to content

Commit c677377

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

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed

qemu/tests/block_4k_discard.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
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):
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 expected_results 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+
try:
44+
expected = int(results_raw[i])
45+
except ValueError:
46+
test.fail(
47+
"Non-integer expected_results[{}]={!r}".format(i, results_raw[i])
48+
)
49+
rc, out = session.cmd_status_output(cmd)
50+
logger.debug(
51+
"guest_io_cmd%d: rc=%s, cmd=%r, out=%s", i, rc, cmd, out.strip()
52+
)
53+
if rc != expected:
54+
test.fail(
55+
"Unexpected rc=%s:%s, cmd=%r, out=%s"
56+
% (rc, expected, cmd, out.strip())
57+
)
58+
59+
def _get_scsi_debug_disk():
60+
cmd = "lsscsi -g -w -s | grep scsi_debug || true"
61+
out = (
62+
process.system_output(cmd, shell=True, ignore_status=True).decode().strip()
63+
)
64+
logger.info("Host cmd output '%s'", out)
65+
if not out:
66+
test.log.warning("Can not find scsi_debug disk")
67+
return
68+
disk_info = []
69+
for line in out.splitlines():
70+
tokens = line.split()
71+
path = next((t for t in tokens if t.startswith("/dev/sd")), None)
72+
sg = next((t for t in tokens if t.startswith("/dev/sg")), None)
73+
size = next(
74+
(t for t in tokens if re.search(r"(?i)\d+(?:\.\d+)?[KMGTPE]B$", t)),
75+
None,
76+
)
77+
wwn_tok = next((t for t in tokens if t.startswith("0x")), None)
78+
wwn = wwn_tok.split("0x", 1)[1]
79+
if not (path and sg):
80+
logger.warning("Unable to parse scsi_debug line: %s", line)
81+
continue
82+
disk_info.append(
83+
{"path": path, "sg": sg, "wwn": wwn, "size": size, "all": line}
84+
)
85+
if not disk_info:
86+
test.fail("Parsed no scsi_debug devices from lsscsi output")
87+
return disk_info
88+
89+
logger = test.log
90+
vm = None
91+
disk_wwn = None
92+
if params.get("get_scsi_device") == "yes":
93+
scsi_debug_devs = _get_scsi_debug_disk()
94+
if scsi_debug_devs:
95+
dev = scsi_debug_devs[0]
96+
disk_wwn = dev["wwn"]
97+
print(disk_wwn)
98+
if params["drive_format_stg1"] == "scsi-generic":
99+
params["image_name_stg1"] = dev["sg"]
100+
else:
101+
params["image_name_stg1"] = dev["path"]
102+
else:
103+
test.fail("Can not find scsi_debug devices")
104+
try:
105+
if params.get("not_preprocess", "no") == "yes":
106+
logger.debug("Ready boot VM : %s", params["images"])
107+
env_process.process(
108+
test,
109+
params,
110+
env,
111+
env_process.preprocess_image,
112+
env_process.preprocess_vm,
113+
)
114+
115+
logger.info("Get the main VM")
116+
vm = env.get_vm(params["main_vm"])
117+
vm.verify_alive()
118+
timeout = params.get_numeric("timeout", 300)
119+
session = vm.wait_for_login(timeout=timeout)
120+
serial = params.get("serial_stg1")
121+
identifier = serial or disk_wwn
122+
if not identifier:
123+
test.fail("Missing serial and no WWN parsed; cannot locate drive in guest")
124+
_execute_io_in_guest(identifier)
125+
126+
logger.info("Ready to destroy vm")
127+
vm.destroy()
128+
finally:
129+
if vm and vm.is_alive():
130+
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)