From d1697c4ff8ce4581ccb9db2169477ec59bfc6689 Mon Sep 17 00:00:00 2001 From: Konstantin Shkolnyy Date: Tue, 23 Jun 2026 15:16:42 -0500 Subject: [PATCH] kmod-setup: support early loading for virtio-ccw devices Before this change, the code checked for presence of virtio-pci devices to decide whether transport-agnostic virtio drivers needed to be loaded early. Do it also if virtio-ccw devices are present, that is, devices with the control unit type (CU type) 0x3832, under /sys/devices/css0. (This CU type value is documented in "Virtio Over Channel I/O" virtio specification section.) In other words, extend to virtio-ccw devices the fix previously done for virtio-pci: #40161: commit 356cc4a1c32cee21107174be7a7991602eb861d2 #40503: commit 6d36e5fae618aeadc6b4ff39db6ec2cfa777543f Tested-by: Marc Hartmayer Reviewed-by: Marc Hartmayer --- src/core/kmod-setup.c | 92 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 8 deletions(-) diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c index 7d0d1d9b67..6e606e311e 100644 --- a/src/core/kmod-setup.c +++ b/src/core/kmod-setup.c @@ -15,7 +15,7 @@ #include "virt.h" #if HAVE_KMOD -static int match_modalias_recurse_dir_cb( +static int match_pci_modalias_recurse_dir_cb( RecurseDirEvent event, const char *path, int dir_fd, @@ -49,7 +49,7 @@ static int match_modalias_recurse_dir_cb( return RECURSE_DIR_LEAVE_DIRECTORY; } -static bool has_virtio_feature(const char *name, char **modaliases) { +static bool has_virtio_pci_feature(const char *name, char **modaliases) { int r; /* Directory traversal might be slow, hence let's do a cheap check first if it's even worth it */ @@ -62,25 +62,100 @@ static bool has_virtio_feature(const char *name, char **modaliases) { /* statx_mask= */ 0, /* n_depth_max= */ 3, RECURSE_DIR_ENSURE_TYPE, - match_modalias_recurse_dir_cb, + match_pci_modalias_recurse_dir_cb, modaliases); if (r < 0) - log_debug_errno(r, "Failed to determine whether host has %s device, ignoring: %m", name); + log_debug_errno(r, "Failed to determine whether host has %s PCI device, ignoring: %m", name); return r > 0; } +#if defined(__s390__) || defined(__s390x__) +static int match_ccw_modalias_recurse_dir_cb( + RecurseDirEvent event, + const char *path, + int dir_fd, + int inode_fd, + const struct dirent *de, + const struct statx *sx, + void *userdata) { + + _cleanup_free_ char *alias = NULL; + char **modaliases = ASSERT_PTR(userdata); + int r; + + if (event != RECURSE_DIR_ENTRY) + return RECURSE_DIR_CONTINUE; + + if (de->d_type != DT_REG) + return RECURSE_DIR_CONTINUE; + + if (!streq(de->d_name, "modalias")) + return RECURSE_DIR_CONTINUE; + + /* Unlike PCI's "recurse_dir_cb", upon finding a non-matching modalias, + * we don't abandon the current directory but keep looking for virtio + * devices in subdirectories, by returning RECURSE_DIR_CONTINUE. */ + r = read_one_line_file(path, &alias); + if (r < 0) { + log_debug_errno(r, "Failed to read %s, ignoring: %m", path); + return RECURSE_DIR_CONTINUE; + } + + if (startswith_strv(alias, modaliases)) + return 1; + + return RECURSE_DIR_CONTINUE; +} + +static bool has_virtio_ccw_feature(const char *name, char **modaliases) { + int r; + + /* Directory traversal might be slow, hence let's do a cheap check first if it's even worth it */ + if (detect_vm() == VIRTUALIZATION_NONE) + return false; + + r = recurse_dir_at( + AT_FDCWD, + "/sys/devices/css0", + /* statx_mask= */ 0, + /* n_depth_max= */ 3, + RECURSE_DIR_ENSURE_TYPE, + match_ccw_modalias_recurse_dir_cb, + modaliases); + if (r < 0) + log_debug_errno(r, "Failed to determine whether host has %s CCW device, ignoring: %m", name); + + return r > 0; +} + +static bool has_virtio_ccw(void) { + /* All virtio-ccw devices use the control unit type (CU type) 0x3832 */ + return has_virtio_ccw_feature("virtio-ccw", STRV_MAKE("ccw:t3832")); +} +#else +static bool has_virtio_ccw_feature(const char *name, char **modaliases) { + return false; +} + +static bool has_virtio_ccw(void) { + return false; +} +#endif + static bool has_virtio_rng(void) { - return has_virtio_feature("virtio-rng", STRV_MAKE("pci:v00001AF4d00001005", "pci:v00001AF4d00001044")); + return has_virtio_pci_feature("virtio-rng", STRV_MAKE("pci:v00001AF4d00001005", "pci:v00001AF4d00001044")) || + has_virtio_ccw_feature("virtio-rng", STRV_MAKE("ccw:t3832m04")); } static bool has_virtio_pci(void) { - return has_virtio_feature("virtio-pci", STRV_MAKE("pci:v00001AF4d")); + return has_virtio_pci_feature("virtio-pci", STRV_MAKE("pci:v00001AF4d")); } static bool may_have_virtio(void) { - /* FIXME: strictly speaking, other virtio features, e.g. vsock, are independent of the virtio PCI device. */ - return has_virtio_pci(); + /* FIXME: strictly speaking, other virtio features, e.g. vsock, are independent of the virtio PCI + * or CCW device. */ + return has_virtio_pci() || has_virtio_ccw(); } static bool in_qemu(void) { @@ -139,6 +214,7 @@ int kmod_setup(void) { * resolved and the kernel fix is widely available. */ { "virtiofs", "/sys/module/virtiofs", false, false, may_have_virtio }, { "virtio_pci", "/sys/module/virtio_pci", false, false, has_virtio_pci }, + { "virtio_ccw", "/sys/module/virtio_ccw", false, false, has_virtio_ccw }, /* qemu_fw_cfg would be loaded by udev later, but we want to import credentials from it super early */ { "qemu_fw_cfg", "/sys/firmware/qemu_fw_cfg", false, false, in_qemu },