@@ -698,18 +698,46 @@ _adjust_oom_score -500
# systemd doesn't automatically remove transient scopes that fail to terminate
# when systemd tells them to terminate (e.g. programs stuck in D state when
# systemd sends SIGKILL), so we use reset-failed to tear down the scope.
+#
+# Use setsid to run the test program with a separate session id so that we
+# can pkill only the processes started by this test.
_run_seq() {
- local cmd=(bash -c "test -w ${OOM_SCORE_ADJ} && echo 250 > ${OOM_SCORE_ADJ}; exec ./$seq")
+ local res
+ unset CHILDPID
+ unset FSTESTS_ISOL # set by tools/run_seq_*
if [ -n "${HAVE_SYSTEMD_SCOPES}" ]; then
local unit="$(systemd-escape "fs$seq").scope"
systemctl reset-failed "${unit}" &> /dev/null
- systemd-run --quiet --unit "${unit}" --scope "${cmd[@]}"
+ systemd-run --quiet --unit "${unit}" --scope \
+ ./tools/run_seq_setsid "./$seq" &
+ CHILDPID=$!
+ wait
res=$?
+ unset CHILDPID
systemctl stop "${unit}" &> /dev/null
- return "${res}"
else
- "${cmd[@]}"
+ # bash won't run the SIGINT trap handler while there are
+ # foreground children in a separate session, so we must run
+ # the test in the background and wait for it.
+ ./tools/run_seq_setsid "./$seq" &
+ CHILDPID=$!
+ wait
+ res=$?
+ unset CHILDPID
+ fi
+
+ return $res
+}
+
+_kill_seq() {
+ if [ -n "$CHILDPID" ]; then
+ # SIGPIPE will kill all the children (including fsstress)
+ # without bash logging fatal signal termination messages to the
+ # console
+ pkill -PIPE --session "$CHILDPID"
+ wait
+ unset CHILDPID
fi
}
@@ -718,9 +746,9 @@ _prepare_test_list
fstests_start_time="$(date +"%F %T")"
if $OPTIONS_HAVE_SECTIONS; then
- trap "_summary; exit \$status" 0 1 2 3 15
+ trap "_kill_seq; _summary; exit \$status" 0 1 2 3 15
else
- trap "_wrapup; exit \$status" 0 1 2 3 15
+ trap "_kill_seq; _wrapup; exit \$status" 0 1 2 3 15
fi
function run_section()
@@ -33,7 +33,7 @@ _test_sync()
# Kill only the processes started by this test.
_pkill()
{
- pkill "$@"
+ pkill --session 0 "$@"
}
# Common execution handling for fsstress invocation.
@@ -2732,9 +2732,11 @@ _require_user_exists()
[ "$?" == "0" ] || _notrun "$user user not defined."
}
+# Run all non-root processes in the same session as the root. Believe it or
+# not, passing $SHELL in this manner works both for "su" and "su -c cmd".
_su()
{
- su "$@"
+ su --session-command $SHELL "$@"
}
# check if a user exists and is able to execute commands.
new file mode 100755
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2025 Oracle. All Rights Reserved.
+#
+# Try starting things in a new process session so that test processes have
+# something with which to filter only their own subprocesses.
+
+if [ -n "${FSTESTS_ISOL}" ]; then
+ # Allow the test to become a target of the oom killer
+ oom_knob="/proc/self/oom_score_adj"
+ test -w "${oom_knob}" && echo 250 > "${oom_knob}"
+
+ exec "$@"
+fi
+
+if [ -z "$1" ] || [ "$1" = "--help" ]; then
+ echo "Usage: $0 command [args...]"
+ exit 1
+fi
+
+FSTESTS_ISOL=setsid exec setsid "$0" "$@"