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