xref: /spdk/test/vhost/common.sh (revision a711f44526029d628241f7d38c7113bf4dfda279)
1eb53c232Spaul luse#  SPDX-License-Identifier: BSD-3-Clause
2eb53c232Spaul luse#  Copyright (C) 2017 Intel Corporation
3eb53c232Spaul luse#  All rights reserved.
4eb53c232Spaul luse#
5eb53c232Spaul luse
63d11b2feSBen Walker: ${SPDK_VHOST_VERBOSE=false}
78f44d126SBen Walker: ${VHOST_DIR="$HOME/vhost_test"}
86abaf4fcSMichal Berger: ${QEMU_BIN:="qemu-system-x86_64"}
9b9395621SKarol Latecki: ${QEMU_IMG_BIN="qemu-img"}
103d11b2feSBen Walker
11e422bf69SBen WalkerTEST_DIR=$(readlink -f $rootdir/..)
128f44d126SBen WalkerVM_DIR=$VHOST_DIR/vms
138f44d126SBen WalkerTARGET_DIR=$VHOST_DIR/vhost
14671874b7SPawel KaminskiVM_PASSWORD="root"
158f44d126SBen Walker
16a4a04624SMichal BergerVM_IMAGE=${VM_IMAGE:-"$DEPENDENCY_DIR/vhost/spdk_test_image.qcow2"}
17a4a04624SMichal BergerFIO_BIN=${FIO_BIN:-}
189c3ba11aSMichal Berger
199c3ba11aSMichal BergerWORKDIR=$(readlink -f "$(dirname "$0")")
20ad15da13SBen Walker
21b9395621SKarol Lateckiif ! hash $QEMU_IMG_BIN $QEMU_BIN; then
22fb41398aSMichal Berger	echo 'ERROR: QEMU is not installed on this system. Unable to run vhost tests.' >&2
2376a2663eSMichal Berger	return 1
24fdb03395Syidong0635fi
25fdb03395Syidong0635
268f44d126SBen Walkermkdir -p $VHOST_DIR
278f44d126SBen Walkermkdir -p $VM_DIR
288f44d126SBen Walkermkdir -p $TARGET_DIR
29ad25a95cSBen Walker
30ad25a95cSBen Walker#
31ad25a95cSBen Walker# Source config describing QEMU and VHOST cores and NUMA
32ad25a95cSBen Walker#
338be1517dSBen Walkersource $rootdir/test/vhost/common/autotest.config
349463523bSMichal Bergersource "$rootdir/test/scheduler/common.sh"
35ad25a95cSBen Walker
36844c8ec3SMichal Bergerfunction vhosttestinit() {
37683099e3SBen Walker	if [ "$TEST_MODE" == "iso" ]; then
38683099e3SBen Walker		$rootdir/scripts/setup.sh
39ee191fa8SMichal Berger	fi
40ee191fa8SMichal Berger
416f5b9508SMichal Berger	if [[ -e $VM_IMAGE.gz && ! -e $VM_IMAGE ]]; then
42ee191fa8SMichal Berger		gzip -dc "$VM_IMAGE.gz" > "$VM_IMAGE"
43ee191fa8SMichal Berger	fi
44123ccd10SBen Walker
45123ccd10SBen Walker	# Look for the VM image
46123ccd10SBen Walker	if [[ ! -f $VM_IMAGE ]]; then
47ee191fa8SMichal Berger		[[ $1 != "--no_vm" ]] || return 0
48ee191fa8SMichal Berger		echo "$VM_IMAGE is missing" >&2
49ee191fa8SMichal Berger		return 1
50683099e3SBen Walker	fi
51683099e3SBen Walker}
52683099e3SBen Walker
53844c8ec3SMichal Bergerfunction vhosttestfini() {
54683099e3SBen Walker	if [ "$TEST_MODE" == "iso" ]; then
55683099e3SBen Walker		$rootdir/scripts/setup.sh reset
56683099e3SBen Walker	fi
57683099e3SBen Walker}
58683099e3SBen Walker
59844c8ec3SMichal Bergerfunction message() {
60074df1d8SPawel Kaminski	local verbose_out
613d11b2feSBen Walker	if ! $SPDK_VHOST_VERBOSE; then
62074df1d8SPawel Kaminski		verbose_out=""
633d11b2feSBen Walker	elif [[ ${FUNCNAME[2]} == "source" ]]; then
64074df1d8SPawel Kaminski		verbose_out=" (file $(basename ${BASH_SOURCE[1]}):${BASH_LINENO[1]})"
653d11b2feSBen Walker	else
66074df1d8SPawel Kaminski		verbose_out=" (function ${FUNCNAME[2]}:${BASH_LINENO[1]})"
673d11b2feSBen Walker	fi
683d11b2feSBen Walker
693d11b2feSBen Walker	local msg_type="$1"
703d11b2feSBen Walker	shift
717c4bb5e2SMaciej Wawryk	echo -e "${msg_type}${verbose_out}: $*"
723d11b2feSBen Walker}
733d11b2feSBen Walker
74844c8ec3SMichal Bergerfunction fail() {
753d11b2feSBen Walker	echo "===========" >&2
763d11b2feSBen Walker	message "FAIL" "$@" >&2
773d11b2feSBen Walker	echo "===========" >&2
783d11b2feSBen Walker	exit 1
793d11b2feSBen Walker}
803d11b2feSBen Walker
81844c8ec3SMichal Bergerfunction error() {
823d11b2feSBen Walker	echo "===========" >&2
833d11b2feSBen Walker	message "ERROR" "$@" >&2
843d11b2feSBen Walker	echo "===========" >&2
853d11b2feSBen Walker	# Don't 'return 1' since the stack trace will be incomplete (why?) missing upper command.
863d11b2feSBen Walker	false
873d11b2feSBen Walker}
883d11b2feSBen Walker
89844c8ec3SMichal Bergerfunction warning() {
903d11b2feSBen Walker	message "WARN" "$@" >&2
913d11b2feSBen Walker}
923d11b2feSBen Walker
93844c8ec3SMichal Bergerfunction notice() {
943d11b2feSBen Walker	message "INFO" "$@"
953d11b2feSBen Walker}
963d11b2feSBen Walker
97262c35fcSKarol Lateckifunction check_qemu_packedring_support() {
98262c35fcSKarol Latecki	qemu_version=$($QEMU_BIN -version | grep -Po "(?<=version )\d+.\d+.\d+")
99262c35fcSKarol Latecki	if [[ "$qemu_version" < "4.2.0" ]]; then
100262c35fcSKarol Latecki		error "This qemu binary does not support packed ring"
101262c35fcSKarol Latecki	fi
102262c35fcSKarol Latecki}
103262c35fcSKarol Latecki
104844c8ec3SMichal Bergerfunction get_vhost_dir() {
105fa563858SBen Walker	local vhost_name="$1"
106fa563858SBen Walker
107fa563858SBen Walker	if [[ -z "$vhost_name" ]]; then
108fa563858SBen Walker		error "vhost name must be provided to get_vhost_dir"
109fa563858SBen Walker		return 1
1103d11b2feSBen Walker	fi
1113d11b2feSBen Walker
112fa563858SBen Walker	echo "$TARGET_DIR/${vhost_name}"
1133d11b2feSBen Walker}
1143d11b2feSBen Walker
115844c8ec3SMichal Bergerfunction vhost_run() {
1169f5f5da8SKarol Latecki	local OPTIND
1179f5f5da8SKarol Latecki	local vhost_name
11880881761SKarol Latecki	local run_gen_nvme=true
1195c385271SKarol Latecki	local vhost_bin="vhost"
1204641aa53SMichal Berger	local vhost_args=()
1214641aa53SMichal Berger	local cmd=()
1223d11b2feSBen Walker
1234641aa53SMichal Berger	while getopts "n:b:g" optchar; do
1249f5f5da8SKarol Latecki		case "$optchar" in
1259f5f5da8SKarol Latecki			n) vhost_name="$OPTARG" ;;
1265c385271SKarol Latecki			b) vhost_bin="$OPTARG" ;;
1279f5f5da8SKarol Latecki			g)
1289f5f5da8SKarol Latecki				run_gen_nvme=false
1299f5f5da8SKarol Latecki				notice "Skipping gen_nvme.sh NVMe bdev configuration"
1309f5f5da8SKarol Latecki				;;
1319f5f5da8SKarol Latecki			*)
1329f5f5da8SKarol Latecki				error "Unknown param $optchar"
1339f5f5da8SKarol Latecki				return 1
1349f5f5da8SKarol Latecki				;;
1359f5f5da8SKarol Latecki		esac
1369f5f5da8SKarol Latecki	done
1374641aa53SMichal Berger	shift $((OPTIND - 1))
1384641aa53SMichal Berger
1394641aa53SMichal Berger	vhost_args=("$@")
1409f5f5da8SKarol Latecki
141fa563858SBen Walker	if [[ -z "$vhost_name" ]]; then
142fa563858SBen Walker		error "vhost name must be provided to vhost_run"
143fa563858SBen Walker		return 1
144fa563858SBen Walker	fi
14580881761SKarol Latecki
146074df1d8SPawel Kaminski	local vhost_dir
147074df1d8SPawel Kaminski	vhost_dir="$(get_vhost_dir $vhost_name)"
1485c385271SKarol Latecki	local vhost_app="$SPDK_BIN_DIR/$vhost_bin"
1493d11b2feSBen Walker	local vhost_log_file="$vhost_dir/vhost.log"
1503d11b2feSBen Walker	local vhost_pid_file="$vhost_dir/vhost.pid"
1513d11b2feSBen Walker	local vhost_socket="$vhost_dir/usvhost"
1523d11b2feSBen Walker	notice "starting vhost app in background"
1531b10706eSKarol Latecki	[[ -r "$vhost_pid_file" ]] && vhost_kill $vhost_name
1543d11b2feSBen Walker	[[ -d $vhost_dir ]] && rm -f $vhost_dir/*
1553d11b2feSBen Walker	mkdir -p $vhost_dir
1563d11b2feSBen Walker
1573d11b2feSBen Walker	if [[ ! -x $vhost_app ]]; then
1583d11b2feSBen Walker		error "application not found: $vhost_app"
1593d11b2feSBen Walker		return 1
1603d11b2feSBen Walker	fi
1613d11b2feSBen Walker
1624641aa53SMichal Berger	cmd=("$vhost_app" "-r" "$vhost_dir/rpc.sock" "${vhost_args[@]}")
163da242a6fSKarol Latecki	if [[ "$vhost_bin" =~ vhost ]]; then
1644641aa53SMichal Berger		cmd+=(-S "$vhost_dir")
165da242a6fSKarol Latecki	fi
1663d11b2feSBen Walker
16734edd9f1SKamil Godzwon	notice "Logging to:   $vhost_log_file"
1683d11b2feSBen Walker	notice "Socket:      $vhost_socket"
16974519d80SMichal Berger	notice "Command:     ${cmd[*]}"
1703d11b2feSBen Walker
1713d11b2feSBen Walker	timing_enter vhost_start
172a182f55bSKarol Latecki
173c6d73b5aSKarol Latecki	iobuf_small_count=${iobuf_small_count:-16383}
174c6d73b5aSKarol Latecki	iobuf_large_count=${iobuf_large_count:-2047}
175c6d73b5aSKarol Latecki
1764641aa53SMichal Berger	"${cmd[@]}" --wait-for-rpc &
1773d11b2feSBen Walker	vhost_pid=$!
1783d11b2feSBen Walker	echo $vhost_pid > $vhost_pid_file
1793d11b2feSBen Walker
1803d11b2feSBen Walker	notice "waiting for app to run..."
1813d11b2feSBen Walker	waitforlisten "$vhost_pid" "$vhost_dir/rpc.sock"
182c6d73b5aSKarol Latecki
183c6d73b5aSKarol Latecki	"$rootdir/scripts/rpc.py" -s "$vhost_dir/rpc.sock" \
184c6d73b5aSKarol Latecki		iobuf_set_options \
185c6d73b5aSKarol Latecki		--small-pool-count="$iobuf_small_count" \
186c6d73b5aSKarol Latecki		--large-pool-count="$iobuf_large_count"
187c6d73b5aSKarol Latecki
188c6d73b5aSKarol Latecki	"$rootdir/scripts/rpc.py" -s "$vhost_dir/rpc.sock" \
189c6d73b5aSKarol Latecki		framework_start_init
190c6d73b5aSKarol Latecki
1913d11b2feSBen Walker	#do not generate nvmes if pci access is disabled
19274519d80SMichal Berger	if [[ "${cmd[*]}" != *"--no-pci"* ]] && [[ "${cmd[*]}" != *"-u"* ]] && $run_gen_nvme; then
1938c3e71f0STomasz Zawadzki		$rootdir/scripts/gen_nvme.sh | $rootdir/scripts/rpc.py -s $vhost_dir/rpc.sock load_subsystem_config
1943d11b2feSBen Walker	fi
1953d11b2feSBen Walker
1963d11b2feSBen Walker	notice "vhost started - pid=$vhost_pid"
197a182f55bSKarol Latecki
1983d11b2feSBen Walker	timing_exit vhost_start
1993d11b2feSBen Walker}
2003d11b2feSBen Walker
201844c8ec3SMichal Bergerfunction vhost_kill() {
2023d11b2feSBen Walker	local rc=0
203fa563858SBen Walker	local vhost_name="$1"
204fa563858SBen Walker
205fa563858SBen Walker	if [[ -z "$vhost_name" ]]; then
206fa563858SBen Walker		error "Must provide vhost name to vhost_kill"
207fa563858SBen Walker		return 0
2083d11b2feSBen Walker	fi
2093d11b2feSBen Walker
210074df1d8SPawel Kaminski	local vhost_dir
211074df1d8SPawel Kaminski	vhost_dir="$(get_vhost_dir $vhost_name)"
21251672da0SBen Walker	local vhost_pid_file="$vhost_dir/vhost.pid"
2133d11b2feSBen Walker
2143d11b2feSBen Walker	if [[ ! -r $vhost_pid_file ]]; then
2153d11b2feSBen Walker		warning "no vhost pid file found"
2163d11b2feSBen Walker		return 0
2173d11b2feSBen Walker	fi
2183d11b2feSBen Walker
2193d11b2feSBen Walker	timing_enter vhost_kill
220074df1d8SPawel Kaminski	local vhost_pid
221074df1d8SPawel Kaminski	vhost_pid="$(cat $vhost_pid_file)"
2223d11b2feSBen Walker	notice "killing vhost (PID $vhost_pid) app"
2233d11b2feSBen Walker
22451672da0SBen Walker	if kill -INT $vhost_pid > /dev/null; then
2253d11b2feSBen Walker		notice "sent SIGINT to vhost app - waiting 60 seconds to exit"
2263d11b2feSBen Walker		for ((i = 0; i < 60; i++)); do
22751672da0SBen Walker			if kill -0 $vhost_pid; then
2283d11b2feSBen Walker				echo "."
2293d11b2feSBen Walker				sleep 1
2303d11b2feSBen Walker			else
2313d11b2feSBen Walker				break
2323d11b2feSBen Walker			fi
2333d11b2feSBen Walker		done
23451672da0SBen Walker		if kill -0 $vhost_pid; then
2353d11b2feSBen Walker			error "ERROR: vhost was NOT killed - sending SIGABRT"
23651672da0SBen Walker			kill -ABRT $vhost_pid
2373d11b2feSBen Walker			rc=1
2383d11b2feSBen Walker		else
2393d11b2feSBen Walker			while kill -0 $vhost_pid; do
2403d11b2feSBen Walker				echo "."
2413d11b2feSBen Walker			done
2423d11b2feSBen Walker		fi
243*a711f445SMichal Berger		# If this PID is our child, we should attempt to verify its status
244*a711f445SMichal Berger		# to catch any "silent" crashes that may happen upon termination.
245*a711f445SMichal Berger		if is_pid_child "$vhost_pid"; then
246*a711f445SMichal Berger			notice "Checking status of $vhost_pid"
247*a711f445SMichal Berger			wait "$vhost_pid" || rc=1
248*a711f445SMichal Berger		fi
249*a711f445SMichal Berger
25051672da0SBen Walker	elif kill -0 $vhost_pid; then
2513d11b2feSBen Walker		error "vhost NOT killed - you need to kill it manually"
2523d11b2feSBen Walker		rc=1
2533d11b2feSBen Walker	else
25451672da0SBen Walker		notice "vhost was not running"
2553d11b2feSBen Walker	fi
2563d11b2feSBen Walker
2573d11b2feSBen Walker	timing_exit vhost_kill
2583d11b2feSBen Walker
25951672da0SBen Walker	rm -rf "$vhost_dir"
26051672da0SBen Walker
2613d11b2feSBen Walker	return $rc
2623d11b2feSBen Walker}
2633d11b2feSBen Walker
264844c8ec3SMichal Bergerfunction vhost_rpc() {
265fa563858SBen Walker	local vhost_name="$1"
266fa563858SBen Walker
267fa563858SBen Walker	if [[ -z "$vhost_name" ]]; then
268fa563858SBen Walker		error "vhost name must be provided to vhost_rpc"
269fa563858SBen Walker		return 1
270c66685deSBen Walker	fi
271c66685deSBen Walker	shift
272c66685deSBen Walker
273fdc82d3bSMaciej Wawryk	$rootdir/scripts/rpc.py -s $(get_vhost_dir $vhost_name)/rpc.sock "$@"
274c66685deSBen Walker}
275c66685deSBen Walker
2763d11b2feSBen Walker###
2773d11b2feSBen Walker# Mgmt functions
2783d11b2feSBen Walker###
2793d11b2feSBen Walker
280844c8ec3SMichal Bergerfunction assert_number() {
2813d11b2feSBen Walker	[[ "$1" =~ [0-9]+ ]] && return 0
2823d11b2feSBen Walker
283c9c7c281SJosh Soref	error "Invalid or missing parameter: need number but got '$1'"
284844c8ec3SMichal Berger	return 1
2853d11b2feSBen Walker}
2863d11b2feSBen Walker
2874f31e107SPawel Kaminski# Run command on vm with given password
2884f31e107SPawel Kaminski# First argument - vm number
2894f31e107SPawel Kaminski# Second argument - ssh password for vm
2904f31e107SPawel Kaminski#
291844c8ec3SMichal Bergerfunction vm_sshpass() {
2924f31e107SPawel Kaminski	vm_num_is_valid $1 || return 1
2934f31e107SPawel Kaminski
294074df1d8SPawel Kaminski	local ssh_cmd
295074df1d8SPawel Kaminski	ssh_cmd="sshpass -p $2 ssh \
2964f31e107SPawel Kaminski		-o UserKnownHostsFile=/dev/null \
2974f31e107SPawel Kaminski		-o StrictHostKeyChecking=no \
2984f31e107SPawel Kaminski		-o User=root \
2994f31e107SPawel Kaminski		-p $(vm_ssh_socket $1) $VM_SSH_OPTIONS 127.0.0.1"
3004f31e107SPawel Kaminski
3014f31e107SPawel Kaminski	shift 2
3024f31e107SPawel Kaminski	$ssh_cmd "$@"
3034f31e107SPawel Kaminski}
3044f31e107SPawel Kaminski
3053d11b2feSBen Walker# Helper to validate VM number
3063d11b2feSBen Walker# param $1 VM number
3073d11b2feSBen Walker#
308844c8ec3SMichal Bergerfunction vm_num_is_valid() {
3093d11b2feSBen Walker	[[ "$1" =~ ^[0-9]+$ ]] && return 0
3103d11b2feSBen Walker
311c9c7c281SJosh Soref	error "Invalid or missing parameter: vm number '$1'"
312844c8ec3SMichal Berger	return 1
3133d11b2feSBen Walker}
3143d11b2feSBen Walker
3153d11b2feSBen Walker# Print network socket for given VM number
3163d11b2feSBen Walker# param $1 virtual machine number
3173d11b2feSBen Walker#
318844c8ec3SMichal Bergerfunction vm_ssh_socket() {
3193d11b2feSBen Walker	vm_num_is_valid $1 || return 1
3208f44d126SBen Walker	local vm_dir="$VM_DIR/$1"
3213d11b2feSBen Walker
3223d11b2feSBen Walker	cat $vm_dir/ssh_socket
3233d11b2feSBen Walker}
3243d11b2feSBen Walker
325844c8ec3SMichal Bergerfunction vm_fio_socket() {
3263d11b2feSBen Walker	vm_num_is_valid $1 || return 1
3278f44d126SBen Walker	local vm_dir="$VM_DIR/$1"
3283d11b2feSBen Walker
3293d11b2feSBen Walker	cat $vm_dir/fio_socket
3303d11b2feSBen Walker}
3313d11b2feSBen Walker
33297df5bccSBen Walker# Execute command on given VM
3333d11b2feSBen Walker# param $1 virtual machine number
3343d11b2feSBen Walker#
335844c8ec3SMichal Bergerfunction vm_exec() {
3363d11b2feSBen Walker	vm_num_is_valid $1 || return 1
3373d11b2feSBen Walker
33897df5bccSBen Walker	local vm_num="$1"
3393d11b2feSBen Walker	shift
34097df5bccSBen Walker
341671874b7SPawel Kaminski	sshpass -p "$VM_PASSWORD" ssh \
34297df5bccSBen Walker		-o UserKnownHostsFile=/dev/null \
34397df5bccSBen Walker		-o StrictHostKeyChecking=no \
34497df5bccSBen Walker		-o User=root \
34597df5bccSBen Walker		-p $(vm_ssh_socket $vm_num) $VM_SSH_OPTIONS 127.0.0.1 \
34697df5bccSBen Walker		"$@"
3473d11b2feSBen Walker}
3483d11b2feSBen Walker
3493d11b2feSBen Walker# Execute scp command on given VM
3503d11b2feSBen Walker# param $1 virtual machine number
3513d11b2feSBen Walker#
352844c8ec3SMichal Bergerfunction vm_scp() {
3533d11b2feSBen Walker	vm_num_is_valid $1 || return 1
3543d11b2feSBen Walker
35597df5bccSBen Walker	local vm_num="$1"
3563d11b2feSBen Walker	shift
35797df5bccSBen Walker
358671874b7SPawel Kaminski	sshpass -p "$VM_PASSWORD" scp \
35997df5bccSBen Walker		-o UserKnownHostsFile=/dev/null \
36097df5bccSBen Walker		-o StrictHostKeyChecking=no \
36197df5bccSBen Walker		-o User=root \
36297df5bccSBen Walker		-P $(vm_ssh_socket $vm_num) $VM_SSH_OPTIONS \
36397df5bccSBen Walker		"$@"
3643d11b2feSBen Walker}
3653d11b2feSBen Walker
3663d11b2feSBen Walker# check if specified VM is running
3673d11b2feSBen Walker# param $1 VM num
368844c8ec3SMichal Bergerfunction vm_is_running() {
3693d11b2feSBen Walker	vm_num_is_valid $1 || return 1
3708f44d126SBen Walker	local vm_dir="$VM_DIR/$1"
3713d11b2feSBen Walker
3723d11b2feSBen Walker	if [[ ! -r $vm_dir/qemu.pid ]]; then
3733d11b2feSBen Walker		return 1
3743d11b2feSBen Walker	fi
3753d11b2feSBen Walker
376074df1d8SPawel Kaminski	local vm_pid
377074df1d8SPawel Kaminski	vm_pid="$(cat $vm_dir/qemu.pid)"
3783d11b2feSBen Walker
3793d11b2feSBen Walker	if /bin/kill -0 $vm_pid; then
3803d11b2feSBen Walker		return 0
3813d11b2feSBen Walker	else
3823d11b2feSBen Walker		if [[ $EUID -ne 0 ]]; then
3833d11b2feSBen Walker			warning "not root - assuming VM running since can't be checked"
3843d11b2feSBen Walker			return 0
3853d11b2feSBen Walker		fi
3863d11b2feSBen Walker
3873d11b2feSBen Walker		# not running - remove pid file
3881efd5745SMichal Berger		rm -f $vm_dir/qemu.pid
3893d11b2feSBen Walker		return 1
3903d11b2feSBen Walker	fi
3913d11b2feSBen Walker}
3923d11b2feSBen Walker
3933d11b2feSBen Walker# check if specified VM is running
3943d11b2feSBen Walker# param $1 VM num
395844c8ec3SMichal Bergerfunction vm_os_booted() {
3963d11b2feSBen Walker	vm_num_is_valid $1 || return 1
3978f44d126SBen Walker	local vm_dir="$VM_DIR/$1"
3983d11b2feSBen Walker
3993d11b2feSBen Walker	if [[ ! -r $vm_dir/qemu.pid ]]; then
4003d11b2feSBen Walker		error "VM $1 is not running"
4013d11b2feSBen Walker		return 1
4023d11b2feSBen Walker	fi
4033d11b2feSBen Walker
40497df5bccSBen Walker	if ! VM_SSH_OPTIONS="-o ControlMaster=no" vm_exec $1 "true" 2> /dev/null; then
4053d11b2feSBen Walker		# Shutdown existing master. Ignore errors as it might not exist.
40697df5bccSBen Walker		VM_SSH_OPTIONS="-O exit" vm_exec $1 "true" 2> /dev/null
4073d11b2feSBen Walker		return 1
4083d11b2feSBen Walker	fi
4093d11b2feSBen Walker
4103d11b2feSBen Walker	return 0
4113d11b2feSBen Walker}
4123d11b2feSBen Walker
4133d11b2feSBen Walker# Shutdown given VM
4143d11b2feSBen Walker# param $1 virtual machine number
4153d11b2feSBen Walker# return non-zero in case of error.
416844c8ec3SMichal Bergerfunction vm_shutdown() {
4173d11b2feSBen Walker	vm_num_is_valid $1 || return 1
4188f44d126SBen Walker	local vm_dir="$VM_DIR/$1"
4193d11b2feSBen Walker	if [[ ! -d "$vm_dir" ]]; then
4203d11b2feSBen Walker		error "VM$1 ($vm_dir) not exist - setup it first"
4213d11b2feSBen Walker		return 1
4223d11b2feSBen Walker	fi
4233d11b2feSBen Walker
4243d11b2feSBen Walker	if ! vm_is_running $1; then
4253d11b2feSBen Walker		notice "VM$1 ($vm_dir) is not running"
4263d11b2feSBen Walker		return 0
4273d11b2feSBen Walker	fi
4283d11b2feSBen Walker
4293d11b2feSBen Walker	# Temporarily disabling exit flag for next ssh command, since it will
4303d11b2feSBen Walker	# "fail" due to shutdown
4313d11b2feSBen Walker	notice "Shutting down virtual machine $vm_dir"
4323d11b2feSBen Walker	set +e
43397df5bccSBen Walker	vm_exec $1 "nohup sh -c 'shutdown -h -P now'" || true
4343d11b2feSBen Walker	notice "VM$1 is shutting down - wait a while to complete"
4353d11b2feSBen Walker	set -e
4363d11b2feSBen Walker}
4373d11b2feSBen Walker
4383d11b2feSBen Walker# Kill given VM
4393d11b2feSBen Walker# param $1 virtual machine number
4403d11b2feSBen Walker#
441844c8ec3SMichal Bergerfunction vm_kill() {
4423d11b2feSBen Walker	vm_num_is_valid $1 || return 1
4438f44d126SBen Walker	local vm_dir="$VM_DIR/$1"
4443d11b2feSBen Walker
4453d11b2feSBen Walker	if [[ ! -r $vm_dir/qemu.pid ]]; then
4463d11b2feSBen Walker		return 0
4473d11b2feSBen Walker	fi
4483d11b2feSBen Walker
449074df1d8SPawel Kaminski	local vm_pid
450074df1d8SPawel Kaminski	vm_pid="$(cat $vm_dir/qemu.pid)"
4513d11b2feSBen Walker
4523d11b2feSBen Walker	notice "Killing virtual machine $vm_dir (pid=$vm_pid)"
4533d11b2feSBen Walker	# First kill should fail, second one must fail
4543d11b2feSBen Walker	if /bin/kill $vm_pid; then
4553d11b2feSBen Walker		notice "process $vm_pid killed"
456ad15da13SBen Walker		rm -rf $vm_dir
4573d11b2feSBen Walker	elif vm_is_running $1; then
4583d11b2feSBen Walker		error "Process $vm_pid NOT killed"
4593d11b2feSBen Walker		return 1
4603d11b2feSBen Walker	fi
4613d11b2feSBen Walker}
4623d11b2feSBen Walker
4638f44d126SBen Walker# List all VM numbers in VM_DIR
4643d11b2feSBen Walker#
465844c8ec3SMichal Bergerfunction vm_list_all() {
4664641aa53SMichal Berger	local vms=()
4674641aa53SMichal Berger	vms=("$VM_DIR"/+([0-9]))
4684641aa53SMichal Berger	if ((${#vms[@]} > 0)); then
4694641aa53SMichal Berger		basename --multiple "${vms[@]}"
4703d11b2feSBen Walker	fi
4713d11b2feSBen Walker}
4723d11b2feSBen Walker
4738f44d126SBen Walker# Kills all VM in $VM_DIR
4743d11b2feSBen Walker#
475844c8ec3SMichal Bergerfunction vm_kill_all() {
4763d11b2feSBen Walker	local vm
4773d11b2feSBen Walker	for vm in $(vm_list_all); do
4783d11b2feSBen Walker		vm_kill $vm
4793d11b2feSBen Walker	done
480ad15da13SBen Walker
4818f44d126SBen Walker	rm -rf $VM_DIR
4823d11b2feSBen Walker}
4833d11b2feSBen Walker
4848f44d126SBen Walker# Shutdown all VM in $VM_DIR
4853d11b2feSBen Walker#
486844c8ec3SMichal Bergerfunction vm_shutdown_all() {
487ea340dc4SMichal Berger	local timeo=${1:-90} vms vm
4883d11b2feSBen Walker
489ea340dc4SMichal Berger	vms=($(vm_list_all))
4903d11b2feSBen Walker
491ea340dc4SMichal Berger	for vm in "${vms[@]}"; do
492ea340dc4SMichal Berger		vm_shutdown "$vm"
4933d11b2feSBen Walker	done
4943d11b2feSBen Walker
4953d11b2feSBen Walker	notice "Waiting for VMs to shutdown..."
496ea340dc4SMichal Berger	while ((timeo-- > 0 && ${#vms[@]} > 0)); do
497ea340dc4SMichal Berger		for vm in "${!vms[@]}"; do
498ea340dc4SMichal Berger			vm_is_running "${vms[vm]}" || unset -v "vms[vm]"
4993d11b2feSBen Walker		done
5003d11b2feSBen Walker		sleep 1
5013d11b2feSBen Walker	done
5023d11b2feSBen Walker
503ea340dc4SMichal Berger	if ((${#vms[@]} == 0)); then
504ea340dc4SMichal Berger		notice "All VMs successfully shut down"
505ea340dc4SMichal Berger		return 0
506ea340dc4SMichal Berger	fi
507ad15da13SBen Walker
508ea340dc4SMichal Berger	warning "Not all VMs were shut down. Leftovers: ${vms[*]}"
509ea340dc4SMichal Berger
510ea340dc4SMichal Berger	for vm in "${vms[@]}"; do
511ea340dc4SMichal Berger		vm_print_logs "$vm"
512ea340dc4SMichal Berger	done
513ea340dc4SMichal Berger
514ea340dc4SMichal Berger	return 1
5153d11b2feSBen Walker}
5163d11b2feSBen Walker
517844c8ec3SMichal Bergerfunction vm_setup() {
51834ae1172SSeth Howell	xtrace_disable
5193d11b2feSBen Walker	local OPTIND optchar vm_num
5203d11b2feSBen Walker
5213d11b2feSBen Walker	local os=""
5223d11b2feSBen Walker	local os_mode=""
523e1ddec2cSMichal Berger	local qemu_args=()
5243d11b2feSBen Walker	local disk_type_g=NOT_DEFINED
5253d11b2feSBen Walker	local read_only="false"
52664471319SMichal Berger	# List created of a strings separated with a ":"
52764471319SMichal Berger	local disks=()
5283d11b2feSBen Walker	local raw_cache=""
5293d11b2feSBen Walker	local vm_incoming=""
5303d11b2feSBen Walker	local vm_migrate_to=""
5313d11b2feSBen Walker	local force_vm=""
5323d11b2feSBen Walker	local guest_memory=1024
533074df1d8SPawel Kaminski	local vhost_dir
534262c35fcSKarol Latecki	local packed=false
535074df1d8SPawel Kaminski	vhost_dir="$(get_vhost_dir 0)"
5363d11b2feSBen Walker	while getopts ':-:' optchar; do
5373d11b2feSBen Walker		case "$optchar" in
5383d11b2feSBen Walker			-)
5393d11b2feSBen Walker				case "$OPTARG" in
540074df1d8SPawel Kaminski					os=*) os="${OPTARG#*=}" ;;
541074df1d8SPawel Kaminski					os-mode=*) os_mode="${OPTARG#*=}" ;;
542e1ddec2cSMichal Berger					qemu-args=*) qemu_args+=("${OPTARG#*=}") ;;
543074df1d8SPawel Kaminski					disk-type=*) disk_type_g="${OPTARG#*=}" ;;
544074df1d8SPawel Kaminski					read-only=*) read_only="${OPTARG#*=}" ;;
54564471319SMichal Berger					disks=*) IFS=":" read -ra disks <<< "${OPTARG#*=}" ;;
546074df1d8SPawel Kaminski					raw-cache=*) raw_cache=",cache${OPTARG#*=}" ;;
547074df1d8SPawel Kaminski					force=*) force_vm=${OPTARG#*=} ;;
548074df1d8SPawel Kaminski					memory=*) guest_memory=${OPTARG#*=} ;;
549074df1d8SPawel Kaminski					incoming=*) vm_incoming="${OPTARG#*=}" ;;
550074df1d8SPawel Kaminski					migrate-to=*) vm_migrate_to="${OPTARG#*=}" ;;
551074df1d8SPawel Kaminski					vhost-name=*) vhost_dir="$(get_vhost_dir ${OPTARG#*=})" ;;
5523d11b2feSBen Walker					spdk-boot=*) local boot_from="${OPTARG#*=}" ;;
553262c35fcSKarol Latecki					packed) packed=true ;;
5543d11b2feSBen Walker					*)
5553d11b2feSBen Walker						error "unknown argument $OPTARG"
5563d11b2feSBen Walker						return 1
557844c8ec3SMichal Berger						;;
5583d11b2feSBen Walker				esac
5593d11b2feSBen Walker				;;
5603d11b2feSBen Walker			*)
5613d11b2feSBen Walker				error "vm_create Unknown param $OPTARG"
5623d11b2feSBen Walker				return 1
5633d11b2feSBen Walker				;;
5643d11b2feSBen Walker		esac
5653d11b2feSBen Walker	done
5663d11b2feSBen Walker
5673d11b2feSBen Walker	# Find next directory we can use
5681ccc878eSKarol Latecki	if [[ -n $force_vm ]]; then
5693d11b2feSBen Walker		vm_num=$force_vm
5703d11b2feSBen Walker
5713d11b2feSBen Walker		vm_num_is_valid $vm_num || return 1
5728f44d126SBen Walker		local vm_dir="$VM_DIR/$vm_num"
5733d11b2feSBen Walker		[[ -d $vm_dir ]] && warning "removing existing VM in '$vm_dir'"
5743d11b2feSBen Walker	else
5753d11b2feSBen Walker		local vm_dir=""
5763d11b2feSBen Walker
5773d11b2feSBen Walker		set +x
5783d11b2feSBen Walker		for ((i = 0; i <= 256; i++)); do
5798f44d126SBen Walker			local vm_dir="$VM_DIR/$i"
5803d11b2feSBen Walker			[[ ! -d $vm_dir ]] && break
5813d11b2feSBen Walker		done
58234ae1172SSeth Howell		xtrace_restore
5833d11b2feSBen Walker
5843d11b2feSBen Walker		vm_num=$i
5853d11b2feSBen Walker	fi
5863d11b2feSBen Walker
5876b9e48dfSSeth Howell	if [[ $vm_num -eq 256 ]]; then
5883d11b2feSBen Walker		error "no free VM found. do some cleanup (256 VMs created, are you insane?)"
5893d11b2feSBen Walker		return 1
5903d11b2feSBen Walker	fi
5913d11b2feSBen Walker
5921ccc878eSKarol Latecki	if [[ -n "$vm_migrate_to" && -n "$vm_incoming" ]]; then
5933d11b2feSBen Walker		error "'--incoming' and '--migrate-to' cannot be used together"
5943d11b2feSBen Walker		return 1
5951ccc878eSKarol Latecki	elif [[ -n "$vm_incoming" ]]; then
5964d0c5091SPawel Kaminski		if [[ -n "$os_mode" || -n "$os" ]]; then
5973d11b2feSBen Walker			error "'--incoming' can't be used together with '--os' nor '--os-mode'"
5983d11b2feSBen Walker			return 1
5993d11b2feSBen Walker		fi
6003d11b2feSBen Walker
6013d11b2feSBen Walker		os_mode="original"
6028f44d126SBen Walker		os="$VM_DIR/$vm_incoming/os.qcow2"
6031ccc878eSKarol Latecki	elif [[ -n "$vm_migrate_to" ]]; then
6043d11b2feSBen Walker		[[ "$os_mode" != "backing" ]] && warning "Using 'backing' mode for OS since '--migrate-to' is used"
6053d11b2feSBen Walker		os_mode=backing
6063d11b2feSBen Walker	fi
6073d11b2feSBen Walker
6083d11b2feSBen Walker	notice "Creating new VM in $vm_dir"
6093d11b2feSBen Walker	mkdir -p $vm_dir
6103d11b2feSBen Walker
6113d11b2feSBen Walker	if [[ "$os_mode" == "backing" ]]; then
6123d11b2feSBen Walker		notice "Creating backing file for OS image file: $os"
6136d1e0c0eSJaroslaw Chachulski		if ! $QEMU_IMG_BIN create -f qcow2 -b $os $vm_dir/os.qcow2 -F qcow2; then
6143d11b2feSBen Walker			error "Failed to create OS backing file in '$vm_dir/os.qcow2' using '$os'"
6153d11b2feSBen Walker			return 1
6163d11b2feSBen Walker		fi
6173d11b2feSBen Walker
6183d11b2feSBen Walker		local os=$vm_dir/os.qcow2
6193d11b2feSBen Walker	elif [[ "$os_mode" == "original" ]]; then
6203d11b2feSBen Walker		warning "Using original OS image file: $os"
6213d11b2feSBen Walker	elif [[ "$os_mode" != "snapshot" ]]; then
6223d11b2feSBen Walker		if [[ -z "$os_mode" ]]; then
6233d11b2feSBen Walker			notice "No '--os-mode' parameter provided - using 'snapshot'"
6243d11b2feSBen Walker			os_mode="snapshot"
6253d11b2feSBen Walker		else
6263d11b2feSBen Walker			error "Invalid '--os-mode=$os_mode'"
6273d11b2feSBen Walker			return 1
6283d11b2feSBen Walker		fi
6293d11b2feSBen Walker	fi
6303d11b2feSBen Walker
6313d11b2feSBen Walker	local qemu_mask_param="VM_${vm_num}_qemu_mask"
6323d11b2feSBen Walker	local qemu_numa_node_param="VM_${vm_num}_qemu_numa_node"
6333d11b2feSBen Walker
6343d11b2feSBen Walker	if [[ -z "${!qemu_mask_param}" ]] || [[ -z "${!qemu_numa_node_param}" ]]; then
6353d11b2feSBen Walker		error "Parameters ${qemu_mask_param} or ${qemu_numa_node_param} not found in autotest.config file"
6363d11b2feSBen Walker		return 1
6373d11b2feSBen Walker	fi
6383d11b2feSBen Walker
6393d11b2feSBen Walker	local task_mask=${!qemu_mask_param}
6403d11b2feSBen Walker
6413d11b2feSBen Walker	notice "TASK MASK: $task_mask"
642e1ddec2cSMichal Berger	local cmd=(taskset -a -c "$task_mask" "$QEMU_BIN")
6433d11b2feSBen Walker	local vm_socket_offset=$((10000 + 100 * vm_num))
6443d11b2feSBen Walker
6453d11b2feSBen Walker	local ssh_socket=$((vm_socket_offset + 0))
6463d11b2feSBen Walker	local fio_socket=$((vm_socket_offset + 1))
6473d11b2feSBen Walker	local monitor_port=$((vm_socket_offset + 2))
6483d11b2feSBen Walker	local migration_port=$((vm_socket_offset + 3))
6493d11b2feSBen Walker	local gdbserver_socket=$((vm_socket_offset + 4))
6503d11b2feSBen Walker	local vnc_socket=$((100 + vm_num))
6513d11b2feSBen Walker	local qemu_pid_file="$vm_dir/qemu.pid"
652632342a0SMichal Berger	local cpu_list
653632342a0SMichal Berger	local cpu_num=0 queue_number=0
6543d11b2feSBen Walker
655632342a0SMichal Berger	cpu_list=($(parse_cpu_list <(echo "$task_mask")))
656632342a0SMichal Berger	cpu_num=${#cpu_list[@]} queue_number=$cpu_num
6573d11b2feSBen Walker
658632342a0SMichal Berger	# Let's be paranoid about it
659632342a0SMichal Berger	((cpu_num > 0 && queue_number > 0)) || return 1
6603d11b2feSBen Walker
661905c4dcfSMichal Berger	# Normalize tcp ports to make sure they are available
662905c4dcfSMichal Berger	ssh_socket=$(get_free_tcp_port "$ssh_socket")
663905c4dcfSMichal Berger	fio_socket=$(get_free_tcp_port "$fio_socket")
664905c4dcfSMichal Berger	monitor_port=$(get_free_tcp_port "$monitor_port")
665905c4dcfSMichal Berger	migration_port=$(get_free_tcp_port "$migration_port")
666905c4dcfSMichal Berger	gdbserver_socket=$(get_free_tcp_port "$gdbserver_socket")
667905c4dcfSMichal Berger	vnc_socket=$(get_free_tcp_port "$vnc_socket")
668905c4dcfSMichal Berger
66934ae1172SSeth Howell	xtrace_restore
6703d11b2feSBen Walker
6713d11b2feSBen Walker	local node_num=${!qemu_numa_node_param}
6723d11b2feSBen Walker	local boot_disk_present=false
6733d11b2feSBen Walker	notice "NUMA NODE: $node_num"
674e1ddec2cSMichal Berger	cmd+=(-m "$guest_memory" --enable-kvm -cpu host -smp "$cpu_num" -vga std -vnc ":$vnc_socket" -daemonize)
675e1ddec2cSMichal Berger	cmd+=(-object "memory-backend-file,id=mem,size=${guest_memory}M,mem-path=/dev/hugepages,share=on,prealloc=yes,host-nodes=$node_num,policy=bind")
676e1ddec2cSMichal Berger	[[ $os_mode == snapshot ]] && cmd+=(-snapshot)
677e1ddec2cSMichal Berger	[[ -n "$vm_incoming" ]] && cmd+=(-incoming "tcp:0:$migration_port")
678e1ddec2cSMichal Berger	cmd+=(-monitor "telnet:127.0.0.1:$monitor_port,server,nowait")
679e1ddec2cSMichal Berger	cmd+=(-numa "node,memdev=mem")
680e1ddec2cSMichal Berger	cmd+=(-pidfile "$qemu_pid_file")
681e1ddec2cSMichal Berger	cmd+=(-serial "file:$vm_dir/serial.log")
682e1ddec2cSMichal Berger	cmd+=(-D "$vm_dir/qemu.log")
683e1ddec2cSMichal Berger	cmd+=(-chardev "file,path=$vm_dir/seabios.log,id=seabios" -device "isa-debugcon,iobase=0x402,chardev=seabios")
684e1ddec2cSMichal Berger	cmd+=(-net "user,hostfwd=tcp::$ssh_socket-:22,hostfwd=tcp::$fio_socket-:8765")
685e1ddec2cSMichal Berger	cmd+=(-net nic)
6863d11b2feSBen Walker	if [[ -z "$boot_from" ]]; then
687e1ddec2cSMichal Berger		cmd+=(-drive "file=$os,if=none,id=os_disk")
688e1ddec2cSMichal Berger		cmd+=(-device "ide-hd,drive=os_disk,bootindex=0")
6893d11b2feSBen Walker	fi
6903d11b2feSBen Walker
69164471319SMichal Berger	if ((${#disks[@]} == 0)) && [[ $disk_type_g == virtio* ]]; then
69264471319SMichal Berger		disks=("default_virtio.img")
69364471319SMichal Berger	elif ((${#disks[@]} == 0)); then
69464471319SMichal Berger		error "No disks defined, aborting"
69564471319SMichal Berger		return 1
6963d11b2feSBen Walker	fi
6973d11b2feSBen Walker
69864471319SMichal Berger	for disk in "${disks[@]}"; do
69964471319SMichal Berger		# Each disk can define its type in a form of a disk_name,type. The remaining parts
70064471319SMichal Berger		# of the string are dropped.
70164471319SMichal Berger		IFS="," read -r disk disk_type _ <<< "$disk"
70264471319SMichal Berger		[[ -z $disk_type ]] && disk_type=$disk_type_g
7033d11b2feSBen Walker
7043d11b2feSBen Walker		case $disk_type in
7053d11b2feSBen Walker			virtio)
7063d11b2feSBen Walker				local raw_name="RAWSCSI"
7073d11b2feSBen Walker				local raw_disk=$vm_dir/test.img
7083d11b2feSBen Walker
7093d11b2feSBen Walker				# Create disk file if it not exist or it is smaller than 1G
710bf93cbdfSMichal Berger				if [[ -f $disk && $(stat --printf="%s" $disk) -ge $((1024 * 1024 * 1024)) ]]; then
711bf93cbdfSMichal Berger					raw_disk=$disk
712bf93cbdfSMichal Berger					notice "Using existing image $raw_disk"
713bf93cbdfSMichal Berger				else
7143d11b2feSBen Walker					notice "Creating Virtio disc $raw_disk"
7153d11b2feSBen Walker					dd if=/dev/zero of=$raw_disk bs=1024k count=1024
7163d11b2feSBen Walker				fi
7173d11b2feSBen Walker
718e1ddec2cSMichal Berger				cmd+=(-device "virtio-scsi-pci,num_queues=$queue_number")
719e1ddec2cSMichal Berger				cmd+=(-device "scsi-hd,drive=hd$i,vendor=$raw_name")
720e1ddec2cSMichal Berger				cmd+=(-drive "if=none,id=hd$i,file=$raw_disk,format=raw$raw_cache")
7213d11b2feSBen Walker				;;
7223d11b2feSBen Walker			spdk_vhost_scsi)
7233d11b2feSBen Walker				notice "using socket $vhost_dir/naa.$disk.$vm_num"
724e1ddec2cSMichal Berger				cmd+=(-chardev "socket,id=char_$disk,path=$vhost_dir/naa.$disk.$vm_num")
725e1ddec2cSMichal Berger				cmd+=(-device "vhost-user-scsi-pci,id=scsi_$disk,num_queues=$queue_number,chardev=char_$disk")
7263d11b2feSBen Walker				if [[ "$disk" == "$boot_from" ]]; then
727e1ddec2cSMichal Berger					cmd[-1]+=,bootindex=0
7283d11b2feSBen Walker					boot_disk_present=true
7293d11b2feSBen Walker				fi
7303d11b2feSBen Walker				;;
7313d11b2feSBen Walker			spdk_vhost_blk)
7323d11b2feSBen Walker				notice "using socket $vhost_dir/naa.$disk.$vm_num"
733e1ddec2cSMichal Berger				cmd+=(-chardev "socket,id=char_$disk,path=$vhost_dir/naa.$disk.$vm_num")
734e1ddec2cSMichal Berger				cmd+=(-device "vhost-user-blk-pci,num-queues=$queue_number,chardev=char_$disk")
7353d11b2feSBen Walker				if [[ "$disk" == "$boot_from" ]]; then
736e1ddec2cSMichal Berger					cmd[-1]+=,bootindex=0
7373d11b2feSBen Walker					boot_disk_present=true
7383d11b2feSBen Walker				fi
739262c35fcSKarol Latecki
740262c35fcSKarol Latecki				if $packed; then
741262c35fcSKarol Latecki					check_qemu_packedring_support
742262c35fcSKarol Latecki					notice "Enabling packed ring support for VM $vm_num, controller $vhost_dir/naa.$disk.$vm_num"
743262c35fcSKarol Latecki					cmd[-1]+=,packed=on
744262c35fcSKarol Latecki				fi
7453d11b2feSBen Walker				;;
7463d11b2feSBen Walker			kernel_vhost)
7473d11b2feSBen Walker				if [[ -z $disk ]]; then
7483d11b2feSBen Walker					error "need WWN for $disk_type"
7493d11b2feSBen Walker					return 1
7503d11b2feSBen Walker				elif [[ ! $disk =~ ^[[:alpha:]]{3}[.][[:xdigit:]]+$ ]]; then
7513d11b2feSBen Walker					error "$disk_type - disk(wnn)=$disk does not look like WNN number"
7523d11b2feSBen Walker					return 1
7533d11b2feSBen Walker				fi
7543d11b2feSBen Walker				notice "Using kernel vhost disk wwn=$disk"
755e1ddec2cSMichal Berger				cmd+=(-device "vhost-scsi-pci,wwpn=$disk,num_queues=$queue_number")
7563d11b2feSBen Walker				;;
7575c385271SKarol Latecki			vfio_user)
7585c385271SKarol Latecki				notice "using socket $VM_DIR/$vm_num/domain/muser$disk/$disk/cntrl"
75939f5b26bSChangpeng Liu				cmd+=(-device "vfio-user-pci,x-msg-timeout=5000,socket=$VM_DIR/$vm_num/muser/domain/muser$disk/$disk/cntrl")
7605c385271SKarol Latecki				if [[ "$disk" == "$boot_from" ]]; then
7615c385271SKarol Latecki					cmd[-1]+=",bootindex=0"
7625c385271SKarol Latecki					boot_disk_present=true
7635c385271SKarol Latecki				fi
7645c385271SKarol Latecki				;;
7656d7f012aSChangpeng Liu			vfio_user_virtio)
7666d7f012aSChangpeng Liu				notice "using socket $VM_DIR/vfu_tgt/virtio.$disk"
7676d7f012aSChangpeng Liu				cmd+=(-device "vfio-user-pci,x-msg-timeout=5000,socket=$VM_DIR/vfu_tgt/virtio.$disk")
7686d7f012aSChangpeng Liu				if [[ "$disk" == "$boot_from" ]]; then
7696d7f012aSChangpeng Liu					cmd[-1]+=",bootindex=0"
7706d7f012aSChangpeng Liu					boot_disk_present=true
7716d7f012aSChangpeng Liu				fi
7726d7f012aSChangpeng Liu				;;
7733d11b2feSBen Walker			*)
7746d7f012aSChangpeng Liu				error "unknown mode '$disk_type', use: virtio, spdk_vhost_scsi, spdk_vhost_blk, kernel_vhost, vfio_user or vfio_user_virtio"
7753d11b2feSBen Walker				return 1
77616e16c77SMichal Berger				;;
7773d11b2feSBen Walker		esac
7783d11b2feSBen Walker	done
7793d11b2feSBen Walker
7803d11b2feSBen Walker	if [[ -n $boot_from ]] && [[ $boot_disk_present == false ]]; then
7813d11b2feSBen Walker		error "Boot from $boot_from is selected but device is not present"
7823d11b2feSBen Walker		return 1
7833d11b2feSBen Walker	fi
7843d11b2feSBen Walker
785e1ddec2cSMichal Berger	((${#qemu_args[@]})) && cmd+=("${qemu_args[@]}")
7863d11b2feSBen Walker	notice "Saving to $vm_dir/run.sh"
78708f0abebSMichal Berger	cat <<- RUN > "$vm_dir/run.sh"
78808f0abebSMichal Berger		#!/bin/bash
7892d8b9911SMichal Berger		shopt -s nullglob extglob
7906872c67eSMichal Berger		rootdir=$rootdir
7916872c67eSMichal Berger		source "\$rootdir/test/scheduler/common.sh"
792d9d62e11SMichal Berger		qemu_log () {
793d9d62e11SMichal Berger			echo "=== qemu.log ==="
794d9d62e11SMichal Berger			[[ -s $vm_dir/qemu.log ]] && cat $vm_dir/qemu.log
795d9d62e11SMichal Berger			echo "=== qemu.log ==="
796d9d62e11SMichal Berger		}
79708f0abebSMichal Berger
79808f0abebSMichal Berger		if [[ \$EUID -ne 0 ]]; then
79908f0abebSMichal Berger			echo "Go away user come back as root"
80008f0abebSMichal Berger			exit 1
80108f0abebSMichal Berger		fi
80208f0abebSMichal Berger
803d9d62e11SMichal Berger		trap "qemu_log" EXIT
80408f0abebSMichal Berger
805d9d62e11SMichal Berger		qemu_cmd=($(printf '%s\n' "${cmd[@]}"))
806d9d62e11SMichal Berger		chmod +r $vm_dir/*
80708f0abebSMichal Berger		echo "Running VM in $vm_dir"
80808f0abebSMichal Berger		rm -f $qemu_pid_file
8096872c67eSMichal Berger		cgroup=\$(get_cgroup \$$)
8106872c67eSMichal Berger		set_cgroup_attr_top_bottom \$$ cgroup.subtree_control "+cpuset"
8116872c67eSMichal Berger		create_cgroup \$cgroup/qemu.$vm_num
8126872c67eSMichal Berger		set_cgroup_attr "\$cgroup/qemu.$vm_num" cpuset.mems "$node_num"
8136872c67eSMichal Berger		set_cgroup_attr "\$cgroup/qemu.$vm_num" cpuset.cpus "$task_mask"
81408f0abebSMichal Berger		"\${qemu_cmd[@]}"
815d9d62e11SMichal Berger
81608f0abebSMichal Berger		echo "Waiting for QEMU pid file"
81708f0abebSMichal Berger		sleep 1
81808f0abebSMichal Berger		[[ ! -f $qemu_pid_file ]] && sleep 1
81908f0abebSMichal Berger		[[ ! -f $qemu_pid_file ]] && echo "ERROR: no qemu pid file found" && exit 1
8206872c67eSMichal Berger		set_cgroup_attr "\$cgroup/qemu.$vm_num" cgroup.threads \$(< "$qemu_pid_file")
821d9d62e11SMichal Berger		exit 0
82208f0abebSMichal Berger		# EOF
82308f0abebSMichal Berger	RUN
8243d11b2feSBen Walker	chmod +x $vm_dir/run.sh
8253d11b2feSBen Walker
8263d11b2feSBen Walker	# Save generated sockets redirection
8273d11b2feSBen Walker	echo $ssh_socket > $vm_dir/ssh_socket
8283d11b2feSBen Walker	echo $fio_socket > $vm_dir/fio_socket
8293d11b2feSBen Walker	echo $monitor_port > $vm_dir/monitor_port
8303d11b2feSBen Walker
8313d11b2feSBen Walker	rm -f $vm_dir/migration_port
8323d11b2feSBen Walker	[[ -z $vm_incoming ]] || echo $migration_port > $vm_dir/migration_port
8333d11b2feSBen Walker
8343d11b2feSBen Walker	echo $gdbserver_socket > $vm_dir/gdbserver_socket
8353d11b2feSBen Walker	echo $vnc_socket >> $vm_dir/vnc_socket
8363d11b2feSBen Walker
8378f44d126SBen Walker	[[ -z $vm_incoming ]] || ln -fs $VM_DIR/$vm_incoming $vm_dir/vm_incoming
8388f44d126SBen Walker	[[ -z $vm_migrate_to ]] || ln -fs $VM_DIR/$vm_migrate_to $vm_dir/vm_migrate_to
8393d11b2feSBen Walker}
8403d11b2feSBen Walker
841844c8ec3SMichal Bergerfunction vm_run() {
8423d11b2feSBen Walker	local OPTIND optchar vm
8433d11b2feSBen Walker	local run_all=false
8443d11b2feSBen Walker	local vms_to_run=""
8453d11b2feSBen Walker
8463d11b2feSBen Walker	while getopts 'a-:' optchar; do
8473d11b2feSBen Walker		case "$optchar" in
8483d11b2feSBen Walker			a) run_all=true ;;
8493d11b2feSBen Walker			*)
8503d11b2feSBen Walker				error "Unknown param $OPTARG"
8513d11b2feSBen Walker				return 1
8523d11b2feSBen Walker				;;
8533d11b2feSBen Walker		esac
8543d11b2feSBen Walker	done
8553d11b2feSBen Walker
8563d11b2feSBen Walker	if $run_all; then
8573d11b2feSBen Walker		vms_to_run="$(vm_list_all)"
8583d11b2feSBen Walker	else
8593d11b2feSBen Walker		shift $((OPTIND - 1))
860fdc82d3bSMaciej Wawryk		for vm in "$@"; do
8613d11b2feSBen Walker			vm_num_is_valid $1 || return 1
8628f44d126SBen Walker			if [[ ! -x $VM_DIR/$vm/run.sh ]]; then
8633d11b2feSBen Walker				error "VM$vm not defined - setup it first"
8643d11b2feSBen Walker				return 1
8653d11b2feSBen Walker			fi
8663d11b2feSBen Walker			vms_to_run+=" $vm"
8673d11b2feSBen Walker		done
8683d11b2feSBen Walker	fi
8693d11b2feSBen Walker
8703d11b2feSBen Walker	for vm in $vms_to_run; do
8713d11b2feSBen Walker		if vm_is_running $vm; then
8728f44d126SBen Walker			warning "VM$vm ($VM_DIR/$vm) already running"
8733d11b2feSBen Walker			continue
8743d11b2feSBen Walker		fi
8753d11b2feSBen Walker
8768f44d126SBen Walker		notice "running $VM_DIR/$vm/run.sh"
8778f44d126SBen Walker		if ! $VM_DIR/$vm/run.sh; then
8783d11b2feSBen Walker			error "FAILED to run vm $vm"
8793d11b2feSBen Walker			return 1
8803d11b2feSBen Walker		fi
8813d11b2feSBen Walker	done
8823d11b2feSBen Walker}
8833d11b2feSBen Walker
884844c8ec3SMichal Bergerfunction vm_print_logs() {
8853d11b2feSBen Walker	vm_num=$1
8863d11b2feSBen Walker	warning "================"
8873d11b2feSBen Walker	warning "QEMU LOG:"
8888f44d126SBen Walker	if [[ -r $VM_DIR/$vm_num/qemu.log ]]; then
8898f44d126SBen Walker		cat $VM_DIR/$vm_num/qemu.log
8903d11b2feSBen Walker	else
8913d11b2feSBen Walker		warning "LOG qemu.log not found"
8923d11b2feSBen Walker	fi
8933d11b2feSBen Walker
8943d11b2feSBen Walker	warning "VM LOG:"
8958f44d126SBen Walker	if [[ -r $VM_DIR/$vm_num/serial.log ]]; then
8968f44d126SBen Walker		cat $VM_DIR/$vm_num/serial.log
8973d11b2feSBen Walker	else
8983d11b2feSBen Walker		warning "LOG serial.log not found"
8993d11b2feSBen Walker	fi
9003d11b2feSBen Walker
9013d11b2feSBen Walker	warning "SEABIOS LOG:"
9028f44d126SBen Walker	if [[ -r $VM_DIR/$vm_num/seabios.log ]]; then
9038f44d126SBen Walker		cat $VM_DIR/$vm_num/seabios.log
9043d11b2feSBen Walker	else
9053d11b2feSBen Walker		warning "LOG seabios.log not found"
9063d11b2feSBen Walker	fi
9073d11b2feSBen Walker	warning "================"
9083d11b2feSBen Walker}
9093d11b2feSBen Walker
9103d11b2feSBen Walker# Wait for all created VMs to boot.
9113d11b2feSBen Walker# param $1 max wait time
912844c8ec3SMichal Bergerfunction vm_wait_for_boot() {
9133d11b2feSBen Walker	assert_number $1
9143d11b2feSBen Walker
91534ae1172SSeth Howell	xtrace_disable
9163d11b2feSBen Walker
9173d11b2feSBen Walker	local all_booted=false
9183d11b2feSBen Walker	local timeout_time=$1
9193d11b2feSBen Walker	[[ $timeout_time -lt 10 ]] && timeout_time=10
920074df1d8SPawel Kaminski	local timeout_time
921074df1d8SPawel Kaminski	timeout_time=$(date -d "+$timeout_time seconds" +%s)
9223d11b2feSBen Walker
9233d11b2feSBen Walker	notice "Waiting for VMs to boot"
9243d11b2feSBen Walker	shift
925eda1ec69SSeth Howell	if [[ "$*" == "" ]]; then
9268f44d126SBen Walker		local vms_to_check="$VM_DIR/[0-9]*"
9273d11b2feSBen Walker	else
9283d11b2feSBen Walker		local vms_to_check=""
929fdc82d3bSMaciej Wawryk		for vm in "$@"; do
9308f44d126SBen Walker			vms_to_check+=" $VM_DIR/$vm"
9313d11b2feSBen Walker		done
9323d11b2feSBen Walker	fi
9333d11b2feSBen Walker
9343d11b2feSBen Walker	for vm in $vms_to_check; do
935074df1d8SPawel Kaminski		local vm_num
936074df1d8SPawel Kaminski		vm_num=$(basename $vm)
9373d11b2feSBen Walker		local i=0
9383d11b2feSBen Walker		notice "waiting for VM$vm_num ($vm)"
9393d11b2feSBen Walker		while ! vm_os_booted $vm_num; do
9403d11b2feSBen Walker			if ! vm_is_running $vm_num; then
9413d11b2feSBen Walker				warning "VM $vm_num is not running"
9423d11b2feSBen Walker				vm_print_logs $vm_num
94334ae1172SSeth Howell				xtrace_restore
9443d11b2feSBen Walker				return 1
9453d11b2feSBen Walker			fi
9463d11b2feSBen Walker
9473d11b2feSBen Walker			if [[ $(date +%s) -gt $timeout_time ]]; then
9483d11b2feSBen Walker				warning "timeout waiting for machines to boot"
9493d11b2feSBen Walker				vm_print_logs $vm_num
95034ae1172SSeth Howell				xtrace_restore
9513d11b2feSBen Walker				return 1
9523d11b2feSBen Walker			fi
9533d11b2feSBen Walker			if ((i > 30)); then
9543d11b2feSBen Walker				local i=0
9553d11b2feSBen Walker				echo
9563d11b2feSBen Walker			fi
9573d11b2feSBen Walker			echo -n "."
9583d11b2feSBen Walker			sleep 1
9593d11b2feSBen Walker		done
9603d11b2feSBen Walker		echo ""
9613d11b2feSBen Walker		notice "VM$vm_num ready"
9623d11b2feSBen Walker		#Change Timeout for stopping services to prevent lengthy powerdowns
9633d11b2feSBen Walker		#Check that remote system is not Cygwin in case of Windows VMs
964074df1d8SPawel Kaminski		local vm_os
965074df1d8SPawel Kaminski		vm_os=$(vm_exec $vm_num "uname -o")
9663d11b2feSBen Walker		if [[ "$vm_os" != "Cygwin" ]]; then
96797df5bccSBen Walker			vm_exec $vm_num "echo 'DefaultTimeoutStopSec=10' >> /etc/systemd/system.conf; systemctl daemon-reexec"
9683d11b2feSBen Walker		fi
9693d11b2feSBen Walker	done
9703d11b2feSBen Walker
9713d11b2feSBen Walker	notice "all VMs ready"
97234ae1172SSeth Howell	xtrace_restore
9733d11b2feSBen Walker	return 0
9743d11b2feSBen Walker}
9753d11b2feSBen Walker
976844c8ec3SMichal Bergerfunction vm_start_fio_server() {
9773d11b2feSBen Walker	local OPTIND optchar
9783d11b2feSBen Walker	local readonly=''
979d3e367a5SKarol Latecki	local fio_bin=''
9803d11b2feSBen Walker	while getopts ':-:' optchar; do
9813d11b2feSBen Walker		case "$optchar" in
9823d11b2feSBen Walker			-)
9833d11b2feSBen Walker				case "$OPTARG" in
9843d11b2feSBen Walker					fio-bin=*) local fio_bin="${OPTARG#*=}" ;;
9853d11b2feSBen Walker					readonly) local readonly="--readonly" ;;
9863d11b2feSBen Walker					*) error "Invalid argument '$OPTARG'" && return 1 ;;
9873d11b2feSBen Walker				esac
9883d11b2feSBen Walker				;;
9893d11b2feSBen Walker			*) error "Invalid argument '$OPTARG'" && return 1 ;;
9903d11b2feSBen Walker		esac
9913d11b2feSBen Walker	done
9923d11b2feSBen Walker
9933d11b2feSBen Walker	shift $((OPTIND - 1))
994fdc82d3bSMaciej Wawryk	for vm_num in "$@"; do
9953d11b2feSBen Walker		notice "Starting fio server on VM$vm_num"
9963d11b2feSBen Walker		if [[ $fio_bin != "" ]]; then
99713c6c8dbSPawel Kaminski			vm_exec $vm_num 'cat > /root/fio; chmod +x /root/fio' < $fio_bin
99897df5bccSBen Walker			vm_exec $vm_num /root/fio $readonly --eta=never --server --daemonize=/root/fio.pid
9993d11b2feSBen Walker		else
100097df5bccSBen Walker			vm_exec $vm_num fio $readonly --eta=never --server --daemonize=/root/fio.pid
10013d11b2feSBen Walker		fi
10023d11b2feSBen Walker	done
10033d11b2feSBen Walker}
10043d11b2feSBen Walker
1005844c8ec3SMichal Bergerfunction vm_check_scsi_location() {
10063d11b2feSBen Walker	# Script to find wanted disc
10076956b0ecSMaciej Wawryk	local script='shopt -s nullglob;
10086956b0ecSMaciej Wawryk	for entry in /sys/block/sd*; do
10096956b0ecSMaciej Wawryk		disk_type="$(cat $entry/device/vendor)";
10106956b0ecSMaciej Wawryk		if [[ $disk_type == INTEL* ]] || [[ $disk_type == RAWSCSI* ]] || [[ $disk_type == LIO-ORG* ]]; then
10116956b0ecSMaciej Wawryk			fname=$(basename $entry);
10126956b0ecSMaciej Wawryk			echo -n " $fname";
10136956b0ecSMaciej Wawryk		fi;
10143d11b2feSBen Walker	done'
10153d11b2feSBen Walker
101697df5bccSBen Walker	SCSI_DISK="$(echo "$script" | vm_exec $1 bash -s)"
10173d11b2feSBen Walker
10183d11b2feSBen Walker	if [[ -z "$SCSI_DISK" ]]; then
10193d11b2feSBen Walker		error "no test disk found!"
10203d11b2feSBen Walker		return 1
10213d11b2feSBen Walker	fi
10223d11b2feSBen Walker}
10233d11b2feSBen Walker
10243d11b2feSBen Walker# Script to perform scsi device reset on all disks in VM
10253d11b2feSBen Walker# param $1 VM num
10263d11b2feSBen Walker# param $2..$n Disks to perform reset on
1027844c8ec3SMichal Bergerfunction vm_reset_scsi_devices() {
10283d11b2feSBen Walker	for disk in "${@:2}"; do
10293d11b2feSBen Walker		notice "VM$1 Performing device reset on disk $disk"
103097df5bccSBen Walker		vm_exec $1 sg_reset /dev/$disk -vNd
10313d11b2feSBen Walker	done
10323d11b2feSBen Walker}
10333d11b2feSBen Walker
1034844c8ec3SMichal Bergerfunction vm_check_blk_location() {
10353d11b2feSBen Walker	local script='shopt -s nullglob; cd /sys/block; echo vd*'
103697df5bccSBen Walker	SCSI_DISK="$(echo "$script" | vm_exec $1 bash -s)"
10373d11b2feSBen Walker
10383d11b2feSBen Walker	if [[ -z "$SCSI_DISK" ]]; then
10393d11b2feSBen Walker		error "no blk test disk found!"
10403d11b2feSBen Walker		return 1
10413d11b2feSBen Walker	fi
10423d11b2feSBen Walker}
10433d11b2feSBen Walker
10445c385271SKarol Lateckifunction vm_check_nvme_location() {
10457cd8de9cSMichal Berger	SCSI_DISK="$(vm_exec $1 "grep -l SPDK /sys/class/nvme/*/model" | awk -F/ '{print $5"n1"}')"
10465c385271SKarol Latecki	if [[ -z "$SCSI_DISK" ]]; then
10475c385271SKarol Latecki		error "no vfio-user nvme test disk found!"
10485c385271SKarol Latecki		return 1
10495c385271SKarol Latecki	fi
10505c385271SKarol Latecki}
10515c385271SKarol Latecki
1052844c8ec3SMichal Bergerfunction run_fio() {
10533d11b2feSBen Walker	local arg
10543d11b2feSBen Walker	local job_file=""
10553d11b2feSBen Walker	local fio_bin=""
10563d11b2feSBen Walker	local vms=()
10573d11b2feSBen Walker	local out=""
10583d11b2feSBen Walker	local vm
10593d11b2feSBen Walker	local run_server_mode=true
1060a0e6c88dSKarol Latecki	local run_plugin_mode=false
1061a70d47beSKarol Latecki	local fio_start_cmd
1062a70d47beSKarol Latecki	local fio_output_format="normal"
1063757eddebSKarol Latecki	local fio_gtod_reduce=false
106401425928SKarol Latecki	local wait_for_fio=true
10653d11b2feSBen Walker
1066fdc82d3bSMaciej Wawryk	for arg in "$@"; do
10673d11b2feSBen Walker		case "$arg" in
10683d11b2feSBen Walker			--job-file=*) local job_file="${arg#*=}" ;;
10693d11b2feSBen Walker			--fio-bin=*) local fio_bin="${arg#*=}" ;;
10703d11b2feSBen Walker			--vm=*) vms+=("${arg#*=}") ;;
10713d11b2feSBen Walker			--out=*)
10723d11b2feSBen Walker				local out="${arg#*=}"
10733d11b2feSBen Walker				mkdir -p $out
10743d11b2feSBen Walker				;;
10753d11b2feSBen Walker			--local) run_server_mode=false ;;
1076a0e6c88dSKarol Latecki			--plugin)
1077a0e6c88dSKarol Latecki				notice "Using plugin mode. Disabling server mode."
1078a0e6c88dSKarol Latecki				run_plugin_mode=true
1079844c8ec3SMichal Berger				run_server_mode=false
1080844c8ec3SMichal Berger				;;
1081a70d47beSKarol Latecki			--json) fio_output_format="json" ;;
1082a70d47beSKarol Latecki			--hide-results) hide_results=true ;;
108301425928SKarol Latecki			--no-wait-for-fio) wait_for_fio=false ;;
1084757eddebSKarol Latecki			--gtod-reduce) fio_gtod_reduce=true ;;
10853d11b2feSBen Walker			*)
10863d11b2feSBen Walker				error "Invalid argument '$arg'"
10873d11b2feSBen Walker				return 1
10883d11b2feSBen Walker				;;
10893d11b2feSBen Walker		esac
10903d11b2feSBen Walker	done
10913d11b2feSBen Walker
10921ccc878eSKarol Latecki	if [[ -n "$fio_bin" && ! -r "$fio_bin" ]]; then
10933d11b2feSBen Walker		error "FIO binary '$fio_bin' does not exist"
10943d11b2feSBen Walker		return 1
10953d11b2feSBen Walker	fi
10963d11b2feSBen Walker
10972c7ba231SKarol Latecki	if [[ -z "$fio_bin" ]]; then
10982c7ba231SKarol Latecki		fio_bin="fio"
10992c7ba231SKarol Latecki	fi
11002c7ba231SKarol Latecki
11013d11b2feSBen Walker	if [[ ! -r "$job_file" ]]; then
11023d11b2feSBen Walker		error "Fio job '$job_file' does not exist"
11033d11b2feSBen Walker		return 1
11043d11b2feSBen Walker	fi
11053d11b2feSBen Walker
1106a70d47beSKarol Latecki	fio_start_cmd="$fio_bin --eta=never "
1107a70d47beSKarol Latecki
1108074df1d8SPawel Kaminski	local job_fname
1109074df1d8SPawel Kaminski	job_fname=$(basename "$job_file")
11103eb1aa93SKarol Latecki	log_fname="${job_fname%%.*}.log"
11113eb1aa93SKarol Latecki	fio_start_cmd+=" --output=$out/$log_fname --output-format=$fio_output_format "
1112a70d47beSKarol Latecki
11133d11b2feSBen Walker	# prepare job file for each VM
1114fdc82d3bSMaciej Wawryk	for vm in "${vms[@]}"; do
11153d11b2feSBen Walker		local vm_num=${vm%%:*}
11163d11b2feSBen Walker		local vmdisks=${vm#*:}
11173d11b2feSBen Walker
1118ce6550a9SMichal Berger		sed "s@filename=@filename=$vmdisks@;s@description=\(.*\)@description=\1 (VM=$vm_num)@" "$job_file" \
1119ce6550a9SMichal Berger			| vm_exec $vm_num "cat > /root/$job_fname"
1120757eddebSKarol Latecki
1121757eddebSKarol Latecki		if $fio_gtod_reduce; then
1122757eddebSKarol Latecki			vm_exec $vm_num "echo 'gtod_reduce=1' >> /root/$job_fname"
1123757eddebSKarol Latecki		fi
1124757eddebSKarol Latecki
112597df5bccSBen Walker		vm_exec $vm_num cat /root/$job_fname
1126a70d47beSKarol Latecki
1127a70d47beSKarol Latecki		if $run_server_mode; then
1128a70d47beSKarol Latecki			fio_start_cmd+="--client=127.0.0.1,$(vm_fio_socket $vm_num) --remote-config /root/$job_fname "
1129a70d47beSKarol Latecki		fi
1130a70d47beSKarol Latecki
11313d11b2feSBen Walker		if ! $run_server_mode; then
11321ccc878eSKarol Latecki			if [[ -n "$fio_bin" ]]; then
1133a4a04624SMichal Berger				if ! $run_plugin_mode && [[ -e $fio_bin ]]; then
113413c6c8dbSPawel Kaminski					vm_exec $vm_num 'cat > /root/fio; chmod +x /root/fio' < $fio_bin
1135a0e6c88dSKarol Latecki					vm_fio_bin="/root/fio"
1136a0e6c88dSKarol Latecki				else
1137a4a04624SMichal Berger					vm_fio_bin=$fio_bin
1138a0e6c88dSKarol Latecki				fi
11393d11b2feSBen Walker			fi
11403d11b2feSBen Walker
11413d11b2feSBen Walker			notice "Running local fio on VM $vm_num"
114201425928SKarol Latecki			vm_exec $vm_num "$vm_fio_bin --output=/root/$log_fname --output-format=$fio_output_format /root/$job_fname & echo \$! > /root/fio.pid" &
11439fc706f4SKarol Latecki			vm_exec_pids+=("$!")
11443d11b2feSBen Walker		fi
11453d11b2feSBen Walker	done
11463d11b2feSBen Walker
11473d11b2feSBen Walker	if ! $run_server_mode; then
114801425928SKarol Latecki		if ! $wait_for_fio; then
114901425928SKarol Latecki			return 0
115001425928SKarol Latecki		fi
11519fc706f4SKarol Latecki		echo "Waiting for guest fio instances to finish.."
11529fc706f4SKarol Latecki		wait "${vm_exec_pids[@]}"
11539fc706f4SKarol Latecki
11549fc706f4SKarol Latecki		for vm in "${vms[@]}"; do
11559fc706f4SKarol Latecki			local vm_num=${vm%%:*}
11563eb1aa93SKarol Latecki			vm_exec $vm_num cat /root/$log_fname > "$out/vm${vm_num}_${log_fname}"
11579fc706f4SKarol Latecki		done
11583d11b2feSBen Walker		return 0
11593d11b2feSBen Walker	fi
11603d11b2feSBen Walker
1161a70d47beSKarol Latecki	$fio_start_cmd
11622c7ba231SKarol Latecki	sleep 1
1163a70d47beSKarol Latecki
1164782681e0SKarol Latecki	if [[ "$fio_output_format" == "json" ]]; then
1165782681e0SKarol Latecki		# Fio in client-server mode produces a lot of "trash" output
1166782681e0SKarol Latecki		# preceding JSON structure, making it not possible to parse.
1167782681e0SKarol Latecki		# Remove these lines from file.
1168782681e0SKarol Latecki		# shellcheck disable=SC2005
1169782681e0SKarol Latecki		echo "$(grep -vP '^[<\w]' "$out/$log_fname")" > "$out/$log_fname"
1170782681e0SKarol Latecki	fi
1171782681e0SKarol Latecki
1172a70d47beSKarol Latecki	if [[ ! $hide_results ]]; then
11733eb1aa93SKarol Latecki		cat $out/$log_fname
1174a70d47beSKarol Latecki	fi
11753d11b2feSBen Walker}
11763d11b2feSBen Walker
1177c3dc7fb5SKarol Latecki# Parsing fio results for json output and client-server mode only!
1178c3dc7fb5SKarol Lateckifunction parse_fio_results() {
1179c3dc7fb5SKarol Latecki	local fio_log_dir=$1
1180c3dc7fb5SKarol Latecki	local fio_log_filename=$2
1181c3dc7fb5SKarol Latecki	local fio_csv_filename
1182c3dc7fb5SKarol Latecki
1183c3dc7fb5SKarol Latecki	# Variables used in parsing loop
1184c3dc7fb5SKarol Latecki	local log_file
1185c3dc7fb5SKarol Latecki	local rwmode mixread mixwrite
1186c3dc7fb5SKarol Latecki	local lat_key lat_divisor
1187c3dc7fb5SKarol Latecki	local client_stats iops bw
1188c3dc7fb5SKarol Latecki	local read_avg_lat read_min_lat read_max_lat
1189c3dc7fb5SKarol Latecki	local write_avg_lat write_min_lat write_min_lat
119051a8f16eSMichal Berger	local clients
1191c3dc7fb5SKarol Latecki
1192c3dc7fb5SKarol Latecki	declare -A results
1193c3dc7fb5SKarol Latecki	results["iops"]=0
1194c3dc7fb5SKarol Latecki	results["bw"]=0
1195c3dc7fb5SKarol Latecki	results["avg_lat"]=0
1196c3dc7fb5SKarol Latecki	results["min_lat"]=0
1197c3dc7fb5SKarol Latecki	results["max_lat"]=0
1198c3dc7fb5SKarol Latecki
1199c3dc7fb5SKarol Latecki	# Loop using the log filename to see if there are any other
1200c3dc7fb5SKarol Latecki	# matching files. This is in case we ran fio test multiple times.
1201c3dc7fb5SKarol Latecki	log_files=("$fio_log_dir/$fio_log_filename"*)
1202c3dc7fb5SKarol Latecki	for log_file in "${log_files[@]}"; do
120351a8f16eSMichal Berger		# Save entire array to avoid opening $log_file multiple times
120451a8f16eSMichal Berger		clients=$(jq -r '.client_stats' "$log_file")
120551a8f16eSMichal Berger		[[ -n $clients ]]
120651a8f16eSMichal Berger		rwmode=$(jq -r '.[0]["job options"]["rw"]' <<< "$clients")
1207c3dc7fb5SKarol Latecki		mixread=1
1208c3dc7fb5SKarol Latecki		mixwrite=1
1209c3dc7fb5SKarol Latecki		if [[ $rwmode = *"rw"* ]]; then
121051a8f16eSMichal Berger			mixread=$(jq -r '.[0]["job options"]["rwmixread"]' <<< "$clients")
1211c3dc7fb5SKarol Latecki			mixread=$(bc -l <<< "scale=3; $mixread/100")
1212c3dc7fb5SKarol Latecki			mixwrite=$(bc -l <<< "scale=3; 1-$mixread")
1213c3dc7fb5SKarol Latecki		fi
1214c3dc7fb5SKarol Latecki
121551a8f16eSMichal Berger		client_stats=$(jq -r '.[] | select(.jobname == "All clients")' <<< "$clients")
121651a8f16eSMichal Berger		if [[ -z $client_stats ]]; then
121751a8f16eSMichal Berger			# Potentially single client (single VM)
121851a8f16eSMichal Berger			client_stats=$(jq -r '.[]' <<< "$clients")
121951a8f16eSMichal Berger		fi
1220c3dc7fb5SKarol Latecki
1221c3dc7fb5SKarol Latecki		# Check latency unit and later normalize to microseconds
1222c3dc7fb5SKarol Latecki		lat_key="lat_us"
1223c3dc7fb5SKarol Latecki		lat_divisor=1
1224c3dc7fb5SKarol Latecki		if jq -er '.read["lat_ns"]' &> /dev/null <<< $client_stats; then
1225c3dc7fb5SKarol Latecki			lat_key="lat_ns"
1226c3dc7fb5SKarol Latecki			lat_divisor=1000
1227c3dc7fb5SKarol Latecki		fi
1228c3dc7fb5SKarol Latecki
1229c9c7c281SJosh Soref		# Horrific bash float point arithmetic operations below.
1230c3dc7fb5SKarol Latecki		# Viewer discretion is advised.
1231c3dc7fb5SKarol Latecki		iops=$(jq -r '[.read["iops"],.write["iops"]] | add' <<< $client_stats)
1232c3dc7fb5SKarol Latecki		bw=$(jq -r '[.read["bw"],.write["bw"]] | add' <<< $client_stats)
1233c3dc7fb5SKarol Latecki		read_avg_lat=$(jq -r --arg lat_key $lat_key '.read[$lat_key]["mean"]' <<< $client_stats)
1234c3dc7fb5SKarol Latecki		read_min_lat=$(jq -r --arg lat_key $lat_key '.read[$lat_key]["min"]' <<< $client_stats)
1235c3dc7fb5SKarol Latecki		read_max_lat=$(jq -r --arg lat_key $lat_key '.read[$lat_key]["max"]' <<< $client_stats)
1236c3dc7fb5SKarol Latecki		write_avg_lat=$(jq -r --arg lat_key $lat_key '.write[$lat_key]["mean"]' <<< $client_stats)
1237c3dc7fb5SKarol Latecki		write_min_lat=$(jq -r --arg lat_key $lat_key '.write[$lat_key]["min"]' <<< $client_stats)
1238c3dc7fb5SKarol Latecki		write_max_lat=$(jq -r --arg lat_key $lat_key '.write[$lat_key]["max"]' <<< $client_stats)
1239c3dc7fb5SKarol Latecki
1240c3dc7fb5SKarol Latecki		results["iops"]=$(bc -l <<< "${results[iops]} + $iops")
1241c3dc7fb5SKarol Latecki		results["bw"]=$(bc -l <<< "${results[bw]} + $bw")
1242c3dc7fb5SKarol Latecki		results["avg_lat"]=$(bc -l <<< "${results[avg_lat]} + ($mixread*$read_avg_lat + $mixwrite*$write_avg_lat)/$lat_divisor")
1243c3dc7fb5SKarol Latecki		results["min_lat"]=$(bc -l <<< "${results[min_lat]} + ($mixread*$read_min_lat + $mixwrite*$write_min_lat)/$lat_divisor")
1244c3dc7fb5SKarol Latecki		results["max_lat"]=$(bc -l <<< "${results[max_lat]} + ($mixread*$read_max_lat + $mixwrite*$write_max_lat)/$lat_divisor")
1245c3dc7fb5SKarol Latecki	done
1246c3dc7fb5SKarol Latecki
1247c3dc7fb5SKarol Latecki	results["iops"]=$(bc -l <<< "scale=3; ${results[iops]} / ${#log_files[@]}")
1248c3dc7fb5SKarol Latecki	results["bw"]=$(bc -l <<< "scale=3; ${results[bw]} / ${#log_files[@]}")
1249c3dc7fb5SKarol Latecki	results["avg_lat"]=$(bc -l <<< "scale=3; ${results[avg_lat]} / ${#log_files[@]}")
1250c3dc7fb5SKarol Latecki	results["min_lat"]=$(bc -l <<< "scale=3; ${results[min_lat]} / ${#log_files[@]}")
1251c3dc7fb5SKarol Latecki	results["max_lat"]=$(bc -l <<< "scale=3; ${results[max_lat]} / ${#log_files[@]}")
1252c3dc7fb5SKarol Latecki
1253c3dc7fb5SKarol Latecki	fio_csv_filename="${fio_log_filename%%.*}.csv"
1254c3dc7fb5SKarol Latecki	cat <<- EOF > "$fio_log_dir/$fio_csv_filename"
1255c3dc7fb5SKarol Latecki		iops,bw,avg_lat,min_lat,max_lat
1256c3dc7fb5SKarol Latecki		${results["iops"]},${results["bw"]},${results["avg_lat"]},${results["min_lat"]},${results["max_lat"]}
1257c3dc7fb5SKarol Latecki	EOF
1258c3dc7fb5SKarol Latecki}
1259c3dc7fb5SKarol Latecki
12603d11b2feSBen Walker# Shutdown or kill any running VM and SPDK APP.
12613d11b2feSBen Walker#
1262844c8ec3SMichal Bergerfunction at_app_exit() {
1263fa563858SBen Walker	local vhost_name
12643d11b2feSBen Walker
12653d11b2feSBen Walker	notice "APP EXITING"
12663d11b2feSBen Walker	notice "killing all VMs"
12673d11b2feSBen Walker	vm_kill_all
12683d11b2feSBen Walker	# Kill vhost application
12693d11b2feSBen Walker	notice "killing vhost app"
12703d11b2feSBen Walker
127119e48a66SMaciej Wawryk	for vhost_name in "$TARGET_DIR"/*; do
1272feb68300SMichal Berger		vhost_kill "$(basename "$vhost_name")"
12733d11b2feSBen Walker	done
12743d11b2feSBen Walker
12753d11b2feSBen Walker	notice "EXIT DONE"
12763d11b2feSBen Walker}
12773d11b2feSBen Walker
1278844c8ec3SMichal Bergerfunction error_exit() {
12793d11b2feSBen Walker	trap - ERR
12803d11b2feSBen Walker	print_backtrace
12813d11b2feSBen Walker	set +e
12823d11b2feSBen Walker	error "Error on $1 $2"
12833d11b2feSBen Walker
12843d11b2feSBen Walker	at_app_exit
12853d11b2feSBen Walker	exit 1
12863d11b2feSBen Walker}
12877c764edfSMichal Berger
12887c764edfSMichal Bergerfunction lookup_dev_irqs() {
12897c764edfSMichal Berger	local vm=$1 irqs=() cpus=()
12907c764edfSMichal Berger	local script_get_irqs script_get_cpus
12917c764edfSMichal Berger
12927c764edfSMichal Berger	mkdir -p "$VHOST_DIR/irqs"
12937c764edfSMichal Berger
12947c764edfSMichal Berger	# All vhost tests depend either on virtio_blk or virtio_scsi drivers on the VM side.
12957c764edfSMichal Berger	# Considering that, simply iterate over virtio bus and pick pci device corresponding
12967c764edfSMichal Berger	# to each virtio device.
12977c764edfSMichal Berger	# For vfio-user setup, look for bare nvme devices.
12987c764edfSMichal Berger
12997c764edfSMichal Berger	script_get_irqs=$(
13007c764edfSMichal Berger		cat <<- 'SCRIPT'
13017c764edfSMichal Berger			shopt -s nullglob
13027c764edfSMichal Berger			for virtio in /sys/bus/virtio/devices/virtio*; do
13037c764edfSMichal Berger			  irqs+=("$(readlink -f "$virtio")/../msi_irqs/"*)
13047c764edfSMichal Berger			done
13057c764edfSMichal Berger			irqs+=(/sys/class/nvme/nvme*/device/msi_irqs/*)
13067c764edfSMichal Berger			printf '%u\n' "${irqs[@]##*/}"
13077c764edfSMichal Berger		SCRIPT
13087c764edfSMichal Berger	)
13097c764edfSMichal Berger
13107c764edfSMichal Berger	script_get_cpus=$(
13117c764edfSMichal Berger		cat <<- 'SCRIPT'
13127c764edfSMichal Berger			cpus=(/sys/devices/system/cpu/cpu[0-9]*)
13137c764edfSMichal Berger			printf '%u\n' "${cpus[@]##*cpu}"
13147c764edfSMichal Berger		SCRIPT
13157c764edfSMichal Berger	)
13167c764edfSMichal Berger
13177c764edfSMichal Berger	irqs=($(vm_exec "$vm" "$script_get_irqs"))
13187c764edfSMichal Berger	cpus=($(vm_exec "$vm" "$script_get_cpus"))
13197c764edfSMichal Berger	((${#irqs[@]} > 0 && ${#cpus[@]} > 0))
13207c764edfSMichal Berger
13217c764edfSMichal Berger	printf '%u\n' "${irqs[@]}" > "$VHOST_DIR/irqs/$vm.irqs"
13227c764edfSMichal Berger	printf '%u\n' "${cpus[@]}" > "$VHOST_DIR/irqs/$vm.cpus"
13237c764edfSMichal Berger}
13247c764edfSMichal Berger
13257c764edfSMichal Bergerfunction irqs() {
13267c764edfSMichal Berger	local vm
13277c764edfSMichal Berger	for vm; do
13287c764edfSMichal Berger		vm_exec "$vm" "while :; do cat /proc/interrupts; sleep 1s; done" > "$VHOST_DIR/irqs/$vm.interrupts" &
13297c764edfSMichal Berger		irqs_pids+=($!)
13307c764edfSMichal Berger	done
13317c764edfSMichal Berger}
13327c764edfSMichal Berger
13337c764edfSMichal Bergerfunction parse_irqs() {
13347c764edfSMichal Berger	local iter=${1:-1}
13357c764edfSMichal Berger	"$rootdir/test/vhost/parse_irqs.sh" "$VHOST_DIR/irqs/"*.interrupts
13367c764edfSMichal Berger	rm "$VHOST_DIR/irqs/"*.interrupts
13377c764edfSMichal Berger
13387c764edfSMichal Berger	mkdir -p "$VHOST_DIR/irqs/$iter"
13397c764edfSMichal Berger	mv "$VHOST_DIR/irqs/"*.parsed "$VHOST_DIR/irqs/$iter/"
13407c764edfSMichal Berger}
1341c1d2bdfeSMichal Berger
1342c1d2bdfeSMichal Bergerfunction collect_perf() {
1343c1d2bdfeSMichal Berger	local cpus=$1 outf=$2 runtime=$3 delay=$4
1344c1d2bdfeSMichal Berger
1345c1d2bdfeSMichal Berger	mkdir -p "$VHOST_DIR/perf"
1346c1d2bdfeSMichal Berger
1347c1d2bdfeSMichal Berger	perf record -g \
1348c1d2bdfeSMichal Berger		${cpus:+-C "$cpus"} \
1349c1d2bdfeSMichal Berger		${outf:+-o "$outf"} \
1350c1d2bdfeSMichal Berger		${delay:+-D $((delay * 1000))} \
1351c1d2bdfeSMichal Berger		-z \
1352c1d2bdfeSMichal Berger		${runtime:+ -- sleep $((runtime + delay))}
1353c1d2bdfeSMichal Berger}
1354c1d2bdfeSMichal Berger
1355c1d2bdfeSMichal Bergerfunction parse_perf() {
1356c1d2bdfeSMichal Berger	local iter=${1:-1}
1357c1d2bdfeSMichal Berger	local report out
1358c1d2bdfeSMichal Berger
1359c1d2bdfeSMichal Berger	mkdir -p "$VHOST_DIR/perf/$iter"
1360c1d2bdfeSMichal Berger	shift
1361c1d2bdfeSMichal Berger
1362c1d2bdfeSMichal Berger	for report in "$@" "$VHOST_DIR/perf/"*.perf; do
1363c1d2bdfeSMichal Berger		[[ -f $report ]] || continue
1364c1d2bdfeSMichal Berger		perf report \
1365c1d2bdfeSMichal Berger			-n \
1366c1d2bdfeSMichal Berger			-i "$report" \
1367c1d2bdfeSMichal Berger			--header \
1368c1d2bdfeSMichal Berger			--stdio > "$VHOST_DIR/perf/$iter/${report##*/}.parsed"
1369c1d2bdfeSMichal Berger		cp "$report" "$VHOST_DIR/perf/$iter/"
1370c1d2bdfeSMichal Berger	done
1371c1d2bdfeSMichal Berger	rm "$VHOST_DIR/perf/"*.perf
1372c1d2bdfeSMichal Berger}
1373c1d2bdfeSMichal Berger
1374c1d2bdfeSMichal Bergerfunction get_from_fio() {
1375c1d2bdfeSMichal Berger	local opt=$1 conf=$2
1376c1d2bdfeSMichal Berger
1377c1d2bdfeSMichal Berger	[[ -n $opt && -f $conf ]] || return 1
1378c1d2bdfeSMichal Berger
1379c1d2bdfeSMichal Berger	awk -F= "/^$opt/{print \$2}" "$conf"
1380c1d2bdfeSMichal Berger}
1381905c4dcfSMichal Berger
1382905c4dcfSMichal Bergerfunction get_free_tcp_port() {
1383905c4dcfSMichal Berger	local port=$1 to=${2:-1} sockets=()
1384905c4dcfSMichal Berger
1385905c4dcfSMichal Berger	mapfile -t sockets < /proc/net/tcp
1386905c4dcfSMichal Berger
1387905c4dcfSMichal Berger	# If there's a TCP socket in a listening state keep incrementing $port until
1388905c4dcfSMichal Berger	# we find one that's not used. $to determines how long should we look for:
1389905c4dcfSMichal Berger	#  0: don't increment, just check if given $port is in use
1390905c4dcfSMichal Berger	# >0: increment $to times
1391905c4dcfSMichal Berger	# <0: no increment limit
1392905c4dcfSMichal Berger
1393905c4dcfSMichal Berger	while [[ ${sockets[*]} == *":$(printf '%04X' "$port") 00000000:0000 0A"* ]]; do
1394905c4dcfSMichal Berger		((to-- && ++port <= 65535)) || return 1
1395905c4dcfSMichal Berger	done
1396905c4dcfSMichal Berger
1397905c4dcfSMichal Berger	echo "$port"
1398905c4dcfSMichal Berger}
13999463523bSMichal Berger
1400b86184c5SMichal Bergerfunction gen_cpu_vm_spdk_config() (
1401b86184c5SMichal Berger	local vm_count=$1 vm_cpu_num=$2 vm
1402b86184c5SMichal Berger	local spdk_cpu_num=${3:-1} spdk_cpu_list=${4:-} spdk_cpus
1403b86184c5SMichal Berger	local nodes=("${@:5}") node
1404b86184c5SMichal Berger	local env
1405b86184c5SMichal Berger
1406b86184c5SMichal Berger	spdk_cpus=spdk_cpu_num
1407b86184c5SMichal Berger	[[ -n $spdk_cpu_list ]] && spdk_cpus=spdk_cpu_list
1408b86184c5SMichal Berger
1409b86184c5SMichal Berger	if ((${#nodes[@]} > 0)); then
1410b86184c5SMichal Berger		((${#nodes[@]} == 1)) && node=${nodes[0]}
1411b86184c5SMichal Berger		for ((vm = 0; vm < vm_count; vm++)); do
1412b86184c5SMichal Berger			env+=("VM${vm}_NODE=${nodes[vm]:-$node}")
1413b86184c5SMichal Berger		done
1414b86184c5SMichal Berger	fi
1415b86184c5SMichal Berger
1416b86184c5SMichal Berger	env+=("$spdk_cpus=${!spdk_cpus}")
1417b86184c5SMichal Berger	env+=("vm_count=$vm_count")
1418b86184c5SMichal Berger	env+=("vm_cpu_num=$vm_cpu_num")
1419b86184c5SMichal Berger
1420b86184c5SMichal Berger	export "${env[@]}"
1421b86184c5SMichal Berger
1422b86184c5SMichal Berger	"$rootdir/scripts/perf/vhost/conf-generator" -p cpu
1423b86184c5SMichal Berger)
1424