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