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