Hi Shinichiro, Thanks for the test, please see my in-line comments. On 05/12/2019 07:03 PM, Shin'ichiro Kawasaki wrote: > Check that zones sector mapping is correct for zoned block devices that > are not an entire full device (null_block device or physical device). > These logical devices are for now partition devices or device-mapper > devices (dm-linear or dm-flakey). This test case requires that such a > logical device be specified in TEST_DEVS in config. The test is skipped > for devices that are identified as not logically created. > > To test that the zone mapping is correct, select a few sequential write > required zones of the logical device and move the write pointers of > these zones through the container device of the logical device, using > the physical sector mapping of the zones. The write pointers position of > the selected zones is then checked through a zone report of the logical > device using the logical sector mapping of the zones. The test reports a > success if the position of the zone write pointers relative to the zone > start sector must be identical for both the logical and physical > locations of the zones. > > To implement this test case, introduce several helper functions. > _find_last_sequential_zone() and _find_sequential_zone_in_middle() > help target zones selection. _test_dev_is_logical() checks the target > device type. If false is returned, the test case is skipped. > _get_dev_container_and_sector() helps to get the container device and > sector mappings. At this moment, these helper functions support > partition devices and dm-linear/flakey devices as the logical devices. > _test_dev_has_dm_map() helps to check that the dm target is linear or > flakey. > > Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@xxxxxxx> > --- > tests/zbd/007 | 95 +++++++++++++++++++++++++++++++++ > tests/zbd/007.out | 2 + > tests/zbd/rc | 132 ++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 229 insertions(+) > create mode 100755 tests/zbd/007 > create mode 100644 tests/zbd/007.out > > diff --git a/tests/zbd/007 b/tests/zbd/007 > new file mode 100755 > index 0000000..e4723d7 > --- /dev/null > +++ b/tests/zbd/007 > @@ -0,0 +1,95 @@ > +#!/bin/bash > +# SPDX-License-Identifier: GPL-3.0+ > +# Copyright (C) 2019 Western Digital Corporation or its affiliates. > +# > +# Test zones are mapped correctly between a logical device and its container > +# device. Move write pointers of sequential write required zones on the > +# container devices, and confirm same write pointer positions of zones on the > +# logical devices. > + > +. tests/zbd/rc > + > +DESCRIPTION="zone mapping" Can this be more explanatory ? > +CAN_BE_ZONED=1 Do we need QUICK=1 ? > + > +requires() { > + _have_program dmsetup > +} > + > +device_requires() { > + _test_dev_is_logical > +} > + > +test_device() { > + local -i bs > + local -i zone_idx > + local -a test_z # test target zones > + local -a test_z_start > + > + echo "Running ${TEST_NAME}" > + > + # Get physical block size to meet zoned block device I/O requirement > + _get_sysfs_variable "${TEST_DEV}" || return $? > + bs=${SYSFS_VARS[SV_PHYS_BLK_SIZE]} > + _put_sysfs_variable > + > + # Select test target zones. Pick up the first sequential required zones. > + # If available, add one or two more sequential required zones. One is at > + # the last end of TEST_DEV. The other is in middle between the first > + # and the last zones. > + _get_blkzone_report "${TEST_DEV}" || return $? > + zone_idx=$(_find_first_sequential_zone) || return $? > + test_z=( "${zone_idx}" ) > + if zone_idx=$(_find_last_sequential_zone); then > + test_z+=( "${zone_idx}" ) > + if zone_idx=$(_find_sequential_zone_in_middle \ > + "${test_z[0]}" "${test_z[1]}"); then > + test_z+=( "${zone_idx}" ) > + fi > + fi > + > + for ((i = 0; i < ${#test_z[@]}; i++)); do > + test_z_start+=("${ZONE_STARTS[test_z[i]]}") > + done > + echo "${test_z[*]}" >> "$FULL" > + echo "${test_z_start[*]}" >> "$FULL" > + > + _put_blkzone_report I think above code of building an array should be move to the same file in a helper function. It is just making entire test look bigger than it is. > + > + # Reset and move write pointers of the container device > + for ((i=0; i < ${#test_z[@]}; i++)); do > + local -a arr nit:- add a new line after declaration. > + read -r -a arr < <(_get_dev_container_and_sector \ > + "${test_z_start[i]}") > + container_dev="${arr[0]}" > + container_start="${arr[1]}" > + > + echo "${container_dev}" "${container_start}" >> "$FULL" > + > + blkzone reset -o "${container_start}" -c 1 "${container_dev}" do we need to check the return value here ? > + > + if ! dd if=/dev/zero of="${container_dev}" bs="${bs}" \ > + count=$((4096 * (i + 1) / bs)) oflag=direct \ > + seek=$((container_start * 512 / bs)) \ > + >> "$FULL" 2>&1 ; then > + echo "dd failed" > + fi > + > + # Wait for partition table re-read event settles > + udevadm settle > + done > + > + # Check write pointer positions on the logical device > + _get_blkzone_report "${TEST_DEV}" || return $? > + for ((i=0; i < ${#test_z[@]}; i++)); do > + if ((ZONE_WPTRS[test_z[i]] != 8 * (i + 1))); then > + echo "Unexpected write pointer position" > + echo -n "zone=${i}, wp=${ZONE_WPTRS[i]}, " > + echo "dev=${TEST_DEV}" > + fi > + echo "${ZONE_WPTRS[${test_z[i]}]}" >> "$FULL" > + done > + _put_blkzone_report > + > + echo "Test complete" > +} > diff --git a/tests/zbd/007.out b/tests/zbd/007.out > new file mode 100644 > index 0000000..28a1395 > --- /dev/null > +++ b/tests/zbd/007.out > @@ -0,0 +1,2 @@ > +Running zbd/007 > +Test complete > diff --git a/tests/zbd/rc b/tests/zbd/rc > index 5f04c84..1168c4e 100644 For rc related code changes can you please send a separate preparation patche ? It will be great if we can isolate the actual test from the rc changes. > --- a/tests/zbd/rc > +++ b/tests/zbd/rc > @@ -193,6 +193,42 @@ _find_first_sequential_zone() { > return 1 > } > > +_find_last_sequential_zone() { > + for ((idx = REPORTED_COUNT - 1; idx > 0; idx--)); do > + if ((ZONE_TYPES[idx] == ZONE_TYPE_SEQ_WRITE_REQUIRED)); then > + echo "${idx}" > + return 0 > + fi > + done > + > + echo "-1" > + return 1 > +} > + > +# Try to find a sequential required zone between given two zone indices > +_find_sequential_zone_in_middle() { > + local -i s=${1} > + local -i e=${2} > + local -i idx=$(((s + e) / 2)) > + local -i i=1 > + > + while ((idx != s)) && ((idx != e)); do > + if ((ZONE_TYPES[idx] == ZONE_TYPE_SEQ_WRITE_REQUIRED)); then > + echo "${idx}" > + return 0 > + fi > + if ((i%2 == 0)); then > + : $((idx += i)) > + else > + : $((idx -= i)) > + fi > + : $((i++)) > + done > + > + echo "-1" > + return 1 > +} > + > # Search zones and find two contiguous sequential required zones. > # Return index of the first zone of the found two zones. > # Call _get_blkzone_report() beforehand. > @@ -210,3 +246,99 @@ _find_two_contiguous_seq_zones() { > echo "Contiguous sequential write required zones not found" > return 1 > } > + > +_test_dev_is_dm() { > + if [[ ! -r "${TEST_DEV_SYSFS}/dm/name" ]]; then > + SKIP_REASON="$TEST_DEV is not device-mapper" > + return 1 > + fi > + return 0 > +} > + > +_test_dev_is_logical() { > + if ! _test_dev_is_partition && ! _test_dev_is_dm; then > + SKIP_REASON="$TEST_DEV is not a logical device" > + return 1 > + fi > + return 0 > +} > + > +_test_dev_has_dm_map() { > + local target_type=${1} > + local dm_name nit:- new line after declaration. > + dm_name=$(cat "${TEST_DEV_SYSFS}/dm/name") > + if ! dmsetup status "${dm_name}" | grep -qe "${target_type}"; then > + SKIP_REASON="$TEST_DEV does not have ${target_type} map" > + return 1 > + fi > + if dmsetup status "${dm_name}" | grep -v "${target_type}"; then > + SKIP_REASON="$TEST_DEV has map other than ${target_type}" > + return 1 > + fi > + return 0 > +} > + > +# Get device file path from the device ID "major:minor". > +_get_dev_path_by_id() { > + for d in /sys/block/*; do > + if [[ ! -r "${d}/dev" ]]; then > + continue > + fi > + dev_id=$(cat "${d}/dev") > + if [[ "${1}" == "${dev_id}" ]]; then > + echo "/dev/${d##*/}" > + return 0 > + fi > + done > + return 1 > +} > + > +# Given sector of TEST_DEV, return the device which contain the sector and > +# corresponding sector of the container device. > +_get_dev_container_and_sector() { > + local -i sector=${1} > + local cont_dev > + local -i offset > + local -a tbl_line > + > + if _test_dev_is_partition; then > + offset=$(cat "${TEST_DEV_PART_SYSFS}/start") > + cont_dev=$(_get_dev_path_by_id "$(cat "${TEST_DEV_SYSFS}/dev")") > + echo "${cont_dev}" "$((offset + sector))" > + return 0 > + fi > + > + if ! _test_dev_is_dm; then > + echo "${TEST_DEV} is not a logical device" > + return 1 > + fi > + if ! _test_dev_has_dm_map linear && > + ! _test_dev_has_dm_map flakey; then > + echo -n "dm mapping test other than linear/flakey is" > + echo "not implemented" > + return 1 > + fi > + > + # Parse dm table lines for dm-linear or dm-flakey target > + while read -r -a tbl_line; do > + local -i map_start=${tbl_line[0]} > + local -i map_end=$((tbl_line[0] + tbl_line[1])) > + if ((sector < map_start)) || (((map_end) <= sector)); then > + continue > + fi > + > + offset=${tbl_line[4]} > + if ! cont_dev=$(_get_dev_path_by_id "${tbl_line[3]}"); then > + echo -n "Cannot access to container device: " > + echo "${tbl_line[3]}" > + return 1 > + fi > + > + echo "${cont_dev}" "$((offset + sector - map_start))" > + return 0 > + > + done < <(dmsetup table "$(cat "${TEST_DEV_SYSFS}/dm/name")") > + > + echo -n "Cannot find container device of ${TEST_DEV}" > + return 1 > +} >