1#!/usr/bin/env bash 2# SPDX-License-Identifier: BSD-3-Clause 3# Copyright (C) 2015 Intel Corporation 4# All rights reserved. 5# Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 6# 7rpc_py=rpc_cmd 8 9function xtrace_disable() { 10 set +x 11 X_STACK+=("${FUNCNAME[*]}") # push 12} 13 14function xtrace_restore() { 15 # unset'ing foo[-1] under older Bash (4.2 -> Centos7) won't work, hence the dance 16 unset -v "X_STACK[${#X_STACK[@]} - 1 < 0 ? 0 : ${#X_STACK[@]} - 1]" # pop 17 if ((${#X_STACK[@]} == 0)); then 18 set -x 19 fi 20} 21 22function xtrace_disable_per_cmd() { eval "$* ${BASH_XTRACEFD}> /dev/null"; } 23 24function xtrace_fd() { 25 if [[ -n ${BASH_XTRACEFD:-} && -e /proc/self/fd/$BASH_XTRACEFD ]]; then 26 # Close it first to make sure it's sane 27 exec {BASH_XTRACEFD}>&- 28 fi 29 exec {BASH_XTRACEFD}>&2 30 31 xtrace_restore 32} 33 34set -e 35shopt -s nullglob 36shopt -s extglob 37shopt -s inherit_errexit 38 39if [ -z "${output_dir:-}" ]; then 40 mkdir -p "$rootdir/../output" 41 export output_dir="$rootdir/../output" 42fi 43 44if [[ -e $rootdir/test/common/build_config.sh ]]; then 45 source "$rootdir/test/common/build_config.sh" 46elif [[ -e $rootdir/mk/config.mk ]]; then 47 build_config=$(< "$rootdir/mk/config.mk") 48 source <(echo "${build_config//\?=/=}") 49else 50 source "$rootdir/CONFIG" 51fi 52 53# Source scripts after the config so that the definitions are available. 54source "$rootdir/test/common/applications.sh" 55source "$rootdir/scripts/common.sh" 56source "$rootdir/scripts/perf/pm/common" 57 58: ${RUN_NIGHTLY:=0} 59export RUN_NIGHTLY 60 61# Set defaults for missing test config options 62: ${SPDK_AUTOTEST_DEBUG_APPS:=0} 63export SPDK_AUTOTEST_DEBUG_APPS 64: ${SPDK_RUN_VALGRIND=0} 65export SPDK_RUN_VALGRIND 66: ${SPDK_RUN_FUNCTIONAL_TEST=0} 67export SPDK_RUN_FUNCTIONAL_TEST 68: ${SPDK_TEST_UNITTEST=0} 69export SPDK_TEST_UNITTEST 70: ${SPDK_TEST_AUTOBUILD=""} 71export SPDK_TEST_AUTOBUILD 72: ${SPDK_TEST_RELEASE_BUILD=0} 73export SPDK_TEST_RELEASE_BUILD 74: ${SPDK_TEST_ISAL=0} 75export SPDK_TEST_ISAL 76: ${SPDK_TEST_ISCSI=0} 77export SPDK_TEST_ISCSI 78: ${SPDK_TEST_ISCSI_INITIATOR=0} 79export SPDK_TEST_ISCSI_INITIATOR 80: ${SPDK_TEST_NVME=0} 81export SPDK_TEST_NVME 82: ${SPDK_TEST_NVME_PMR=0} 83export SPDK_TEST_NVME_PMR 84: ${SPDK_TEST_NVME_BP=0} 85export SPDK_TEST_NVME_BP 86: ${SPDK_TEST_NVME_CLI=0} 87export SPDK_TEST_NVME_CLI 88: ${SPDK_TEST_NVME_CUSE=0} 89export SPDK_TEST_NVME_CUSE 90: ${SPDK_TEST_NVME_FDP=0} 91export SPDK_TEST_NVME_FDP 92: ${SPDK_TEST_NVMF=0} 93export SPDK_TEST_NVMF 94: ${SPDK_TEST_VFIOUSER=0} 95export SPDK_TEST_VFIOUSER 96: ${SPDK_TEST_VFIOUSER_QEMU=0} 97export SPDK_TEST_VFIOUSER_QEMU 98: ${SPDK_TEST_FUZZER=0} 99export SPDK_TEST_FUZZER 100: ${SPDK_TEST_FUZZER_SHORT=0} 101export SPDK_TEST_FUZZER_SHORT 102: ${SPDK_TEST_NVMF_TRANSPORT="rdma"} 103export SPDK_TEST_NVMF_TRANSPORT 104: ${SPDK_TEST_RBD=0} 105export SPDK_TEST_RBD 106: ${SPDK_TEST_VHOST=0} 107export SPDK_TEST_VHOST 108: ${SPDK_TEST_BLOCKDEV=0} 109export SPDK_TEST_BLOCKDEV 110: ${SPDK_TEST_IOAT=0} 111export SPDK_TEST_IOAT 112: ${SPDK_TEST_BLOBFS=0} 113export SPDK_TEST_BLOBFS 114: ${SPDK_TEST_VHOST_INIT=0} 115export SPDK_TEST_VHOST_INIT 116: ${SPDK_TEST_LVOL=0} 117export SPDK_TEST_LVOL 118: ${SPDK_TEST_VBDEV_COMPRESS=0} 119export SPDK_TEST_VBDEV_COMPRESS 120: ${SPDK_RUN_ASAN=0} 121export SPDK_RUN_ASAN 122: ${SPDK_RUN_UBSAN=0} 123export SPDK_RUN_UBSAN 124: ${SPDK_RUN_EXTERNAL_DPDK=""} 125export SPDK_RUN_EXTERNAL_DPDK 126: ${SPDK_RUN_NON_ROOT=0} 127export SPDK_RUN_NON_ROOT 128: ${SPDK_TEST_CRYPTO=0} 129export SPDK_TEST_CRYPTO 130: ${SPDK_TEST_FTL=0} 131export SPDK_TEST_FTL 132: ${SPDK_TEST_OCF=0} 133export SPDK_TEST_OCF 134: ${SPDK_TEST_VMD=0} 135export SPDK_TEST_VMD 136: ${SPDK_TEST_OPAL=0} 137export SPDK_TEST_OPAL 138: ${SPDK_TEST_NATIVE_DPDK} 139export SPDK_TEST_NATIVE_DPDK 140: ${SPDK_AUTOTEST_X=true} 141export SPDK_AUTOTEST_X 142: ${SPDK_TEST_RAID5=0} 143export SPDK_TEST_RAID5 144: ${SPDK_TEST_URING=0} 145export SPDK_TEST_URING 146: ${SPDK_TEST_USDT=0} 147export SPDK_TEST_USDT 148: ${SPDK_TEST_USE_IGB_UIO:=0} 149export SPDK_TEST_USE_IGB_UIO 150: ${SPDK_TEST_SCHEDULER:=0} 151export SPDK_TEST_SCHEDULER 152: ${SPDK_TEST_SCANBUILD:=0} 153export SPDK_TEST_SCANBUILD 154: ${SPDK_TEST_NVMF_NICS:=} 155export SPDK_TEST_NVMF_NICS 156: ${SPDK_TEST_SMA=0} 157export SPDK_TEST_SMA 158: ${SPDK_TEST_DAOS=0} 159export SPDK_TEST_DAOS 160: ${SPDK_TEST_XNVME:=0} 161export SPDK_TEST_XNVME 162: ${SPDK_TEST_ACCEL_DSA=0} 163export SPDK_TEST_ACCEL_DSA 164: ${SPDK_TEST_ACCEL_IAA=0} 165export SPDK_TEST_ACCEL_IAA 166# Comma-separated list of fuzzer targets matching test/fuzz/llvm/$target 167: ${SPDK_TEST_FUZZER_TARGET:=} 168export SPDK_TEST_FUZZER_TARGET 169: ${SPDK_TEST_NVMF_MDNS=0} 170export SPDK_TEST_NVMF_MDNS 171: ${SPDK_JSONRPC_GO_CLIENT=0} 172export SPDK_JSONRPC_GO_CLIENT 173 174# always test with SPDK shared objects. 175export SPDK_LIB_DIR="$rootdir/build/lib" 176export DPDK_LIB_DIR="${SPDK_RUN_EXTERNAL_DPDK:-$rootdir/dpdk/build}/lib" 177export VFIO_LIB_DIR="$rootdir/build/libvfio-user/usr/local/lib" 178export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SPDK_LIB_DIR:$DPDK_LIB_DIR:$VFIO_LIB_DIR 179 180# Tell setup.sh to wait for block devices upon each reset 181export PCI_BLOCK_SYNC_ON_RESET=yes 182 183# Export PYTHONPATH with addition of RPC framework. New scripts can be created 184# specific use cases for tests. 185export PYTHONPATH=$PYTHONPATH:$rootdir/python 186 187# Don't create Python .pyc files. When running with sudo these will be 188# created with root ownership and can cause problems when cleaning the repository. 189export PYTHONDONTWRITEBYTECODE=1 190 191# Export new_delete_type_mismatch to skip the known bug that exists in librados 192# https://tracker.ceph.com/issues/24078 193export ASAN_OPTIONS=new_delete_type_mismatch=0:disable_coredump=0:abort_on_error=1:use_sigaltstack=0 194export UBSAN_OPTIONS='halt_on_error=1:print_stacktrace=1:abort_on_error=1:disable_coredump=0:exitcode=134' 195 196# Export LeakSanitizer option to use suppression file in order to prevent false positives 197# and known leaks in external executables or libraries from showing up. 198asan_suppression_file="/var/tmp/asan_suppression_file" 199rm -rf "$asan_suppression_file" 2> /dev/null || sudo rm -rf "$asan_suppression_file" 200cat << EOL >> "$asan_suppression_file" 201# ASAN has some bugs around thread_local variables. We have a destructor in place 202# to free the thread contexts, but ASAN complains about the leak before those 203# destructors have a chance to run. So suppress this one specific leak using 204# LSAN_OPTIONS. 205leak:spdk_fs_alloc_thread_ctx 206 207# Suppress known leaks in fio project 208leak:$CONFIG_FIO_SOURCE_DIR/parse.c 209leak:$CONFIG_FIO_SOURCE_DIR/iolog.c 210leak:$CONFIG_FIO_SOURCE_DIR/init.c 211leak:$CONFIG_FIO_SOURCE_DIR/filesetup.c 212leak:fio_memalign 213leak:spdk_fio_io_u_init 214# Suppress leaks in gperftools-libs from fio 215leak:libtcmalloc_minimal.so 216 217# Suppress leaks in libiscsi 218leak:libiscsi.so 219 220# Suppress leaks in libcrypto 221# Below is caused by openssl 3.0.8 leaks 222leak:libcrypto.so 223 224# Suppress leaks in accel-config 225# Versions with unresolved leaks: 226# v3.4.6.4 [Fedora 37] 227leak:add_wq 228leak:add_group 229# v3.5.2 [Fedora 38] 230leak:accfg_get_param_str 231# v4.0 [Fedora 39] 232leak:__scandir64_tail 233EOL 234 235# Suppress leaks in libfuse3 236echo "leak:libfuse3.so" >> "$asan_suppression_file" 237 238export LSAN_OPTIONS=suppressions="$asan_suppression_file" 239 240export DEFAULT_RPC_ADDR="/var/tmp/spdk.sock" 241 242if [ -z "${DEPENDENCY_DIR:-}" ]; then 243 export DEPENDENCY_DIR=/var/spdk/dependencies 244else 245 export DEPENDENCY_DIR 246fi 247 248# Export location of where all the SPDK binaries are 249export SPDK_BIN_DIR="$rootdir/build/bin" 250export SPDK_EXAMPLE_DIR="$rootdir/build/examples" 251 252# for vhost, vfio-user tests 253export QEMU_BIN=${QEMU_BIN:-} 254export VFIO_QEMU_BIN=${VFIO_QEMU_BIN:-} 255 256export AR_TOOL=$rootdir/scripts/ar-xnvme-fixer 257 258# For testing nvmes which are attached to some sort of a fanout switch in the CI pool 259export UNBIND_ENTIRE_IOMMU_GROUP=${UNBIND_ENTIRE_IOMMU_GROUP:-no} 260 261# pass our valgrind desire on to unittest.sh 262if [ $SPDK_RUN_VALGRIND -eq 0 ]; then 263 export valgrind='' 264else 265 # unset all DEBUGINFOD_* vars that may affect our valgrind instance 266 unset -v "${!DEBUGINFOD_@}" 267fi 268 269if [ "$(uname -s)" = "Linux" ]; then 270 HUGEMEM=${HUGEMEM:-4096} 271 export CLEAR_HUGE=yes 272 if [[ $SPDK_TEST_CRYPTO -eq 1 || $SPDK_TEST_VBDEV_COMPRESS -eq 1 ]]; then 273 # Make sure that memory is distributed across all NUMA nodes - by default, all goes to 274 # node0, but if QAT devices are attached to a different node, all of their VFs will end 275 # up under that node too and memory needs to be available there for the tests. 276 export HUGE_EVEN_ALLOC=yes 277 fi 278 279 MAKE="make" 280 MAKEFLAGS=${MAKEFLAGS:--j$(nproc)} 281elif [ "$(uname -s)" = "FreeBSD" ]; then 282 MAKE="gmake" 283 MAKEFLAGS=${MAKEFLAGS:--j$(sysctl -a | grep -E -i 'hw.ncpu' | awk '{print $2}')} 284 # FreeBSD runs a much more limited set of tests, so keep the default 2GB. 285 HUGEMEM=${HUGEMEM:-2048} 286elif [ "$(uname -s)" = "Windows" ]; then 287 MAKE="make" 288 MAKEFLAGS=${MAKEFLAGS:--j$(nproc)} 289 # Keep the default 2GB for Windows. 290 HUGEMEM=${HUGEMEM:-2048} 291else 292 echo "Unknown OS \"$(uname -s)\"" 293 exit 1 294fi 295 296export HUGEMEM=$HUGEMEM 297 298NO_HUGE=() 299TEST_MODE= 300for i in "$@"; do 301 case "$i" in 302 --iso) 303 TEST_MODE=iso 304 ;; 305 --transport=*) 306 TEST_TRANSPORT="${i#*=}" 307 ;; 308 --sock=*) 309 TEST_SOCK="${i#*=}" 310 ;; 311 --no-hugepages) 312 NO_HUGE=(--no-huge -s 1024) 313 ;; 314 esac 315done 316 317# start rpc.py coprocess if it's not started yet 318if [[ -z ${RPC_PIPE_PID:-} ]] || ! kill -0 "$RPC_PIPE_PID" &> /dev/null; then 319 # Include list to all known plugins we use in the tests 320 PYTHONPATH+=":$rootdir/test/rpc_plugins" 321 coproc RPC_PIPE { PYTHONPATH="$PYTHONPATH" "$rootdir/scripts/rpc.py" --server; } 322 exec {RPC_PIPE_OUTPUT}<&${RPC_PIPE[0]} {RPC_PIPE_INPUT}>&${RPC_PIPE[1]} 323 # all descriptors will automatically close together with this bash 324 # process, this will make rpc.py stop reading and exit gracefully 325fi 326 327function set_test_storage() { 328 [[ -v testdir ]] || return 0 329 330 local requested_size=$1 # bytes 331 local mount target_dir 332 333 local -A mounts fss sizes avails uses 334 local source fs size avail mount use 335 336 local storage_fallback storage_candidates 337 338 storage_fallback=$(mktemp -udt spdk.XXXXXX) 339 storage_candidates=( 340 "$testdir" 341 "$storage_fallback/tests/${testdir##*/}" 342 "$storage_fallback" 343 ) 344 345 if [[ -n ${ADD_TEST_STORAGE:-} ]]; then 346 # List of dirs|mounts separated by whitespaces 347 storage_candidates+=($ADD_TEST_STORAGE) 348 fi 349 350 if [[ -n ${DEDICATED_TEST_STORAGE:-} ]]; then 351 # Single, dedicated dir|mount 352 storage_candidates=("$DEDICATED_TEST_STORAGE") 353 fi 354 355 mkdir -p "${storage_candidates[@]}" 356 357 # add some headroom - 64M 358 requested_size=$((requested_size + (64 << 20))) 359 360 while read -r source fs size use avail _ mount; do 361 mounts["$mount"]=$source fss["$mount"]=$fs 362 avails["$mount"]=$((avail * 1024)) sizes["$mount"]=$((size * 1024)) 363 uses["$mount"]=$((use * 1024)) 364 done < <(df -T | grep -v Filesystem) 365 366 printf '* Looking for test storage...\n' >&2 367 368 local target_space new_size 369 for target_dir in "${storage_candidates[@]}"; do 370 # FreeBSD's df is lacking the --output arg 371 # mount=$(df --output=target "$target_dir" | grep -v "Mounted on") 372 mount=$(df "$target_dir" | awk '$1 !~ /Filesystem/{print $6}') 373 374 target_space=${avails["$mount"]} 375 if ((target_space == 0 || target_space < requested_size)); then 376 continue 377 fi 378 if ((target_space >= requested_size)); then 379 # For in-memory fs, and / make sure our requested size won't fill most of the space. 380 if [[ ${fss["$mount"]} == tmpfs ]] || [[ ${fss["$mount"]} == ramfs ]] || [[ $mount == / ]]; then 381 new_size=$((uses["$mount"] + requested_size)) 382 if ((new_size * 100 / sizes["$mount"] > 95)); then 383 continue 384 fi 385 fi 386 fi 387 export SPDK_TEST_STORAGE=$target_dir 388 printf '* Found test storage at %s\n' "$SPDK_TEST_STORAGE" >&2 389 return 0 390 done 391 printf '* Test storage is not available\n' 392 return 1 393} 394 395function get_config_params() { 396 xtrace_disable 397 config_params='--enable-debug --enable-werror' 398 399 # for options with dependencies but no test flag, set them here 400 if [ -f /usr/include/infiniband/verbs.h ]; then 401 config_params+=' --with-rdma' 402 fi 403 404 if [ $SPDK_TEST_USDT -eq 1 ]; then 405 config_params+=" --with-usdt" 406 fi 407 408 if [ $(uname -s) == "FreeBSD" ]; then 409 intel="hw.model: Intel" 410 cpu_vendor=$(sysctl -a | grep hw.model | cut -c 1-15) 411 else 412 intel="GenuineIntel" 413 cpu_vendor=$(grep -i 'vendor' /proc/cpuinfo --max-count=1) 414 fi 415 if [[ "$cpu_vendor" != *"$intel"* ]]; then 416 config_params+=" --without-idxd" 417 else 418 config_params+=" --with-idxd" 419 fi 420 421 if [[ -d $CONFIG_FIO_SOURCE_DIR ]]; then 422 config_params+=" --with-fio=$CONFIG_FIO_SOURCE_DIR" 423 fi 424 425 if [ -d ${DEPENDENCY_DIR}/vtune_codes ]; then 426 config_params+=' --with-vtune='${DEPENDENCY_DIR}'/vtune_codes' 427 fi 428 429 if [ -d /usr/include/iscsi ]; then 430 [[ $(< /usr/include/iscsi/iscsi.h) =~ "define LIBISCSI_API_VERSION ("([0-9]+)")" ]] \ 431 && libiscsi_version=${BASH_REMATCH[1]} 432 if ((libiscsi_version >= 20150621)); then 433 config_params+=' --with-iscsi-initiator' 434 fi 435 fi 436 437 if [[ $SPDK_TEST_UNITTEST -eq 0 && \ 438 $SPDK_TEST_SCANBUILD -eq 0 && -z \ 439 ${SPDK_TEST_AUTOBUILD:-} ]]; then 440 config_params+=' --disable-unit-tests' 441 fi 442 443 if [ -f /usr/include/libpmem.h ] && [ $SPDK_TEST_VBDEV_COMPRESS -eq 1 ]; then 444 if ge "$(nasm --version | awk '{print $3}')" 2.14 && [[ $SPDK_TEST_ISAL -eq 1 ]]; then 445 config_params+=' --with-vbdev-compress --with-dpdk-compressdev' 446 fi 447 fi 448 449 if [ -d /usr/include/rbd ] && [ -d /usr/include/rados ] && [ $SPDK_TEST_RBD -eq 1 ]; then 450 config_params+=' --with-rbd' 451 fi 452 453 # for options with no required dependencies, just test flags, set them here 454 if [ $SPDK_TEST_CRYPTO -eq 1 ]; then 455 config_params+=' --with-crypto' 456 fi 457 458 if [ $SPDK_TEST_OCF -eq 1 ]; then 459 config_params+=" --with-ocf" 460 fi 461 462 if [ $SPDK_RUN_UBSAN -eq 1 ]; then 463 config_params+=' --enable-ubsan' 464 fi 465 466 if [ $SPDK_RUN_ASAN -eq 1 ]; then 467 config_params+=' --enable-asan' 468 fi 469 470 if [ "$(uname -s)" = "Linux" ]; then 471 config_params+=' --enable-coverage' 472 fi 473 474 if [ $SPDK_TEST_BLOBFS -eq 1 ]; then 475 if [[ -d /usr/include/fuse3 ]] || [[ -d /usr/local/include/fuse3 ]]; then 476 config_params+=' --with-fuse' 477 fi 478 fi 479 480 if [[ -f /usr/include/liburing/io_uring.h && -f /usr/include/linux/ublk_cmd.h ]]; then 481 config_params+=' --with-ublk' 482 fi 483 484 if [ $SPDK_TEST_RAID5 -eq 1 ]; then 485 config_params+=' --with-raid5f' 486 fi 487 488 if [ $SPDK_TEST_VFIOUSER -eq 1 ] || [ $SPDK_TEST_VFIOUSER_QEMU -eq 1 ] || [ $SPDK_TEST_SMA -eq 1 ]; then 489 config_params+=' --with-vfio-user' 490 fi 491 492 # Check whether liburing library header exists 493 if [ -f /usr/include/liburing/io_uring.h ] && [ $SPDK_TEST_URING -eq 1 ]; then 494 config_params+=' --with-uring' 495 fi 496 497 if [ -n "${SPDK_RUN_EXTERNAL_DPDK:-}" ]; then 498 config_params+=" --with-dpdk=$SPDK_RUN_EXTERNAL_DPDK" 499 fi 500 501 if [[ $SPDK_TEST_SMA -eq 1 ]]; then 502 config_params+=' --with-sma' 503 config_params+=' --with-crypto' 504 fi 505 506 if [ -f /usr/include/daos.h ] && [ $SPDK_TEST_DAOS -eq 1 ]; then 507 config_params+=' --with-daos' 508 fi 509 510 # Make the xnvme module available for the tests 511 if [[ $SPDK_TEST_XNVME -eq 1 ]]; then 512 config_params+=' --with-xnvme' 513 fi 514 515 if [[ $SPDK_TEST_FUZZER -eq 1 ]]; then 516 config_params+=" $(get_fuzzer_target_config)" 517 fi 518 519 if [[ $SPDK_TEST_NVMF_MDNS -eq 1 ]]; then 520 config_params+=' --with-avahi' 521 fi 522 523 if [[ $SPDK_JSONRPC_GO_CLIENT -eq 1 ]]; then 524 config_params+=' --with-golang' 525 fi 526 527 echo "$config_params" 528 xtrace_restore 529} 530 531function get_fuzzer_target_config() { 532 local -A fuzzer_targets_to_config=() 533 local config target 534 535 fuzzer_targets_to_config["vfio"]="--with-vfio-user" 536 for target in $(get_fuzzer_targets); do 537 [[ -n ${fuzzer_targets_to_config["$target"]:-} ]] || continue 538 config+=("${fuzzer_targets_to_config["$target"]}") 539 done 540 541 if ((${#config[@]} > 0)); then 542 echo "${config[*]}" 543 fi 544} 545 546function get_fuzzer_targets() { 547 local fuzzers=() 548 549 if [[ -n ${SPDK_TEST_FUZZER_TARGET:-} ]]; then 550 IFS="," read -ra fuzzers <<< "$SPDK_TEST_FUZZER_TARGET" 551 else 552 fuzzers=("$rootdir/test/fuzz/llvm/"*) 553 fuzzers=("${fuzzers[@]##*/}") 554 fi 555 556 echo "${fuzzers[*]}" 557} 558 559function rpc_cmd() { 560 xtrace_disable 561 local rsp rc=1 562 local stdin cmd cmds_number=0 status_number=0 status 563 564 if (($#)); then 565 cmds_number=1 566 echo "$@" >&$RPC_PIPE_INPUT 567 elif [[ ! -t 0 ]]; then 568 mapfile -t stdin <&0 569 cmds_number=${#stdin[@]} 570 printf '%s\n' "${stdin[@]}" >&$RPC_PIPE_INPUT 571 else 572 return 0 573 fi 574 575 while read -t "${RPC_PIPE_TIMEOUT:-15}" -ru $RPC_PIPE_OUTPUT rsp; do 576 if [[ $rsp == "**STATUS="* ]]; then 577 status[${rsp#*=}]=$rsp 578 if ((++status_number == cmds_number)); then 579 break 580 fi 581 continue 582 fi 583 echo "$rsp" 584 done 585 586 rc=${!status[*]} 587 xtrace_restore 588 [[ $rc == 0 ]] 589} 590 591function rpc_cmd_simple_data_json() { 592 593 local elems="$1[@]" elem 594 local -gA jq_out=() 595 local jq val 596 597 local lvs=( 598 "uuid" 599 "name" 600 "base_bdev" 601 "total_data_clusters" 602 "free_clusters" 603 "block_size" 604 "cluster_size" 605 ) 606 607 local bdev=( 608 "name" 609 "aliases[0]" 610 "block_size" 611 "num_blocks" 612 "uuid" 613 "product_name" 614 "supported_io_types.read" 615 "supported_io_types.write" 616 "driver_specific.lvol.clone" 617 "driver_specific.lvol.base_snapshot" 618 "driver_specific.lvol.esnap_clone" 619 "driver_specific.lvol.external_snapshot_name" 620 ) 621 622 [[ -v $elems ]] || return 1 623 624 for elem in "${!elems}"; do 625 jq="${jq:+$jq,\"\\n\",}\"$elem\",\" \",.[0].$elem" 626 done 627 jq+=',"\n"' 628 629 shift 630 while read -r elem val; do 631 jq_out["$elem"]=$val 632 done < <(rpc_cmd "$@" | jq -jr "$jq") 633 ((${#jq_out[@]} > 0)) || return 1 634} 635 636function valid_exec_arg() { 637 local arg=$1 638 # First argument must be the executable so do some basic sanity checks first. For bash, this 639 # covers two basic cases where es == 126 || es == 127 so catch them early on and fail hard 640 # if needed. 641 case "$(type -t "$arg")" in 642 builtin | function) ;; 643 file) arg=$(type -P "$arg") && [[ -x $arg ]] ;; 644 *) return 1 ;; 645 esac 646} 647 648function NOT() { 649 local es=0 650 651 valid_exec_arg "$@" || return 1 652 "$@" || es=$? 653 654 # Logic looks like so: 655 # - return false if command exit successfully 656 # - return false if command exit after receiving a core signal (FIXME: or any signal?) 657 # - return true if command exit with an error 658 659 # This naively assumes that the process doesn't exit with > 128 on its own. 660 if ((es > 128)); then 661 es=$((es & ~128)) 662 case "$es" in 663 3) ;& # SIGQUIT 664 4) ;& # SIGILL 665 6) ;& # SIGABRT 666 8) ;& # SIGFPE 667 9) ;& # SIGKILL 668 11) es=0 ;; # SIGSEGV 669 *) es=1 ;; 670 esac 671 elif [[ -n ${EXIT_STATUS:-} ]] && ((es != EXIT_STATUS)); then 672 es=0 673 fi 674 675 # invert error code of any command and also trigger ERR on 0 (unlike bash ! prefix) 676 ((!es == 0)) 677} 678 679function timing() { 680 direction="$1" 681 testname="$2" 682 683 now=$(date +%s) 684 685 if [ "$direction" = "enter" ]; then 686 export timing_stack="${timing_stack:-};${now}" 687 export test_stack="${test_stack:-};${testname}" 688 else 689 touch "$output_dir/timing.txt" 690 child_time=$(grep "^${test_stack:1};" $output_dir/timing.txt | awk '{s+=$2} END {print s}') 691 692 start_time=$(echo "$timing_stack" | sed -e 's@^.*;@@') 693 timing_stack=$(echo "$timing_stack" | sed -e 's@;[^;]*$@@') 694 695 elapsed=$((now - start_time - child_time)) 696 echo "${test_stack:1} $elapsed" >> $output_dir/timing.txt 697 698 test_stack=$(echo "$test_stack" | sed -e 's@;[^;]*$@@') 699 fi 700} 701 702function timing_cmd() ( 703 # The use-case here is this: ts=$(timing_cmd echo bar). Since stdout is always redirected 704 # to a pipe handling the $(), lookup the stdin's device and determine if it's sane to send 705 # cmd's output to it. If not, just null it. 706 local cmd_es=$? 707 708 [[ -t 0 ]] && exec {cmd_out}>&0 || exec {cmd_out}> /dev/null 709 710 local time=0 TIMEFORMAT=%2R # seconds 711 712 # We redirect cmd's std{out,err} to a separate fd dup'ed to stdin's device (or /dev/null) to 713 # catch only output from the time builtin - output from the actual cmd would be still visible, 714 # but $() will return just the time's data, hence making it possible to just do: 715 # time_of_super_verbose_cmd=$(timing_cmd super_verbose_cmd) 716 time=$({ time "$@" >&"$cmd_out" 2>&1; } 2>&1) || cmd_es=$? 717 echo "$time" 718 719 return "$cmd_es" 720) 721 722function timing_enter() { 723 xtrace_disable 724 timing "enter" "$1" 725 xtrace_restore 726} 727 728function timing_exit() { 729 xtrace_disable 730 timing "exit" "$1" 731 xtrace_restore 732} 733 734function timing_finish() { 735 flamegraph='/usr/local/FlameGraph/flamegraph.pl' 736 if [ -x "$flamegraph" ]; then 737 "$flamegraph" \ 738 --title 'Build Timing' \ 739 --nametype 'Step:' \ 740 --countname seconds \ 741 $output_dir/timing.txt \ 742 > $output_dir/timing.svg 743 fi 744} 745 746function create_test_list() { 747 xtrace_disable 748 # First search all scripts in main SPDK directory. 749 completion=$(grep -shI -d skip --include="*.sh" -e "run_test " $rootdir/*) 750 # Follow up with search in test directory recursively. 751 completion+=$'\n'$(grep -rshI --include="*.sh" --exclude="*autotest_common.sh" -e "run_test " $rootdir/test) 752 printf "%s" "$completion" | grep -v "#" \ 753 | sed 's/^.*run_test/run_test/' | awk '{print $2}' \ 754 | sed 's/\"//g' | sort > $output_dir/all_tests.txt || true 755 xtrace_restore 756} 757 758function gdb_attach() { 759 gdb -q --batch \ 760 -ex 'handle SIGHUP nostop pass' \ 761 -ex 'handle SIGQUIT nostop pass' \ 762 -ex 'handle SIGPIPE nostop pass' \ 763 -ex 'handle SIGALRM nostop pass' \ 764 -ex 'handle SIGTERM nostop pass' \ 765 -ex 'handle SIGUSR1 nostop pass' \ 766 -ex 'handle SIGUSR2 nostop pass' \ 767 -ex 'handle SIGCHLD nostop pass' \ 768 -ex 'set print thread-events off' \ 769 -ex 'cont' \ 770 -ex 'thread apply all bt' \ 771 -ex 'quit' \ 772 --tty=/dev/stdout \ 773 -p $1 774} 775 776function process_core() { 777 # Note that this always was racy as we can't really sync with the kernel 778 # to see if there's any core queued up for writing. We could check if 779 # collector is running and wait for it explicitly, but it doesn't seem 780 # to be worth the effort. So assume that if we are being called via 781 # trap, as in, when some error has occurred, wait up to 10s for any 782 # potential cores. If we are called just for cleanup at the very end, 783 # don't wait since all the tests ended successfully, hence having any 784 # critical cores lying around is unlikely. 785 ((autotest_es != 0)) && sleep 10 786 787 local coredumps core 788 789 coredumps=("$output_dir/coredumps/"*.bt.txt) 790 791 ((${#coredumps[@]} > 0)) || return 0 792 chmod -R a+r "$output_dir/coredumps" 793 794 for core in "${coredumps[@]}"; do 795 cat <<- BT 796 ##### CORE BT ${core##*/} ##### 797 798 $(<"$core") 799 800 -- 801 BT 802 done 803 return 1 804} 805 806function process_shm() { 807 type=$1 808 id=$2 809 if [ "$type" = "--pid" ]; then 810 id="pid${id}" 811 fi 812 813 shm_files=$(find /dev/shm -name "*.${id}" -printf "%f\n") 814 815 if [[ -z ${shm_files:-} ]]; then 816 echo "SHM File for specified PID or shared memory id: ${id} not found!" 817 return 1 818 fi 819 for n in $shm_files; do 820 tar -C /dev/shm/ -cvzf $output_dir/${n}_shm.tar.gz ${n} 821 done 822 return 0 823} 824 825# Parameters: 826# $1 - process pid 827# $2 - rpc address (optional) 828# $3 - max retries (optional) 829function waitforlisten() { 830 if [ -z "${1:-}" ]; then 831 exit 1 832 fi 833 834 local rpc_addr="${2:-$DEFAULT_RPC_ADDR}" 835 local max_retries=${3:-100} 836 837 echo "Waiting for process to start up and listen on UNIX domain socket $rpc_addr..." 838 # turn off trace for this loop 839 xtrace_disable 840 local ret=0 841 local i 842 for ((i = max_retries; i != 0; i--)); do 843 # if the process is no longer running, then exit the script 844 # since it means the application crashed 845 if ! kill -s 0 $1; then 846 echo "ERROR: process (pid: $1) is no longer running" 847 ret=1 848 break 849 fi 850 851 if $rootdir/scripts/rpc.py -t 1 -s "$rpc_addr" rpc_get_methods &> /dev/null; then 852 break 853 fi 854 855 sleep 0.5 856 done 857 858 xtrace_restore 859 if ((i == 0)); then 860 echo "ERROR: timeout while waiting for process (pid: $1) to start listening on '$rpc_addr'" 861 ret=1 862 fi 863 return $ret 864} 865 866function waitfornbd() { 867 local nbd_name=$1 868 local i 869 870 for ((i = 1; i <= 20; i++)); do 871 if grep -q -w $nbd_name /proc/partitions; then 872 break 873 else 874 sleep 0.1 875 fi 876 done 877 878 # The nbd device is now recognized as a block device, but there can be 879 # a small delay before we can start I/O to that block device. So loop 880 # here trying to read the first block of the nbd block device to a temp 881 # file. Note that dd returns success when reading an empty file, so we 882 # need to check the size of the output file instead. 883 for ((i = 1; i <= 20; i++)); do 884 dd if=/dev/$nbd_name of="$SPDK_TEST_STORAGE/nbdtest" bs=4096 count=1 iflag=direct 885 size=$(stat -c %s "$SPDK_TEST_STORAGE/nbdtest") 886 rm -f "$SPDK_TEST_STORAGE/nbdtest" 887 if [ "$size" != "0" ]; then 888 return 0 889 else 890 sleep 0.1 891 fi 892 done 893 894 return 1 895} 896 897function waitforbdev() { 898 local bdev_name=$1 899 local bdev_timeout=$2 900 local i 901 [[ -z ${bdev_timeout:-} ]] && bdev_timeout=2000 # ms 902 903 $rpc_py bdev_wait_for_examine 904 905 if $rpc_py bdev_get_bdevs -b $bdev_name -t $bdev_timeout; then 906 return 0 907 fi 908 909 return 1 910} 911 912function waitforcondition() { 913 local cond=$1 914 local max=${2:-10} 915 while ((max--)); do 916 if eval $cond; then 917 return 0 918 fi 919 sleep 1 920 done 921 return 1 922} 923 924function make_filesystem() { 925 local fstype=$1 926 local dev_name=$2 927 local i=0 928 local force 929 930 if [ $fstype = ext4 ]; then 931 force=-F 932 else 933 force=-f 934 fi 935 936 while ! mkfs.${fstype} $force ${dev_name}; do 937 if [ $i -ge 15 ]; then 938 return 1 939 fi 940 i=$((i + 1)) 941 sleep 1 942 done 943 944 return 0 945} 946 947function killprocess() { 948 # $1 = process pid 949 if [ -z "${1:-}" ]; then 950 return 1 951 fi 952 953 if kill -0 $1; then 954 if [ $(uname) = Linux ]; then 955 process_name=$(ps --no-headers -o comm= $1) 956 else 957 process_name=$(ps -c -o command $1 | tail -1) 958 fi 959 if [ "$process_name" = "sudo" ]; then 960 # kill the child process, which is the actual app 961 # (assume $1 has just one child) 962 local child 963 child="$(pgrep -P $1)" 964 echo "killing process with pid $child" 965 kill $child 966 else 967 echo "killing process with pid $1" 968 kill $1 969 fi 970 971 # wait for the process regardless if its the dummy sudo one 972 # or the actual app - it should terminate anyway 973 wait $1 974 else 975 # the process is not there anymore 976 echo "Process with pid $1 is not found" 977 fi 978} 979 980function iscsicleanup() { 981 echo "Cleaning up iSCSI connection" 982 iscsiadm -m node --logout || true 983 iscsiadm -m node -o delete || true 984 rm -rf /var/lib/iscsi/nodes/* 985} 986 987function stop_iscsi_service() { 988 if cat /etc/*-release | grep Ubuntu; then 989 service open-iscsi stop 990 else 991 service iscsid stop 992 fi 993} 994 995function start_iscsi_service() { 996 if cat /etc/*-release | grep Ubuntu; then 997 service open-iscsi start 998 else 999 service iscsid start 1000 fi 1001} 1002 1003function rbd_setup() { 1004 # $1 = monitor ip address 1005 # $2 = name of the namespace 1006 if [ -z "${1:-}" ]; then 1007 echo "No monitor IP address provided for ceph" 1008 exit 1 1009 fi 1010 if [ -n "${2:-}" ]; then 1011 if ip netns list | grep "$2"; then 1012 NS_CMD="ip netns exec $2" 1013 else 1014 echo "No namespace $2 exists" 1015 exit 1 1016 fi 1017 fi 1018 1019 if hash ceph; then 1020 export PG_NUM=128 1021 export RBD_POOL=rbd 1022 export RBD_NAME=foo 1023 $NS_CMD $rootdir/scripts/ceph/stop.sh || true 1024 $NS_CMD $rootdir/scripts/ceph/start.sh $1 1025 1026 $NS_CMD ceph osd pool create $RBD_POOL $PG_NUM || true 1027 $NS_CMD rbd create $RBD_NAME --size 1000 1028 fi 1029} 1030 1031function rbd_cleanup() { 1032 if hash ceph; then 1033 $rootdir/scripts/ceph/stop.sh || true 1034 rm -f /var/tmp/ceph_raw.img 1035 fi 1036} 1037 1038function daos_setup() { 1039 # $1 = pool name 1040 # $2 = cont name 1041 if [ -z "${1:-}" ]; then 1042 echo "No pool name provided" 1043 exit 1 1044 fi 1045 if [ -z "${2:-}" ]; then 1046 echo "No cont name provided" 1047 exit 1 1048 fi 1049 1050 dmg pool create --size=10G $1 || true 1051 daos container create --type=POSIX --label=$2 $1 || true 1052} 1053 1054function daos_cleanup() { 1055 local pool=${1:-testpool} 1056 local cont=${2:-testcont} 1057 1058 daos container destroy -f $pool $cont || true 1059 sudo dmg pool destroy -f $pool || true 1060} 1061 1062function _start_stub() { 1063 # Disable ASLR for multi-process testing. SPDK does support using DPDK multi-process, 1064 # but ASLR can still be unreliable in some cases. 1065 # We will re-enable it again after multi-process testing is complete in kill_stub(). 1066 # Save current setting so it can be restored upon calling kill_stub(). 1067 _randomize_va_space=$(< /proc/sys/kernel/randomize_va_space) 1068 echo 0 > /proc/sys/kernel/randomize_va_space 1069 $rootdir/test/app/stub/stub $1 & 1070 stubpid=$! 1071 echo Waiting for stub to ready for secondary processes... 1072 while ! [ -e /var/run/spdk_stub0 ]; do 1073 # If stub dies while we wait, bail 1074 [[ -e /proc/$stubpid ]] || return 1 1075 sleep 1s 1076 done 1077 echo done. 1078} 1079 1080function start_stub() { 1081 if ! _start_stub "$@"; then 1082 echo "stub failed" >&2 1083 return 1 1084 fi 1085} 1086 1087function kill_stub() { 1088 if [[ -e /proc/$stubpid ]]; then 1089 kill $1 $stubpid 1090 wait $stubpid 1091 fi 2> /dev/null || : 1092 rm -f /var/run/spdk_stub0 1093 # Re-enable ASLR now that we are done with multi-process testing 1094 # Note: "1" enables ASLR w/o randomizing data segments, "2" adds data segment 1095 # randomizing and is the default on all recent Linux kernels 1096 echo "${_randomize_va_space:-2}" > /proc/sys/kernel/randomize_va_space 1097} 1098 1099function run_test() { 1100 if [ $# -le 1 ]; then 1101 echo "Not enough parameters" 1102 echo "usage: run_test test_name test_script [script_params]" 1103 exit 1 1104 fi 1105 1106 xtrace_disable 1107 local test_name="$1" pid 1108 shift 1109 1110 if [ -n "${test_domain:-}" ]; then 1111 export test_domain="${test_domain}.${test_name}" 1112 else 1113 export test_domain="$test_name" 1114 fi 1115 1116 # Signal our daemons to update the test tag 1117 update_tag_monitor_resources "$test_domain" 1118 1119 timing_enter $test_name 1120 echo "************************************" 1121 echo "START TEST $test_name" 1122 echo "************************************" 1123 xtrace_restore 1124 time "$@" 1125 xtrace_disable 1126 echo "************************************" 1127 echo "END TEST $test_name" 1128 echo "************************************" 1129 timing_exit $test_name 1130 1131 export test_domain=${test_domain%"$test_name"} 1132 if [ -n "$test_domain" ]; then 1133 export test_domain=${test_domain%?} 1134 fi 1135 1136 if [ -z "${test_domain:-}" ]; then 1137 echo "top_level $test_name" >> $output_dir/test_completions.txt 1138 else 1139 echo "$test_domain $test_name" >> $output_dir/test_completions.txt 1140 fi 1141 xtrace_restore 1142} 1143 1144function skip_run_test_with_warning() { 1145 echo "WARNING: $1" 1146 echo "Test run may fail if run with autorun.sh" 1147 echo "Please check your $rootdir/test/common/skipped_tests.txt" 1148} 1149 1150function print_backtrace() { 1151 # if errexit is not enabled, don't print a backtrace 1152 [[ "$-" =~ e ]] || return 0 1153 1154 local args=("${BASH_ARGV[@]}") 1155 1156 xtrace_disable 1157 # Reset IFS in case we were called from an environment where it was modified 1158 IFS=" "$'\t'$'\n' 1159 echo "========== Backtrace start: ==========" 1160 echo "" 1161 for ((i = 1; i < ${#FUNCNAME[@]}; i++)); do 1162 local func="${FUNCNAME[$i]}" 1163 local line_nr="${BASH_LINENO[$((i - 1))]}" 1164 local src="${BASH_SOURCE[$i]}" 1165 local bt="" cmdline=() 1166 1167 if [[ -f $src ]]; then 1168 bt=$(nl -w 4 -ba -nln $src | grep -B 5 -A 5 "^${line_nr}[^0-9]" \ 1169 | sed "s/^/ /g" | sed "s/^ $line_nr /=> $line_nr /g") 1170 fi 1171 1172 # If extdebug set the BASH_ARGC[i], try to fetch all the args 1173 if ((BASH_ARGC[i] > 0)); then 1174 # Use argc as index to reverse the stack 1175 local argc=${BASH_ARGC[i]} arg 1176 for arg in "${args[@]::BASH_ARGC[i]}"; do 1177 cmdline[argc--]="[\"$arg\"]" 1178 done 1179 args=("${args[@]:BASH_ARGC[i]}") 1180 fi 1181 1182 echo "in $src:$line_nr -> $func($( 1183 IFS="," 1184 printf '%s\n' "${cmdline[*]:-[]}" 1185 ))" 1186 echo " ..." 1187 echo "${bt:-backtrace unavailable}" 1188 echo " ..." 1189 done 1190 echo "" 1191 echo "========== Backtrace end ==========" 1192 xtrace_restore 1193 return 0 1194} 1195 1196function waitforserial() { 1197 local i=0 1198 local nvme_device_counter=1 nvme_devices=0 1199 if [[ -n "${2:-}" ]]; then 1200 nvme_device_counter=$2 1201 fi 1202 1203 # Wait initially for min 2s to make sure all devices are ready for use. 1204 sleep 2 1205 while ((i++ <= 15)); do 1206 nvme_devices=$(lsblk -l -o NAME,SERIAL | grep -c "$1") 1207 ((nvme_devices == nvme_device_counter)) && return 0 1208 if ((nvme_devices > nvme_device_counter)); then 1209 echo "$nvme_device_counter device(s) expected, found $nvme_devices" >&2 1210 fi 1211 echo "Waiting for devices" 1212 sleep 1 1213 done 1214 return 1 1215} 1216 1217function waitforserial_disconnect() { 1218 local i=0 1219 while lsblk -o NAME,SERIAL | grep -q -w $1; do 1220 [ $i -lt 15 ] || break 1221 i=$((i + 1)) 1222 echo "Waiting for disconnect devices" 1223 sleep 1 1224 done 1225 1226 if lsblk -l -o NAME,SERIAL | grep -q -w $1; then 1227 return 1 1228 fi 1229 1230 return 0 1231} 1232 1233function waitforblk() { 1234 local i=0 1235 while ! lsblk -l -o NAME | grep -q -w $1; do 1236 [ $i -lt 15 ] || break 1237 i=$((i + 1)) 1238 sleep 1 1239 done 1240 1241 if ! lsblk -l -o NAME | grep -q -w $1; then 1242 return 1 1243 fi 1244 1245 return 0 1246} 1247 1248function waitforblk_disconnect() { 1249 local i=0 1250 while lsblk -l -o NAME | grep -q -w $1; do 1251 [ $i -lt 15 ] || break 1252 i=$((i + 1)) 1253 sleep 1 1254 done 1255 1256 if lsblk -l -o NAME | grep -q -w $1; then 1257 return 1 1258 fi 1259 1260 return 0 1261} 1262 1263function waitforfile() { 1264 local i=0 1265 while [ ! -e $1 ]; do 1266 [ $i -lt 200 ] || break 1267 i=$((i + 1)) 1268 sleep 0.1 1269 done 1270 1271 if [ ! -e $1 ]; then 1272 return 1 1273 fi 1274 1275 return 0 1276} 1277 1278function fio_config_gen() { 1279 local config_file=$1 1280 local workload=$2 1281 local bdev_type=$3 1282 local env_context=$4 1283 local fio_dir=$CONFIG_FIO_SOURCE_DIR 1284 1285 if [ -e "$config_file" ]; then 1286 echo "Configuration File Already Exists!: $config_file" 1287 return 1 1288 fi 1289 1290 if [ -z "${workload:-}" ]; then 1291 workload=randrw 1292 fi 1293 1294 if [ -n "$env_context" ]; then 1295 env_context="env_context=$env_context" 1296 fi 1297 1298 touch $1 1299 1300 cat > $1 << EOL 1301[global] 1302thread=1 1303$env_context 1304group_reporting=1 1305direct=1 1306norandommap=1 1307percentile_list=50:99:99.9:99.99:99.999 1308time_based=1 1309ramp_time=0 1310EOL 1311 1312 if [ "$workload" == "verify" ]; then 1313 cat <<- EOL >> $config_file 1314 verify=sha1 1315 verify_backlog=1024 1316 rw=randwrite 1317 EOL 1318 1319 # To avoid potential data race issue due to the AIO device 1320 # flush mechanism, add the flag to serialize the writes. 1321 # This is to fix the intermittent IO failure issue of #935 1322 if [ "$bdev_type" == "AIO" ]; then 1323 if [[ $($fio_dir/fio --version) == *"fio-3"* ]]; then 1324 echo "serialize_overlap=1" >> $config_file 1325 fi 1326 fi 1327 elif [ "$workload" == "trim" ]; then 1328 echo "rw=trimwrite" >> $config_file 1329 else 1330 echo "rw=$workload" >> $config_file 1331 fi 1332} 1333 1334function fio_plugin() { 1335 # Setup fio binary cmd line 1336 local fio_dir=$CONFIG_FIO_SOURCE_DIR 1337 # gcc and clang uses different sanitizer libraries 1338 local sanitizers=(libasan libclang_rt.asan) 1339 local plugin=$1 1340 shift 1341 1342 local asan_lib= 1343 for sanitizer in "${sanitizers[@]}"; do 1344 asan_lib=$(ldd $plugin | grep $sanitizer | awk '{print $3}') 1345 if [[ -n "${asan_lib:-}" ]]; then 1346 break 1347 fi 1348 done 1349 1350 # Preload the sanitizer library to fio if fio_plugin was compiled with it 1351 LD_PRELOAD="$asan_lib $plugin" "$fio_dir"/fio "$@" 1352} 1353 1354function fio_bdev() { 1355 fio_plugin "$rootdir/build/fio/spdk_bdev" "$@" 1356} 1357 1358function fio_nvme() { 1359 fio_plugin "$rootdir/build/fio/spdk_nvme" "$@" 1360} 1361 1362function get_lvs_free_mb() { 1363 local lvs_uuid=$1 1364 local lvs_info 1365 local fc 1366 local cs 1367 lvs_info=$($rpc_py bdev_lvol_get_lvstores) 1368 fc=$(jq ".[] | select(.uuid==\"$lvs_uuid\") .free_clusters" <<< "$lvs_info") 1369 cs=$(jq ".[] | select(.uuid==\"$lvs_uuid\") .cluster_size" <<< "$lvs_info") 1370 1371 # Change to MB's 1372 free_mb=$((fc * cs / 1024 / 1024)) 1373 echo "$free_mb" 1374} 1375 1376function get_bdev_size() { 1377 local bdev_name=$1 1378 local bdev_info 1379 local bs 1380 local nb 1381 bdev_info=$($rpc_py bdev_get_bdevs -b $bdev_name) 1382 bs=$(jq ".[] .block_size" <<< "$bdev_info") 1383 nb=$(jq ".[] .num_blocks" <<< "$bdev_info") 1384 1385 # Change to MB's 1386 bdev_size=$((bs * nb / 1024 / 1024)) 1387 echo "$bdev_size" 1388} 1389 1390function autotest_cleanup() { 1391 local autotest_es=$? 1392 xtrace_disable 1393 1394 # Slurp at_app_exit() so we can kill all lingering vhost and qemu processes 1395 # in one swing. We do this in a subshell as vhost/common.sh is too eager to 1396 # do some extra work which we don't care about in this context. 1397 # shellcheck source=/dev/null 1398 vhost_reap() (source "$rootdir/test/vhost/common.sh" &> /dev/null || return 0 && at_app_exit) 1399 1400 # catch any stray core files and kill all remaining SPDK processes. Update 1401 # autotest_es in case autotest reported success but cores and/or processes 1402 # were left behind regardless. 1403 1404 process_core || autotest_es=1 1405 reap_spdk_processes || autotest_es=1 1406 vhost_reap || autotest_es=1 1407 1408 $rootdir/scripts/setup.sh reset 1409 $rootdir/scripts/setup.sh cleanup 1410 if [ $(uname -s) = "Linux" ]; then 1411 modprobe -r uio_pci_generic 1412 fi 1413 rm -rf "$asan_suppression_file" 1414 if [[ -n ${old_core_pattern:-} ]]; then 1415 echo "$old_core_pattern" > /proc/sys/kernel/core_pattern 1416 fi 1417 if [[ -e /proc/$udevadm_pid/status ]]; then 1418 kill "$udevadm_pid" || : 1419 fi 1420 1421 local storage_fallback_purge=("${TMPDIR:-/tmp}/spdk."??????) 1422 1423 if ((${#storage_fallback_purge[@]} > 0)); then 1424 rm -rf "${storage_fallback_purge[@]}" 1425 fi 1426 1427 if ((autotest_es)); then 1428 if [[ $(uname) == FreeBSD ]]; then 1429 ps aux 1430 elif [[ $(uname) == Linux ]]; then 1431 # Get more detailed view 1432 grep . /proc/[0-9]*/status 1433 # Dump some extra info into kernel log 1434 echo "######## Autotest Cleanup Dump ########" > /dev/kmsg 1435 # Show cpus backtraces 1436 echo l > /proc/sysrq-trigger 1437 # Show mem usage 1438 echo m > /proc/sysrq-trigger 1439 # show task states 1440 echo t > /proc/sysrq-trigger 1441 # show blocked tasks 1442 echo w > /proc/sysrq-trigger 1443 1444 fi > "$output_dir/proc_list.txt" 2>&1 || : 1445 fi 1446 1447 stop_monitor_resources 1448 1449 xtrace_restore 1450 return $autotest_es 1451} 1452 1453function freebsd_update_contigmem_mod() { 1454 if [ $(uname) = FreeBSD ]; then 1455 kldunload contigmem.ko || true 1456 if [ -n "${SPDK_RUN_EXTERNAL_DPDK:-}" ]; then 1457 cp -f "$SPDK_RUN_EXTERNAL_DPDK/kmod/contigmem.ko" /boot/modules/ 1458 cp -f "$SPDK_RUN_EXTERNAL_DPDK/kmod/contigmem.ko" /boot/kernel/ 1459 cp -f "$SPDK_RUN_EXTERNAL_DPDK/kmod/nic_uio.ko" /boot/modules/ 1460 cp -f "$SPDK_RUN_EXTERNAL_DPDK/kmod/nic_uio.ko" /boot/kernel/ 1461 else 1462 cp -f "$rootdir/dpdk/build/kmod/contigmem.ko" /boot/modules/ 1463 cp -f "$rootdir/dpdk/build/kmod/contigmem.ko" /boot/kernel/ 1464 cp -f "$rootdir/dpdk/build/kmod/nic_uio.ko" /boot/modules/ 1465 cp -f "$rootdir/dpdk/build/kmod/nic_uio.ko" /boot/kernel/ 1466 fi 1467 fi 1468} 1469 1470function freebsd_set_maxsock_buf() { 1471 # FreeBSD needs 4MB maxsockbuf size to pass socket unit tests. 1472 # Otherwise tests fail due to ENOBUFS when trying to do setsockopt(SO_RCVBUF|SO_SNDBUF). 1473 # See https://github.com/spdk/spdk/issues/2943 1474 if [[ $(uname) = FreeBSD ]] && (($(sysctl -n kern.ipc.maxsockbuf) < 4194304)); then 1475 sysctl kern.ipc.maxsockbuf=4194304 1476 fi 1477} 1478 1479function get_nvme_name_from_bdf() { 1480 blkname=() 1481 1482 nvme_devs=$(lsblk -d --output NAME | grep "^nvme") || true 1483 if [ -z "${nvme_devs:-}" ]; then 1484 return 1485 fi 1486 for dev in $nvme_devs; do 1487 link_name=$(readlink /sys/block/$dev/device/device) || true 1488 if [ -z "${link_name:-}" ]; then 1489 link_name=$(readlink /sys/block/$dev/device) 1490 fi 1491 bdf=$(basename "$link_name") 1492 if [ "$bdf" = "$1" ]; then 1493 blkname+=($dev) 1494 fi 1495 done 1496 1497 printf '%s\n' "${blkname[@]}" 1498} 1499 1500function get_nvme_ctrlr_from_bdf() { 1501 bdf_sysfs_path=$(readlink -f /sys/class/nvme/nvme* | grep "$1/nvme/nvme") 1502 if [[ -z "${bdf_sysfs_path:-}" ]]; then 1503 return 1504 fi 1505 1506 printf '%s\n' "$(basename $bdf_sysfs_path)" 1507} 1508 1509# Get BDF addresses of all NVMe drives currently attached to 1510# uio-pci-generic or vfio-pci 1511function get_nvme_bdfs() { 1512 local bdfs=() 1513 bdfs=($("$rootdir/scripts/gen_nvme.sh" | jq -r '.config[].params.traddr')) 1514 if ((${#bdfs[@]} == 0)); then 1515 echo "No bdevs found" >&2 1516 return 1 1517 fi 1518 printf '%s\n' "${bdfs[@]}" 1519} 1520 1521# Same as function above, but just get the first disks BDF address 1522function get_first_nvme_bdf() { 1523 local bdfs=() 1524 bdfs=($(get_nvme_bdfs)) 1525 1526 echo "${bdfs[0]}" 1527} 1528 1529function nvme_namespace_revert() { 1530 $rootdir/scripts/setup.sh 1531 sleep 1 1532 local bdfs=() 1533 bdfs=($(get_nvme_bdfs)) 1534 1535 $rootdir/scripts/setup.sh reset 1536 1537 for bdf in "${bdfs[@]}"; do 1538 nvme_ctrlr=/dev/$(get_nvme_ctrlr_from_bdf ${bdf}) 1539 if [[ -z "${nvme_ctrlr:-}" ]]; then 1540 continue 1541 fi 1542 1543 # Check Optional Admin Command Support for Namespace Management 1544 oacs=$(nvme id-ctrl ${nvme_ctrlr} | grep oacs | cut -d: -f2) 1545 oacs_ns_manage=$((oacs & 0x8)) 1546 1547 if [[ "$oacs_ns_manage" -ne 0 ]]; then 1548 # This assumes every NVMe controller contains single namespace, 1549 # encompassing Total NVM Capacity and formatted as 512 block size. 1550 # 512 block size is needed for test/vhost/vhost_boot.sh to 1551 # successfully run. 1552 1553 unvmcap=$(nvme id-ctrl ${nvme_ctrlr} | grep unvmcap | cut -d: -f2) 1554 if [[ "$unvmcap" -eq 0 ]]; then 1555 # All available space already used 1556 continue 1557 fi 1558 tnvmcap=$(nvme id-ctrl ${nvme_ctrlr} | grep tnvmcap | cut -d: -f2) 1559 cntlid=$(nvme id-ctrl ${nvme_ctrlr} | grep cntlid | cut -d: -f2) 1560 blksize=512 1561 1562 size=$((tnvmcap / blksize)) 1563 1564 nvme detach-ns ${nvme_ctrlr} -n 0xffffffff -c $cntlid || true 1565 nvme delete-ns ${nvme_ctrlr} -n 0xffffffff || true 1566 nvme create-ns ${nvme_ctrlr} -s ${size} -c ${size} -b ${blksize} 1567 nvme attach-ns ${nvme_ctrlr} -n 1 -c $cntlid 1568 nvme reset ${nvme_ctrlr} 1569 waitforfile "${nvme_ctrlr}n1" 1570 fi 1571 done 1572} 1573 1574# Get BDFs based on device ID, such as 0x0a54 1575function get_nvme_bdfs_by_id() { 1576 local bdfs=() 1577 1578 for bdf in $(get_nvme_bdfs); do 1579 device=$(cat /sys/bus/pci/devices/$bdf/device) || true 1580 if [[ "$device" == "$1" ]]; then 1581 bdfs+=($bdf) 1582 fi 1583 done 1584 1585 printf '%s\n' "${bdfs[@]}" 1586} 1587 1588function opal_revert_cleanup() { 1589 # The OPAL CI tests is only used for P4510 devices. 1590 mapfile -t bdfs < <(get_nvme_bdfs_by_id 0x0a54) 1591 if [[ -z ${bdfs[0]:-} ]]; then 1592 return 0 1593 fi 1594 1595 $SPDK_BIN_DIR/spdk_tgt & 1596 spdk_tgt_pid=$! 1597 waitforlisten $spdk_tgt_pid 1598 1599 bdf_id=0 1600 for bdf in "${bdfs[@]}"; do 1601 $rootdir/scripts/rpc.py bdev_nvme_attach_controller -b "nvme"${bdf_id} -t "pcie" -a ${bdf} 1602 # Ignore if this fails. 1603 $rootdir/scripts/rpc.py bdev_nvme_opal_revert -b "nvme"${bdf_id} -p test || true 1604 ((++bdf_id)) 1605 done 1606 1607 killprocess $spdk_tgt_pid 1608} 1609 1610function pap() { 1611 while read -r file; do 1612 cat <<- FILE 1613 --- $file --- 1614 $(<"$file") 1615 --- $file --- 1616 FILE 1617 rm -f "$file" 1618 done < <(find "$@" -type f | sort -u) 1619} 1620 1621function get_proc_paths() { 1622 case "$(uname -s)" in 1623 Linux) # ps -e -opid,exe <- not supported under {centos7,rocky8}'s procps-ng 1624 local pid exe 1625 for pid in /proc/[0-9]*; do 1626 exe=$(readlink "$pid/exe") || continue 1627 exe=${exe/ (deleted)/} 1628 echo "${pid##*/} $exe" 1629 done 1630 ;; 1631 FreeeBSD) procstat -ab | awk '{print $1, $4}' ;; 1632 esac 1633} 1634 1635exec_files() { file "$@" | awk -F: '/ELF.+executable/{print $1}'; } 1636 1637function reap_spdk_processes() { 1638 local bins test_bins procs 1639 local spdk_procs spdk_pids 1640 1641 mapfile -t test_bins < <(find "$rootdir"/test/{app,env,event} -type f) 1642 mapfile -t bins < <( 1643 exec_files "${test_bins[@]}" 1644 readlink -f "$SPDK_BIN_DIR/"* "$SPDK_EXAMPLE_DIR/"* 1645 ) 1646 1647 mapfile -t spdk_procs < <(get_proc_paths | grep -E "$( 1648 IFS="|" 1649 echo "${bins[*]#$rootdir/}" 1650 )" || true) 1651 ((${#spdk_procs[@]} > 0)) || return 0 1652 1653 printf '%s is still up, killing\n' "${spdk_procs[@]}" >&2 1654 mapfile -t spdk_pids < <(printf '%s\n' "${spdk_procs[@]}" | awk '{print $1}') 1655 1656 kill -SIGKILL "${spdk_pids[@]}" 2> /dev/null || : 1657 return 1 1658} 1659 1660function is_block_zoned() { 1661 local device=$1 1662 1663 [[ -e /sys/block/$device/queue/zoned ]] || return 1 1664 [[ $(< "/sys/block/$device/queue/zoned") != none ]] 1665} 1666 1667function get_zoned_devs() { 1668 local -gA zoned_devs=() 1669 local nvme bdf 1670 1671 for nvme in /sys/block/nvme*; do 1672 if is_block_zoned "${nvme##*/}"; then 1673 zoned_devs["${nvme##*/}"]=$(< "$nvme/device/address") 1674 fi 1675 done 1676} 1677 1678# Define temp storage for all the tests. Look for 2GB at minimum 1679set_test_storage "${TEST_MIN_STORAGE_SIZE:-$((1 << 31))}" 1680 1681set -o errtrace 1682shopt -s extdebug 1683trap "trap - ERR; print_backtrace >&2" ERR 1684 1685PS4=' \t $test_domain -- ${BASH_SOURCE#${BASH_SOURCE%/*/*}/}@${LINENO} -- \$ ' 1686if $SPDK_AUTOTEST_X; then 1687 # explicitly enable xtraces, overriding any tracking information. 1688 xtrace_fd 1689else 1690 xtrace_disable 1691fi 1692