Skip to content

Commit

Permalink
qemu: wait for process to be in scope before registering with machined
Browse files Browse the repository at this point in the history
Otherwise if we are unlucky with the timing and the process is added to
the scope after the register request is processed, machined will register
as the unit the user session scope, and it will kill it once the machine
goes away, breaking the testbed/user session.

root@host:~# cat /run/systemd/machines/TEST-64-UDEV-STORAGE-long-sysfs-path-1
NAME=TEST-64-UDEV-STORAGE-long-sysfs-path-1
SCOPE=session-2.scope
SERVICE=mkosi
LEADER=23160
CLASS=vm
REALTIME=1734823438361409
MONOTONIC=11697737480

[  340.373454] systemd-machined[21797]: Got message type=method_return sender=org.freedesktop.DBus destination=:1.13 path=n/a interface=n/a member=n/a  cookie=12 reply_cookie=22 signature=u error-name=n/a error>
[  340.373533] systemd-machined[21797]: Sent message type=error sender=n/a destination=:1.24 path=n/a interface=n/a member=n/a cookie=23 reply_cookie=2 signature=s error-name=org.freedesktop.DBus.Error.FileExis>
[  340.373537] systemd-machined[21797]: Failed to process message type=method_call sender=:1.24 destination=org.freedesktop.machine1 path=/org/freedesktop/machine1 interface=org.freedesktop.machine1.Manager mem>
[  340.373657] busctl[21800]: ‣ Type=method_call  Endian=l  Flags=0  Version=1 Cookie=24  Timestamp="Sat 2024-12-21 20:14:40.997553 UTC"
[  340.373657] busctl[21800]:   Sender=:1.13  Destination=org.freedesktop.systemd1  Path=/org/freedesktop/systemd1  Interface=org.freedesktop.systemd1.Manager  Member=StopUnit
[  340.373657] busctl[21800]:   UniqueName=:1.13
[  340.373657] busctl[21800]:   MESSAGE "ss" {
[  340.373657] busctl[21800]:           STRING "session-c1.scope";
[  340.373657] busctl[21800]:           STRING "fail";
[  340.373657] busctl[21800]:   };
[  340.373551] systemd-machined[21797]: Sent message type=method_call sender=n/a destination=org.freedesktop.systemd1 path=/org/freedesktop/systemd1 interface=org.freedesktop.systemd1.Manager member=StopUnit co>
[  340.380081] systemd[1]: mkosi-TEST-64-UDEV-STORAGE-long-sysfs-path-1.scope: 1 process added to scope's control group.
  • Loading branch information
bluca committed Dec 22, 2024
1 parent 9bc33ad commit 2a009ad
Showing 1 changed file with 27 additions and 2 deletions.
29 changes: 27 additions & 2 deletions mkosi/qemu.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import sys
import tempfile
import textwrap
import time
import uuid
from collections.abc import Iterator, Sequence
from pathlib import Path
Expand Down Expand Up @@ -917,12 +918,36 @@ def scope_cmd(
] # fmt: skip


def register_machine(config: Config, pid: int, fname: Path) -> None:
def register_machine(config: Config, pid: int, fname: Path, unit: str) -> None:
if os.getuid() != 0 or (
"DBUS_SYSTEM_ADDRESS" not in os.environ and not Path("/run/dbus/system_bus_socket").exists()
):
return

# Wait for the scope unit to be actually active before registering the machine with systemd,
# otherwise the process will still be in the session scope of the caller, and if it fails
# machined will stop the session.
for i in range(300):
if str(pid) in run(
[
"busctl",
"call",
"org.freedesktop.systemd1",
f"/org/freedesktop/systemd1/unit/{unit.replace("-", "_2d").replace(".", "_2e")}_2escope",
"org.freedesktop.systemd1.Scope",
"GetProcesses",
], # fmt: skip
foreground=False,
env=os.environ | config.environment,
sandbox=config.sandbox(relaxed=True),
stdout=subprocess.PIPE,
).stdout.strip():
break

time.sleep(0.1)
else:
die(f"systemd-run scope unit {unit}.scope did not become active within 30 seconds")

run(
[
"busctl",
Expand Down Expand Up @@ -1415,7 +1440,7 @@ def add_virtiofs_mount(
for fd in qemu_device_fds.values():
os.close(fd)

register_machine(config, proc.pid, fname)
register_machine(config, proc.pid, fname, name)

if status := int(notifications.get("EXIT_STATUS", 0)):
raise subprocess.CalledProcessError(status, cmdline)
Expand Down

0 comments on commit 2a009ad

Please sign in to comment.