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