From fc0bd373ef3bd1681f135451648297c6b3189019 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Tue, 19 May 2026 22:00:58 +0100 Subject: [PATCH 1/2] test: fix race in TEST-07-PID1.socket-on-failure.sh The test waited for the OnFailure= service's filesystem side effect (`rmdir` of the directory) and then immediately invoked `systemctl is-active`. Between `rmdir(2)` returning (which causes the shell loop to exit) and PID1 reaping the child and transitioning the oneshot service from `activating` to `active`, there is a small window where `is-active` can observe `activating` and fail the test. Wait directly on the unit state instead, matching the pattern used a few lines above for the `is-failed` case. [ 1880.326704] TEST-07-PID1.sh[21489]: + timeout --foreground 60 bash -c 'while [[ -d '\''/tmp/TEST-07-PID1-socket-8467/test'\'' ]]; do sleep .5; done' [ 1880.330482] TEST-07-PID1.sh[21489]: + [[ ! -e /tmp/TEST-07-PID1-socket-8467/test ]] [ 1880.330482] TEST-07-PID1.sh[21489]: + systemctl is-active TEST-07-PID1-socket-OnFailure.service [ 1880.347470] TEST-07-PID1.sh[21520]: activating [ 1880.349508] TEST-07-PID1.sh[21489]: + at_exit [ 1880.349508] TEST-07-PID1.sh[21489]: + systemctl stop TEST-07-PID1-socket-8467.socket [ 1880.367331] TEST-07-PID1.sh[107]: Subtest /usr/lib/systemd/tests/testdata/units/TEST-07-PID1.socket-on-failure.sh failed [ 1880.367331] TEST-07-PID1.sh[107]: + return 1 Co-developed-by: Claude Opus 4.7 --- test/units/TEST-07-PID1.socket-on-failure.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/units/TEST-07-PID1.socket-on-failure.sh b/test/units/TEST-07-PID1.socket-on-failure.sh index 44b8a43634f..ff947b10e26 100755 --- a/test/units/TEST-07-PID1.socket-on-failure.sh +++ b/test/units/TEST-07-PID1.socket-on-failure.sh @@ -65,9 +65,8 @@ mkdir "/tmp/$UNIT_NAME/test" systemctl is-failed "$UNIT_NAME.socket" assert_eq "$(systemctl show "$UNIT_NAME.socket" -P SubState)" "failed" -timeout --foreground 60 bash -c "while [[ -d '/tmp/$UNIT_NAME/test' ]]; do sleep .5; done" +timeout --foreground 60 bash -c "until systemctl is-active TEST-07-PID1-socket-OnFailure.service; do sleep .5; done" [[ ! -e "/tmp/$UNIT_NAME/test" ]] -systemctl is-active TEST-07-PID1-socket-OnFailure.service systemctl start "$UNIT_NAME.socket" systemctl is-active "$UNIT_NAME.socket" From 4ac23697280bf54bb768f0aa7a5c7d7d0bcf3f6b Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Tue, 19 May 2026 22:42:25 +0100 Subject: [PATCH 2/2] test: switch TEST-55-OOMD stress-ng --vm-method to lfsr32 Commit 881e4717c7 ("test: pin stress-ng --vm-method to a portable scalar method in TEST-55-OOMD") pinned --vm-method=zero-one with the rationale that it is "a long-standing scalar method". That rationale is wrong: stress_vm_zero_one() in stress-ng's stress-vm.c is declared static size_t TARGET_CLONES stress_vm_zero_one(...) i.e. it carries the exact same TARGET_CLONES attribute as 33 of the 35 other vm methods. On x86_64 with GCC >=5, TARGET_CLONES expands (see core-target-clones.h in stress-ng) to a target_clones attribute including "arch=skylake-avx512", "arch=cooperlake", "arch=tigerlake", "arch=sapphirerapids", and several other AVX-512-bearing arch variants, plus "default". GCC generates AVX-512 clones of stress_vm_zero_one() and the IFUNC resolver picks them on any CPU that advertises AVX-512. The only vm methods in stress-ng's registry whose function definitions omit TARGET_CLONES entirely (and are therefore guaranteed not to dispatch to an AVX-512 clone) are lfsr32 (portable, always registered) and write64ds (x86_64-only, gated on HAVE_ASM_X86_MOVDIRI, i.e. Intel Tremont / Tiger Lake+ MOVDIRI instruction). Switch the four stress-ng --vm invocations in TEST-55-OOMD to --vm-method=lfsr32 so the AVX-512 SIGILL on CPUs without AVX-512 (e.g. AMD Zen 1-3) can no longer occur regardless of compiler version, optimization level, or stress-ng package build. Follow-up for 881e4717c7981b274853309e68b39153e3b292f4 Co-developed-by: Claude Opus 4.7 --- .../TEST-55-OOMD-testbloat.service | 7 +++---- .../TEST-55-OOMD-testmunch.service | 7 +++---- test/units/TEST-55-OOMD.sh | 15 ++++++--------- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/test/integration-tests/TEST-55-OOMD/TEST-55-OOMD.units/TEST-55-OOMD-testbloat.service b/test/integration-tests/TEST-55-OOMD/TEST-55-OOMD.units/TEST-55-OOMD-testbloat.service index 22bbd210e96..e4109fd60dd 100644 --- a/test/integration-tests/TEST-55-OOMD/TEST-55-OOMD.units/TEST-55-OOMD-testbloat.service +++ b/test/integration-tests/TEST-55-OOMD/TEST-55-OOMD.units/TEST-55-OOMD-testbloat.service @@ -7,7 +7,6 @@ Description=Create a lot of memory pressure # to throttle and be put under heavy pressure. MemoryHigh=3M Slice=TEST-55-OOMD-workload.slice -# Pin --vm-method to a portable method (zero-one): the default 'all' cycles -# through methods, including newer ones using AVX-512 instructions that SIGILL -# on CPUs without AVX-512 (e.g. AMD Zen 1-3), making the test flaky. -ExecStart=stress-ng --timeout 3m --vm 10 --vm-bytes 200M --vm-keep --vm-method=zero-one +# Pin --vm-method=lfsr32: the only stress-ng vm method without TARGET_CLONES, +# so it can't dispatch to an AVX-512 clone and SIGILL on CPUs lacking it. +ExecStart=stress-ng --timeout 3m --vm 10 --vm-bytes 200M --vm-keep --vm-method=lfsr32 diff --git a/test/integration-tests/TEST-55-OOMD/TEST-55-OOMD.units/TEST-55-OOMD-testmunch.service b/test/integration-tests/TEST-55-OOMD/TEST-55-OOMD.units/TEST-55-OOMD-testmunch.service index 06eea10b79a..81305c7e974 100644 --- a/test/integration-tests/TEST-55-OOMD/TEST-55-OOMD.units/TEST-55-OOMD-testmunch.service +++ b/test/integration-tests/TEST-55-OOMD/TEST-55-OOMD.units/TEST-55-OOMD-testmunch.service @@ -5,7 +5,6 @@ Description=Create some memory pressure [Service] MemoryHigh=12M Slice=TEST-55-OOMD-workload.slice -# Pin --vm-method to a portable method (zero-one): the default 'all' cycles -# through methods, including newer ones using AVX-512 instructions that SIGILL -# on CPUs without AVX-512 (e.g. AMD Zen 1-3), making the test flaky. -ExecStart=stress-ng --timeout 3m --vm 10 --vm-bytes 200M --vm-keep --vm-method=zero-one +# Pin --vm-method=lfsr32: the only stress-ng vm method without TARGET_CLONES, +# so it can't dispatch to an AVX-512 clone and SIGILL on CPUs lacking it. +ExecStart=stress-ng --timeout 3m --vm 10 --vm-bytes 200M --vm-keep --vm-method=lfsr32 diff --git a/test/units/TEST-55-OOMD.sh b/test/units/TEST-55-OOMD.sh index b7311e83dca..84baee12a42 100755 --- a/test/units/TEST-55-OOMD.sh +++ b/test/units/TEST-55-OOMD.sh @@ -366,13 +366,12 @@ EOF systemctl reload systemd-oomd.service # Run a transient service with OOMRules=testrule that generates memory pressure. - # Pin --vm-method to a portable method (zero-one): the default 'all' cycles - # through every method, including newer ones using AVX-512 instructions that - # SIGILL on CPUs without AVX-512 (e.g. AMD Zen 1-3), making the test flaky. + # Pin --vm-method=lfsr32: the only stress-ng vm method without TARGET_CLONES, + # so it can't dispatch to an AVX-512 clone and SIGILL on CPUs lacking it. (! systemd-run --wait --unit=TEST-55-OOMD-testrules \ -p MemoryHigh=3M \ -p OOMRules=testrule \ - stress-ng --timeout 3m --vm 10 --vm-bytes 50M --vm-keep --vm-method=zero-one) + stress-ng --timeout 3m --vm 10 --vm-bytes 50M --vm-keep --vm-method=lfsr32) # Verify in the journal that the rule triggered journalctl --sync @@ -457,14 +456,12 @@ EOF # Start the unit without --wait so we can check mid-run state. The # stress-ng timeout bounds the test if anything goes wrong. - # Pin --vm-method to a portable method (zero-one): the default 'all' cycles - # through every method, including newer ones using AVX-512 instructions that - # SIGILL on CPUs without AVX-512 (e.g. AMD Zen 1-3) and would cause stress-ng - # to exit before the 6 s wait below elapses, failing the ActiveState check. + # Pin --vm-method=lfsr32: the only stress-ng vm method without TARGET_CLONES, + # so it can't SIGILL on AVX-512-less CPUs and exit before the 6 s wait below. systemd-run --unit=TEST-55-OOMD-slowrule \ -p MemoryHigh=3M \ -p OOMRules=slowrule \ - stress-ng --timeout 15s --vm 10 --vm-bytes 50M --vm-keep --vm-method=zero-one + stress-ng --timeout 15s --vm 10 --vm-bytes 50M --vm-keep --vm-method=lfsr32 # Wait long enough for oomd's 1s rule-check loop to evaluate the condition # many times. With LastingSec=1h the kill must not fire.