]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
test: cover lingering users surviving a soft-reboot in TEST-82
authorRocker Zhang <zhang.rocker.liyuan@gmail.com>
Thu, 21 May 2026 10:29:24 +0000 (18:29 +0800)
committerLuca Boccassi <luca.boccassi@gmail.com>
Thu, 21 May 2026 15:02:43 +0000 (16:02 +0100)
Regression coverage for the soft-reboot linger bug fixed in
9f25feb4ed18 ("logind: keep lingering users at startup-time GC", #41789):
a lingering user's user@.service was started after a hardware reboot but
not after `systemctl soft-reboot`, because logind GC'd the user at
startup before user_start() ran.

On the first boot, enable lingering for the pre-existing testuser and
wait for its user@UID.service to come up. After the first soft-reboot
(which keeps the same persistent rootfs), assert the service is active
again — this is the regression check. Disable lingering again before the
nextroot switch in the second boot so the lingering user doesn't leak
into the later boots' minimal overlay rootfs.

Verified locally in a qemu/KVM VM: passes with the fix present, and with
the fix reverted the second-boot assertion times out (the lingering user
is GC'd in logind startup and user@UID.service never comes back),
confirming the test exercises the bug.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
test/units/TEST-82-SOFTREBOOT.sh

index 03f6b78e57fb1d6946144d3cd1acd8dbc93895e2..778bdbd7f8dc4bf1f30579a212273282cb4ac5fd 100755 (executable)
@@ -190,6 +190,17 @@ elif [ -f /run/TEST-82-SOFTREBOOT.touch ]; then
     test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive-sigterm.service)" != "active"
     test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive.service)" != "active"
 
+    # Regression test for #41789: the lingering user enabled on the first boot must
+    # have its user@.service started again after the soft reboot. Before the fix it
+    # was GC'd at logind startup and never restarted. Disable lingering again here,
+    # before the nextroot switch below (the third boot runs on a minimal overlay
+    # rootfs that does not have this user). terminate-user is best-effort: it can
+    # race the asynchronous disable-linger/UserStopDelaySec teardown.
+    linger_uid=$(id -u testuser)
+    timeout 30 bash -c "until systemctl is-active --quiet user@${linger_uid}.service; do sleep 1; done"
+    loginctl disable-linger testuser
+    loginctl terminate-user testuser || true
+
     # This time we test the /run/nextroot/ root switching logic. (We synthesize a new rootfs from the old via overlayfs)
     mkdir -p /run/nextroot /tmp/nextroot-lower /original-root
     mount -t tmpfs tmpfs /tmp/nextroot-lower
@@ -313,6 +324,18 @@ EOF
         systemd-run --wait false || true
     done
 
+    # Regression test for #41789: a lingering user's user@.service must come back
+    # after a soft reboot, the same way it does after a hardware reboot. It used
+    # to be garbage-collected at logind startup (before user_start() ran), because
+    # /run/systemd/users is preserved across soft-reboot and fed the user into the
+    # GC queue while its units were not active yet. Enable lingering for the
+    # pre-existing testuser here; the second boot asserts the service is active
+    # again. testuser lives in the persistent rootfs, so it survives the
+    # (non-nextroot) soft reboot into the second boot.
+    loginctl enable-linger testuser
+    linger_uid=$(id -u testuser)
+    timeout 30 bash -c "until systemctl is-active --quiet user@${linger_uid}.service; do sleep 1; done"
+
     trigger_uevent
 
     # Now issue the soft reboot. We should be right back soon.