[PATCH net-next 04/12] selftests/vsock: avoid multi-VM pidfile collisions with QEMU

Bobby Eshleman posted 12 patches 3 months, 2 weeks ago
There is a newer version of this series
[PATCH net-next 04/12] selftests/vsock: avoid multi-VM pidfile collisions with QEMU
Posted by Bobby Eshleman 3 months, 2 weeks ago
From: Bobby Eshleman <bobbyeshleman@meta.com>

Change QEMU to use generated pidfile names instead of just a single
globally-defined pidfile. This allows multiple QEMU instances to
co-exist with different pidfiles. This is required for future tests that
use multiple VMs to check for CID collissions.

Additionally, this also places the burden of killing the QEMU process
and cleaning up the pidfile on the caller of vm_start(). To help with
this, a function terminate_pidfiles() is introduced that callers use to
perform the cleanup. The terminate_pidfiles() function supports multiple
pidfile removals because future patches will need to process two
pidfiles at a time.

Signed-off-by: Bobby Eshleman <bobbyeshleman@meta.com>
---
 tools/testing/selftests/vsock/vmtest.sh | 53 +++++++++++++++++++--------------
 1 file changed, 30 insertions(+), 23 deletions(-)

diff --git a/tools/testing/selftests/vsock/vmtest.sh b/tools/testing/selftests/vsock/vmtest.sh
index 29b36b4d301d..9c72559aa894 100755
--- a/tools/testing/selftests/vsock/vmtest.sh
+++ b/tools/testing/selftests/vsock/vmtest.sh
@@ -23,7 +23,7 @@ readonly VSOCK_CID=1234
 readonly WAIT_PERIOD=3
 readonly WAIT_PERIOD_MAX=60
 readonly WAIT_TOTAL=$(( WAIT_PERIOD * WAIT_PERIOD_MAX ))
-readonly QEMU_PIDFILE=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
+readonly PIDFILE_TEMPLATE=/tmp/vsock_vmtest_XXXX.pid
 
 # virtme-ng offers a netdev for ssh when using "--ssh", but we also need a
 # control port forwarded for vsock_test.  Because virtme-ng doesn't support
@@ -33,12 +33,6 @@ readonly QEMU_PIDFILE=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
 # add the kernel cmdline options that virtme-init uses to setup the interface.
 readonly QEMU_TEST_PORT_FWD="hostfwd=tcp::${TEST_HOST_PORT}-:${TEST_GUEST_PORT}"
 readonly QEMU_SSH_PORT_FWD="hostfwd=tcp::${SSH_HOST_PORT}-:${SSH_GUEST_PORT}"
-readonly QEMU_OPTS="\
-	 -netdev user,id=n0,${QEMU_TEST_PORT_FWD},${QEMU_SSH_PORT_FWD} \
-	 -device virtio-net-pci,netdev=n0 \
-	 -device vhost-vsock-pci,guest-cid=${VSOCK_CID} \
-	 --pidfile ${QEMU_PIDFILE} \
-"
 readonly KERNEL_CMDLINE="\
 	virtme.dhcp net.ifnames=0 biosdevname=0 \
 	virtme.ssh virtme_ssh_channel=tcp virtme_ssh_user=$USER \
@@ -89,17 +83,6 @@ vm_ssh() {
 	return $?
 }
 
-cleanup() {
-	if [[ -s "${QEMU_PIDFILE}" ]]; then
-		pkill -SIGTERM -F "${QEMU_PIDFILE}" > /dev/null 2>&1
-	fi
-
-	# If failure occurred during or before qemu start up, then we need
-	# to clean this up ourselves.
-	if [[ -e "${QEMU_PIDFILE}" ]]; then
-		rm "${QEMU_PIDFILE}"
-	fi
-}
 
 check_args() {
 	local found
@@ -188,10 +171,26 @@ handle_build() {
 	popd &>/dev/null
 }
 
+terminate_pidfiles() {
+	local pidfile
+
+	for pidfile in "$@"; do
+		if [[ -s "${pidfile}" ]]; then
+			pkill -SIGTERM -F "${pidfile}" > /dev/null 2>&1
+		fi
+
+		if [[ -e "${pidfile}" ]]; then
+			rm -f "${pidfile}"
+		fi
+	done
+}
+
 vm_start() {
+	local pidfile=$1
 	local logfile=/dev/null
 	local verbose_opt=""
 	local kernel_opt=""
+	local qemu_opts=""
 	local qemu
 
 	qemu=$(command -v "${QEMU}")
@@ -201,6 +200,13 @@ vm_start() {
 		logfile=/dev/stdout
 	fi
 
+	qemu_opts="\
+		 -netdev user,id=n0,${QEMU_TEST_PORT_FWD},${QEMU_SSH_PORT_FWD} \
+		 -device virtio-net-pci,netdev=n0 \
+		 -device vhost-vsock-pci,guest-cid=${VSOCK_CID} \
+		--pidfile ${pidfile}
+	"
+
 	if [[ "${BUILD}" -eq 1 ]]; then
 		kernel_opt="${KERNEL_CHECKOUT}"
 	fi
@@ -209,14 +215,14 @@ vm_start() {
 		--run \
 		${kernel_opt} \
 		${verbose_opt} \
-		--qemu-opts="${QEMU_OPTS}" \
+		--qemu-opts="${qemu_opts}" \
 		--qemu="${qemu}" \
 		--user root \
 		--append "${KERNEL_CMDLINE}" \
 		--rw  &> ${logfile} &
 
 	if ! timeout ${WAIT_TOTAL} \
-		bash -c 'while [[ ! -s '"${QEMU_PIDFILE}"' ]]; do sleep 1; done; exit 0'; then
+		bash -c 'while [[ ! -s '"${pidfile}"' ]]; do sleep 1; done; exit 0'; then
 		die "failed to boot VM"
 	fi
 }
@@ -491,8 +497,6 @@ do
 done
 shift $((OPTIND-1))
 
-trap cleanup EXIT
-
 if [[ ${#} -eq 0 ]]; then
 	ARGS=("${TEST_NAMES[@]}")
 else
@@ -507,7 +511,8 @@ handle_build
 echo "1..${#ARGS[@]}"
 
 log_host "Booting up VM"
-vm_start
+pidfile="$(mktemp -u $PIDFILE_TEMPLATE)"
+vm_start "${pidfile}"
 vm_wait_for_ssh
 log_host "VM booted up"
 
@@ -531,6 +536,8 @@ for arg in "${ARGS[@]}"; do
 	cnt_total=$(( cnt_total + 1 ))
 done
 
+terminate_pidfiles "${pidfile}"
+
 echo "SUMMARY: PASS=${cnt_pass} SKIP=${cnt_skip} FAIL=${cnt_fail}"
 echo "Log: ${LOG}"
 

-- 
2.47.3
Re: [PATCH net-next 04/12] selftests/vsock: avoid multi-VM pidfile collisions with QEMU
Posted by Simon Horman 3 months, 2 weeks ago
On Wed, Oct 22, 2025 at 06:00:08PM -0700, Bobby Eshleman wrote:
> From: Bobby Eshleman <bobbyeshleman@meta.com>
> 
> Change QEMU to use generated pidfile names instead of just a single
> globally-defined pidfile. This allows multiple QEMU instances to
> co-exist with different pidfiles. This is required for future tests that
> use multiple VMs to check for CID collissions.
> 
> Additionally, this also places the burden of killing the QEMU process
> and cleaning up the pidfile on the caller of vm_start(). To help with
> this, a function terminate_pidfiles() is introduced that callers use to
> perform the cleanup. The terminate_pidfiles() function supports multiple
> pidfile removals because future patches will need to process two
> pidfiles at a time.

It seems that this will no longer cleanup, via a trap, if
there is an early exit. Is that intentional?

This patch also changes the handling of QEMU_OPTS. I think
that should be mentioned in the commit message too.

> 
> Signed-off-by: Bobby Eshleman <bobbyeshleman@meta.com>

...
Re: [PATCH net-next 04/12] selftests/vsock: avoid multi-VM pidfile collisions with QEMU
Posted by Bobby Eshleman 3 months, 2 weeks ago
On Mon, Oct 27, 2025 at 04:57:29PM +0000, Simon Horman wrote:
> On Wed, Oct 22, 2025 at 06:00:08PM -0700, Bobby Eshleman wrote:
> > From: Bobby Eshleman <bobbyeshleman@meta.com>
> > 
> > Change QEMU to use generated pidfile names instead of just a single
> > globally-defined pidfile. This allows multiple QEMU instances to
> > co-exist with different pidfiles. This is required for future tests that
> > use multiple VMs to check for CID collissions.
> > 
> > Additionally, this also places the burden of killing the QEMU process
> > and cleaning up the pidfile on the caller of vm_start(). To help with
> > this, a function terminate_pidfiles() is introduced that callers use to
> > perform the cleanup. The terminate_pidfiles() function supports multiple
> > pidfile removals because future patches will need to process two
> > pidfiles at a time.
> 
> It seems that this will no longer cleanup, via a trap, if
> there is an early exit. Is that intentional?
> 

Yes, intentional. We're trusting the vm_start() caller to do any cleanup
now. The assumption being that with no "set -e", vm_start() should be
able to return to the caller.

If that seems too bold, we could add some function like create_pidfile()
that generates the pidfiles and registers them into an array that is
cleaned up via trap.

> This patch also changes the handling of QEMU_OPTS. I think
> that should be mentioned in the commit message too.
> 

Sounds good.

Best,
Bobby