]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Rework qemu device support checks
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 17 Oct 2023 20:42:20 +0000 (22:42 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 18 Oct 2023 08:15:43 +0000 (10:15 +0200)
Let's implement an available() method on the QemuDeviceNode enum
and move the checks from load_config() to run_qemu() so they don't
impede showing the summary or other verbs.

Let's also prefer using the file descriptor as a check whether the
feature is available in run_qemu() instead of calling the available()
method, as by the time we get to run_qemu() the available() method
might return a different result.

mkosi/__init__.py
mkosi/config.py
mkosi/qemu.py
mkosi/util.py

index ec9275a524f00394d30b720c141844f7b6e2a41b..29b2ca5edbcc06bb3eb29b8ed51bc8244796ae3f 100644 (file)
@@ -2502,9 +2502,9 @@ def run_verb(args: MkosiArgs, presets: Sequence[MkosiConfig]) -> None:
     # file descriptors to qemu later. Note that we can't pass the kvm file descriptor to qemu until
     # https://gitlab.com/qemu-project/qemu/-/issues/1936 is resolved.
     qemu_device_fds = {
-        d: os.open(f"/dev/{d}", os.O_RDWR|os.O_CLOEXEC|os.O_NONBLOCK)
+        d: os.open(d.device(), os.O_RDWR|os.O_CLOEXEC|os.O_NONBLOCK)
         for d in QemuDeviceNode
-        if os.access(f"/dev/{d}", os.F_OK|os.R_OK|os.W_OK)
+        if d.available(log=True)
     }
 
     # Get the user UID/GID either on the host or in the user namespace running the build
index 749d176b9f29f3424e22db10a1bd77b3ec11c22d..33066bc8feab433c0320b5e2cd9ad06f59c29940 100644 (file)
@@ -33,14 +33,7 @@ from mkosi.log import ARG_DEBUG, ARG_DEBUG_SHELL, Style, die
 from mkosi.pager import page
 from mkosi.run import run
 from mkosi.types import PathString, SupportsRead
-from mkosi.util import (
-    INVOKING_USER,
-    StrEnum,
-    chdir,
-    flatten,
-    qemu_check_kvm_support,
-    qemu_check_vsock_support,
-)
+from mkosi.util import INVOKING_USER, StrEnum, chdir, flatten
 from mkosi.versioncomp import GenericVersion
 
 __version__ = "18"
@@ -2523,12 +2516,6 @@ def load_config(args: argparse.Namespace) -> MkosiConfig:
             die("UEFI SecureBoot enabled, private key was found, but not the certificate.",
                 hint="Consider placing it in mkosi.crt")
 
-    if args.qemu_kvm == ConfigFeature.enabled and not qemu_check_kvm_support(log=False):
-        die("Sorry, the host machine does not support KVM acceleration.")
-
-    if args.qemu_vsock == ConfigFeature.enabled and not qemu_check_vsock_support(log=False):
-        die("Sorry, the host machine does not support vsock")
-
     if args.repositories and not (
         args.distribution.is_dnf_distribution() or
         args.distribution.is_apt_distribution() or
index 51d21ec9f26a4c151503a8e31f208cdd0f7d8f74..9b7e3a43222c808a66ce94cb93b9eddae5027cc0 100644 (file)
@@ -30,17 +30,38 @@ from mkosi.partition import finalize_root, find_partitions
 from mkosi.run import MkosiAsyncioThread, run, spawn
 from mkosi.tree import copy_tree, rmtree
 from mkosi.types import PathString
-from mkosi.util import (
-    INVOKING_USER,
-    StrEnum,
-    qemu_check_kvm_support,
-    qemu_check_vsock_support,
-)
+from mkosi.util import INVOKING_USER, StrEnum
 
 
 class QemuDeviceNode(StrEnum):
+    kvm = enum.auto()
     vhost_vsock = enum.auto()
 
+    def device(self) -> Path:
+        return Path("/dev") / str(self)
+
+    def description(self) -> str:
+        return {
+            QemuDeviceNode.kvm: "KVM acceleration",
+            QemuDeviceNode.vhost_vsock: "a VSock device",
+        }[self]
+
+    def available(self, log: bool = False) -> bool:
+        if not os.access(self.device(), os.F_OK):
+            if log:
+                logging.warning(f"{self.device()} not found. Not adding {self.description()} to the virtual machine.")
+            return False
+
+        if not os.access(self.device(), os.R_OK|os.W_OK):
+            if log:
+                logging.warning(
+                    f"Permission denied to access {self.device()}. "
+                    f"Not adding {self.description()} to the virtual machine."
+                )
+            return False
+
+        return True
+
 
 def machine_cid(config: MkosiConfig) -> int:
     cid = int.from_bytes(hashlib.sha256(config.output_with_version.encode()).digest()[:4], byteorder='little')
@@ -316,11 +337,17 @@ def run_qemu(args: MkosiArgs, config: MkosiConfig, qemu_device_fds: Mapping[Qemu
     if (config.runtime_trees and config.qemu_firmware == QemuFirmware.bios):
         die("RuntimeTrees= cannot be used when booting in BIOS firmware")
 
+    if config.qemu_kvm == ConfigFeature.enabled and not QemuDeviceNode.kvm.available():
+        die("KVM acceleration requested but cannot access /dev/kvm")
+
+    if config.qemu_vsock == ConfigFeature.enabled and QemuDeviceNode.vhost_vsock not in qemu_device_fds:
+        die("VSock requested but cannot access /dev/vhost-vsock")
+
     accel = "tcg"
     auto = (
         config.qemu_kvm == ConfigFeature.auto and
         config.architecture.is_native() and
-        qemu_check_kvm_support(log=True)
+        QemuDeviceNode.kvm.available()
     )
     if config.qemu_kvm == ConfigFeature.enabled or auto:
         accel = "kvm"
@@ -359,9 +386,7 @@ def run_qemu(args: MkosiArgs, config: MkosiConfig, qemu_device_fds: Mapping[Qemu
         *shm,
     ]
 
-    use_vsock = (config.qemu_vsock == ConfigFeature.enabled or
-                (config.qemu_vsock == ConfigFeature.auto and qemu_check_vsock_support(log=True)))
-    if use_vsock:
+    if QemuDeviceNode.vhost_vsock in qemu_device_fds:
         cmdline += [
             "-device",
             f"vhost-vsock-pci,guest-cid={machine_cid(config)},vhostfd={qemu_device_fds[QemuDeviceNode.vhost_vsock]}"
@@ -531,7 +556,7 @@ def run_qemu(args: MkosiArgs, config: MkosiConfig, qemu_device_fds: Mapping[Qemu
             elif config.architecture == Architecture.arm64:
                 cmdline += ["-device", "tpm-tis-device,tpmdev=tpm0"]
 
-        if use_vsock and config.architecture.supports_smbios():
+        if QemuDeviceNode.vhost_vsock in qemu_device_fds and config.architecture.supports_smbios():
             addr, notifications = stack.enter_context(vsock_notify_handler())
             cmdline += ["-smbios", f"type=11,value=io.systemd.credential:vmm.notify_socket={addr}"]
 
index a896e439a2a1c6d142b7422c5fa486f09237ed4d..050f67dcc1da2206c1a6e8723643c047571433cf 100644 (file)
@@ -101,39 +101,6 @@ def chdir(directory: PathString) -> Iterator[None]:
         os.chdir(old)
 
 
-def qemu_check_kvm_support(log: bool) -> bool:
-    # some CI runners may present a non-working KVM device
-
-    if not os.access("/dev/kvm", os.F_OK):
-        if log:
-            logging.warning("/dev/kvm not found. Not using KVM acceleration.")
-        return False
-
-    if not os.access("/dev/kvm", os.R_OK|os.W_OK):
-        if log:
-            logging.warning("Permission denied to access /dev/kvm. Not using KVM acceleration")
-        return False
-
-    return True
-
-
-def qemu_check_vsock_support(log: bool) -> bool:
-    if not os.access("/dev/vhost-vsock", os.F_OK):
-        if log:
-            logging.warning("/dev/vhost-vsock not found. Not adding a vsock device to the virtual machine.")
-        return False
-
-    if not os.access("/dev/vhost-vsock", os.R_OK|os.W_OK):
-        if log:
-            logging.warning(
-                "Permission denied to access /dev/vhost-vsock. "
-                "Not adding a vsock device to the virtual machine."
-            )
-        return False
-
-    return True
-
-
 def make_executable(path: Path) -> None:
     st = path.stat()
     os.chmod(path, st.st_mode | stat.S_IEXEC)