From: Daan De Meyer Date: Tue, 17 Oct 2023 20:42:20 +0000 (+0200) Subject: Rework qemu device support checks X-Git-Tag: v19~74 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6d3febf6a8f0bfdc4fd119f912749d8cb3c40fce;p=thirdparty%2Fmkosi.git Rework qemu device support checks 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. --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index ec9275a52..29b2ca5ed 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -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 diff --git a/mkosi/config.py b/mkosi/config.py index 749d176b9..33066bc8f 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -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 diff --git a/mkosi/qemu.py b/mkosi/qemu.py index 51d21ec9f..9b7e3a432 100644 --- a/mkosi/qemu.py +++ b/mkosi/qemu.py @@ -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}"] diff --git a/mkosi/util.py b/mkosi/util.py index a896e439a..050f67dcc 100644 --- a/mkosi/util.py +++ b/mkosi/util.py @@ -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)