diff options
| author | Breno Leitao <leitao@debian.org> | 2026-08-05 07:52:36 -0700 |
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2026-08-10 11:47:20 -1000 |
| commit | a5bde5d8fde8a8cb28e59a672d5ddc5b9c1e7656 (patch) | |
| tree | 39f5b258386e1127d253d293194e9a2991bf3c34 /tools/testing/selftests/kselftest | |
| download | linux-stable-a5bde5d8fde8a8cb28e59a672d5ddc5b9c1e7656.tar.gz linux-stable-a5bde5d8fde8a8cb28e59a672d5ddc5b9c1e7656.zip | |
workqueue: skip the node_nr_active update for non-unbound workqueuesgrafted
apply_wqattrs_commit() updates node_nr_active->max unconditionally.
wq->node_nr_active[] is only allocated for unbound workqueues, so guard
the call before per-cpu workqueues start using this path.
No functional change: only unbound workqueues reach apply_wqattrs_*()
today.
Signed-off-by: Breno Leitao <leitao@debian.org>
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'tools/testing/selftests/kselftest')
| -rw-r--r-- | tools/testing/selftests/kselftest/ksft.py | 93 | ||||
| -rw-r--r-- | tools/testing/selftests/kselftest/ktap_helpers.sh | 126 | ||||
| -rwxr-xr-x | tools/testing/selftests/kselftest/module.sh | 84 | ||||
| -rwxr-xr-x | tools/testing/selftests/kselftest/prefix.pl | 24 | ||||
| -rw-r--r-- | tools/testing/selftests/kselftest/runner.sh | 228 |
5 files changed, 555 insertions, 0 deletions
diff --git a/tools/testing/selftests/kselftest/ksft.py b/tools/testing/selftests/kselftest/ksft.py new file mode 100644 index 000000000..0e030837f --- /dev/null +++ b/tools/testing/selftests/kselftest/ksft.py @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2023 Collabora Ltd +# +# Kselftest helpers for outputting in KTAP format. Based on kselftest.h. +# + +import sys + +ksft_cnt = {"pass": 0, "fail": 0, "skip": 0} +ksft_num_tests = 0 +ksft_test_number = 1 + +KSFT_PASS = 0 +KSFT_FAIL = 1 +KSFT_SKIP = 4 + + +def print_header(): + print("TAP version 13") + + +def set_plan(num_tests): + global ksft_num_tests + ksft_num_tests = num_tests + print("1..{}".format(num_tests)) + + +def print_cnts(): + if ksft_cnt['skip'] > 0: + print(f"# {ksft_cnt['skip']} skipped test(s) detected. Consider enabling relevant config options to improve coverage.") + + print( + f"# Totals: pass:{ksft_cnt['pass']} fail:{ksft_cnt['fail']} xfail:0 xpass:0 skip:{ksft_cnt['skip']} error:0" + ) + + +def print_msg(msg): + print(f"# {msg}") + + +def _test_print(result, description, directive=None): + if directive: + directive_str = f"# {directive}" + else: + directive_str = "" + + global ksft_test_number + print(f"{result} {ksft_test_number} {description} {directive_str}") + ksft_test_number += 1 + + +def test_result_pass(description): + _test_print("ok", description) + ksft_cnt["pass"] += 1 + + +def test_result_fail(description): + _test_print("not ok", description) + ksft_cnt["fail"] += 1 + + +def test_result_skip(description): + _test_print("ok", description, "SKIP") + ksft_cnt["skip"] += 1 + + +def test_result(condition, description=""): + if condition: + test_result_pass(description) + else: + test_result_fail(description) + + +def finished(): + if ksft_cnt["pass"] + ksft_cnt["skip"] == ksft_num_tests: + exit_code = KSFT_PASS + else: + exit_code = KSFT_FAIL + + print_cnts() + + sys.exit(exit_code) + + +def exit_fail(): + print_cnts() + sys.exit(KSFT_FAIL) + + +def exit_pass(): + print_cnts() + sys.exit(KSFT_PASS) diff --git a/tools/testing/selftests/kselftest/ktap_helpers.sh b/tools/testing/selftests/kselftest/ktap_helpers.sh new file mode 100644 index 000000000..32dbfe9da --- /dev/null +++ b/tools/testing/selftests/kselftest/ktap_helpers.sh @@ -0,0 +1,126 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2023 Collabora Ltd +# +# Helpers for outputting in KTAP format +# +KTAP_TESTNO=1 +KTAP_CNT_PASS=0 +KTAP_CNT_FAIL=0 +KTAP_CNT_XFAIL=0 +KTAP_CNT_SKIP=0 + +KSFT_PASS=0 +KSFT_FAIL=1 +KSFT_XFAIL=2 +KSFT_XPASS=3 +KSFT_SKIP=4 + +KSFT_NUM_TESTS=0 + +ktap_print_header() { + echo "TAP version 13" +} + +ktap_print_msg() +{ + echo "#" $@ +} + +ktap_set_plan() { + KSFT_NUM_TESTS="$1" + + echo "1..$KSFT_NUM_TESTS" +} + +ktap_skip_all() { + echo -n "1..0 # SKIP " + echo $@ +} + +__ktap_test() { + result="$1" + description="$2" + directive="${3:-}" # optional + + local directive_str= + [ ! -z "$directive" ] && directive_str="# $directive" + + echo $result $KTAP_TESTNO $description $directive_str + + KTAP_TESTNO=$((KTAP_TESTNO+1)) +} + +ktap_test_pass() { + description="$1" + + result="ok" + __ktap_test "$result" "$description" + + KTAP_CNT_PASS=$((KTAP_CNT_PASS+1)) +} + +ktap_test_skip() { + description="$1" + + result="ok" + directive="SKIP" + __ktap_test "$result" "$description" "$directive" + + KTAP_CNT_SKIP=$((KTAP_CNT_SKIP+1)) +} + +ktap_test_xfail() { + description="$1" + + result="ok" + directive="XFAIL" + __ktap_test "$result" "$description" "$directive" + + KTAP_CNT_XFAIL=$((KTAP_CNT_XFAIL+1)) +} + +ktap_test_fail() { + description="$1" + + result="not ok" + __ktap_test "$result" "$description" + + KTAP_CNT_FAIL=$((KTAP_CNT_FAIL+1)) +} + +ktap_test_result() { + description="$1" + shift + + if $@; then + ktap_test_pass "$description" + else + ktap_test_fail "$description" + fi +} + +ktap_exit_fail_msg() { + echo "Bail out! " $@ + ktap_print_totals + + exit "$KSFT_FAIL" +} + +ktap_finished() { + ktap_print_totals + + if [ $((KTAP_CNT_PASS + KTAP_CNT_SKIP + KTAP_CNT_XFAIL)) -eq "$KSFT_NUM_TESTS" ]; then + exit "$KSFT_PASS" + else + exit "$KSFT_FAIL" + fi +} + +ktap_print_totals() { + if [ "$KTAP_CNT_SKIP" -gt 0 ]; then + echo "# $KTAP_CNT_SKIP skipped test(s) detected. " \ + "Consider enabling relevant config options to improve coverage." + fi + echo "# Totals: pass:$KTAP_CNT_PASS fail:$KTAP_CNT_FAIL xfail:$KTAP_CNT_XFAIL xpass:0 skip:$KTAP_CNT_SKIP error:0" +} diff --git a/tools/testing/selftests/kselftest/module.sh b/tools/testing/selftests/kselftest/module.sh new file mode 100755 index 000000000..51fb65159 --- /dev/null +++ b/tools/testing/selftests/kselftest/module.sh @@ -0,0 +1,84 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0+ + +# +# Runs an individual test module. +# +# kselftest expects a separate executable for each test, this can be +# created by adding a script like this: +# +# #!/bin/sh +# SPDX-License-Identifier: GPL-2.0+ +# $(dirname $0)/../kselftest/module.sh "description" module_name +# +# Example: tools/testing/selftests/lib/bitmap.sh + +desc="" # Output prefix. +module="" # Filename (without the .ko). +args="" # modprobe arguments. + +modprobe="/sbin/modprobe" + +main() { + parse_args "$@" + assert_root + assert_have_module + run_module +} + +parse_args() { + script=${0##*/} + + if [ $# -lt 2 ]; then + echo "Usage: $script <description> <module_name> [FAIL]" + exit 1 + fi + + desc="$1" + shift || true + module="$1" + shift || true + args="$@" +} + +assert_root() { + if [ ! -w /dev ]; then + skip "please run as root" + fi +} + +assert_have_module() { + if ! $modprobe -q -n $module; then + skip "module $module is not found" + fi +} + +run_module() { + if $modprobe -q $module $args; then + $modprobe -q -r $module + say "ok" + else + fail "" + fi +} + +say() { + echo "$desc: $1" +} + + +fail() { + say "$1 [FAIL]" >&2 + exit 1 +} + +skip() { + say "$1 [SKIP]" >&2 + # Kselftest framework requirement - SKIP code is 4. + exit 4 +} + +# +# Main script +# +main "$@" diff --git a/tools/testing/selftests/kselftest/prefix.pl b/tools/testing/selftests/kselftest/prefix.pl new file mode 100755 index 000000000..12a7f4ca2 --- /dev/null +++ b/tools/testing/selftests/kselftest/prefix.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +# SPDX-License-Identifier: GPL-2.0 +# Prefix all lines with "# ", unbuffered. Command being piped in may need +# to have unbuffering forced with "stdbuf -i0 -o0 -e0 $cmd". +use strict; +use IO::Handle; + +binmode STDIN; +binmode STDOUT; + +STDOUT->autoflush(1); + +my $needed = 1; +while (1) { + my $char; + my $bytes = sysread(STDIN, $char, 1); + exit 0 if ($bytes == 0); + if ($needed) { + print "# "; + $needed = 0; + } + print $char; + $needed = 1 if ($char eq "\n"); +} diff --git a/tools/testing/selftests/kselftest/runner.sh b/tools/testing/selftests/kselftest/runner.sh new file mode 100644 index 000000000..311811dc5 --- /dev/null +++ b/tools/testing/selftests/kselftest/runner.sh @@ -0,0 +1,228 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Runs a set of tests in a given subdirectory. + +# There isn't a shell-agnostic way to find the path of a sourced file, +# so we must rely on BASE_DIR being set to find other tools. +if [ -z "$BASE_DIR" ]; then + echo "Error: BASE_DIR must be set before sourcing." >&2 + exit 1 +fi + +. ${BASE_DIR}/kselftest/ktap_helpers.sh + +export timeout_rc=124 +export logfile=/dev/stdout +export per_test_logging= +export per_test_log_dir=/tmp +export RUN_IN_NETNS= + +# Defaults for "settings" file fields: +# "timeout" how many seconds to let each test run before running +# over our soft timeout limit. +export kselftest_default_timeout=45 + +TR_CMD=$(command -v tr) + +# If Perl is unavailable, we must fall back to line-at-a-time prefixing +# with sed instead of unbuffered output. +tap_prefix() +{ + if [ ! -x /usr/bin/perl ]; then + sed -e 's/^/# /' + else + "$BASE_DIR"/kselftest/prefix.pl + fi +} + +tap_timeout() +{ + # Make sure tests will time out if utility is available. + if [ -x /usr/bin/timeout ] ; then + /usr/bin/timeout --foreground "$kselftest_timeout" \ + /usr/bin/timeout "$kselftest_timeout" $1 + else + $1 + fi +} + +run_one() +{ + DIR="$1" + TEST="$2" + + BASENAME_TEST=$(basename $TEST) + + # Reset any "settings"-file variables. + export kselftest_timeout="$kselftest_default_timeout" + + # Safe default if tr not available + kselftest_cmd_args_ref="KSELFTEST_ARGS" + + # Optional arguments for this command, possibly defined as an + # environment variable built using the test executable in all + # uppercase and sanitized substituting non acceptable shell + # variable name characters with "_" as in: + # + # KSELFTEST_<UPPERCASE_SANITIZED_TESTNAME>_ARGS="<options>" + # + # e.g. + # + # rtctest --> KSELFTEST_RTCTEST_ARGS="/dev/rtc1" + # + # cpu-on-off-test.sh --> KSELFTEST_CPU_ON_OFF_TEST_SH_ARGS="-a -p 10" + # + if [ -n "$TR_CMD" ]; then + BASENAME_SANITIZED=$(echo "$BASENAME_TEST" | \ + $TR_CMD -d "[:blank:][:cntrl:]" | \ + $TR_CMD -c "[:alnum:]_" "_" | \ + $TR_CMD [:lower:] [:upper:]) + kselftest_cmd_args_ref="KSELFTEST_${BASENAME_SANITIZED}_ARGS" + fi + + # Load per-test-directory kselftest "settings" file. + settings="$BASE_DIR/$DIR/settings" + if [ -r "$settings" ] ; then + while read line ; do + # Skip comments. + if echo "$line" | grep -q '^#'; then + continue + fi + field=$(echo "$line" | cut -d= -f1) + value=$(echo "$line" | cut -d= -f2-) + eval "kselftest_$field"="$value" + done < "$settings" + fi + + # Command line timeout overrides the settings file + if [ -n "$kselftest_override_timeout" ]; then + kselftest_timeout="$kselftest_override_timeout" + ktap_print_msg "overriding timeout to $kselftest_timeout" >> "$logfile" + else + ktap_print_msg "timeout set to $kselftest_timeout" >> "$logfile" + fi + + TEST_HDR_MSG="selftests: $DIR: $BASENAME_TEST" + echo "# $TEST_HDR_MSG" + if [ ! -e "$TEST" ]; then + ktap_print_msg "Warning: file $TEST is missing!" + ktap_test_fail "$TEST_HDR_MSG" + rc=$KSFT_FAIL + else + if [ -x /usr/bin/stdbuf ]; then + stdbuf="/usr/bin/stdbuf --output=L " + fi + eval kselftest_cmd_args="\$${kselftest_cmd_args_ref:-}" + if [ -x "$TEST" ]; then + cmd="$stdbuf ./$BASENAME_TEST $kselftest_cmd_args" + elif [ -x "./ksft_runner.sh" ]; then + cmd="$stdbuf ./ksft_runner.sh ./$BASENAME_TEST" + else + ktap_print_msg "Warning: file $TEST is not executable" + + if [ $(head -n 1 "$TEST" | cut -c -2) = "#!" ] + then + interpreter=$(head -n 1 "$TEST" | cut -c 3-) + cmd="$stdbuf $interpreter ./$BASENAME_TEST" + else + ktap_test_fail "$TEST_HDR_MSG" + return $KSFT_FAIL + fi + fi + cd `dirname $TEST` > /dev/null + (((( tap_timeout "$cmd" 2>&1; echo $? >&3) | + tap_prefix >&4) 3>&1) | + (read xs; exit $xs)) 4>>"$logfile" + rc=$? + case "$rc" in + "$KSFT_PASS") + ktap_test_pass "$TEST_HDR_MSG";; + "$KSFT_SKIP") + ktap_test_skip "$TEST_HDR_MSG";; + "$KSFT_XFAIL") + ktap_test_xfail "$TEST_HDR_MSG";; + "$timeout_rc") + ktap_test_fail "$TEST_HDR_MSG # TIMEOUT $kselftest_timeout seconds";; + *) + ktap_test_fail "$TEST_HDR_MSG # exit=$rc";; + esac + cd - >/dev/null + fi + + return $rc +} + +in_netns() +{ + local name=$1 + ip netns exec $name bash <<-EOF + BASE_DIR=$BASE_DIR + source $BASE_DIR/kselftest/runner.sh + logfile=$logfile + run_one $DIR $TEST + EOF +} + +run_in_netns() +{ + local tmplog="/tmp/$(mktemp -u ${BASENAME_TEST}-XXXXXX)" + local netns=$(mktemp -u ${BASENAME_TEST}-XXXXXX) + local rc + + ip netns add $netns + if [ $? -ne 0 ]; then + ktap_print_msg "Warning: Create namespace failed for $BASENAME_TEST" + ktap_test_fail "selftests: $DIR: $BASENAME_TEST # Create NS failed" + fi + ip -n $netns link set lo up + + in_netns $netns &> $tmplog + rc=$? + + ip netns del $netns &> /dev/null + # Cat the log at once to avoid parallel netns logs. + cat $tmplog + rm -f $tmplog + return $rc +} + +run_many() +{ + DIR="${PWD#${BASE_DIR}/}" + local rc + pids= + + for TEST in "$@"; do + BASENAME_TEST=$(basename $TEST) + if [ -n "$per_test_logging" ]; then + logfile="$per_test_log_dir/$BASENAME_TEST" + cat /dev/null > "$logfile" + fi + if [ -n "$RUN_IN_NETNS" ]; then + run_in_netns & + pids="$pids $!" + else + run_one "$DIR" "$TEST" + fi + done + + # These variables are outputs of ktap_helpers.sh but since we've + # run the test in a subprocess we need to update them manually + for pid in $pids; do + wait "$pid" + rc=$? + case "$rc" in + "$KSFT_PASS") + KTAP_CNT_PASS=$((KTAP_CNT_PASS + 1));; + "$KSFT_FAIL") + KTAP_CNT_FAIL=$((KTAP_CNT_FAIL + 1));; + "$KSFT_SKIP") + KTAP_CNT_SKIP=$((KTAP_CNT_SKIP + 1));; + "$KSFT_XFAIL") + KTAP_CNT_XFAIL=$((KTAP_CNT_XFAIL + 1));; + *) + KTAP_CNT_FAIL=$((KTAP_CNT_FAIL + 1));; + esac + done +} |
