diff --git a/autotest.sh b/autotest.sh index 8bdb8bb48..9a53db689 100755 --- a/autotest.sh +++ b/autotest.sh @@ -173,6 +173,9 @@ if [ $SPDK_RUN_FUNCTIONAL_TEST -eq 1 ]; then if [ $SPDK_TEST_BLOCKDEV -eq 1 ]; then run_test "blockdev_general" test/bdev/blockdev.sh run_test "bdev_raid" test/bdev/bdev_raid.sh + if [[ $(uname -s) == Linux ]]; then + run_test "spdk_dd" test/dd/dd.sh + fi fi if [ $SPDK_TEST_JSON -eq 1 ]; then diff --git a/test/dd/basic_rw.sh b/test/dd/basic_rw.sh new file mode 100755 index 000000000..5e9be5363 --- /dev/null +++ b/test/dd/basic_rw.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +testdir=$(readlink -f "$(dirname "$0")") +rootdir=$(readlink -f "$testdir/../../") +source "$testdir/common.sh" + +basic_rw() { + local native_bs=$1 + local count size + local qds bss + + qds=(1 64) + # Generate some bs for tests based on the native_bs + for bs in {0..4}; do + bss+=($((native_bs << bs))) + done + + for bs in "${bss[@]}"; do + for qd in "${qds[@]}"; do + count=$((0xffff / bs)) + count=$((count == 0 ? 1 : count)) + size=$((count * bs)) + + gen_bytes "$size" > "$test_file0" + + "${DD_APP[@]}" \ + --if="$test_file0" \ + --ob="$bdev0" \ + --bs="$bs" \ + --qd="$qd" \ + --json <(gen_conf) + + "${DD_APP[@]}" \ + --ib="$bdev0" \ + --of="$test_file1" \ + --bs="$bs" \ + --qd="$qd" \ + --count="$count" \ + --json <(gen_conf) + + diff -q "$test_file0" "$test_file1" + clear_nvme "$bdev0" "" "$size" + done + done +} + +basic_offset() { + # Check if offseting works - using default io size of 4k + local count seek skip data data_check + + gen_bytes 4096 > "$test_file0" + ((count = seek = skip = 1)) + data=$(< "$test_file0") + + "${DD_APP[@]}" \ + --if="$test_file0" \ + --ob="$bdev0" \ + --seek="$seek" \ + --json <(gen_conf) + + "${DD_APP[@]}" \ + --ib="$bdev0" \ + --of="$test_file1" \ + --skip="$skip" \ + --count="$count" \ + --json <(gen_conf) + + read -rn${#data} data_check < "$test_file1" + [[ $data == "$data_check" ]] +} + +plain_copy() { + # Test if copy between plain files works as well + "${DD_APP[@]}" --if="$test_file0" --of="$test_file1" + diff -q "$test_file0" "$test_file1" +} + +cleanup() { + clear_nvme "$bdev0" + rm -f "$test_file0" "$test_file1" +} + +trap "cleanup" EXIT + +nvmes=("$@") +nvme0=Nvme0 nvme0_pci=${nvmes[0]} bdev0=Nvme0n1 + +declare -A method_bdev_nvme_attach_controller_0=( + ["name"]=$nvme0 + ["traddr"]=$nvme0_pci + ["trtype"]=pcie +) + +test_file0=$SPDK_TEST_STORAGE/dd.dump0 +test_file1=$SPDK_TEST_STORAGE/dd.dump1 +native_bs=$(get_native_nvme_bs "$nvme0_pci") + +# Test if running with bs < native_bs successfully fails +run_test "dd_bs_lt_native_bs" \ + NOT "${DD_APP[@]}" \ + --if=<(:) \ + --ob="$bdev0" \ + --bs=$((native_bs >> 1)) \ + --json <(gen_conf) + +run_test "dd_rw" basic_rw "$native_bs" +run_test "dd_rw_offset" basic_offset +run_test "dd_rw_file_copy" plain_copy diff --git a/test/dd/common.sh b/test/dd/common.sh new file mode 100644 index 000000000..225578602 --- /dev/null +++ b/test/dd/common.sh @@ -0,0 +1,129 @@ +source "$rootdir/test/common/autotest_common.sh" +source "$rootdir/scripts/common.sh" + +clear_nvme() { + local bdev=$1 + local nvme_ref=$2 + local size=${3:-0xffff} + + local bs=$((1024 << 10)) # 1M + local count=$(((size / bs) + (size % bs ? 1 : 0))) + + "${DD_APP[@]}" \ + --if="/dev/zero" \ + --bs="$bs" \ + --ob="$bdev" \ + --count="$count" \ + --json <(gen_conf $nvme_ref) +} + +trunc_files() { + local f + for f; do : > "$f"; done +} + +gen_conf() { + xtrace_disable + + local ref_name + local method methods + local param params + local config + + # Pick references to all assoc arrays and build subsystem's config + # around them. The assoc array should be the name of the rpc method + # suffixed with unique _ID (ID may be any string). Default arrays + # should be prefixed with _method string. The keys of the array + # should store names of the method's parameters - proper quoting + # of the values is done here. extra_subsystems[] can store extra + # json configuration for different subsystems, other than bdev. + + methods=("${@:-${!method_@}}") + local IFS="," + + for ref_name in "${methods[@]}"; do + method=${ref_name#*method_} method=${method%_*} params=() + + # FIXME: centos7's Bash got trapped in 2011: + # local -n ref=$ref_name -> local: -n: invalid option + # HACK: it with eval and partial refs instead. + eval "local refs=(\${!${ref_name}[@]})" + local param_ref + + for param in "${refs[@]}"; do + param_ref="${ref_name}[$param]" + if [[ ${!param_ref} =~ ^([0-9]+|true|false|\{.*\})$ ]]; then + params+=("\"$param\": ${!param_ref}") + else + params+=("\"$param\": \"${!param_ref}\"") + fi + done + + config+=("$( + cat <<- JSON + { + "params": { + ${params[*]} + }, + "method": "$method" + } + JSON + )") + done + + jq . <<- JSON | tee /dev/stderr + { + "subsystems": [ + { + "subsystem": "bdev", + "config": [ + ${config[*]} + ] + } + ${extra_subsystems[*]:+,${extra_subsystems[*]}} + ] + } + JSON + + xtrace_restore +} + +gen_bytes() { + xtrace_disable + + local max=$1 + local bytes + local byte + local string + shift + + bytes=({a..z} {0..9}) + if (($#)); then + bytes=("$@") + fi + + for ((byte = 0; byte < max; byte++)); do + string+=${bytes[RANDOM % ${#bytes[@]}]} + done + printf '%b' "$string" + + xtrace_restore +} + +get_native_nvme_bs() { + # This is now needed since spdk_dd will reject all bs smaller than the + # native bs of given nvme. We need to make sure all tests are using + # bs >= native_bs. Use identify here so we don't have to switch nvmes + # between user space and the kernel back and forth. + local pci=$1 lbaf id + + mapfile -t id < <("$rootdir/build/examples/identify" -r trtype:pcie "traddr:$pci") + + # Get size of the current LBAF + [[ ${id[*]} =~ "Current LBA Format:"\ *"LBA Format #"([0-9]+) ]] + lbaf=${BASH_REMATCH[1]} + [[ ${id[*]} =~ "LBA Format #$lbaf: Data Size:"\ *([0-9]+) ]] + lbaf=${BASH_REMATCH[1]} + + echo "$lbaf" +} diff --git a/test/dd/dd.sh b/test/dd/dd.sh new file mode 100755 index 000000000..b7fc62d70 --- /dev/null +++ b/test/dd/dd.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +testdir=$(readlink -f "$(dirname "$0")") +rootdir=$(readlink -f "$testdir/../../") +source "$testdir/common.sh" + +"$rootdir/scripts/setup.sh" +nvmes=($(nvme_in_userspace)) + +run_test "spdk_dd_basic_rw" "$testdir/basic_rw.sh" "${nvmes[@]}"