diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/spdk/test/common | |
parent | Initial commit. (diff) | |
download | ceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/spdk/test/common')
-rw-r--r-- | src/spdk/test/common/applications.sh | 24 | ||||
-rwxr-xr-x | src/spdk/test/common/autotest_common.sh | 1350 | ||||
-rw-r--r-- | src/spdk/test/common/config/README.md | 104 | ||||
-rw-r--r-- | src/spdk/test/common/config/pkgdep/apt-get | 100 | ||||
-rw-r--r-- | src/spdk/test/common/config/pkgdep/dnf | 72 | ||||
-rw-r--r-- | src/spdk/test/common/config/pkgdep/git | 325 | ||||
-rw-r--r-- | src/spdk/test/common/config/pkgdep/pacman | 62 | ||||
-rw-r--r-- | src/spdk/test/common/config/pkgdep/pkg | 27 | ||||
-rw-r--r-- | src/spdk/test/common/config/pkgdep/swupd | 21 | ||||
-rw-r--r-- | src/spdk/test/common/config/pkgdep/yum | 67 | ||||
-rw-r--r-- | src/spdk/test/common/config/vm_setup.conf | 12 | ||||
-rwxr-xr-x | src/spdk/test/common/config/vm_setup.sh | 176 | ||||
-rw-r--r-- | src/spdk/test/common/lib/nvme/common_stubs.h | 117 | ||||
-rw-r--r-- | src/spdk/test/common/lib/test_env.c | 637 | ||||
-rw-r--r-- | src/spdk/test/common/lib/test_rdma.c | 49 | ||||
-rw-r--r-- | src/spdk/test/common/lib/test_sock.c | 70 | ||||
-rw-r--r-- | src/spdk/test/common/lib/ut_multithread.c | 214 | ||||
-rw-r--r-- | src/spdk/test/common/skipped_build_files.txt | 60 | ||||
-rw-r--r-- | src/spdk/test/common/skipped_tests.txt | 73 |
19 files changed, 3560 insertions, 0 deletions
diff --git a/src/spdk/test/common/applications.sh b/src/spdk/test/common/applications.sh new file mode 100644 index 000000000..041af2932 --- /dev/null +++ b/src/spdk/test/common/applications.sh @@ -0,0 +1,24 @@ +# Default set of apps used in functional testing + +_root=$(readlink -f "$(dirname "${BASH_SOURCE[0]}")") +_root=${_root%/test/common} +_app_dir=$_root/build/bin +_test_app_dir=$_root/test/app + +VHOST_FUZZ_APP=("$_test_app_dir/fuzz/vhost_fuzz/vhost_fuzz") +ISCSI_APP=("$_app_dir/iscsi_tgt") +NVMF_APP=("$_app_dir/nvmf_tgt") +VHOST_APP=("$_app_dir/vhost") +DD_APP=("$_app_dir/spdk_dd") + +# Check if apps should execute under debug flags +if [[ -e $_root/include/spdk/config.h ]]; then + if [[ $(< "$_root/include/spdk/config.h") == *"#define SPDK_CONFIG_DEBUG"* ]] \ + && ((SPDK_AUTOTEST_DEBUG_APPS)); then + VHOST_FUZZ_APP+=("--logflag=all") + ISCSI_APP+=("--logflag=all") + NVMF_APP+=("--logflag=all") + VHOST_APP+=("--logflag=all") + DD_APP+=("--logflag=all") + fi +fi diff --git a/src/spdk/test/common/autotest_common.sh b/src/spdk/test/common/autotest_common.sh new file mode 100755 index 000000000..32cd4e32a --- /dev/null +++ b/src/spdk/test/common/autotest_common.sh @@ -0,0 +1,1350 @@ +#!/usr/bin/env bash + +function xtrace_disable() { + if [ "$XTRACE_DISABLED" != "yes" ]; then + PREV_BASH_OPTS="$-" + if [[ "$PREV_BASH_OPTS" == *"x"* ]]; then + XTRACE_DISABLED="yes" + fi + set +x + elif [ -z $XTRACE_NESTING_LEVEL ]; then + XTRACE_NESTING_LEVEL=1 + else + XTRACE_NESTING_LEVEL=$((++XTRACE_NESTING_LEVEL)) + fi +} + +xtrace_disable +set -e +shopt -s expand_aliases + +source "$rootdir/test/common/applications.sh" +if [[ -e $rootdir/test/common/build_config.sh ]]; then + source "$rootdir/test/common/build_config.sh" +elif [[ -e $rootdir/mk/config.mk ]]; then + build_config=$(< "$rootdir/mk/config.mk") + source <(echo "${build_config//\?=/=}") +else + source "$rootdir/CONFIG" +fi + +# Dummy function to be called after restoring xtrace just so that it appears in the +# xtrace log. This way we can consistently track when xtrace is enabled/disabled. +function xtrace_enable() { + # We have to do something inside a function in bash, and calling any command + # (even `:`) will produce an xtrace entry, so we just define another function. + function xtrace_dummy() { :; } +} + +# Keep it as alias to avoid xtrace_enable backtrace always pointing to xtrace_restore. +# xtrace_enable will appear as called directly from the user script, from the same line +# that "called" xtrace_restore. +alias xtrace_restore='if [ -z $XTRACE_NESTING_LEVEL ]; then + if [[ "$PREV_BASH_OPTS" == *"x"* ]]; then + XTRACE_DISABLED="no"; PREV_BASH_OPTS=""; set -x; xtrace_enable; + fi +else + XTRACE_NESTING_LEVEL=$((--XTRACE_NESTING_LEVEL)); + if [ $XTRACE_NESTING_LEVEL -eq "0" ]; then + unset XTRACE_NESTING_LEVEL + fi +fi' + +: ${RUN_NIGHTLY:=0} +export RUN_NIGHTLY + +# Set defaults for missing test config options +: ${SPDK_AUTOTEST_DEBUG_APPS:=0} +export SPDK_AUTOTEST_DEBUG_APPS +: ${SPDK_RUN_VALGRIND=0} +export SPDK_RUN_VALGRIND +: ${SPDK_RUN_FUNCTIONAL_TEST=0} +export SPDK_RUN_FUNCTIONAL_TEST +: ${SPDK_TEST_UNITTEST=0} +export SPDK_TEST_UNITTEST +: ${SPDK_TEST_AUTOBUILD=0} +export SPDK_TEST_AUTOBUILD +: ${SPDK_TEST_ISAL=0} +export SPDK_TEST_ISAL +: ${SPDK_TEST_ISCSI=0} +export SPDK_TEST_ISCSI +: ${SPDK_TEST_ISCSI_INITIATOR=0} +export SPDK_TEST_ISCSI_INITIATOR +: ${SPDK_TEST_NVME=0} +export SPDK_TEST_NVME +: ${SPDK_TEST_NVME_CLI=0} +export SPDK_TEST_NVME_CLI +: ${SPDK_TEST_NVME_CUSE=0} +export SPDK_TEST_NVME_CUSE +: ${SPDK_TEST_NVMF=0} +export SPDK_TEST_NVMF +: ${SPDK_TEST_NVMF_TRANSPORT="rdma"} +export SPDK_TEST_NVMF_TRANSPORT +: ${SPDK_TEST_RBD=0} +export SPDK_TEST_RBD +: ${SPDK_TEST_VHOST=0} +export SPDK_TEST_VHOST +: ${SPDK_TEST_BLOCKDEV=0} +export SPDK_TEST_BLOCKDEV +: ${SPDK_TEST_IOAT=0} +export SPDK_TEST_IOAT +: ${SPDK_TEST_BLOBFS=0} +export SPDK_TEST_BLOBFS +: ${SPDK_TEST_VHOST_INIT=0} +export SPDK_TEST_VHOST_INIT +: ${SPDK_TEST_PMDK=0} +export SPDK_TEST_PMDK +: ${SPDK_TEST_LVOL=0} +export SPDK_TEST_LVOL +: ${SPDK_TEST_JSON=0} +export SPDK_TEST_JSON +: ${SPDK_TEST_REDUCE=0} +export SPDK_TEST_REDUCE +: ${SPDK_TEST_VPP=0} +export SPDK_TEST_VPP +: ${SPDK_RUN_ASAN=0} +export SPDK_RUN_ASAN +: ${SPDK_RUN_UBSAN=0} +export SPDK_RUN_UBSAN +: ${SPDK_RUN_INSTALLED_DPDK=0} +export SPDK_RUN_INSTALLED_DPDK +: ${SPDK_RUN_NON_ROOT=0} +export SPDK_RUN_NON_ROOT +: ${SPDK_TEST_CRYPTO=0} +export SPDK_TEST_CRYPTO +: ${SPDK_TEST_FTL=0} +export SPDK_TEST_FTL +: ${SPDK_TEST_OCF=0} +export SPDK_TEST_OCF +: ${SPDK_TEST_FTL_EXTENDED=0} +export SPDK_TEST_FTL_EXTENDED +: ${SPDK_TEST_VMD=0} +export SPDK_TEST_VMD +: ${SPDK_TEST_OPAL=0} +export SPDK_TEST_OPAL +: ${SPDK_AUTOTEST_X=true} +export SPDK_AUTOTEST_X +: ${SPDK_TEST_RAID5=0} +export SPDK_TEST_RAID5 +: ${SPDK_TEST_URING=0} +export SPDK_TEST_URING + +# Export PYTHONPATH with addition of RPC framework. New scripts can be created +# specific use cases for tests. +export PYTHONPATH=$PYTHONPATH:$rootdir/scripts + +# Don't create Python .pyc files. When running with sudo these will be +# created with root ownership and can cause problems when cleaning the repository. +export PYTHONDONTWRITEBYTECODE=1 + +# Export flag to skip the known bug that exists in librados +# Bug is reported on ceph bug tracker with number 24078 +export ASAN_OPTIONS=new_delete_type_mismatch=0 +export UBSAN_OPTIONS='halt_on_error=1:print_stacktrace=1:abort_on_error=1' + +# Export LeakSanitizer option to use suppression file in order to prevent false positives +# and known leaks in external executables or libraries from showing up. +asan_suppression_file="/var/tmp/asan_suppression_file" +sudo rm -rf "$asan_suppression_file" +cat << EOL >> "$asan_suppression_file" +# ASAN has some bugs around thread_local variables. We have a destructor in place +# to free the thread contexts, but ASAN complains about the leak before those +# destructors have a chance to run. So suppress this one specific leak using +# LSAN_OPTIONS. +leak:spdk_fs_alloc_thread_ctx + +# Suppress known leaks in fio project +leak:$CONFIG_FIO_SOURCE_DIR/parse.c +leak:$CONFIG_FIO_SOURCE_DIR/iolog.c +leak:$CONFIG_FIO_SOURCE_DIR/init.c +leak:$CONFIG_FIO_SOURCE_DIR/filesetup.c +leak:fio_memalign +leak:spdk_fio_io_u_init + +# Suppress leaks in libiscsi +leak:libiscsi.so +EOL + +# Suppress leaks in libfuse3 +echo "leak:libfuse3.so" >> "$asan_suppression_file" + +export LSAN_OPTIONS=suppressions="$asan_suppression_file" + +export DEFAULT_RPC_ADDR="/var/tmp/spdk.sock" + +if [ -z "$DEPENDENCY_DIR" ]; then + export DEPENDENCY_DIR=/home/sys_sgsw +else + export DEPENDENCY_DIR +fi + +# Export location of where all the SPDK binaries are +export SPDK_BIN_DIR="$rootdir/build/bin" +export SPDK_EXAMPLE_DIR="$rootdir/build/examples" + +# pass our valgrind desire on to unittest.sh +if [ $SPDK_RUN_VALGRIND -eq 0 ]; then + export valgrind='' +fi + +if [ "$(uname -s)" = "Linux" ]; then + MAKE="make" + MAKEFLAGS=${MAKEFLAGS:--j$(nproc)} + DPDK_LINUX_DIR=/usr/share/dpdk/x86_64-default-linuxapp-gcc + if [ -d $DPDK_LINUX_DIR ] && [ $SPDK_RUN_INSTALLED_DPDK -eq 1 ]; then + WITH_DPDK_DIR=$DPDK_LINUX_DIR + fi + # Override the default HUGEMEM in scripts/setup.sh to allocate 8GB in hugepages. + export HUGEMEM=8192 +elif [ "$(uname -s)" = "FreeBSD" ]; then + MAKE="gmake" + MAKEFLAGS=${MAKEFLAGS:--j$(sysctl -a | grep -E -i 'hw.ncpu' | awk '{print $2}')} + DPDK_FREEBSD_DIR=/usr/local/share/dpdk/x86_64-native-bsdapp-clang + if [ -d $DPDK_FREEBSD_DIR ] && [ $SPDK_RUN_INSTALLED_DPDK -eq 1 ]; then + WITH_DPDK_DIR=$DPDK_FREEBSD_DIR + fi + # FreeBSD runs a much more limited set of tests, so keep the default 2GB. + export HUGEMEM=2048 +else + echo "Unknown OS \"$(uname -s)\"" + exit 1 +fi + +if [ -z "$output_dir" ]; then + if [ -z "$rootdir" ] || [ ! -d "$rootdir/../output" ]; then + output_dir=. + else + output_dir=$rootdir/../output + fi + export output_dir +fi + +TEST_MODE= +for i in "$@"; do + case "$i" in + --iso) + TEST_MODE=iso + ;; + --transport=*) + TEST_TRANSPORT="${i#*=}" + ;; + --sock=*) + TEST_SOCK="${i#*=}" + ;; + esac +done + +# start rpc.py coprocess if it's not started yet +if [[ -z $RPC_PIPE_PID ]] || ! kill -0 "$RPC_PIPE_PID" &> /dev/null; then + coproc RPC_PIPE { "$rootdir/scripts/rpc.py" --server; } + exec {RPC_PIPE_OUTPUT}<&${RPC_PIPE[0]} {RPC_PIPE_INPUT}>&${RPC_PIPE[1]} + # all descriptors will automatically close together with this bash + # process, this will make rpc.py stop reading and exit gracefully +fi + +if [ $SPDK_TEST_VPP -eq 1 ]; then + VPP_PATH="/usr/local/src/vpp-19.04/build-root/install-vpp_debug-native/vpp/" + export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${VPP_PATH}/lib/ + export PATH=${PATH}:${VPP_PATH}/bin/ +fi + +function set_test_storage() { + [[ -v testdir ]] || return 0 + + local requested_size=$1 # bytes + local mount target_dir + + local -A mounts fss sizes avails uses + local source fs size avail mount use + + local storage_fallback storage_candidates + local storage_fallback_purge + + storage_fallback_purge=("${TMPDIR:-/tmp}/spdk."??????) + + if ((${#storage_fallback_purge[@]} > 0)); then + printf '* Purging old temporary test storage (%s)\n' \ + "${storage_fallback_purge[*]}" >&2 + rm -rf "${storage_fallback_purge[@]}" + fi + + storage_fallback=$(mktemp -udt spdk.XXXXXX) + storage_candidates=( + "$testdir" + "$storage_fallback/tests/${testdir##*/}" + "$storage_fallback" + ) + + if [[ -n $ADD_TEST_STORAGE ]]; then + # List of dirs|mounts separated by whitespaces + storage_candidates+=($ADD_TEST_STORAGE) + fi + + if [[ -n $DEDICATED_TEST_STORAGE ]]; then + # Single, dedicated dir|mount + storage_candidates=("$DEDICATED_TEST_STORAGE") + fi + + mkdir -p "${storage_candidates[@]}" + + # add some headroom - 64M + requested_size=$((requested_size + (64 << 20))) + + while read -r source fs size use avail _ mount; do + mounts["$mount"]=$source fss["$mount"]=$fs + avails["$mount"]=$((avail * 1024)) sizes["$mount"]=$((size * 1024)) + uses["$mount"]=$((use * 1024)) + done < <(df -T | grep -v Filesystem) + + printf '* Looking for test storage...\n' >&2 + + local target_space new_size + for target_dir in "${storage_candidates[@]}"; do + # FreeBSD's df is lacking the --output arg + # mount=$(df --output=target "$target_dir" | grep -v "Mounted on") + mount=$(df "$target_dir" | awk '$1 !~ /Filesystem/{print $6}') + + target_space=${avails["$mount"]} + if ((target_space == 0 || target_space < requested_size)); then + continue + fi + if ((target_space >= requested_size)); then + # For in-memory fs, and / make sure our requested size won't fill most of the space. + if [[ ${fss["$mount"]} == tmpfs ]] || [[ ${fss["$mount"]} == ramfs ]] || [[ $mount == / ]]; then + new_size=$((uses["$mount"] + requested_size)) + if ((new_size * 100 / sizes["$mount"] > 95)); then + continue + fi + fi + fi + export SPDK_TEST_STORAGE=$target_dir + printf '* Found test storage at %s\n' "$SPDK_TEST_STORAGE" >&2 + return 0 + done + printf '* Test storage is not available\n' + return 1 +} + +function get_config_params() { + xtrace_disable + config_params='--enable-debug --enable-werror' + + # for options with dependencies but no test flag, set them here + if [ -f /usr/include/infiniband/verbs.h ]; then + config_params+=' --with-rdma' + fi + + if [ $(uname -s) == "FreeBSD" ]; then + intel="hw.model: Intel" + cpu_vendor=$(sysctl -a | grep hw.model | cut -c 1-15) + else + intel="GenuineIntel" + cpu_vendor=$(grep -i 'vendor' /proc/cpuinfo --max-count=1) + fi + if [[ "$cpu_vendor" != *"$intel"* ]]; then + config_params+=" --without-idxd" + else + config_params+=" --with-idxd" + fi + + if [[ -d $CONFIG_FIO_SOURCE_DIR ]]; then + config_params+=" --with-fio=$CONFIG_FIO_SOURCE_DIR" + fi + + if [ -d ${DEPENDENCY_DIR}/vtune_codes ]; then + config_params+=' --with-vtune='${DEPENDENCY_DIR}'/vtune_codes' + fi + + if [ -d /usr/include/iscsi ]; then + libiscsi_version=$(grep LIBISCSI_API_VERSION /usr/include/iscsi/iscsi.h | head -1 | awk '{print $3}' | awk -F '(' '{print $2}' | awk -F ')' '{print $1}') + if [ $libiscsi_version -ge 20150621 ]; then + config_params+=' --with-iscsi-initiator' + fi + fi + + if [ $SPDK_TEST_UNITTEST -eq 0 ]; then + config_params+=' --disable-unit-tests' + fi + + if [ $SPDK_TEST_NVME_CUSE -eq 1 ]; then + config_params+=' --with-nvme-cuse' + fi + + # for options with both dependencies and a test flag, set them here + if [ -f /usr/include/libpmemblk.h ] && [ $SPDK_TEST_PMDK -eq 1 ]; then + config_params+=' --with-pmdk' + fi + + if [ -f /usr/include/libpmem.h ] && [ $SPDK_TEST_REDUCE -eq 1 ]; then + if [ $SPDK_TEST_ISAL -eq 1 ]; then + config_params+=' --with-reduce' + fi + fi + + if [ -d /usr/include/rbd ] && [ -d /usr/include/rados ] && [ $SPDK_TEST_RBD -eq 1 ]; then + config_params+=' --with-rbd' + fi + + if [ $SPDK_TEST_VPP -eq 1 ]; then + config_params+=" --with-vpp=${VPP_PATH}" + fi + + # for options with no required dependencies, just test flags, set them here + if [ $SPDK_TEST_CRYPTO -eq 1 ]; then + config_params+=' --with-crypto' + fi + + if [ $SPDK_TEST_OCF -eq 1 ]; then + config_params+=" --with-ocf" + fi + + if [ $SPDK_RUN_UBSAN -eq 1 ]; then + config_params+=' --enable-ubsan' + fi + + if [ $SPDK_RUN_ASAN -eq 1 ]; then + config_params+=' --enable-asan' + fi + + if [ "$(uname -s)" = "Linux" ]; then + config_params+=' --enable-coverage' + fi + + if [ $SPDK_TEST_ISAL -eq 0 ]; then + config_params+=' --without-isal' + fi + + if [ $SPDK_TEST_BLOBFS -eq 1 ]; then + if [[ -d /usr/include/fuse3 ]] || [[ -d /usr/local/include/fuse3 ]]; then + config_params+=' --with-fuse' + fi + fi + + if [ $SPDK_TEST_RAID5 -eq 1 ]; then + config_params+=' --with-raid5' + fi + + # Check whether liburing library header exists + if [ -f /usr/include/liburing/io_uring.h ] && [ $SPDK_TEST_URING -eq 1 ]; then + config_params+=' --with-uring' + fi + + # By default, --with-dpdk is not set meaning the SPDK build will use the DPDK submodule. + # If a DPDK installation is found in a well-known location though, WITH_DPDK_DIR will be + # set which will override the default and use that DPDK installation instead. + if [ -n "$WITH_DPDK_DIR" ]; then + config_params+=" --with-dpdk=$WITH_DPDK_DIR" + fi + + echo "$config_params" + xtrace_restore +} + +function rpc_cmd() { + xtrace_disable + local rsp rc + + echo "$@" >&$RPC_PIPE_INPUT + while read -t 5 -ru $RPC_PIPE_OUTPUT rsp; do + if [[ $rsp == "**STATUS="* ]]; then + break + fi + echo "$rsp" + done + + rc=${rsp#*=} + xtrace_restore + [[ $rc == 0 ]] +} + +function rpc_cmd_simple_data_json() { + + local elems="$1[@]" elem + local -gA jq_out=() + local jq val + + local lvs=( + "uuid" + "name" + "base_bdev" + "total_data_clusters" + "free_clusters" + "block_size" + "cluster_size" + ) + + local bdev=( + "name" + "aliases[0]" + "block_size" + "num_blocks" + "uuid" + "product_name" + ) + + [[ -v $elems ]] || return 1 + + for elem in "${!elems}"; do + jq="${jq:+$jq,\"\\n\",}\"$elem\",\" \",.[0].$elem" + done + jq+=',"\n"' + + shift + while read -r elem val; do + jq_out["$elem"]=$val + done < <(rpc_cmd "$@" | jq -jr "$jq") + ((${#jq_out[@]} > 0)) || return 1 +} + +# invert error code of any command and also trigger ERR on 0 (unlike bash ! prefix) +function NOT() { + if "$@"; then + return 1 + fi +} + +function timing() { + direction="$1" + testname="$2" + + now=$(date +%s) + + if [ "$direction" = "enter" ]; then + export timing_stack="${timing_stack};${now}" + export test_stack="${test_stack};${testname}" + else + touch "$output_dir/timing.txt" + child_time=$(grep "^${test_stack:1};" $output_dir/timing.txt | awk '{s+=$2} END {print s}') + + start_time=$(echo "$timing_stack" | sed -e 's@^.*;@@') + timing_stack=$(echo "$timing_stack" | sed -e 's@;[^;]*$@@') + + elapsed=$((now - start_time - child_time)) + echo "${test_stack:1} $elapsed" >> $output_dir/timing.txt + + test_stack=$(echo "$test_stack" | sed -e 's@;[^;]*$@@') + fi +} + +function timing_enter() { + xtrace_disable + timing "enter" "$1" + xtrace_restore +} + +function timing_exit() { + xtrace_disable + timing "exit" "$1" + xtrace_restore +} + +function timing_finish() { + flamegraph='/usr/local/FlameGraph/flamegraph.pl' + if [ -x "$flamegraph" ]; then + "$flamegraph" \ + --title 'Build Timing' \ + --nametype 'Step:' \ + --countname seconds \ + $output_dir/timing.txt \ + > $output_dir/timing.svg + fi +} + +function create_test_list() { + xtrace_disable + # First search all scripts in main SPDK directory. + completion=$(grep -shI -d skip --include="*.sh" -e "run_test " $rootdir/*) + # Follow up with search in test directory recursively. + completion+=$(grep -rshI --include="*.sh" --exclude="autotest_common.sh" -e "run_test " $rootdir/test) + printf "%s" "$completion" | grep -v "#" \ + | sed 's/^.*run_test/run_test/' | awk '{print $2}' \ + | sed 's/\"//g' | sort > $output_dir/all_tests.txt || true + xtrace_restore +} + +function gdb_attach() { + gdb -q --batch \ + -ex 'handle SIGHUP nostop pass' \ + -ex 'handle SIGQUIT nostop pass' \ + -ex 'handle SIGPIPE nostop pass' \ + -ex 'handle SIGALRM nostop pass' \ + -ex 'handle SIGTERM nostop pass' \ + -ex 'handle SIGUSR1 nostop pass' \ + -ex 'handle SIGUSR2 nostop pass' \ + -ex 'handle SIGCHLD nostop pass' \ + -ex 'set print thread-events off' \ + -ex 'cont' \ + -ex 'thread apply all bt' \ + -ex 'quit' \ + --tty=/dev/stdout \ + -p $1 +} + +function process_core() { + ret=0 + while IFS= read -r -d '' core; do + exe=$(eu-readelf -n "$core" | grep psargs | sed "s/.*psargs: \([^ \'\" ]*\).*/\1/") + if [[ ! -f "$exe" ]]; then + exe=$(eu-readelf -n "$core" | grep -oP -m1 "$exe.+") + fi + echo "exe for $core is $exe" + if [[ -n "$exe" ]]; then + if hash gdb &> /dev/null; then + gdb -batch -ex "thread apply all bt full" $exe $core + fi + cp $exe $output_dir + fi + mv $core $output_dir + chmod a+r $output_dir/$core + ret=1 + done < <(find . -type f \( -name 'core\.?[0-9]*' -o -name '*.core' \) -print0) + return $ret +} + +function process_shm() { + type=$1 + id=$2 + if [ "$type" = "--pid" ]; then + id="pid${id}" + elif [ "$type" = "--id" ]; then + id="${id}" + else + echo "Please specify to search for pid or shared memory id." + return 1 + fi + + shm_files=$(find /dev/shm -name "*.${id}" -printf "%f\n") + + if [[ -z $shm_files ]]; then + echo "SHM File for specified PID or shared memory id: ${id} not found!" + return 1 + fi + for n in $shm_files; do + tar -C /dev/shm/ -cvzf $output_dir/${n}_shm.tar.gz ${n} + done + return 0 +} + +function waitforlisten() { + # $1 = process pid + if [ -z "$1" ]; then + exit 1 + fi + + local rpc_addr="${2:-$DEFAULT_RPC_ADDR}" + + echo "Waiting for process to start up and listen on UNIX domain socket $rpc_addr..." + # turn off trace for this loop + xtrace_disable + local ret=0 + local i + for ((i = 40; i != 0; i--)); do + # if the process is no longer running, then exit the script + # since it means the application crashed + if ! kill -s 0 $1; then + echo "ERROR: process (pid: $1) is no longer running" + ret=1 + break + fi + + if $rootdir/scripts/rpc.py -t 1 -s "$rpc_addr" rpc_get_methods &> /dev/null; then + break + fi + + sleep 0.5 + done + + xtrace_restore + if ((i == 0)); then + echo "ERROR: timeout while waiting for process (pid: $1) to start listening on '$rpc_addr'" + ret=1 + fi + return $ret +} + +function waitfornbd() { + local nbd_name=$1 + local i + + for ((i = 1; i <= 20; i++)); do + if grep -q -w $nbd_name /proc/partitions; then + break + else + sleep 0.1 + fi + done + + # The nbd device is now recognized as a block device, but there can be + # a small delay before we can start I/O to that block device. So loop + # here trying to read the first block of the nbd block device to a temp + # file. Note that dd returns success when reading an empty file, so we + # need to check the size of the output file instead. + for ((i = 1; i <= 20; i++)); do + dd if=/dev/$nbd_name of="$SPDK_TEST_STORAGE/nbdtest" bs=4096 count=1 iflag=direct + size=$(stat -c %s "$SPDK_TEST_STORAGE/nbdtest") + rm -f "$SPDK_TEST_STORAGE/nbdtest" + if [ "$size" != "0" ]; then + return 0 + else + sleep 0.1 + fi + done + + return 1 +} + +function waitforbdev() { + local bdev_name=$1 + local i + + for ((i = 1; i <= 20; i++)); do + if $rpc_py bdev_get_bdevs | jq -r '.[] .name' | grep -qw $bdev_name; then + return 0 + fi + + if $rpc_py bdev_get_bdevs | jq -r '.[] .aliases' | grep -qw $bdev_name; then + return 0 + fi + + sleep 0.1 + done + + return 1 +} + +function make_filesystem() { + local fstype=$1 + local dev_name=$2 + local i=0 + local force + + if [ $fstype = ext4 ]; then + force=-F + else + force=-f + fi + + while ! mkfs.${fstype} $force ${dev_name}; do + if [ $i -ge 15 ]; then + return 1 + fi + i=$((i + 1)) + sleep 1 + done + + return 0 +} + +function killprocess() { + # $1 = process pid + if [ -z "$1" ]; then + exit 1 + fi + + if kill -0 $1; then + if [ $(uname) = Linux ]; then + process_name=$(ps --no-headers -o comm= $1) + else + process_name=$(ps -c -o command $1 | tail -1) + fi + if [ "$process_name" = "sudo" ]; then + # kill the child process, which is the actual app + # (assume $1 has just one child) + local child + child="$(pgrep -P $1)" + echo "killing process with pid $child" + kill $child + else + echo "killing process with pid $1" + kill $1 + fi + + # wait for the process regardless if its the dummy sudo one + # or the actual app - it should terminate anyway + wait $1 + else + # the process is not there anymore + echo "Process with pid $1 is not found" + exit 1 + fi +} + +function iscsicleanup() { + echo "Cleaning up iSCSI connection" + iscsiadm -m node --logout || true + iscsiadm -m node -o delete || true + rm -rf /var/lib/iscsi/nodes/* +} + +function stop_iscsi_service() { + if cat /etc/*-release | grep Ubuntu; then + service open-iscsi stop + else + service iscsid stop + fi +} + +function start_iscsi_service() { + if cat /etc/*-release | grep Ubuntu; then + service open-iscsi start + else + service iscsid start + fi +} + +function rbd_setup() { + # $1 = monitor ip address + # $2 = name of the namespace + if [ -z "$1" ]; then + echo "No monitor IP address provided for ceph" + exit 1 + fi + if [ -n "$2" ]; then + if ip netns list | grep "$2"; then + NS_CMD="ip netns exec $2" + else + echo "No namespace $2 exists" + exit 1 + fi + fi + + if hash ceph; then + export PG_NUM=128 + export RBD_POOL=rbd + export RBD_NAME=foo + $NS_CMD $rootdir/scripts/ceph/stop.sh || true + $NS_CMD $rootdir/scripts/ceph/start.sh $1 + + $NS_CMD ceph osd pool create $RBD_POOL $PG_NUM || true + $NS_CMD rbd create $RBD_NAME --size 1000 + fi +} + +function rbd_cleanup() { + if hash ceph; then + $rootdir/scripts/ceph/stop.sh || true + rm -f /var/tmp/ceph_raw.img + fi +} + +function nvme_cli_build() { + if [[ -z "${DEPENDENCY_DIR}" ]]; then + echo DEPENDENCY_DIR not defined! + exit 1 + fi + + spdk_nvme_cli="${DEPENDENCY_DIR}/nvme-cli" + + if [[ ! -d $spdk_nvme_cli ]]; then + echo "nvme-cli repository not found at $spdk_nvme_cli; skipping tests." + exit 1 + fi + + if ! grep -q "DEF_VER=v1.6" $spdk_nvme_cli/NVME-VERSION-GEN; then + echo "SPDK supports only \"spdk/nvme-cli\" project on \"spdk-1.6\" branch." + exit 1 + fi + + # Build against the version of SPDK under test + pushd $spdk_nvme_cli + + # Remove and recreate git index in case it became corrupted + if ! git clean -dfx; then + rm -f .git/index + git clean -dfx + git reset --hard + fi + + rm -f "$spdk_nvme_cli/spdk" + ln -sf "$rootdir" "$spdk_nvme_cli/spdk" + + make -j$(nproc) LDFLAGS="$(make -s -C $spdk_nvme_cli/spdk ldflags)" + popd +} + +function _start_stub() { + # Disable ASLR for multi-process testing. SPDK does support using DPDK multi-process, + # but ASLR can still be unreliable in some cases. + # We will reenable it again after multi-process testing is complete in kill_stub(). + # Save current setting so it can be restored upon calling kill_stub(). + _randomize_va_space=$(< /proc/sys/kernel/randomize_va_space) + echo 0 > /proc/sys/kernel/randomize_va_space + $rootdir/test/app/stub/stub $1 & + stubpid=$! + echo Waiting for stub to ready for secondary processes... + while ! [ -e /var/run/spdk_stub0 ]; do + # If stub dies while we wait, bail + [[ -e /proc/$stubpid ]] || return 1 + sleep 1s + done + echo done. +} + +function start_stub() { + if ! _start_stub "$@"; then + echo "stub failed" >&2 + return 1 + fi +} + +function kill_stub() { + if [[ -e /proc/$stubpid ]]; then + kill $1 $stubpid + wait $stubpid + fi 2> /dev/null || : + rm -f /var/run/spdk_stub0 + # Re-enable ASLR now that we are done with multi-process testing + # Note: "1" enables ASLR w/o randomizing data segments, "2" adds data segment + # randomizing and is the default on all recent Linux kernels + echo "${_randomize_va_space:-2}" > /proc/sys/kernel/randomize_va_space +} + +function run_test() { + if [ $# -le 1 ]; then + echo "Not enough parameters" + echo "usage: run_test test_name test_script [script_params]" + exit 1 + fi + + xtrace_disable + local test_name="$1" + shift + + if [ -n "$test_domain" ]; then + export test_domain="${test_domain}.${test_name}" + else + export test_domain="$test_name" + fi + + timing_enter $test_name + echo "************************************" + echo "START TEST $test_name" + echo "************************************" + xtrace_restore + time "$@" + xtrace_disable + echo "************************************" + echo "END TEST $test_name" + echo "************************************" + timing_exit $test_name + + export test_domain=${test_domain%"$test_name"} + if [ -n "$test_domain" ]; then + export test_domain=${test_domain%?} + fi + + if [ -z "$test_domain" ]; then + echo "top_level $test_name" >> $output_dir/test_completions.txt + else + echo "$test_domain $test_name" >> $output_dir/test_completions.txt + fi + xtrace_restore +} + +function skip_run_test_with_warning() { + echo "WARNING: $1" + echo "Test run may fail if run with autorun.sh" + echo "Please check your $rootdir/test/common/skipped_tests.txt" +} + +function print_backtrace() { + # if errexit is not enabled, don't print a backtrace + [[ "$-" =~ e ]] || return 0 + + local args=("${BASH_ARGV[@]}") + + xtrace_disable + echo "========== Backtrace start: ==========" + echo "" + for i in $(seq 1 $((${#FUNCNAME[@]} - 1))); do + local func="${FUNCNAME[$i]}" + local line_nr="${BASH_LINENO[$((i - 1))]}" + local src="${BASH_SOURCE[$i]}" + local bt="" cmdline=() + + if [[ -f $src ]]; then + bt=$(nl -w 4 -ba -nln $src | grep -B 5 -A 5 "^${line_nr}[^0-9]" \ + | sed "s/^/ /g" | sed "s/^ $line_nr /=> $line_nr /g") + fi + + # If extdebug set the BASH_ARGC[i], try to fetch all the args + if ((BASH_ARGC[i] > 0)); then + # Use argc as index to reverse the stack + local argc=${BASH_ARGC[i]} arg + for arg in "${args[@]::BASH_ARGC[i]}"; do + cmdline[argc--]="[\"$arg\"]" + done + args=("${args[@]:BASH_ARGC[i]}") + fi + + echo "in $src:$line_nr -> $func($( + IFS="," + printf '%s\n' "${cmdline[*]:-[]}" + ))" + echo " ..." + echo "${bt:-backtrace unavailable}" + echo " ..." + done + echo "" + echo "========== Backtrace end ==========" + xtrace_restore + return 0 +} + +function waitforserial() { + local i=0 + local nvme_device_counter=1 + if [[ -n "$2" ]]; then + nvme_device_counter=$2 + fi + + while [ $(lsblk -l -o NAME,SERIAL | grep -c $1) -lt $nvme_device_counter ]; do + [ $i -lt 15 ] || break + i=$((i + 1)) + echo "Waiting for devices" + sleep 1 + done + + if [[ $(lsblk -l -o NAME,SERIAL | grep -c $1) -lt $nvme_device_counter ]]; then + return 1 + fi + + return 0 +} + +function waitforserial_disconnect() { + local i=0 + while lsblk -o NAME,SERIAL | grep -q -w $1; do + [ $i -lt 15 ] || break + i=$((i + 1)) + echo "Waiting for disconnect devices" + sleep 1 + done + + if lsblk -l -o NAME | grep -q -w $1; then + return 1 + fi + + return 0 +} + +function waitforblk() { + local i=0 + while ! lsblk -l -o NAME | grep -q -w $1; do + [ $i -lt 15 ] || break + i=$((i + 1)) + sleep 1 + done + + if ! lsblk -l -o NAME | grep -q -w $1; then + return 1 + fi + + return 0 +} + +function waitforblk_disconnect() { + local i=0 + while lsblk -l -o NAME | grep -q -w $1; do + [ $i -lt 15 ] || break + i=$((i + 1)) + sleep 1 + done + + if lsblk -l -o NAME | grep -q -w $1; then + return 1 + fi + + return 0 +} + +function waitforfile() { + local i=0 + while [ ! -e $1 ]; do + [ $i -lt 200 ] || break + i=$((i + 1)) + sleep 0.1 + done + + if [ ! -e $1 ]; then + return 1 + fi + + return 0 +} + +function fio_config_gen() { + local config_file=$1 + local workload=$2 + local bdev_type=$3 + local fio_dir=$CONFIG_FIO_SOURCE_DIR + + if [ -e "$config_file" ]; then + echo "Configuration File Already Exists!: $config_file" + return 1 + fi + + if [ -z "$workload" ]; then + workload=randrw + fi + + touch $1 + + cat > $1 << EOL +[global] +thread=1 +group_reporting=1 +direct=1 +norandommap=1 +percentile_list=50:99:99.9:99.99:99.999 +time_based=1 +ramp_time=0 +EOL + + if [ "$workload" == "verify" ]; then + cat <<- EOL >> $config_file + verify=sha1 + verify_backlog=1024 + rw=randwrite + EOL + + # To avoid potential data race issue due to the AIO device + # flush mechanism, add the flag to serialize the writes. + # This is to fix the intermittent IO failure issue of #935 + if [ "$bdev_type" == "AIO" ]; then + if [[ $($fio_dir/fio --version) == *"fio-3"* ]]; then + echo "serialize_overlap=1" >> $config_file + fi + fi + elif [ "$workload" == "trim" ]; then + echo "rw=trimwrite" >> $config_file + else + echo "rw=$workload" >> $config_file + fi +} + +function fio_bdev() { + # Setup fio binary cmd line + local fio_dir=$CONFIG_FIO_SOURCE_DIR + local bdev_plugin="$rootdir/build/fio/spdk_bdev" + + # Preload AddressSanitizer library to fio if fio_plugin was compiled with it + local asan_lib + asan_lib=$(ldd $bdev_plugin | grep libasan | awk '{print $3}') + + LD_PRELOAD="$asan_lib $bdev_plugin" "$fio_dir"/fio "$@" +} + +function fio_nvme() { + # Setup fio binary cmd line + local fio_dir=$CONFIG_FIO_SOURCE_DIR + local nvme_plugin="$rootdir/build/fio/spdk_nvme" + + # Preload AddressSanitizer library to fio if fio_plugin was compiled with it + asan_lib=$(ldd $nvme_plugin | grep libasan | awk '{print $3}') + + LD_PRELOAD="$asan_lib $nvme_plugin" "$fio_dir"/fio "$@" +} + +function get_lvs_free_mb() { + local lvs_uuid=$1 + local lvs_info + local fc + local cs + lvs_info=$($rpc_py bdev_lvol_get_lvstores) + fc=$(jq ".[] | select(.uuid==\"$lvs_uuid\") .free_clusters" <<< "$lvs_info") + cs=$(jq ".[] | select(.uuid==\"$lvs_uuid\") .cluster_size" <<< "$lvs_info") + + # Change to MB's + free_mb=$((fc * cs / 1024 / 1024)) + echo "$free_mb" +} + +function get_bdev_size() { + local bdev_name=$1 + local bdev_info + local bs + local nb + bdev_info=$($rpc_py bdev_get_bdevs -b $bdev_name) + bs=$(jq ".[] .block_size" <<< "$bdev_info") + nb=$(jq ".[] .num_blocks" <<< "$bdev_info") + + # Change to MB's + bdev_size=$((bs * nb / 1024 / 1024)) + echo "$bdev_size" +} + +function autotest_cleanup() { + $rootdir/scripts/setup.sh reset + $rootdir/scripts/setup.sh cleanup + if [ $(uname -s) = "Linux" ]; then + if grep -q '#define SPDK_CONFIG_IGB_UIO_DRIVER 1' $rootdir/include/spdk/config.h; then + [[ -e /sys/module/igb_uio ]] && rmmod igb_uio + else + modprobe -r uio_pci_generic + fi + fi + rm -rf "$asan_suppression_file" +} + +function freebsd_update_contigmem_mod() { + if [ $(uname) = FreeBSD ]; then + kldunload contigmem.ko || true + if [ -n "$WITH_DPDK_DIR" ]; then + echo "Warning: SPDK only works on FreeBSD with patches that only exist in SPDK's dpdk submodule" + cp -f "$WITH_DPDK_DIR/kmod/contigmem.ko" /boot/modules/ + cp -f "$WITH_DPDK_DIR/kmod/contigmem.ko" /boot/kernel/ + cp -f "$WITH_DPDK_DIR/kmod/nic_uio.ko" /boot/modules/ + cp -f "$WITH_DPDK_DIR/kmod/nic_uio.ko" /boot/kernel/ + else + cp -f "$rootdir/dpdk/build/kmod/contigmem.ko" /boot/modules/ + cp -f "$rootdir/dpdk/build/kmod/contigmem.ko" /boot/kernel/ + cp -f "$rootdir/dpdk/build/kmod/nic_uio.ko" /boot/modules/ + cp -f "$rootdir/dpdk/build/kmod/nic_uio.ko" /boot/kernel/ + fi + fi +} + +function get_nvme_name_from_bdf() { + blkname=() + + nvme_devs=$(lsblk -d --output NAME | grep "^nvme") || true + if [ -z "$nvme_devs" ]; then + return + fi + for dev in $nvme_devs; do + link_name=$(readlink /sys/block/$dev/device/device) || true + if [ -z "$link_name" ]; then + link_name=$(readlink /sys/block/$dev/device) + fi + bdf=$(basename "$link_name") + if [ "$bdf" = "$1" ]; then + blkname+=($dev) + fi + done + + printf '%s\n' "${blkname[@]}" +} + +function get_nvme_ctrlr_from_bdf() { + bdf_sysfs_path=$(readlink -f /sys/class/nvme/nvme* | grep "$1/nvme/nvme") + if [[ -z "$bdf_sysfs_path" ]]; then + return + fi + + printf '%s\n' "$(basename $bdf_sysfs_path)" +} + +# Get BDF addresses of all NVMe drives currently attached to +# uio-pci-generic or vfio-pci +function get_nvme_bdfs() { + xtrace_disable + bdfs=$(jq -r .config[].params.traddr <<< $($rootdir/scripts/gen_nvme.sh --json)) + if [[ -z $bdfs ]]; then + echo "No devices to test on!" + exit 1 + fi + echo "$bdfs" + xtrace_restore +} + +# Same as function above, but just get the first disks BDF address +function get_first_nvme_bdf() { + head -1 <<< "$(get_nvme_bdfs)" +} + +function nvme_namespace_revert() { + $rootdir/scripts/setup.sh + sleep 1 + bdfs=$(get_nvme_bdfs) + + $rootdir/scripts/setup.sh reset + sleep 1 + + for bdf in $bdfs; do + nvme_ctrlr=/dev/$(get_nvme_ctrlr_from_bdf ${bdf}) + if [[ -z "$nvme_ctrlr" ]]; then + continue + fi + + # Check Optional Admin Command Support for Namespace Management + oacs=$(nvme id-ctrl ${nvme_ctrlr} | grep oacs | cut -d: -f2) + oacs_ns_manage=$((oacs & 0x8)) + + if [[ "$oacs_ns_manage" -ne 0 ]]; then + # This assumes every NVMe controller contains single namespace, + # encompassing Total NVM Capacity and formatted as 512 block size. + # 512 block size is needed for test/vhost/vhost_boot.sh to + # succesfully run. + + unvmcap=$(nvme id-ctrl ${nvme_ctrlr} | grep unvmcap | cut -d: -f2) + if [[ "$unvmcap" -eq 0 ]]; then + # All available space already used + continue + fi + tnvmcap=$(nvme id-ctrl ${nvme_ctrlr} | grep tnvmcap | cut -d: -f2) + blksize=512 + + size=$((tnvmcap / blksize)) + + nvme detach-ns ${nvme_ctrlr} -n 0xffffffff -c 0 || true + nvme delete-ns ${nvme_ctrlr} -n 0xffffffff || true + nvme create-ns ${nvme_ctrlr} -s ${size} -c ${size} -b ${blksize} + nvme attach-ns ${nvme_ctrlr} -n 1 -c 0 + nvme reset ${nvme_ctrlr} + waitforblk "${nvme_ctrlr}n1" + fi + done +} + +# Get BDFs based on device ID, such as 0x0a54 +function get_nvme_bdfs_by_id() { + local bdfs=() + + for bdf in $(get_nvme_bdfs); do + device=$(cat /sys/bus/pci/devices/$bdf/device) || true + if [[ "$device" == "$1" ]]; then + bdfs+=($bdf) + fi + done + + printf '%s\n' "${bdfs[@]}" +} + +function opal_revert_cleanup() { + # The OPAL CI tests is only used for P4510 devices. + mapfile -t bdfs < <(get_nvme_bdfs_by_id 0x0a54) + if [[ -z ${bdfs[0]} ]]; then + return 0 + fi + + $SPDK_BIN_DIR/spdk_tgt & + spdk_tgt_pid=$! + waitforlisten $spdk_tgt_pid + + for bdf in "${bdfs[@]}"; do + $rootdir/scripts/rpc.py bdev_nvme_attach_controller -b "nvme0" -t "pcie" -a ${bdf} + # Ignore if this fails. + $rootdir/scripts/rpc.py bdev_nvme_opal_revert -b nvme0 -p test || true + done + + killprocess $spdk_tgt_pid +} + +# Define temp storage for all the tests. Look for 2GB at minimum +set_test_storage "${TEST_MIN_STORAGE_SIZE:-$((1 << 31))}" + +set -o errtrace +shopt -s extdebug +trap "trap - ERR; print_backtrace >&2" ERR + +PS4=' \t \$ ' +if $SPDK_AUTOTEST_X; then + # explicitly enable xtraces, overriding any tracking information. + unset XTRACE_DISABLED + unset XTRACE_NESTING_LEVEL + set -x + xtrace_enable +else + xtrace_restore +fi diff --git a/src/spdk/test/common/config/README.md b/src/spdk/test/common/config/README.md new file mode 100644 index 000000000..26a587709 --- /dev/null +++ b/src/spdk/test/common/config/README.md @@ -0,0 +1,104 @@ +# Virtual Test Configuration + +This readme and the associated bash script, vm_setup.sh, are intended to assist developers in quickly +preparing a virtual test environment on which to run the SPDK validation tests rooted at autorun.sh. +This file contains basic information about SPDK environment requirements, an introduction to the +autorun-spdk.conf files used to moderate which tests are run by autorun.sh, and step-by-step instructions +for spinning up a VM capable of running the SPDK test suite. +There is no need for external hardware to run these tests. The linux kernel comes with the drivers necessary +to emulate an RDMA enabled NIC. NVMe controllers can also be virtualized in emulators such as QEMU. + +## VM Envronment Requirements (Host) + +- 8 GiB of RAM (for DPDK) +- Enable intel_kvm on the host machine from the bios. +- Enable nesting for VMs in kernel command line (for vhost tests). + - In `/etc/default/grub` append the following to the GRUB_CMDLINE_LINUX line: intel_iommu=on kvm-intel.nested=1. + +## VM Specs + +When creating the user during the fedora installation, it is best to use the name sys_sgsw. Efforts are being made +to remove all references to this user, or files specific to this user from the codebase, but there are still some +trailing references to it. + +## Autorun-spdk.conf + +Every machine that runs the autotest scripts should include a file titled autorun-spdk.conf in the home directory +of the user that will run them. This file consists of several lines of the form 'variable_name=0/1'. autorun.sh sources +this file each time it is run, and determines which tests to attempt based on which variables are defined in the +configuration file. For a full list of the variable declarations available for autorun-spdk.conf, please see +`test/common/autotest_common.sh` starting at line 13. + +## Steps for Configuring the VM + +1. Download a fresh Fedora 26 image. +2. Perform the installation of Fedora 26 server. +3. Create an admin user sys_sgsw (enabling passwordless sudo for this account will make life easier during the tests). +4. Run the vm_setup.sh script which will install all proper dependencies. +5. Modify the autorun-spdk.conf file in the home directory. +6. Reboot the VM. +7. Run autorun.sh for SPDK. Any output files will be placed in `~/spdk_repo/output/`. + +## Additional Steps for Preparing the Vhost Tests + +The Vhost tests also require the creation of a second virtual machine nested inside of the test VM. +Please follow the directions below to complete that installation. Note that host refers to the Fedora VM +created above and guest or VM refer to the Ubuntu VM created in this section. + +1. Follow instructions from spdk/scripts/vagrant/README.md + - install all needed packages mentioned in "Mac OSX Setup" or "Windows 10 Setup" sections + - follow steps from "Configure Vagrant" section + +2. Use Vagrant scripts located in spdk/scripts/vagrant to automatically generate + VM image to use in SPDK vhost tests. + Example command: + ~~~{.sh} + spdk/scripts/vagrant/create_vhost_vm.sh --move-to-def-dirs ubuntu16 + ~~~ + This command will: + - Download a Ubuntu 16.04 image file + - upgrade the system and install needed dependencies (fio, sg3-utils, bc) + - add entry to VM's ~/.ssh/autorized_keys + - add appropriate options to GRUB command line and update grub + - convert the image to .qcow2 format + - move .qcow2 file and ssh keys to default locations used by vhost test scripts + +Alternatively it is possible to create the VM image manually using following steps: + +1. Create an image file for the VM. It does not have to be large, about 3.5G should suffice. +2. Create an ssh keypair for host-guest communications (performed on the host): + - Generate an ssh keypair with the name spdk_vhost_id_rsa and save it in `/root/.ssh`. + - Make sure that only root has read access to the private key. +3. Install the OS in the VM image (performed on guest): + - Use the latest Ubuntu server (Currently 16.04 LTS). + - When partitioning the disk, make one partion that consumes the whole disk mounted at /. Do not encrypt the disk or enable LVM. + - Choose the OpenSSH server packages during install. +4. Post installation configuration (performed on guest): + - Run the following commands to enable all necessary dependencies: + ~~~{.sh} + sudo apt update + sudo apt upgrade + sudo apt install fio sg3-utils bc + ~~~ + - Enable the root user: "sudo passwd root -> root". + - Enable root login over ssh: vim `/etc/ssh/sshd_config` -> PermitRootLogin=yes. + - Disable DNS for ssh: `/etc/ssh/sshd_config` -> UseDNS=no. + - Add the spdk_vhost key to root's known hosts: `/root/.ssh/authorized_keys` -> add spdk_vhost_id_rsa.pub key to authorized keys. + Remember to save the private key in `~/.ssh/spdk_vhost_id_rsa` on the host. + - Change the grub boot options for the guest as follows: + - Add "console=ttyS0 earlyprintk=ttyS0" to the boot options in `/etc/default/grub` (for serial output redirect). + - Add "scsi_mod.use_blk_mq=1" to boot options in `/etc/default/grub`. + ~~~{.sh} + sudo update-grub + ~~~ + - Reboot the VM. + - Remove any unnecessary packages (this is to make booting the VM faster): + ~~~{.sh} + apt purge snapd + apt purge Ubuntu-core-launcher + apt purge squashfs-tools + apt purge unattended-upgrades + ~~~ +5. Copy the fio binary from the guest location `/usr/bin/fio` to the host location `/home/sys_sgsw/fio_ubuntu`. +6. Place the guest VM in the host at the following location: `/home/sys_sgsw/vhost_vm_image.qcow2`. +7. On the host, edit the `~/autorun-spdk.conf` file to include the following line: SPDK_TEST_VHOST=1. diff --git a/src/spdk/test/common/config/pkgdep/apt-get b/src/spdk/test/common/config/pkgdep/apt-get new file mode 100644 index 000000000..a1630620d --- /dev/null +++ b/src/spdk/test/common/config/pkgdep/apt-get @@ -0,0 +1,100 @@ +package_manager=apt-get + +update() { + sudo "$package_manager" update +} + +install() { + (( $# )) || return 0 + + sudo "$package_manager" install -y "$@" +} + +upgrade() { + sudo "$package_manager" update + sudo "$package_manager" upgrade -y +} + + +pre_install() { + echo "Package perl-open is not available at Ubuntu repositories" >&2 + + update + + if [[ $INSTALL_TSOCKS == true ]]; then + install tsocks + fi + + # asan an ubsan have to be installed together to not mix up gcc versions + if install libasan5; then + install libubsan1 + else + echo "Latest libasan5 is not available" >&2 + echo " installing libasan2 and corresponding libubsan0" >&2 + install libasan2 + install libubsan0 + fi + if ! install rdma-core; then + echo "Package rdma-core is avaliable at Ubuntu 18 [universe] repositorium" >&2 + install rdmacm-utils + install ibverbs-utils + else + LIBRXE_INSTALL=false + fi + if ! install libpmempool1; then + echo "Package libpmempool1 is available at Ubuntu 18 [universe] repositorium" >&2 + fi + if ! install clang-tools; then + echo "Package clang-tools is available at Ubuntu 18 [universe] repositorium" >&2 + fi + if ! install --no-install-suggests --no-install-recommends open-isns-utils; then + echo "Package open-isns-utils is available at Ubuntu 18 [universe] repositorium" >&2 + fi + + # Package name for Ubuntu 18 is targetcli-fb but for Ubuntu 16 it's targetcli + if ! install targetcli-fb; then + install targetcli + fi + + # On Ubuntu 20.04 (focal) btrfs-tools are available under different name - btrfs-progs + if ! install btrfs-tools; then + install btrfs-progs + fi +} + +packages=( + valgrind + jq + nvme-cli + ceph + gdb + fio + librbd-dev + linux-headers-generic + libgflags-dev + autoconf + automake + libtool + libmount-dev + open-iscsi + libglib2.0-dev + libpixman-1-dev + astyle + elfutils + libelf-dev + flex + bison + libswitch-perl + gdisk + socat + sshfs + sshpass + python3-pandas + bc + smartmontools + wget +) + +if [[ $OSID != ubuntu ]]; then + echo "Located apt-get package manager, but it was tested for Ubuntu only" +fi diff --git a/src/spdk/test/common/config/pkgdep/dnf b/src/spdk/test/common/config/pkgdep/dnf new file mode 100644 index 000000000..b009f106e --- /dev/null +++ b/src/spdk/test/common/config/pkgdep/dnf @@ -0,0 +1,72 @@ +package_manager=dnf + +upgrade() { + sudo "$package_manager" upgrade -y +} + +install() { + (($#)) || return 0 + + sudo "$package_manager" install -y "$@" +} + +packages=( + valgrind + jq + nvme-cli + ceph + gdb + fio + librbd-devel + kernel-devel + gflags-devel + libasan + libubsan + autoconf + automake + libtool + libmount-devel + iscsi-initiator-utils + isns-utils-devel + pmempool + perl-open + glib2-devel + pixman-devel + astyle-devel + elfutils + libabigail + elfutils-libelf-devel + flex + bison + targetcli + perl-Switch + librdmacm-utils + libibverbs-utils + gdisk + socat + sshfs + sshpass + python3-pandas + btrfs-progs + rpm-build + iptables + clang-analyzer + bc + kernel-modules-extra + systemd-devel + smartmontools + wget +) + +pre_install() { + if [[ $INTSALL_TSOCKS == true ]]; then + # currently, tsocks package is retired in fedora 31, so don't exit in case + # installation failed + # FIXME: Review when fedora starts to successfully build this package again. + install tsocks || echo "Installation of the tsocks package failed, proxy may not be available" + fi +} + +if [[ $OSID != fedora ]]; then + echo "Located dnf package manager, but it was tested for Fedora only" +fi diff --git a/src/spdk/test/common/config/pkgdep/git b/src/spdk/test/common/config/pkgdep/git new file mode 100644 index 000000000..f46183ac8 --- /dev/null +++ b/src/spdk/test/common/config/pkgdep/git @@ -0,0 +1,325 @@ +function install_spdk() { + mkdir -p "$GIT_REPOS/spdk_repo/output" || echo "Can not create spdk_repo/output directory." + + if [[ -d $GIT_REPOS/spdk_repo/spdk ]]; then + echo "spdk source already present, not cloning" + else + git -C "$GIT_REPOS/spdk_repo" clone "${GIT_REPO_SPDK}" + fi + git -C "$GIT_REPOS/spdk_repo/spdk" config submodule.dpdk.url "${GIT_REPO_DPDK}" + git -C "$GIT_REPOS/spdk_repo/spdk" config submodule.intel-ipsec-mb.url "${GIT_REPO_INTEL_IPSEC_MB}" + git -C "$GIT_REPOS/spdk_repo/spdk" submodule update --init --recursive +} + +function install_refspdk() { + local last_release + local output_dir + local config_params + local rootdir + + # Create a reference SPDK build for ABI tests + git -C "$GIT_REPOS/spdk_repo/spdk" fetch --tags + last_release=$(git -C "$GIT_REPOS/spdk_repo/spdk" tag | sort --version-sort | grep -v rc | tail -n1) + output_dir="$GIT_REPOS/spdk_$(tr . _ < <(tr -d '[:alpha:]' <<< $last_release))" + + if [[ ! -d $output_dir ]]; then + cp -r "$GIT_REPOS/spdk_repo/spdk" "$output_dir" + fi + + git -C "$output_dir" checkout "$last_release" + git -C "$output_dir" submodule update --init + + cat > $HOME/autorun-spdk.conf <<- EOF + SPDK_BUILD_SHARED_OBJECT=1 + SPDK_TEST_AUTOBUILD=1 + SPDK_TEST_UNITTEST=1 + SPDK_TEST_BLOCKDEV=1 + SPDK_TEST_PMDK=1 + SPDK_TEST_ISAL=1 + SPDK_TEST_REDUCE=1 + SPDK_TEST_CRYPTO=1 + SPDK_TEST_FTL=1 + SPDK_TEST_OCF=1 + SPDK_TEST_RAID5=1 + SPDK_TEST_RBD=1 + SPDK_RUN_ASAN=1 + SPDK_RUN_UBSAN=1 + EOF + + mkdir -p $HOME/output + + ( + rootdir="$output_dir" + source $HOME/autorun-spdk.conf + source $output_dir/test/common/autotest_common.sh + + # Prepare separate, fixed, cmdline for the FreeBSD, Issue #1397. + if [[ $OSID == freebsd ]]; then + config_params="--enable-debug --enable-werror" + config_params+=" --with-idxd --with-fio=/usr/src/fio" + config_params+=" --disable-unit-tests --without-isal" + MAKE=gmake + else + config_params="$(get_config_params)" + fi + $output_dir/configure $(echo $config_params | sed 's/--enable-coverage//g') + if [[ $OSID != freebsd ]]; then + $MAKE -C $output_dir $MAKEFLAGS include/spdk/config.h + CONFIG_OCF_PATH="$output_dir/ocf" $MAKE -C $output_dir/lib/env_ocf $MAKEFLAGS exportlib O=$output_dir/build/ocf.a + $output_dir/configure $config_params --with-ocf=$output_dir/build/ocf.a --with-shared + fi + $MAKE -C $output_dir $MAKEFLAGS + ) +} + +function install_qat() { + + kernel_maj=$(uname -r | cut -d'.' -f1) + kernel_min=$(uname -r | cut -d'.' -f2) + + if [[ -e /sys/module/qat_c62x ]]; then + sudo modprobe -r qat_c62x || : + fi + if [[ -d $GIT_REPOS/QAT ]]; then + sudo rm -rf "$GIT_REPOS/QAT" + fi + + mkdir "$GIT_REPOS/QAT" + + tar -C "$GIT_REPOS/QAT" -xzof - < <(wget -O- "$DRIVER_LOCATION_QAT") + + #The driver version 1.7.l.4.3.0-00033 contains a reference to a deprecated function. Remove it so the build won't fail. + if [ $kernel_maj -le 4 ]; then + if [ $kernel_min -le 17 ]; then + sudo sed -i 's/rdtscll(timestamp);/timestamp = rdtsc_ordered();/g' \ + "$GIT_REPOS/QAT/quickassist/utilities/osal/src/linux/kernel_space/OsalServices.c" || true + fi + fi + + (cd "$GIT_REPOS/QAT" && sudo ./configure --enable-icp-sriov=host && sudo make install) + + if sudo service qat_service start; then + echo "failed to start the qat service. Something may be wrong with your device or package." + fi +} + +function install_rocksdb() { + # Rocksdb is installed for use with the blobfs tests. + if [ ! -d /usr/src/rocksdb ]; then + git clone "${GIT_REPO_ROCKSDB}" "$GIT_REPOS/rocksdb" + git -C "$GIT_REPOS/rocksdb" checkout spdk-v5.6.1 + sudo mv "$GIT_REPOS/rocksdb" /usr/src/ + else + sudo git -C /usr/src/rocksdb checkout spdk-v5.6.1 + echo "rocksdb already in /usr/src. Not checking out again" + fi +} + +function install_fio() { + # This version of fio is installed in /usr/src/fio to enable + # building the spdk fio plugin. + local fio_version="fio-3.19" + + if [ ! -d /usr/src/fio ]; then + if [ ! -d fio ]; then + git clone "${GIT_REPO_FIO}" "$GIT_REPOS/fio" + sudo mv "$GIT_REPOS/fio" /usr/src/ + else + sudo mv "$GIT_REPOS/fio" /usr/src/ + fi + ( + git -C /usr/src/fio checkout master \ + && git -C /usr/src/fio pull \ + && git -C /usr/src/fio checkout $fio_version \ + && if [ $OSID == 'freebsd' ]; then + gmake -C /usr/src/fio -j${jobs} \ + && sudo gmake -C /usr/src/fio install + else + make -C /usr/src/fio -j${jobs} \ + && sudo make -C /usr/src/fio install + fi + ) + else + echo "fio already in /usr/src/fio. Not installing" + fi +} + +function install_flamegraph() { + # Flamegraph is used when printing out timing graphs for the tests. + if [ ! -d /usr/local/FlameGraph ]; then + git clone "${GIT_REPO_FLAMEGRAPH}" "$GIT_REPOS/FlameGraph" + mkdir -p /usr/local + sudo mv "$GIT_REPOS/FlameGraph" /usr/local/FlameGraph + else + echo "flamegraph already installed. Skipping" + fi +} + +function install_qemu() { + # Two versions of QEMU are used in the tests. + # Stock QEMU is used for vhost. A special fork + # is used to test OCSSDs. Install both. + + # Forked QEMU + SPDK_QEMU_BRANCH=spdk-5.0.0 + mkdir -p "$GIT_REPOS/qemu" + if [[ ! -d $GIT_REPOS/qemu/$SPDK_QEMU_BRANCH ]]; then + git clone "${GIT_REPO_QEMU}" -b "$SPDK_QEMU_BRANCH" "$GIT_REPOS/qemu/$SPDK_QEMU_BRANCH" + else + echo "qemu already checked out. Skipping" + fi + + declare -a opt_params=("--prefix=/usr/local/qemu/$SPDK_QEMU_BRANCH") + if ((gcc_version >= 9)); then + # GCC 9 fails to compile Qemu due to some old warnings which were not detected by older versions. + opt_params+=("--extra-cflags=-Wno-error=stringop-truncation -Wno-error=deprecated-declarations -Wno-error=incompatible-pointer-types -Wno-error=format-truncation") + opt_params+=("--disable-glusterfs") + fi + + # Most tsocks proxies rely on a configuration file in /etc/tsocks.conf. + # If using tsocks, please make sure to complete this config before trying to build qemu. + if [[ $INSTALL_TSOCKS == true && $NO_TSOCKS != true ]]; then + if hash tsocks 2> /dev/null; then + opt_params+=("--with-git='tsocks git'") + fi + fi + + sed -i s@git://git.qemu.org/@https://github.com/qemu/@g "$GIT_REPOS/qemu/$SPDK_QEMU_BRANCH/.gitmodules" + sed -i s@git://git.qemu.org/@https://github.com/qemu/@g "$GIT_REPOS/qemu/$SPDK_QEMU_BRANCH/.git/config" + sed -i s@git://git.qemu-project.org/@https://github.com/qemu/@g "$GIT_REPOS/qemu/$SPDK_QEMU_BRANCH/.gitmodules" + sed -i s@git://git.qemu-project.org/@https://github.com/qemu/@g "$GIT_REPOS/qemu/$SPDK_QEMU_BRANCH/.git/config" + # The qemu configure script places several output files in the CWD. + (cd "$GIT_REPOS/qemu/$SPDK_QEMU_BRANCH" && ./configure "${opt_params[@]}" --target-list="x86_64-softmmu" --enable-kvm --enable-linux-aio --enable-numa) + + make -C "$GIT_REPOS/qemu/$SPDK_QEMU_BRANCH" -j${jobs} + sudo make -C "$GIT_REPOS/qemu/$SPDK_QEMU_BRANCH" install +} + +function install_nvmecli() { + SPDK_NVME_CLI_BRANCH=spdk-1.6 + if [[ ! -d $GIT_REPOS/nvme-cli ]]; then + git clone "${GIT_REPO_SPDK_NVME_CLI}" -b "$SPDK_NVME_CLI_BRANCH" "$GIT_REPOS/nvme-cli" + else + echo "nvme-cli already checked out. Skipping" + fi + if [ ! -d "/usr/local/src/nvme-cli" ]; then + # Changes required for SPDK are already merged on top of + # nvme-cli, however not released yet. + # Support for SPDK should be released in nvme-cli >1.11.1 + if [[ ! -d $GIT_REPOS/nvme-cli-cuse ]]; then + git clone "https://github.com/linux-nvme/nvme-cli.git" "$GIT_REPOS/nvme-cli-cuse" + fi + git -C "$GIT_REPOS/nvme-cli-cuse" checkout "e770466615096a6d41f038a28819b00bc3078e1d" + make -C "$GIT_REPOS/nvme-cli-cuse" + sudo mv "$GIT_REPOS/nvme-cli-cuse" /usr/local/src/nvme-cli + fi +} + +function install_libiscsi() { + # We currently don't make any changes to the libiscsi repository for our tests, but it is possible that we will need + # to later. Cloning from git is just future proofing the machines. + if [[ ! -d $GIT_REPOS/libiscsi ]]; then + git clone "${GIT_REPO_LIBISCSI}" "$GIT_REPOS/libiscsi" + else + echo "libiscsi already checked out. Skipping" + fi + (cd "$GIT_REPOS/libiscsi" && ./autogen.sh && ./configure --prefix=/usr/local/libiscsi) + make -C "$GIT_REPOS/libiscsi" -j${jobs} + sudo make -C "$GIT_REPOS/libiscsi" install +} + +function install_git() { + install zlib-devel curl-devel + tar -C "$GIT_REPOS" -xzof <(wget -qO- "$GIT_REPO_GIT") + (cd "$GIT_REPOS/git-$GIT_VERSION" \ + && make configure \ + && ./configure --prefix=/usr/local/git \ + && sudo make -j${jobs} install) + sudo sh -c "echo 'export PATH=/usr/local/git/bin:$PATH' >> /etc/bashrc" + export "PATH=/usr/local/git/bin:$PATH" +} + +function install_extra_pkgs() { + if [[ $INSTALL_QAT == true ]]; then + install libudev-devel || install libudev-dev + fi + + if [[ $INSTALL_QEMU == true ]]; then + install qemu-system-x86 qemu-img \ + || install qemu-system-x86 qemu-utils \ + || install qemu + fi +} + +GIT_VERSION=2.25.1 +: ${GIT_REPO_SPDK=https://github.com/spdk/spdk.git} +export GIT_REPO_SPDK +: ${GIT_REPO_DPDK=https://github.com/spdk/dpdk.git} +export GIT_REPO_DPDK +: ${GIT_REPO_ROCKSDB=https://review.spdk.io/spdk/rocksdb} +export GIT_REPO_ROCKSDB +: ${GIT_REPO_FIO=http://git.kernel.dk/fio.git} +export GIT_REPO_FIO +: ${GIT_REPO_FLAMEGRAPH=https://github.com/brendangregg/FlameGraph.git} +export GIT_REPO_FLAMEGRAPH +: ${GIT_REPO_QEMU=https://github.com/spdk/qemu} +export GIT_REPO_QEMU +: ${GIT_REPO_LIBISCSI=https://github.com/sahlberg/libiscsi} +export GIT_REPO_LIBISCSI +: ${GIT_REPO_SPDK_NVME_CLI=https://github.com/spdk/nvme-cli} +export GIT_REPO_SPDK_NVME_CLI +: ${GIT_REPO_INTEL_IPSEC_MB=https://github.com/spdk/intel-ipsec-mb.git} +export GIT_REPO_INTEL_IPSEC_MB +: ${DRIVER_LOCATION_QAT=https://01.org/sites/default/files/downloads//qat1.7.l.4.9.0-00008.tar.gz} +export DRIVER_LOCATION_QAT +: ${GIT_REPO_GIT=https://github.com/git/git/archive/v${GIT_VERSION}.tar.gz} +export GIT_REPO_GIT +GIT_REPOS=${GIT_REPOS:-$HOME} + +gcc_version=$(gcc -dumpversion) gcc_version=${gcc_version%%.*} +if [[ $ID == centos ]] && (( VERSION_ID == 7 )); then + # install proper version of the git first + install_git +fi + +IFS="," read -ra conf_env <<< "$CONF" +for conf in "${conf_env[@]}"; do + export "INSTALL_${conf^^}=true" +done +sources=(install_refspdk) + +if [[ $OS == FreeBSD ]]; then + jobs=$(($(sysctl -n hw.ncpu) * 2)) +else + jobs=$(($(nproc) * 2)) + sources+=( + install_libiscsi + install_nvmecli + install_qat + install_rocksdb + install_flamegraph + install_qemu + ) +fi +sources+=(install_fio) + +sudo mkdir -p /usr/{,local}/src +sudo mkdir -p "$GIT_REPOS" + +install_extra_pkgs + +if [[ $INSTALL_REFSPDK == true ]]; then + # Serialize builds as refspdk depends on spdk + install_spdk + install_refspdk +else + sources+=(install_spdk) +fi + +for source in "${sources[@]}"; do + source_conf=${source^^} + if [[ ${!source_conf} == true ]]; then + "$source" & + fi +done +wait diff --git a/src/spdk/test/common/config/pkgdep/pacman b/src/spdk/test/common/config/pkgdep/pacman new file mode 100644 index 000000000..43d3db2f5 --- /dev/null +++ b/src/spdk/test/common/config/pkgdep/pacman @@ -0,0 +1,62 @@ +package_manager=pacman + +upgrade() { + sudo "$package_manager" -Syu --noconfirm --needed +} + +install() { + (($#)) || return 0 + + sudo "$package_manager" -Sy --noconfirm --needed "$@" +} + +pre_install() { + if [[ $INTSALL_TSOCKS == true ]]; then + install tsocks + fi +} + +packages=( + valgrind + jq + nvme-cli + ceph + gdb + fio + linux-headers + gflags + autoconf + automake + libtool + libutil-linux + libiscsi + open-isns + glib2 + pixman + flex + bison + elfutils + libelf + astyle + gptfdisk + socat + sshfs + sshpass + python-pandas + btrfs-progs + iptables + clang + bc + perl-switch + open-iscsi + smartmontools + parted + wget +) + +# TODO: +# These are either missing or require some other installation method +# than pacman: +# librbd-devel +# perl-open +# targetcli diff --git a/src/spdk/test/common/config/pkgdep/pkg b/src/spdk/test/common/config/pkgdep/pkg new file mode 100644 index 000000000..3f3f41725 --- /dev/null +++ b/src/spdk/test/common/config/pkgdep/pkg @@ -0,0 +1,27 @@ +package_manager=pkg + +upgrade() { + sudo "$package_manager" upgrade -y +} + +install() { + (($#)) || return 0 + + sudo "$package_manager" install -y "$@" +} + +packages=( + pciutils + jq + gdb + fio + p5-extutils-pkgconfig + libtool + flex + bison + gdisk + socat + sshpass + py37-pandas + wget +) diff --git a/src/spdk/test/common/config/pkgdep/swupd b/src/spdk/test/common/config/pkgdep/swupd new file mode 100644 index 000000000..c1d2a8a6b --- /dev/null +++ b/src/spdk/test/common/config/pkgdep/swupd @@ -0,0 +1,21 @@ +package_manager=swupd + +upgrade() { + sudo "$package_manager" update -y +} + +install() { + (($#)) || return 0 + + sudo "$package_manager" bundle-add -y "$@" +} + +packages=( + jq +) + +pre_install() { + if [[ $INTSALL_TSOCKS == true ]]; then + install tsocks || echo "Installation of the tsocks package failed, proxy may not be available" + fi +} diff --git a/src/spdk/test/common/config/pkgdep/yum b/src/spdk/test/common/config/pkgdep/yum new file mode 100644 index 000000000..32e89bc15 --- /dev/null +++ b/src/spdk/test/common/config/pkgdep/yum @@ -0,0 +1,67 @@ +package_manager=yum + +upgrade() { + sudo "$package_manager" upgrade -y +} + +install() { + (($#)) || return 0 + + sudo "$package_manager" install -y "$@" +} + +packages=( + pciutils + valgrind + jq + nvme-cli + gdb + fio + librbd-devel + kernel-devel + gflags-devel + libasan + libubsan + autoconf + automake + libtool + libmount-devel + iscsi-initiator-utils + isns-utils-devel pmempool + perl-open + glib2-devel + pixman-devel + astyle-devel + elfutils + elfutils-libelf-devel + flex + bison + targetcli + perl-Switch + librdmacm-utils + libibverbs-utils + gdisk + socat + sshfs + sshpass + python3-pandas + rpm-build + iptables + clang-analyzer + bc + kernel-modules-extra + systemd-devel + python3 + wget +) + +pre_install() { + if [[ $ID == centos ]] && (( VERSION_ID == 8 )); then + "$package_manager" update -y --refresh + fi + + install nbd || { + wget -O nbd.rpm https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/n/nbd-3.14-2.el7.x86_64.rpm + install nbd.rpm + } +} diff --git a/src/spdk/test/common/config/vm_setup.conf b/src/spdk/test/common/config/vm_setup.conf new file mode 100644 index 000000000..a8e58d82a --- /dev/null +++ b/src/spdk/test/common/config/vm_setup.conf @@ -0,0 +1,12 @@ +# This configuration file is provided for reference purposes. +GIT_REPO_SPDK=https://review.spdk.io/gerrit/spdk/spdk +GIT_REPO_DPDK=https://github.com/spdk/dpdk.git +GIT_REPO_OPEN_ISCSI=https://github.com/open-iscsi/open-iscsi +GIT_REPO_ROCKSDB=https://review.gerrithub.io/spdk/rocksdb +GIT_REPO_FIO=http://git.kernel.dk/fio.git +GIT_REPO_FLAMEGRAPH=https://github.com/brendangregg/FlameGraph.git +GIT_REPO_QEMU=https://github.com/spdk/qemu +GIT_REPO_VPP=https://gerrit.fd.io/r/vpp +GIT_REPO_LIBISCSI=https://github.com/sahlberg/libiscsi +GIT_REPO_SPDK_NVME_CLI=https://github.com/spdk/nvme-cli +DRIVER_LOCATION_QAT=https://01.org/sites/default/files/downloads/intelr-quickassist-technology/qat1.7.l.4.3.0-00033.tar.gz diff --git a/src/spdk/test/common/config/vm_setup.sh b/src/spdk/test/common/config/vm_setup.sh new file mode 100755 index 000000000..b2b3a8fc1 --- /dev/null +++ b/src/spdk/test/common/config/vm_setup.sh @@ -0,0 +1,176 @@ +#!/usr/bin/env bash + +# Virtual Machine environment requirements: +# 8 GiB of RAM (for DPDK) +# enable intel_kvm on your host machine + +# The purpose of this script is to provide a simple procedure for spinning up a new +# virtual test environment capable of running our whole test suite. This script, when +# applied to a fresh install of fedora 26 or ubuntu 16,18 server will install all of the +# necessary dependencies to run almost the complete test suite. The main exception being VHost. +# Vhost requires the configuration of a second virtual machine. instructions for how to configure +# that vm are included in the file TEST_ENV_SETUP_README inside this repository + +# it is important to enable nesting for vms in kernel command line of your machine for the vhost tests. +# in /etc/default/grub +# append the following to the GRUB_CMDLINE_LINUX line +# intel_iommu=on kvm-intel.nested=1 + +# We have made a lot of progress with removing hardcoded paths from the tests, + +sudo() { + "$(type -P sudo)" -E "$@" +} + +set -e + +VM_SETUP_PATH=$(readlink -f ${BASH_SOURCE%/*}) + +UPGRADE=false +INSTALL=false +CONF="rocksdb,fio,flamegraph,tsocks,qemu,libiscsi,nvmecli,qat,spdk,refspdk" + +if [[ -e /etc/os-release ]]; then + source /etc/os-release +fi + +if [ $(uname -s) == "FreeBSD" ]; then + OSID="freebsd" + OSVERSION=$(freebsd-version | cut -d. -f1) +else + OSID=$(source /etc/os-release && echo $ID) + OSVERSION=$(source /etc/os-release && echo $VERSION_ID) +fi + +function usage() { + echo "This script is intended to automate the environment setup for a linux virtual machine." + echo "Please run this script as your regular user. The script will make calls to sudo as needed." + echo "" + echo "./vm_setup.sh" + echo " -h --help" + echo " -u --upgrade Run $package_manager upgrade" + echo " -i --install-deps Install $package_manager based dependencies" + echo " -t --test-conf List of test configurations to enable (${CONF})" + echo " -c --conf-path Path to configuration file" + echo " -d --dir-git Path to where git sources should be saved" + echo " -s --disable-tsocks Disable use of tsocks" + exit 0 +} + +vmsetupdir=$(readlink -f "$(dirname "$0")") +rootdir=$(readlink -f "$vmsetupdir/../../../") + +managers=("$vmsetupdir/pkgdep/"*) +# Get package manager # +if hash dnf &> /dev/null; then + source "$vmsetupdir/pkgdep/dnf" +elif hash yum &> /dev/null; then + source "$vmsetupdir/pkgdep/yum" +elif hash apt-get &> /dev/null; then + source "$vmsetupdir/pkgdep/apt-get" +elif hash pacman &> /dev/null; then + source "$vmsetupdir/pkgdep/pacman" +elif hash pkg &> /dev/null; then + source "$vmsetupdir/pkgdep/pkg" +elif hash swupd &> /dev/null; then + source "$vmsetupdir/pkgdep/swupd" +else + package_manager="undefined" +fi + +# Parse input arguments # +while getopts 'd:siuht:c:-:' optchar; do + case "$optchar" in + -) + case "$OPTARG" in + help) usage ;; + upgrade) UPGRADE=true ;; + install-deps) INSTALL=true ;; + test-conf=*) CONF="${OPTARG#*=}" ;; + conf-path=*) CONF_PATH="${OPTARG#*=}" ;; + dir-git=*) GIT_REPOS="${OPTARG#*=}" ;; + disable-tsocks) NO_TSOCKS=true ;; + *) + echo "Invalid argument '$OPTARG'" + usage + ;; + esac + ;; + h) usage ;; + u) UPGRADE=true ;; + i) INSTALL=true ;; + t) CONF="$OPTARG" ;; + c) CONF_PATH="$OPTARG" ;; + d) GIT_REPOS="$OPTARG" ;; + s) NO_TSOCKS=true ;; + *) + echo "Invalid argument '$OPTARG'" + usage + ;; + esac +done + +if [[ "$package_manager" == "undefined" ]]; then + echo "Supported package manager not found. Script supports:" + printf ' * %s\n' "${managers[@]##*/}" + exit 1 +fi + +if [ -n "$CONF_PATH" ]; then + if [ ! -f "$CONF_PATH" ]; then + echo Configuration file does not exist: "$CONF_PATH" + exit 1 + else + source "$CONF_PATH" + fi +fi + +if $UPGRADE; then + upgrade +fi + +if $INSTALL; then + sudo "$rootdir/scripts/pkgdep.sh" --all + pre_install + install "${packages[@]}" +fi + +source "$vmsetupdir/pkgdep/git" + +# create autorun-spdk.conf in home folder. This is sourced by the autotest_common.sh file. +# By setting any one of the values below to 0, you can skip that specific test. If you are +# using your autotest platform to do sanity checks before uploading to the build pool, it is +# probably best to only run the tests that you believe your changes have modified along with +# Scanbuild and check format. This is because running the whole suite of tests in series can +# take ~40 minutes to complete. +if [ ! -e ~/autorun-spdk.conf ]; then + cat > ~/autorun-spdk.conf << EOF +# assign a value of 1 to all of the pertinent tests +SPDK_RUN_VALGRIND=1 +SPDK_TEST_CRYPTO=1 +SPDK_RUN_FUNCTIONAL_TEST=1 +SPDK_TEST_AUTOBUILD=1 +SPDK_TEST_UNITTEST=1 +SPDK_TEST_ISCSI=1 +SPDK_TEST_ISCSI_INITIATOR=1 +SPDK_TEST_NVME=1 +SPDK_TEST_NVME_CLI=1 +SPDK_TEST_NVMF=1 +SPDK_TEST_RBD=1 +SPDK_TEST_BLOCKDEV=1 +SPDK_TEST_BLOBFS=1 +SPDK_TEST_PMDK=1 +SPDK_TEST_LVOL=1 +SPDK_TEST_JSON=1 +SPDK_RUN_ASAN=1 +SPDK_RUN_UBSAN=1 +# doesn't work on vm +SPDK_TEST_IOAT=0 +# requires some extra configuration. see TEST_ENV_SETUP_README +SPDK_TEST_VHOST=0 +SPDK_TEST_VHOST_INIT=0 +# Not configured here +SPDK_RUN_INSTALLED_DPDK=0 + +EOF +fi diff --git a/src/spdk/test/common/lib/nvme/common_stubs.h b/src/spdk/test/common/lib/nvme/common_stubs.h new file mode 100644 index 000000000..1dc22a162 --- /dev/null +++ b/src/spdk/test/common/lib/nvme/common_stubs.h @@ -0,0 +1,117 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "common/lib/test_env.c" + +const char * +spdk_nvme_transport_id_trtype_str(enum spdk_nvme_transport_type trtype) +{ + switch (trtype) { + case SPDK_NVME_TRANSPORT_PCIE: + return "PCIe"; + case SPDK_NVME_TRANSPORT_RDMA: + return "RDMA"; + case SPDK_NVME_TRANSPORT_FC: + return "FC"; + default: + return NULL; + } +} + +int +spdk_nvme_transport_id_populate_trstring(struct spdk_nvme_transport_id *trid, const char *trstring) +{ + int len, i; + + if (trstring == NULL) { + return -EINVAL; + } + + len = strnlen(trstring, SPDK_NVMF_TRSTRING_MAX_LEN); + if (len == SPDK_NVMF_TRSTRING_MAX_LEN) { + return -EINVAL; + } + + /* cast official trstring to uppercase version of input. */ + for (i = 0; i < len; i++) { + trid->trstring[i] = toupper(trstring[i]); + } + return 0; +} + +DEFINE_STUB(nvme_request_check_timeout, int, (struct nvme_request *req, uint16_t cid, + struct spdk_nvme_ctrlr_process *active_proc, uint64_t now_tick), 0); +DEFINE_STUB_V(nvme_ctrlr_destruct_finish, (struct spdk_nvme_ctrlr *ctrlr)); +DEFINE_STUB(nvme_ctrlr_construct, int, (struct spdk_nvme_ctrlr *ctrlr), 0); +DEFINE_STUB_V(nvme_ctrlr_destruct, (struct spdk_nvme_ctrlr *ctrlr)); +DEFINE_STUB_V(nvme_ctrlr_init_cap, (struct spdk_nvme_ctrlr *ctrlr, + const union spdk_nvme_cap_register *cap, + const union spdk_nvme_vs_register *vs)); +DEFINE_STUB(nvme_ctrlr_get_vs, int, (struct spdk_nvme_ctrlr *ctrlr, + union spdk_nvme_vs_register *vs), 0); +DEFINE_STUB(nvme_ctrlr_get_cap, int, (struct spdk_nvme_ctrlr *ctrlr, + union spdk_nvme_cap_register *cap), 0); +DEFINE_STUB(nvme_qpair_init, int, (struct spdk_nvme_qpair *qpair, uint16_t id, + struct spdk_nvme_ctrlr *ctrlr, + enum spdk_nvme_qprio qprio, + uint32_t num_requests), 0); +DEFINE_STUB_V(nvme_qpair_deinit, (struct spdk_nvme_qpair *qpair)); +DEFINE_STUB_V(spdk_nvme_transport_register, (const struct spdk_nvme_transport_ops *ops)); +DEFINE_STUB(nvme_transport_ctrlr_connect_qpair, int, (struct spdk_nvme_ctrlr *ctrlr, + struct spdk_nvme_qpair *qpair), 0); +DEFINE_STUB(nvme_ctrlr_get_current_process, struct spdk_nvme_ctrlr_process *, + (struct spdk_nvme_ctrlr *ctrlr), (struct spdk_nvme_ctrlr_process *)(uintptr_t)0x1); +DEFINE_STUB(nvme_ctrlr_add_process, int, (struct spdk_nvme_ctrlr *ctrlr, void *devhandle), 0); +DEFINE_STUB_V(spdk_nvme_trid_populate_transport, (struct spdk_nvme_transport_id *trid, + enum spdk_nvme_transport_type trtype)); +DEFINE_STUB(nvme_get_transport, const struct spdk_nvme_transport *, (const char *transport_name), + NULL); +DEFINE_STUB(spdk_nvme_qpair_process_completions, int32_t, (struct spdk_nvme_qpair *qpair, + uint32_t max_completions), 0); + +/* Fabric transports only */ +DEFINE_STUB_V(nvme_ctrlr_disconnect_qpair, (struct spdk_nvme_qpair *qpair)); +DEFINE_STUB(nvme_fabric_ctrlr_set_reg_4, int, (struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, + uint32_t value), 0); +DEFINE_STUB(nvme_fabric_ctrlr_set_reg_8, int, (struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, + uint64_t value), 0); +DEFINE_STUB(nvme_fabric_ctrlr_get_reg_4, int, (struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, + uint32_t *value), 0); +DEFINE_STUB(nvme_fabric_ctrlr_get_reg_8, int, (struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, + uint64_t *value), 0); +DEFINE_STUB(nvme_fabric_ctrlr_scan, int, (struct spdk_nvme_probe_ctx *probe_ctx, + bool direct_connect), 0); +DEFINE_STUB(nvme_fabric_qpair_connect, int, (struct spdk_nvme_qpair *qpair, uint32_t num_entries), + 0); +DEFINE_STUB_V(nvme_transport_ctrlr_disconnect_qpair, (struct spdk_nvme_ctrlr *ctrlr, + struct spdk_nvme_qpair *qpair)); +DEFINE_STUB(nvme_poll_group_disconnect_qpair, int, (struct spdk_nvme_qpair *qpair), 0); diff --git a/src/spdk/test/common/lib/test_env.c b/src/spdk/test/common/lib/test_env.c new file mode 100644 index 000000000..5e2912b5c --- /dev/null +++ b/src/spdk/test/common/lib/test_env.c @@ -0,0 +1,637 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk_internal/mock.h" + +#include "spdk/env.h" +#include "spdk/queue.h" +#include "spdk/util.h" + +static uint32_t g_ut_num_cores; +static bool *g_ut_cores; + +void allocate_cores(uint32_t num_cores); +void free_cores(void); + +DEFINE_STUB(spdk_process_is_primary, bool, (void), true) +DEFINE_STUB(spdk_memzone_lookup, void *, (const char *name), NULL) +DEFINE_STUB_V(spdk_pci_driver_register, (const char *name, struct spdk_pci_id *id_table, + uint32_t flags)); +DEFINE_STUB(spdk_pci_nvme_get_driver, struct spdk_pci_driver *, (void), NULL) +DEFINE_STUB(spdk_pci_ioat_get_driver, struct spdk_pci_driver *, (void), NULL) +DEFINE_STUB(spdk_pci_virtio_get_driver, struct spdk_pci_driver *, (void), NULL) + +void +allocate_cores(uint32_t num_cores) +{ + uint32_t i; + + g_ut_num_cores = num_cores; + + g_ut_cores = calloc(num_cores, sizeof(bool)); + assert(g_ut_cores != NULL); + + for (i = 0; i < num_cores; i++) { + g_ut_cores[i] = true; + } +} + +void +free_cores(void) +{ + free(g_ut_cores); + g_ut_cores = NULL; + g_ut_num_cores = 0; +} + +static uint32_t +ut_get_next_core(uint32_t i) +{ + i++; + + while (i < g_ut_num_cores) { + if (!g_ut_cores[i]) { + i++; + continue; + } + break; + } + + if (i < g_ut_num_cores) { + return i; + } else { + return UINT32_MAX; + } +} + +uint32_t +spdk_env_get_first_core(void) +{ + return ut_get_next_core(-1); +} + +uint32_t +spdk_env_get_next_core(uint32_t prev_core) +{ + return ut_get_next_core(prev_core); +} + +uint32_t +spdk_env_get_core_count(void) +{ + return g_ut_num_cores; +} + +uint32_t +spdk_env_get_last_core(void) +{ + uint32_t i; + uint32_t last_core = UINT32_MAX; + + SPDK_ENV_FOREACH_CORE(i) { + last_core = i; + } + + return last_core; +} + +DEFINE_RETURN_MOCK(spdk_env_get_current_core, uint32_t); +uint32_t +spdk_env_get_current_core(void) +{ + HANDLE_RETURN_MOCK(spdk_env_get_current_core); + + return UINT32_MAX; +} + +DEFINE_RETURN_MOCK(spdk_env_get_socket_id, uint32_t); +uint32_t +spdk_env_get_socket_id(uint32_t core) +{ + HANDLE_RETURN_MOCK(spdk_env_get_socket_id); + + return SPDK_ENV_SOCKET_ID_ANY; +} + +/* + * These mocks don't use the DEFINE_STUB macros because + * their default implementation is more complex. + */ + +DEFINE_RETURN_MOCK(spdk_memzone_reserve, void *); +void * +spdk_memzone_reserve(const char *name, size_t len, int socket_id, unsigned flags) +{ + HANDLE_RETURN_MOCK(spdk_memzone_reserve); + + return malloc(len); +} + +DEFINE_RETURN_MOCK(spdk_memzone_reserve_aligned, void *); +void * +spdk_memzone_reserve_aligned(const char *name, size_t len, int socket_id, + unsigned flags, unsigned align) +{ + HANDLE_RETURN_MOCK(spdk_memzone_reserve_aligned); + + return malloc(len); +} + +DEFINE_RETURN_MOCK(spdk_malloc, void *); +void * +spdk_malloc(size_t size, size_t align, uint64_t *phys_addr, int socket_id, uint32_t flags) +{ + HANDLE_RETURN_MOCK(spdk_malloc); + + void *buf = NULL; + + if (align == 0) { + align = 8; + } + + if (posix_memalign(&buf, align, size)) { + return NULL; + } + if (phys_addr) { + *phys_addr = (uint64_t)buf; + } + + return buf; +} + +DEFINE_RETURN_MOCK(spdk_zmalloc, void *); +void * +spdk_zmalloc(size_t size, size_t align, uint64_t *phys_addr, int socket_id, uint32_t flags) +{ + HANDLE_RETURN_MOCK(spdk_zmalloc); + + void *buf = spdk_malloc(size, align, phys_addr, -1, 1); + + if (buf != NULL) { + memset(buf, 0, size); + } + return buf; +} + +DEFINE_RETURN_MOCK(spdk_dma_malloc, void *); +void * +spdk_dma_malloc(size_t size, size_t align, uint64_t *phys_addr) +{ + HANDLE_RETURN_MOCK(spdk_dma_malloc); + + return spdk_malloc(size, align, phys_addr, -1, 1); +} + +DEFINE_RETURN_MOCK(spdk_realloc, void *); +void * +spdk_realloc(void *buf, size_t size, size_t align) +{ + HANDLE_RETURN_MOCK(spdk_realloc); + + return realloc(buf, size); +} + +DEFINE_RETURN_MOCK(spdk_dma_zmalloc, void *); +void * +spdk_dma_zmalloc(size_t size, size_t align, uint64_t *phys_addr) +{ + HANDLE_RETURN_MOCK(spdk_dma_zmalloc); + + return spdk_zmalloc(size, align, phys_addr, -1, 1); +} + +DEFINE_RETURN_MOCK(spdk_dma_malloc_socket, void *); +void * +spdk_dma_malloc_socket(size_t size, size_t align, uint64_t *phys_addr, int socket_id) +{ + HANDLE_RETURN_MOCK(spdk_dma_malloc_socket); + + return spdk_dma_malloc(size, align, phys_addr); +} + +DEFINE_RETURN_MOCK(spdk_dma_zmalloc_socket, void *); +void * +spdk_dma_zmalloc_socket(size_t size, size_t align, uint64_t *phys_addr, int socket_id) +{ + HANDLE_RETURN_MOCK(spdk_dma_zmalloc_socket); + + return spdk_dma_zmalloc(size, align, phys_addr); +} + +DEFINE_RETURN_MOCK(spdk_dma_realloc, void *); +void * +spdk_dma_realloc(void *buf, size_t size, size_t align, uint64_t *phys_addr) +{ + HANDLE_RETURN_MOCK(spdk_dma_realloc); + + return realloc(buf, size); +} + +void +spdk_free(void *buf) +{ + /* fix for false-positives in *certain* static analysis tools. */ + assert((uintptr_t)buf != UINTPTR_MAX); + free(buf); +} + +void +spdk_dma_free(void *buf) +{ + return spdk_free(buf); +} + +#ifndef UNIT_TEST_NO_VTOPHYS +DEFINE_RETURN_MOCK(spdk_vtophys, uint64_t); +uint64_t +spdk_vtophys(void *buf, uint64_t *size) +{ + HANDLE_RETURN_MOCK(spdk_vtophys); + + return (uintptr_t)buf; +} +#endif + +void +spdk_memzone_dump(FILE *f) +{ + return; +} + +DEFINE_RETURN_MOCK(spdk_memzone_free, int); +int +spdk_memzone_free(const char *name) +{ + HANDLE_RETURN_MOCK(spdk_memzone_free); + + return 0; +} + +struct test_mempool { + size_t count; + size_t ele_size; +}; + +DEFINE_RETURN_MOCK(spdk_mempool_create, struct spdk_mempool *); +struct spdk_mempool * +spdk_mempool_create(const char *name, size_t count, + size_t ele_size, size_t cache_size, int socket_id) +{ + struct test_mempool *mp; + + HANDLE_RETURN_MOCK(spdk_mempool_create); + + mp = calloc(1, sizeof(*mp)); + if (mp == NULL) { + return NULL; + } + + mp->count = count; + mp->ele_size = ele_size; + + return (struct spdk_mempool *)mp; +} + +void +spdk_mempool_free(struct spdk_mempool *_mp) +{ + struct test_mempool *mp = (struct test_mempool *)_mp; + + free(mp); +} + +DEFINE_RETURN_MOCK(spdk_mempool_get, void *); +void * +spdk_mempool_get(struct spdk_mempool *_mp) +{ + struct test_mempool *mp = (struct test_mempool *)_mp; + size_t ele_size = 0x10000; + void *buf; + + HANDLE_RETURN_MOCK(spdk_mempool_get); + + if (mp && mp->count == 0) { + return NULL; + } + + if (mp) { + ele_size = mp->ele_size; + } + + if (posix_memalign(&buf, 64, spdk_align32pow2(ele_size))) { + return NULL; + } else { + if (mp) { + mp->count--; + } + return buf; + } +} + +int +spdk_mempool_get_bulk(struct spdk_mempool *mp, void **ele_arr, size_t count) +{ + for (size_t i = 0; i < count; i++) { + ele_arr[i] = spdk_mempool_get(mp); + if (ele_arr[i] == NULL) { + return -1; + } + } + return 0; +} + +void +spdk_mempool_put(struct spdk_mempool *_mp, void *ele) +{ + struct test_mempool *mp = (struct test_mempool *)_mp; + + if (mp) { + mp->count++; + } + free(ele); +} + +void +spdk_mempool_put_bulk(struct spdk_mempool *mp, void **ele_arr, size_t count) +{ + for (size_t i = 0; i < count; i++) { + spdk_mempool_put(mp, ele_arr[i]); + } +} + +DEFINE_RETURN_MOCK(spdk_mempool_count, size_t); +size_t +spdk_mempool_count(const struct spdk_mempool *_mp) +{ + struct test_mempool *mp = (struct test_mempool *)_mp; + + HANDLE_RETURN_MOCK(spdk_mempool_count); + + if (mp) { + return mp->count; + } else { + return 1024; + } +} + +struct spdk_ring_ele { + void *ele; + TAILQ_ENTRY(spdk_ring_ele) link; +}; + +struct spdk_ring { + TAILQ_HEAD(, spdk_ring_ele) elements; + pthread_mutex_t lock; + size_t count; +}; + +DEFINE_RETURN_MOCK(spdk_ring_create, struct spdk_ring *); +struct spdk_ring * +spdk_ring_create(enum spdk_ring_type type, size_t count, int socket_id) +{ + struct spdk_ring *ring; + + HANDLE_RETURN_MOCK(spdk_ring_create); + + ring = calloc(1, sizeof(*ring)); + if (!ring) { + return NULL; + } + + if (pthread_mutex_init(&ring->lock, NULL)) { + free(ring); + return NULL; + } + + TAILQ_INIT(&ring->elements); + return ring; +} + +void +spdk_ring_free(struct spdk_ring *ring) +{ + struct spdk_ring_ele *ele, *tmp; + + if (!ring) { + return; + } + + TAILQ_FOREACH_SAFE(ele, &ring->elements, link, tmp) { + free(ele); + } + + pthread_mutex_destroy(&ring->lock); + free(ring); +} + +DEFINE_RETURN_MOCK(spdk_ring_enqueue, size_t); +size_t +spdk_ring_enqueue(struct spdk_ring *ring, void **objs, size_t count, + size_t *free_space) +{ + struct spdk_ring_ele *ele; + size_t i; + + HANDLE_RETURN_MOCK(spdk_ring_enqueue); + + pthread_mutex_lock(&ring->lock); + + for (i = 0; i < count; i++) { + ele = calloc(1, sizeof(*ele)); + if (!ele) { + break; + } + + ele->ele = objs[i]; + TAILQ_INSERT_TAIL(&ring->elements, ele, link); + ring->count++; + } + + pthread_mutex_unlock(&ring->lock); + return i; +} + +DEFINE_RETURN_MOCK(spdk_ring_dequeue, size_t); +size_t +spdk_ring_dequeue(struct spdk_ring *ring, void **objs, size_t count) +{ + struct spdk_ring_ele *ele, *tmp; + size_t i = 0; + + HANDLE_RETURN_MOCK(spdk_ring_dequeue); + + if (count == 0) { + return 0; + } + + pthread_mutex_lock(&ring->lock); + + TAILQ_FOREACH_SAFE(ele, &ring->elements, link, tmp) { + TAILQ_REMOVE(&ring->elements, ele, link); + ring->count--; + objs[i] = ele->ele; + free(ele); + i++; + if (i >= count) { + break; + } + } + + pthread_mutex_unlock(&ring->lock); + return i; + +} + + +DEFINE_RETURN_MOCK(spdk_ring_count, size_t); +size_t +spdk_ring_count(struct spdk_ring *ring) +{ + HANDLE_RETURN_MOCK(spdk_ring_count); + return ring->count; +} + +DEFINE_RETURN_MOCK(spdk_get_ticks, uint64_t); +uint64_t +spdk_get_ticks(void) +{ + HANDLE_RETURN_MOCK(spdk_get_ticks); + + return ut_spdk_get_ticks; +} + +DEFINE_RETURN_MOCK(spdk_get_ticks_hz, uint64_t); +uint64_t +spdk_get_ticks_hz(void) +{ + HANDLE_RETURN_MOCK(spdk_get_ticks_hz); + + return 1000000; +} + +void +spdk_delay_us(unsigned int us) +{ + /* spdk_get_ticks_hz is 1000000, meaning 1 tick per us. */ + ut_spdk_get_ticks += us; +} + +#ifndef UNIT_TEST_NO_PCI_ADDR +DEFINE_RETURN_MOCK(spdk_pci_addr_parse, int); +int +spdk_pci_addr_parse(struct spdk_pci_addr *addr, const char *bdf) +{ + unsigned domain, bus, dev, func; + + HANDLE_RETURN_MOCK(spdk_pci_addr_parse); + + if (addr == NULL || bdf == NULL) { + return -EINVAL; + } + + if ((sscanf(bdf, "%x:%x:%x.%x", &domain, &bus, &dev, &func) == 4) || + (sscanf(bdf, "%x.%x.%x.%x", &domain, &bus, &dev, &func) == 4)) { + /* Matched a full address - all variables are initialized */ + } else if (sscanf(bdf, "%x:%x:%x", &domain, &bus, &dev) == 3) { + func = 0; + } else if ((sscanf(bdf, "%x:%x.%x", &bus, &dev, &func) == 3) || + (sscanf(bdf, "%x.%x.%x", &bus, &dev, &func) == 3)) { + domain = 0; + } else if ((sscanf(bdf, "%x:%x", &bus, &dev) == 2) || + (sscanf(bdf, "%x.%x", &bus, &dev) == 2)) { + domain = 0; + func = 0; + } else { + return -EINVAL; + } + + if (bus > 0xFF || dev > 0x1F || func > 7) { + return -EINVAL; + } + + addr->domain = domain; + addr->bus = bus; + addr->dev = dev; + addr->func = func; + + return 0; +} + +DEFINE_RETURN_MOCK(spdk_pci_addr_fmt, int); +int +spdk_pci_addr_fmt(char *bdf, size_t sz, const struct spdk_pci_addr *addr) +{ + int rc; + + HANDLE_RETURN_MOCK(spdk_pci_addr_fmt); + + rc = snprintf(bdf, sz, "%04x:%02x:%02x.%x", + addr->domain, addr->bus, + addr->dev, addr->func); + + if (rc > 0 && (size_t)rc < sz) { + return 0; + } + + return -1; +} + +DEFINE_RETURN_MOCK(spdk_pci_addr_compare, int); +int +spdk_pci_addr_compare(const struct spdk_pci_addr *a1, const struct spdk_pci_addr *a2) +{ + HANDLE_RETURN_MOCK(spdk_pci_addr_compare); + + if (a1->domain > a2->domain) { + return 1; + } else if (a1->domain < a2->domain) { + return -1; + } else if (a1->bus > a2->bus) { + return 1; + } else if (a1->bus < a2->bus) { + return -1; + } else if (a1->dev > a2->dev) { + return 1; + } else if (a1->dev < a2->dev) { + return -1; + } else if (a1->func > a2->func) { + return 1; + } else if (a1->func < a2->func) { + return -1; + } + + return 0; +} +#endif diff --git a/src/spdk/test/common/lib/test_rdma.c b/src/spdk/test/common/lib/test_rdma.c new file mode 100644 index 000000000..109862fe6 --- /dev/null +++ b/src/spdk/test/common/lib/test_rdma.c @@ -0,0 +1,49 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. All rights reserved. + * Copyright (c) 2020 Mellanox Technologies LTD. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk_internal/rdma.h" +#include "spdk_internal/mock.h" + +DEFINE_STUB(spdk_rdma_qp_create, struct spdk_rdma_qp *, (struct rdma_cm_id *cm_id, + struct spdk_rdma_qp_init_attr *qp_attr), NULL); +DEFINE_STUB(spdk_rdma_qp_accept, int, (struct spdk_rdma_qp *spdk_rdma_qp, + struct rdma_conn_param *conn_param), 0); +DEFINE_STUB(spdk_rdma_qp_complete_connect, int, (struct spdk_rdma_qp *spdk_rdma_qp), 0); +DEFINE_STUB_V(spdk_rdma_qp_destroy, (struct spdk_rdma_qp *spdk_rdma_qp)); +DEFINE_STUB(spdk_rdma_qp_disconnect, int, (struct spdk_rdma_qp *spdk_rdma_qp), 0); +DEFINE_STUB(spdk_rdma_qp_queue_send_wrs, bool, (struct spdk_rdma_qp *spdk_rdma_qp, + struct ibv_send_wr *first), true); +DEFINE_STUB(spdk_rdma_qp_flush_send_wrs, int, (struct spdk_rdma_qp *spdk_rdma_qp, + struct ibv_send_wr **bad_wr), 0); diff --git a/src/spdk/test/common/lib/test_sock.c b/src/spdk/test/common/lib/test_sock.c new file mode 100644 index 000000000..d2c83b732 --- /dev/null +++ b/src/spdk/test/common/lib/test_sock.c @@ -0,0 +1,70 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk_internal/sock.h" +#include "spdk_internal/mock.h" + +DEFINE_STUB(spdk_sock_getaddr, int, (struct spdk_sock *sock, char *saddr, int slen, uint16_t *sport, + char *caddr, int clen, uint16_t *cport), 0); +DEFINE_STUB(spdk_sock_connect, struct spdk_sock *, (const char *ip, int port, char *impl_name), + NULL); +DEFINE_STUB(spdk_sock_connect_ext, struct spdk_sock *, (const char *ip, int port, char *impl_name, + struct spdk_sock_opts *opts), NULL); +DEFINE_STUB(spdk_sock_listen, struct spdk_sock *, (const char *ip, int port, char *impl_name), + NULL); +DEFINE_STUB(spdk_sock_listen_ext, struct spdk_sock *, (const char *ip, int port, char *impl_name, + struct spdk_sock_opts *opts), NULL); +DEFINE_STUB_V(spdk_sock_get_default_opts, (struct spdk_sock_opts *opts)); +DEFINE_STUB(spdk_sock_accept, struct spdk_sock *, (struct spdk_sock *sock), NULL); +DEFINE_STUB(spdk_sock_close, int, (struct spdk_sock **sock), 0); +DEFINE_STUB(spdk_sock_recv, ssize_t, (struct spdk_sock *sock, void *buf, size_t len), 0); +DEFINE_STUB(spdk_sock_writev, ssize_t, (struct spdk_sock *sock, struct iovec *iov, int iovcnt), 0); +DEFINE_STUB(spdk_sock_readv, ssize_t, (struct spdk_sock *sock, struct iovec *iov, int iovcnt), 0); +DEFINE_STUB(spdk_sock_set_recvlowat, int, (struct spdk_sock *sock, int nbytes), 0); +DEFINE_STUB(spdk_sock_set_recvbuf, int, (struct spdk_sock *sock, int sz), 0); +DEFINE_STUB(spdk_sock_set_sendbuf, int, (struct spdk_sock *sock, int sz), 0); +DEFINE_STUB_V(spdk_sock_writev_async, (struct spdk_sock *sock, struct spdk_sock_request *req)); +DEFINE_STUB(spdk_sock_flush, int, (struct spdk_sock *sock), 0); +DEFINE_STUB(spdk_sock_is_ipv6, bool, (struct spdk_sock *sock), false); +DEFINE_STUB(spdk_sock_is_ipv4, bool, (struct spdk_sock *sock), true); +DEFINE_STUB(spdk_sock_is_connected, bool, (struct spdk_sock *sock), true); +DEFINE_STUB(spdk_sock_group_create, struct spdk_sock_group *, (void *ctx), NULL); +DEFINE_STUB(spdk_sock_group_add_sock, int, (struct spdk_sock_group *group, struct spdk_sock *sock, + spdk_sock_cb cb_fn, void *cb_arg), 0); +DEFINE_STUB(spdk_sock_group_remove_sock, int, (struct spdk_sock_group *group, + struct spdk_sock *sock), 0); +DEFINE_STUB(spdk_sock_group_poll, int, (struct spdk_sock_group *group), 0); +DEFINE_STUB(spdk_sock_group_poll_count, int, (struct spdk_sock_group *group, int max_events), 0); +DEFINE_STUB(spdk_sock_group_close, int, (struct spdk_sock_group **group), 0); diff --git a/src/spdk/test/common/lib/ut_multithread.c b/src/spdk/test/common/lib/ut_multithread.c new file mode 100644 index 000000000..30b78f74d --- /dev/null +++ b/src/spdk/test/common/lib/ut_multithread.c @@ -0,0 +1,214 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk_cunit.h" +#include "spdk/thread.h" +#include "spdk_internal/mock.h" +#include "spdk_internal/thread.h" + +#include "common/lib/test_env.c" + +static uint32_t g_ut_num_threads; + +int allocate_threads(int num_threads); +void free_threads(void); +void poll_threads(void); +bool poll_thread(uintptr_t thread_id); +bool poll_thread_times(uintptr_t thread_id, uint32_t max_polls); + +struct ut_msg { + spdk_msg_fn fn; + void *ctx; + TAILQ_ENTRY(ut_msg) link; +}; + +struct ut_thread { + struct spdk_thread *thread; + struct spdk_io_channel *ch; +}; + +struct ut_thread *g_ut_threads; + +#define INVALID_THREAD 0x1000 + +static uint64_t g_ut_thread_id = INVALID_THREAD; + +static void +set_thread(uintptr_t thread_id) +{ + g_ut_thread_id = thread_id; + if (thread_id == INVALID_THREAD) { + spdk_set_thread(NULL); + } else { + spdk_set_thread(g_ut_threads[thread_id].thread); + } + +} + +int +allocate_threads(int num_threads) +{ + struct spdk_thread *thread; + uint32_t i; + + spdk_thread_lib_init(NULL, 0); + + g_ut_num_threads = num_threads; + + g_ut_threads = calloc(num_threads, sizeof(*g_ut_threads)); + assert(g_ut_threads != NULL); + + for (i = 0; i < g_ut_num_threads; i++) { + set_thread(i); + thread = spdk_thread_create(NULL, NULL); + assert(thread != NULL); + g_ut_threads[i].thread = thread; + } + + set_thread(INVALID_THREAD); + return 0; +} + +void +free_threads(void) +{ + uint32_t i, num_threads; + struct spdk_thread *thread; + + for (i = 0; i < g_ut_num_threads; i++) { + set_thread(i); + thread = g_ut_threads[i].thread; + spdk_thread_exit(thread); + } + + num_threads = g_ut_num_threads; + + while (num_threads != 0) { + for (i = 0; i < g_ut_num_threads; i++) { + set_thread(i); + thread = g_ut_threads[i].thread; + if (thread == NULL) { + continue; + } + + if (spdk_thread_is_exited(thread)) { + g_ut_threads[i].thread = NULL; + num_threads--; + spdk_thread_destroy(thread); + } else { + spdk_thread_poll(thread, 0, 0); + } + } + } + + g_ut_num_threads = 0; + free(g_ut_threads); + g_ut_threads = NULL; + + spdk_thread_lib_fini(); +} + +bool +poll_thread_times(uintptr_t thread_id, uint32_t max_polls) +{ + bool busy = false; + struct ut_thread *thread = &g_ut_threads[thread_id]; + uintptr_t original_thread_id; + uint32_t polls_executed = 0; + uint64_t now; + + if (max_polls == 0) { + /* If max_polls is set to 0, + * poll until no operation is pending. */ + return poll_thread(thread_id); + } + assert(thread_id != (uintptr_t)INVALID_THREAD); + assert(thread_id < g_ut_num_threads); + + original_thread_id = g_ut_thread_id; + set_thread(INVALID_THREAD); + + now = spdk_get_ticks(); + while (polls_executed < max_polls) { + if (spdk_thread_poll(thread->thread, 1, now) > 0) { + busy = true; + } + now = spdk_thread_get_last_tsc(thread->thread); + polls_executed++; + } + + set_thread(original_thread_id); + + return busy; +} + +bool +poll_thread(uintptr_t thread_id) +{ + bool busy = false; + struct ut_thread *thread = &g_ut_threads[thread_id]; + uintptr_t original_thread_id; + uint64_t now; + + assert(thread_id != (uintptr_t)INVALID_THREAD); + assert(thread_id < g_ut_num_threads); + + original_thread_id = g_ut_thread_id; + set_thread(INVALID_THREAD); + + now = spdk_get_ticks(); + while (spdk_thread_poll(thread->thread, 0, now) > 0) { + now = spdk_thread_get_last_tsc(thread->thread); + busy = true; + } + + set_thread(original_thread_id); + + return busy; +} + +void +poll_threads(void) +{ + while (true) { + bool busy = false; + + for (uint32_t i = 0; i < g_ut_num_threads; i++) { + busy = busy || poll_thread(i); + } + + if (!busy) { + break; + } + } +} diff --git a/src/spdk/test/common/skipped_build_files.txt b/src/spdk/test/common/skipped_build_files.txt new file mode 100644 index 000000000..dca967681 --- /dev/null +++ b/src/spdk/test/common/skipped_build_files.txt @@ -0,0 +1,60 @@ +# Not configured to test vtune. +lib/bdev/vtune + +# Not configured to test VPP +module/sock/vpp/vpp + +# Not configured to test rocksdb env file +lib/rocksdb/env_spdk.cc + +# Not configured to test FC +lib/nvmf/fc +lib/nvmf/fc_ls +test/unit/lib/nvmf/fc.c/fc_ut +test/unit/lib/nvmf/fc_ls.c/fc_ls_ut + +# Not configured for Neon testing +lib/util/base64_neon + +# Not configured for mlx5 dv testing +lib/rdma/rdma_mlx5_dv + +# Files related to testing our internal vhost implementation. +lib/rte_vhost/fd_man +lib/rte_vhost/socket +lib/rte_vhost/vhost +lib/rte_vhost/vhost_user +lib/vhost/vhost_nvme +lib/virtio/vhost_user + +# Cuse related files, enable when ready. +lib/nvme/nvme_cuse +module/bdev/nvme/bdev_nvme_cuse_rpc +test/nvme/cuse/cuse + +# Currently we don't have this plumbed for testing, enable when ready. +module/bdev/uring/bdev_uring +module/bdev/uring/bdev_uring_rpc +module/sock/uring/uring + +# Currently not testing blobfs_fuse, enable when ready. +module/blobfs/bdev/blobfs_fuse +test/blobfs/fuse/fuse + + +# These files all represent c files that are only compiled by direct inclusion in other files. +test/common/lib/test_env +test/common/lib/test_sock +test/common/lib/ut_multithread +test/common/lib/test_rdma +test/unit/lib/blob/bs_dev_common +test/unit/lib/blob/bs_scheduler +test/unit/lib/ftl/common/utils +test/unit/lib/iscsi/common +test/unit/lib/json_mock +test/unit/lib/sock/uring.c/uring_ut + +# These files are in the external_code directory which doesn't get compiled with SPDK. +test/external_code/hello_world/hello_bdev +test/external_code/passthru/vbdev_passthru +test/external_code/passthru/vbdev_passthru_rpc diff --git a/src/spdk/test/common/skipped_tests.txt b/src/spdk/test/common/skipped_tests.txt new file mode 100644 index 000000000..d96957f2b --- /dev/null +++ b/src/spdk/test/common/skipped_tests.txt @@ -0,0 +1,73 @@ +# This file represents the tests we are intentionally skipping in CI testing. + +# cases +ftl_dirty_shutdown +ftl_fio_basic +ftl_fio_extended +ftl_restore_nv_cache + +# Waiting for test refactor +iscsi_tgt_fio_remote_nvme + +# VPP deprecated with 20.07 +iscsi_tgt_vpp + +# Waiting on significant test rewrite +nvme_opal +nvme_opal_bdevio +nvme_opal_bdevperf +nvme_opal_spdk_tgt + +# CI doesn't have FC hardware +nvmf_fc +spdkcli_nvmf_fc +unittest_nvmf_fc +unittest_nvmf_fc_ls + +# Enable after cuse tests switch to physical devices +nvme_ns_manage_cuse + +# These tests are currently only run manually +vhost_blk_fs_integrity +vhost_blk_hot_remove +vhost_scsi_hot_remove +vhost_hotplug + +# Waiting on hardware +vmd +vmd_bdev_svc +vmd_fio +vmd_hello_world +vmd_identify +vmd_perf + +# nightly tests +bdev_fio_rw_verify_ext +bdev_fio_trim_ext +bdev_reset +iscsi_tgt_digest +iscsi_tgt_data_digest +iscsi_tgt_pmem +iscsi_tgt_ext4test +iscsi_tgt_digests +iscsi_tgt_multiconnection +iscsi_tgt_fuzz +nvmf_fuzz +nvmf_multiconnection +nvmf_initiator_timeout +vhost_blk_2core_2ctrl +vhost_blk_1core_2ctrl +vhost_blk_fs_integrity +vhost_blk_integrity +vhost_blk_nightly +vhost_lvol_integrity_1core_1ctrl +vhost_migration +vhost_migration_tc1 +vhost_migration_tc2 +vhost_readonly +vhost_scsi_fs_integrity +vhost_scsi_integrity +vhost_scsi_nightly +vhost_scsi_2core_2ctrl +vhost_scsi_1core_2ctrl +vhost_scsi_1core_1ctrl |