Re: [OE-core] [PATCH v3 03/11] kernel.bbclass: add kernel-initrd-modules meta package

Mikko Rapeli
2025-04-10T13:01:00Z

Hi,

On Thu, Apr 10, 2025 at 01:42:12PM +0100, Richard Purdie wrote:
> On Fri, 2025-04-04 at 19:29 +0300, Mikko Rapeli via lists.openembedded.org wrote:
> > At the moment linux-yocto kernels for various architectures
> > are not very modular and a lot of drivers are built into the kernel
> > even when they are not needed at runtime. These make the main kernel
> > binary big and slow to boot. This also impacts udev in userspace
> > which takes a long time processing events from all these built in drivers,
> > for example when udev runs in initrd.
> >
> > Then constructing the initrd is very device and kernel configuration specific.
> > initrd image needs explicitly define which binary packages to install
> > to avoid pulling in complex dependencies. A full set of kernel modules
> > via kernel-modules meta package is too big for initrd and most of the
> > drivers are not needed for use cases like "just load modules to mount
> > main rootfs". Then the initrd configuration breaks if kernel driver
> > is built into the kernel since the binary package doesn't exist.
> >
> > Introduce kernel-initrd-modules meta package to solve these problems.
> > The meta package adds dependencies to real kernel modules based on
> > the kernel module file paths so that it will include several
> > kernel subsystems and their drivers which are often needed to find
> > main rootfs from some block device. This works when drivers are built
> > as modules but does not break if drivers are built into the kernel.
> >
> > The resulting initrd is also smaller since only a subset of drivers
> > are needed for "mount the rootfs" usecase. Tested on genericarm64
> > kernel and qemu and AMD KV260 HW.
> >
> > Signed-off-by: Mikko Rapeli <mikko.rapeli@linaro.org>
> > ---
> > ï¿½.../kernel-module-split.bbclassï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ | 48 +++++++++++++++++++
> > ï¿½meta/classes-recipe/kernel.bbclassï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ |ï¿½ 5 +-
> > ï¿½meta/classes-recipe/module.bbclassï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ | 37 ++++++++++++++
> > ï¿½3 files changed, 89 insertions(+), 1 deletion(-)
> >
> > diff --git a/meta/classes-recipe/kernel-module-split.bbclass b/meta/classes-recipe/kernel-module-split.bbclass
> > index 9487365eb7..101c5cd959 100644
> > --- a/meta/classes-recipe/kernel-module-split.bbclass
> > +++ b/meta/classes-recipe/kernel-module-split.bbclass
> > @@ -42,6 +42,40 @@ KERNEL_MODULE_PACKAGE_PREFIX ?= ""
> > ï¿½KERNEL_MODULE_PACKAGE_SUFFIX ?= "-${KERNEL_VERSION}"
> > ï¿½KERNEL_MODULE_PROVIDE_VIRTUAL ?= "1"
> > ï¿½
> > +# subset of kernel modules needed in initrd, to e.g. mount rootfs from block device
> > +KERNEL_INITRD_MODULES_META_PACKAGE ?= "${@ d.getVar("KERNEL_PACKAGE_NAME") or "kernel" }-initrd-modules"
> > +
> > +# match regex to path or file name. E.g. include all drivers with files in path /drivers/ata/
> > +KERNEL_INITRD_MODULES_REGEX ?= "(.*)(\
> > +/drivers/acpi/|\
> > +/drivers/ata/|\
> > +/drivers/block/|\
> > +/drivers/cdrom/|\
> > +/drivers/char/hw_random/|\
> > +/drivers/char/tpm/|\
> > +/drivers/char/|\
> > +/drivers/crypto/|\
> > +/drivers/dax/|\
> > +/drivers/firmware/arm_scmi/|\
> > +/drivers/gpu/drm/|\
> > +/drivers/md/|\
> > +/drivers/mmc/|\
> > +/drivers/mtd/|\
> > +/drivers/nvdimm/|\
> > +/drivers/nvme/|\
> > +/drivers/pci/|\
> > +/drivers/scsi/|\
> > +/drivers/tee/|\
> > +/drivers/tty/serial/|\
> > +/drivers/virtio/|\
> > +/drivers/watchdog/|\
> > +/kernel/arch/|\
> > +/kernel/block/|\
> > +/kernel/crypto/|\
> > +/kernel/fs/|\
> > +/kernel/lib/\
> > +)(.*)"
> > +
> > ï¿½python split_kernel_module_packages () {
> > ï¿½ï¿½ï¿½ï¿½ import re
> > ï¿½
> > @@ -183,6 +217,20 @@ python split_kernel_module_packages () {
> > ï¿½ï¿½ï¿½ï¿½ modules = do_split_packages(d, root='${nonarch_base_libdir}/modules', file_regex=module_regex, output_pattern=module_pattern, description='%s kernel module', postinst=postinst, postrm=postrm, recursive=True, hook=frob_metadata, extra_depends='%s-%s' % (kernel_package_name, kernel_version))
> > ï¿½ï¿½ï¿½ï¿½ if modules:
> > ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ d.appendVar('RDEPENDS:' + metapkg, ' '+' '.join(modules))
> > +
> > +ï¿½ï¿½ï¿½ initrd_metapkg = d.getVar('KERNEL_INITRD_MODULES_META_PACKAGE') or ""
> > +ï¿½ï¿½ï¿½ initrd_module_regex = d.getVar('KERNEL_INITRD_MODULES_REGEX') or ""
> > +ï¿½ï¿½ï¿½ if (initrd_metapkg != "") and (initrd_module_regex != ""):
> > +ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ initrd_module_regex = re.compile(initrd_module_regex)
> > +ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ initrd_modules = []
> > +ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ for module in modules:
> > +ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ files = d.getVar('FILES:' + module)
> > +ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ m = re.match(initrd_module_regex, files)
> > +ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ if m:
> > +ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ initrd_modules.append(module)
> > +
> > +ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ if initrd_modules:
> > +ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ d.appendVar('RDEPENDS:' + initrd_metapkg, ' '+' '.join(initrd_modules))
> > ï¿½}
> > ï¿½
> > ï¿½do_package[vardeps] += '${@" ".join(map(lambda s: "module_conf_" + s, (d.getVar("KERNEL_MODULE_PROBECONF") or "").split()))}'
> > diff --git a/meta/classes-recipe/kernel.bbclass b/meta/classes-recipe/kernel.bbclass
> > index 36ce659762..3dcaebcaed 100644
> > --- a/meta/classes-recipe/kernel.bbclass
> > +++ b/meta/classes-recipe/kernel.bbclass
> > @@ -695,13 +695,14 @@ EXPORT_FUNCTIONS do_compile do_transform_kernel do_transform_bundled_initramfs d
> > ï¿½
> > ï¿½# kernel-base becomes kernel-${KERNEL_VERSION}
> > ï¿½# kernel-image becomes kernel-image-${KERNEL_VERSION}
> > -PACKAGES = "${KERNEL_PACKAGE_NAME} ${KERNEL_PACKAGE_NAME}-base ${KERNEL_PACKAGE_NAME}-vmlinux ${KERNEL_PACKAGE_NAME}-image ${KERNEL_PACKAGE_NAME}-dev ${KERNEL_PACKAGE_NAME}-modules ${KERNEL_PACKAGE_NAME}-dbg"
> > +PACKAGES = "${KERNEL_PACKAGE_NAME} ${KERNEL_PACKAGE_NAME}-base ${KERNEL_PACKAGE_NAME}-vmlinux ${KERNEL_PACKAGE_NAME}-image ${KERNEL_PACKAGE_NAME}-dev ${KERNEL_PACKAGE_NAME}-modules ${KERNEL_PACKAGE_NAME}-initrd-modules ${KERNEL_PACKAGE_NAME}-dbg"
> > ï¿½FILES:${PN} = ""
> > ï¿½FILES:${KERNEL_PACKAGE_NAME}-base = "${nonarch_base_libdir}/modules/${KERNEL_VERSION}/modules.order ${nonarch_base_libdir}/modules/${KERNEL_VERSION}/modules.builtin ${nonarch_base_libdir}/modules/${KERNEL_VERSION}/modules.builtin.modinfo"
> > ï¿½FILES:${KERNEL_PACKAGE_NAME}-image = ""
> > ï¿½FILES:${KERNEL_PACKAGE_NAME}-dev = "/${KERNEL_IMAGEDEST}/System.map* /${KERNEL_IMAGEDEST}/Module.symvers* /${KERNEL_IMAGEDEST}/config* ${KERNEL_SRC_PATH} ${nonarch_base_libdir}/modules/${KERNEL_VERSION}/build"
> > ï¿½FILES:${KERNEL_PACKAGE_NAME}-vmlinux = "/${KERNEL_IMAGEDEST}/vmlinux-${KERNEL_VERSION_NAME}"
> > ï¿½FILES:${KERNEL_PACKAGE_NAME}-modules = ""
> > +FILES:${KERNEL_PACKAGE_NAME}-initrd-modules = ""
> > ï¿½FILES:${KERNEL_PACKAGE_NAME}-dbg = "/usr/lib/debug /usr/src/debug"
> > ï¿½RDEPENDS:${KERNEL_PACKAGE_NAME} = "${KERNEL_PACKAGE_NAME}-base (= ${EXTENDPKGV})"
> > ï¿½# Allow machines to override this dependency if kernel image files are
> > @@ -716,7 +717,9 @@ ALLOW_EMPTY:${KERNEL_PACKAGE_NAME} = "1"
> > ï¿½ALLOW_EMPTY:${KERNEL_PACKAGE_NAME}-base = "1"
> > ï¿½ALLOW_EMPTY:${KERNEL_PACKAGE_NAME}-image = "1"
> > ï¿½ALLOW_EMPTY:${KERNEL_PACKAGE_NAME}-modules = "1"
> > +ALLOW_EMPTY:${KERNEL_PACKAGE_NAME}-initrd-modules = "1"
> > ï¿½DESCRIPTION:${KERNEL_PACKAGE_NAME}-modules = "Kernel modules meta package"
> > +DESCRIPTION:${KERNEL_PACKAGE_NAME}-initrd-modules = "Kernel initrd modules meta package"
> > ï¿½
> > ï¿½pkg_postinst:${KERNEL_PACKAGE_NAME}-base () {
> > ï¿½ if [ ! -e "$D/lib/modules/${KERNEL_VERSION}" ]; then
> > diff --git a/meta/classes-recipe/module.bbclass b/meta/classes-recipe/module.bbclass
> > index f2f0b25a2d..51f864f1f9 100644
> > --- a/meta/classes-recipe/module.bbclass
> > +++ b/meta/classes-recipe/module.bbclass
> > @@ -86,3 +86,40 @@ EXPORT_FUNCTIONS do_compile do_install
> > ï¿½KERNEL_MODULES_META_PACKAGE = "${PN}"
> > ï¿½FILES:${PN} = ""
> > ï¿½ALLOW_EMPTY:${PN} = "1"
> > +
> > +# subset of kernel modules needed in initrd, to e.g. mount rootfs from block device
> > +KERNEL_INITRD_MODULES_META_PACKAGE ?= "${@ d.getVar("KERNEL_PACKAGE_NAME") or "kernel" }-initrd-modules"
> > +
> > +# match regex to path or file name. E.g. include all drivers with files in path /drivers/ata/
> > +KERNEL_INITRD_MODULES_REGEX ?= "(.*)(\
> > +/drivers/acpi/|\
> > +/drivers/ata/|\
> > +/drivers/block/|\
> > +/drivers/cdrom/|\
> > +/drivers/char/hw_random/|\
> > +/drivers/char/tpm/|\
> > +/drivers/char/|\
> > +/drivers/crypto/|\
> > +/drivers/dax/|\
> > +/drivers/firmware/arm_scmi/|\
> > +/drivers/gpu/drm/|\
> > +/drivers/md/|\
> > +/drivers/mmc/|\
> > +/drivers/mtd/|\
> > +/drivers/nvdimm/|\
> > +/drivers/nvme/|\
> > +/drivers/pci/|\
> > +/drivers/scsi/|\
> > +/drivers/tee/|\
> > +/drivers/tty/serial/|\
> > +/drivers/virtio/|\
> > +/drivers/watchdog/|\
> > +/kernel/arch/|\
> > +/kernel/block/|\
> > +/kernel/crypto/|\
> > +/kernel/fs/|\
> > +/kernel/lib/\
> > +)(.*)"
> > +
> > +FILES:${PN}-initrd = ""
> > +ALLOW_EMPTY:${PN}-initrd = "1"
>
> What is the difference between the variable defined in kernel-module-
> split.bbclass and this one in module.bbclass? Do we need/want to
> separate but seemingly similar definitions?

One is for kernel compilation and in-tree drivers, the other is for
out-of-tree modules.

The "kernel-modules" meta package is handled this way too, with
duplication in both.

Bruce says this should be moved to linux-yocto kernel recipe,
which IMO breaks the use of kernel-initrd-modules for vendor kernel recipes
outside of oe-core. I'd rather support them too to e.g. more easily boot
qemu or run oeqa selftests with qemu.

Cheers,

-Mikko