diff mbox series

[v3,03/11] kernel.bbclass: add kernel-initrd-modules meta package

Message ID 20250404162932.447699-4-mikko.rapeli@linaro.org
State New
Headers show
Series systemd based initrd and modular kernel support | expand

Commit Message

Mikko Rapeli April 4, 2025, 4:29 p.m. UTC
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(-)

Comments

Bruce Ashfield April 8, 2025, 3:42 a.m. UTC | #1
On Fri, Apr 4, 2025 at 12:29 PM Mikko Rapeli via lists.openembedded.org
<mikko.rapeli=linaro.org@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/\
> +)(.*)"
> +
>

Apologies for not replying to your reply to my other review, I've had some
unexpected travel
and significant time away from my desk, so I'm running way behind on
everything.

I still don't agree with these values being defined in the base classes.
There's simply too
many kernels and versions out there to make sure this works (and is sane
everywhere)
.. I've lived that for 15 years in supporting the reference kernels.

The reality is that everyone will use the defaults, and never look at them
or otherwise
make sure they are valid for their kernel. We'll end up churning the
values, when really
it is specific to a kernel, a board and even a use case. A kernel recipe is
where all of
those things are explicitly handled, so putting the regex there makes it
very clear that
you need to define something.

There's also still the issue with the repeated set of directories in the
two classes.
To address that, why can't the variable definition be moved to a .inc file ?

With the variables defined in a .inc file, it then becomes very easy for
kernel recipes
to include the .inc and get a default definition .. but we are still
putting the requirement
on them that they explicitly include the file to get the default, versus it
silently being
defined and used in the classes.

Bruce



>  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"
> --
> 2.43.0
>
>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#214354):
> https://lists.openembedded.org/g/openembedded-core/message/214354
> Mute This Topic: https://lists.openembedded.org/mt/112087526/1050810
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [
> bruce.ashfield@gmail.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
>
Richard Purdie April 10, 2025, 12:42 p.m. UTC | #2
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?

Cheers,

Richard
Mikko Rapeli April 10, 2025, 1 p.m. UTC | #3
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
Bruce Ashfield April 10, 2025, 1:15 p.m. UTC | #4
On Thu, Apr 10, 2025 at 9:00 AM Mikko Rapeli via lists.openembedded.org
<mikko.rapeli=linaro.org@lists.openembedded.org> wrote:

> 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.
>

That's not quite what I said (but it is close), I said it shouldn't be
defined
at the base with no requirement opt-in from a recipe (even if this way
of constructing an initrd with the modules is not the default). It is a (
weak)
binding to specific kernel versions and directory layouts, but it is a
binding
none the less. If it sits at the base in the classes no one will ever look
at
it or even know that it should be considered.

My suggestion was not that it should only be in linux-yocto (but I'd
insist on overriding it or doing it slightly differently in linux-yocto),
I was saying that it I think  that the two definitions are far to similar
and even if there remain two definitions, they should be moved
into a .inc file.

Any kernel recipe that wants to build an initrd like this can opt-in by
including the .inc, and/or creating their own definition.

Bruce



>
> Cheers,
>
> -Mikko
>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#214664):
> https://lists.openembedded.org/g/openembedded-core/message/214664
> Mute This Topic: https://lists.openembedded.org/mt/112087526/1050810
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [
> bruce.ashfield@gmail.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
>
Mikko Rapeli April 11, 2025, 7:48 a.m. UTC | #5
Hi,

On Thu, Apr 10, 2025 at 09:15:02AM -0400, Bruce Ashfield wrote:
> On Thu, Apr 10, 2025 at 9:00 AM Mikko Rapeli via lists.openembedded.org
> <mikko.rapeli=linaro.org@lists.openembedded.org> wrote:
> 
> > 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.
> >
> 
> That's not quite what I said (but it is close), I said it shouldn't be
> defined
> at the base with no requirement opt-in from a recipe (even if this way
> of constructing an initrd with the modules is not the default). It is a (
> weak)
> binding to specific kernel versions and directory layouts, but it is a
> binding
> none the less. If it sits at the base in the classes no one will ever look
> at
> it or even know that it should be considered.
> 
> My suggestion was not that it should only be in linux-yocto (but I'd
> insist on overriding it or doing it slightly differently in linux-yocto),
> I was saying that it I think  that the two definitions are far to similar
> and even if there remain two definitions, they should be moved
> into a .inc file.

Actually the duplication is a bug. All duplication in module.bbclass can be
removed since it includes kernel-module-split.bbclass. Both kernel.bbclass and
module.bbclass include kernel-module-split.bbclass. Sorry about this.
I must have stopped half way when moving things there.

Sending v4 with this fixed soon.

> Any kernel recipe that wants to build an initrd like this can opt-in by
> including the .inc, and/or creating their own definition.

This I don't get. I think the kernel.bbclass and module.bbclass should
work out of the box with sane defaults. The kernel recipes can override
and adjust these as they see fit. Yes there is a dependency to some kernel
APIs (kernel module install paths) which can change, but those have been
stable for, over 25 years (as long as I have been compiling kernels)?

For full control, initrd recipe maintainers can define the exact set
of kernel and other binary packages to install which makes the recipe
kernel config and machine specific.

I don't think moving the definitions to a linux-yocto side .inc file
and then using that as basis in non-core kernel recipes is good. The
kernel.bbclass and module.bbclass would not work independently anymore
and require meta/recipes-kernel/linux/ side .inc file for working defaults.
Or should the .inc file live in meta/conf/distro/include?

I think the defaults belong to kernel-module-split.bbclass used by both
kernel and modules bbclasses.

Cheers,

-Mikko
Mikko Rapeli April 11, 2025, 8:07 a.m. UTC | #6
Hi,

On Thu, Apr 10, 2025 at 04:00:50PM +0300, Mikko Rapeli via lists.openembedded.org wrote:
> 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.

Sorry, I was wrong. KERNEL_INITRD_MODULES_REGEX duplication is a bug.
I will remove this from module.bbclass. It includes kernel-module-split.bbclass
so defition can be taken from there, just like for kernel.bbclass users.

Cheers,

-Mikko
Bruce Ashfield April 11, 2025, 12:52 p.m. UTC | #7
On Fri, Apr 11, 2025 at 3:48 AM Mikko Rapeli <mikko.rapeli@linaro.org>
wrote:

> Hi,
>
> On Thu, Apr 10, 2025 at 09:15:02AM -0400, Bruce Ashfield wrote:
> > On Thu, Apr 10, 2025 at 9:00 AM Mikko Rapeli via lists.openembedded.org
> > <mikko.rapeli=linaro.org@lists.openembedded.org> wrote:
> >
> > > 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.
> > >
> >
> > That's not quite what I said (but it is close), I said it shouldn't be
> > defined
> > at the base with no requirement opt-in from a recipe (even if this way
> > of constructing an initrd with the modules is not the default). It is a (
> > weak)
> > binding to specific kernel versions and directory layouts, but it is a
> > binding
> > none the less. If it sits at the base in the classes no one will ever
> look
> > at
> > it or even know that it should be considered.
> >
> > My suggestion was not that it should only be in linux-yocto (but I'd
> > insist on overriding it or doing it slightly differently in linux-yocto),
> > I was saying that it I think  that the two definitions are far to similar
> > and even if there remain two definitions, they should be moved
> > into a .inc file.
>
> Actually the duplication is a bug. All duplication in module.bbclass can be
> removed since it includes kernel-module-split.bbclass. Both kernel.bbclass
> and
> module.bbclass include kernel-module-split.bbclass. Sorry about this.
> I must have stopped half way when moving things there.
>
> Sending v4 with this fixed soon.
>
> > Any kernel recipe that wants to build an initrd like this can opt-in by
> > including the .inc, and/or creating their own definition.
>
> This I don't get. I think the kernel.bbclass and module.bbclass should
> work out of the box with sane defaults. The kernel recipes can override
> and adjust these as they see fit. Yes there is a dependency to some kernel
> APIs (kernel module install paths) which can change, but those have been
> stable for, over 25 years (as long as I have been compiling kernels)?
>
> For full control, initrd recipe maintainers can define the exact set
> of kernel and other binary packages to install which makes the recipe
> kernel config and machine specific.
>
> I don't think moving the definitions to a linux-yocto side .inc file
> and then using that as basis in non-core kernel recipes is good. The
> kernel.bbclass and module.bbclass would not work independently anymore
> and require meta/recipes-kernel/linux/ side .inc file for working defaults.
> Or should the .inc file live in meta/conf/distro/include?
>

Let me be clear. I am not saying "linux-yocto" here. I said a ".inc" file.

Put that .inc file in a common directory and call it something like
initrd-kernel-<foo>.inc, recipes include that .inc file to opt into the
behaviour and get the base definition if they want it.

This modular based initrd isn't going to be the default, so it has
to be opt-in anyway. So put the opt-in and the definitions in a .inc
file, a recipe including it, opts-in.

I don't like the directory listings at all, but that's the best way to
not hide them and again, you can't get a general enough set of
definitions in a base class to serve all possible use cases. It needs
to come from top down.

Bruce



>
> I think the defaults belong to kernel-module-split.bbclass used by both
> kernel and modules bbclasses.
>
> Cheers,
>
> -Mikko
>
Mikko Rapeli April 11, 2025, 1:12 p.m. UTC | #8
Hi,

On Fri, Apr 11, 2025 at 08:52:24AM -0400, Bruce Ashfield wrote:
> On Fri, Apr 11, 2025 at 3:48 AM Mikko Rapeli <mikko.rapeli@linaro.org>
> wrote:
> 
> > Hi,
> >
> > On Thu, Apr 10, 2025 at 09:15:02AM -0400, Bruce Ashfield wrote:
> > > On Thu, Apr 10, 2025 at 9:00 AM Mikko Rapeli via lists.openembedded.org
> > > <mikko.rapeli=linaro.org@lists.openembedded.org> wrote:
> > >
> > > > 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.
> > > >
> > >
> > > That's not quite what I said (but it is close), I said it shouldn't be
> > > defined
> > > at the base with no requirement opt-in from a recipe (even if this way
> > > of constructing an initrd with the modules is not the default). It is a (
> > > weak)
> > > binding to specific kernel versions and directory layouts, but it is a
> > > binding
> > > none the less. If it sits at the base in the classes no one will ever
> > look
> > > at
> > > it or even know that it should be considered.
> > >
> > > My suggestion was not that it should only be in linux-yocto (but I'd
> > > insist on overriding it or doing it slightly differently in linux-yocto),
> > > I was saying that it I think  that the two definitions are far to similar
> > > and even if there remain two definitions, they should be moved
> > > into a .inc file.
> >
> > Actually the duplication is a bug. All duplication in module.bbclass can be
> > removed since it includes kernel-module-split.bbclass. Both kernel.bbclass
> > and
> > module.bbclass include kernel-module-split.bbclass. Sorry about this.
> > I must have stopped half way when moving things there.
> >
> > Sending v4 with this fixed soon.
> >
> > > Any kernel recipe that wants to build an initrd like this can opt-in by
> > > including the .inc, and/or creating their own definition.
> >
> > This I don't get. I think the kernel.bbclass and module.bbclass should
> > work out of the box with sane defaults. The kernel recipes can override
> > and adjust these as they see fit. Yes there is a dependency to some kernel
> > APIs (kernel module install paths) which can change, but those have been
> > stable for, over 25 years (as long as I have been compiling kernels)?
> >
> > For full control, initrd recipe maintainers can define the exact set
> > of kernel and other binary packages to install which makes the recipe
> > kernel config and machine specific.
> >
> > I don't think moving the definitions to a linux-yocto side .inc file
> > and then using that as basis in non-core kernel recipes is good. The
> > kernel.bbclass and module.bbclass would not work independently anymore
> > and require meta/recipes-kernel/linux/ side .inc file for working defaults.
> > Or should the .inc file live in meta/conf/distro/include?
> >
> 
> Let me be clear. I am not saying "linux-yocto" here. I said a ".inc" file.
> 
> Put that .inc file in a common directory and call it something like
> initrd-kernel-<foo>.inc, recipes include that .inc file to opt into the
> behaviour and get the base definition if they want it.

Ok I will do this in v5.
 
> This modular based initrd isn't going to be the default, so it has
> to be opt-in anyway. So put the opt-in and the definitions in a .inc
> file, a recipe including it, opts-in.

I think this should be the default on most machines which use
core-image-initramfs-boot in oe-core.

genericarm64, beagleplay etc machines already for install of "kernel-modules"
to all images, including core-image-initramfs-boot:

$ git grep MACHINE_EXTRA_RRECOMMENDS meta/conf/machine meta-yocto-bsp/conf/machine/ | grep kernel-modules
meta-yocto-bsp/conf/machine/beaglebone-yocto.conf:MACHINE_EXTRA_RRECOMMENDS = "kernel-modules"
meta-yocto-bsp/conf/machine/genericarm64.conf:MACHINE_EXTRA_RRECOMMENDS += "kernel-modules"
meta-yocto-bsp/conf/machine/include/genericx86-common.inc:MACHINE_EXTRA_RRECOMMENDS += "kernel-modules linux-firmware"
meta/conf/machine/include/loongarch/qemuloongarch.inc:MACHINE_EXTRA_RRECOMMENDS += " kernel-modules"
meta/conf/machine/include/riscv/qemuriscv.inc:MACHINE_EXTRA_RRECOMMENDS += " kernel-modules"
meta/conf/machine/qemuppc64.conf:MACHINE_EXTRA_RRECOMMENDS += " kernel-modules"

Some qemu machines don't and that causes issues since
initrd is not flexible to boot even slightly different configurations,
like block device emulation moved from scsi to virtio.
This causes issues with oeqa selftests when small kernel or qemuboot
differences break tests.

initrd itself is optional, but in core-image-initramfs-boot I made
including "kernel-initrd-modules" the default. To me this makes sense.

Kernels for different machines can enable drivers as modules or as built-in
but the initrd config stays the same and will mostly just work. I think
this is a good default.

And then "kernel-initrd-modules" are much smaller than "kernel-modules".
Still too big for real products but better than nothing. For
genericarm64 this reduced initrd image size from 200 Mb to 54 Mb.

> I don't like the directory listings at all, but that's the best way to
> not hide them and again, you can't get a general enough set of
> definitions in a base class to serve all possible use cases. It needs
> to come from top down.

Yes, improvements welcome. At least this doesn't break when drivers
change from built-in or as modules and new features added to linux-yocto
configs don't bloat the kernel so much anymore. Like the pmem patches
which just got in. They work as modules.

Cheers,

-Mikko
Bruce Ashfield April 11, 2025, 1:39 p.m. UTC | #9
On Fri, Apr 11, 2025 at 9:12 AM Mikko Rapeli <mikko.rapeli@linaro.org>
wrote:

> Hi,
>
> On Fri, Apr 11, 2025 at 08:52:24AM -0400, Bruce Ashfield wrote:
> > On Fri, Apr 11, 2025 at 3:48 AM Mikko Rapeli <mikko.rapeli@linaro.org>
> > wrote:
> >
> > > Hi,
> > >
> > > On Thu, Apr 10, 2025 at 09:15:02AM -0400, Bruce Ashfield wrote:
> > > > On Thu, Apr 10, 2025 at 9:00 AM Mikko Rapeli via
> lists.openembedded.org
> > > > <mikko.rapeli=linaro.org@lists.openembedded.org> wrote:
> > > >
> > > > > 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.
> > > > >
> > > >
> > > > That's not quite what I said (but it is close), I said it shouldn't
> be
> > > > defined
> > > > at the base with no requirement opt-in from a recipe (even if this
> way
> > > > of constructing an initrd with the modules is not the default). It
> is a (
> > > > weak)
> > > > binding to specific kernel versions and directory layouts, but it is
> a
> > > > binding
> > > > none the less. If it sits at the base in the classes no one will ever
> > > look
> > > > at
> > > > it or even know that it should be considered.
> > > >
> > > > My suggestion was not that it should only be in linux-yocto (but I'd
> > > > insist on overriding it or doing it slightly differently in
> linux-yocto),
> > > > I was saying that it I think  that the two definitions are far to
> similar
> > > > and even if there remain two definitions, they should be moved
> > > > into a .inc file.
> > >
> > > Actually the duplication is a bug. All duplication in module.bbclass
> can be
> > > removed since it includes kernel-module-split.bbclass. Both
> kernel.bbclass
> > > and
> > > module.bbclass include kernel-module-split.bbclass. Sorry about this.
> > > I must have stopped half way when moving things there.
> > >
> > > Sending v4 with this fixed soon.
> > >
> > > > Any kernel recipe that wants to build an initrd like this can opt-in
> by
> > > > including the .inc, and/or creating their own definition.
> > >
> > > This I don't get. I think the kernel.bbclass and module.bbclass should
> > > work out of the box with sane defaults. The kernel recipes can override
> > > and adjust these as they see fit. Yes there is a dependency to some
> kernel
> > > APIs (kernel module install paths) which can change, but those have
> been
> > > stable for, over 25 years (as long as I have been compiling kernels)?
> > >
> > > For full control, initrd recipe maintainers can define the exact set
> > > of kernel and other binary packages to install which makes the recipe
> > > kernel config and machine specific.
> > >
> > > I don't think moving the definitions to a linux-yocto side .inc file
> > > and then using that as basis in non-core kernel recipes is good. The
> > > kernel.bbclass and module.bbclass would not work independently anymore
> > > and require meta/recipes-kernel/linux/ side .inc file for working
> defaults.
> > > Or should the .inc file live in meta/conf/distro/include?
> > >
> >
> > Let me be clear. I am not saying "linux-yocto" here. I said a ".inc"
> file.
> >
> > Put that .inc file in a common directory and call it something like
> > initrd-kernel-<foo>.inc, recipes include that .inc file to opt into the
> > behaviour and get the base definition if they want it.
>
> Ok I will do this in v5.
>
> > This modular based initrd isn't going to be the default, so it has
> > to be opt-in anyway. So put the opt-in and the definitions in a .inc
> > file, a recipe including it, opts-in.
>
> I think this should be the default on most machines which use
> core-image-initramfs-boot in oe-core.


I'll disagree on that point, but in the end, it isn't a hill that
is worth climbing (for me). If that's the way the default policy
goes, I'll just roll with it.




>
> genericarm64, beagleplay etc machines already for install of
> "kernel-modules"
> to all images, including core-image-initramfs-boot:
>
> $ git grep MACHINE_EXTRA_RRECOMMENDS meta/conf/machine
> meta-yocto-bsp/conf/machine/ | grep kernel-modules
> meta-yocto-bsp/conf/machine/beaglebone-yocto.conf:MACHINE_EXTRA_RRECOMMENDS
> = "kernel-modules"
> meta-yocto-bsp/conf/machine/genericarm64.conf:MACHINE_EXTRA_RRECOMMENDS +=
> "kernel-modules"
> meta-yocto-bsp/conf/machine/include/genericx86-common.inc:MACHINE_EXTRA_RRECOMMENDS
> += "kernel-modules linux-firmware"
> meta/conf/machine/include/loongarch/qemuloongarch.inc:MACHINE_EXTRA_RRECOMMENDS
> += " kernel-modules"
> meta/conf/machine/include/riscv/qemuriscv.inc:MACHINE_EXTRA_RRECOMMENDS +=
> " kernel-modules"
> meta/conf/machine/qemuppc64.conf:MACHINE_EXTRA_RRECOMMENDS += "
> kernel-modules"
>
>
Right, and that was by design.

The philosophy has been that the kernel provider should understand
and control its configuration (since we are talking about embedded
devices here). Sure, those examples took the simplest path, and that
was their decision / tradeoff.

We package all the modules individually (I'm stating the obvious,
since we all know this) so that they can be individually installed
and required for something that really wants to control the configuration
tightly.

In any machine / BSP that I build, the configuration is on purpose
and if I want to install individual modules, I'll do that, otherwise,
I trust my configuration and take all the modules.

What you have is something in the middle, and why I still think it
needs to be opt-in. BSP creators need to understand their
configuration and tune it. Having something down at the packaging
level pick and choose which modules on their behalf means that
they are relying on something that needs to be discovered and
tweaked (versus the "all of it" or "you chose your own" as it was
before).


> Some qemu machines don't and that causes issues since
> initrd is not flexible to boot even slightly different configurations,
> like block device emulation moved from scsi to virtio.
> This causes issues with oeqa selftests when small kernel or qemuboot
> differences break tests.
>

And we'll continue to do that, as all the boot methods and kernels
need to be tested. But I agree, there are pros and cons to the
various methods.


> initrd itself is optional, but in core-image-initramfs-boot I made
> including "kernel-initrd-modules" the default. To me this makes sense.
>
> Kernels for different machines can enable drivers as modules or as built-in
> but the initrd config stays the same and will mostly just work. I think
> this is a good default.
>
>
It is just that behaviour which is why I'm saying it should be
explicit and opt-in. If they change their configuration it should
be with a direct line of sight to how the various components
consume it.

Preferably not "I have a custom driver, I need it to boot, I'm
now building it as a module" .. and then wondering why it isn't
picked up in the initrd. If they had to opt-in, they'll already be
aware of the mechanism that is selecting their modules over
and above what their kernel configuration dictates.


> And then "kernel-initrd-modules" are much smaller than "kernel-modules".
> Still too big for real products but better than nothing. For
> genericarm64 this reduced initrd image size from 200 Mb to 54 Mb.


Definitely a valid point / improvement. I'm again back to saying it
just has to be explicit. The same way that many (most?) people
don't want or use linux-yocto as production, we have to design
our configurations as something to be opt-in and something that
is clear it needs to be tweaked for production.

We aren't far off in our view on this.  Most of this looks really
good to me, and is a good step forward. I think that our
different point of view is about the breadth of the types of
kernels, machines, boot methods, products, etc, that are built
on top and how to enable this mechanism.


> > I don't like the directory listings at all, but that's the best way to
> > not hide them and again, you can't get a general enough set of
> > definitions in a base class to serve all possible use cases. It needs
> > to come from top down.
>
> Yes, improvements welcome. At least this doesn't break when drivers
> change from built-in or as modules and new features added to linux-yocto
> configs don't bloat the kernel so much anymore. Like the pmem patches
> which just got in. They work as modules.
>
>
I'm still working on this part, but trying to get this release out
the door has my time mostly chewed up.  I'd still like to explore
a way that either the kernel configuration or the packaging of the
modules is how a recipe indicates that something belongs in
this essential module list for the initrd (or whatever else).

Richard: If you are reading this and get this far, is there any way
to add some sort of RPROVIDES to a package that is almost a
wild card ?  I just haven't had time to think it through or experiment.
Rather than the directory listings, if the new initrd kernel module
meta-package could be constructed (or just the image doing the
installs) from something like IMAGE_INSTALL += "kernel-essential-boot-*'
and that RPROVIDES was put into the packages when they were
created .. we'd have the top down control and explicit configuration
I'm looking for.

Bruce



> Cheers,
>
> -Mikko
>
Richard Purdie April 11, 2025, 1:45 p.m. UTC | #10
On Fri, 2025-04-11 at 09:39 -0400, Bruce Ashfield wrote:
> Richard: If you are reading this and get this far, is there any way
> to add some sort of RPROVIDES to a package that is almost a
> wild card ?  I just haven't had time to think it through or
> experiment.
> Rather than the directory listings, if the new initrd kernel module
> meta-package could be constructed (or just the image doing the
> installs) from something like IMAGE_INSTALL += "kernel-essential-
> boot-*'
> and that RPROVIDES was put into the packages when they were
> created .. we'd have the top down control and explicit configuration
> I'm looking for.

I think the package rprovides would have to be unique but you could do
that with kernel-essential-boot-XXX. Installing globs of packages
doesn't work well at the package manager level but we do have support
for things like the dev/dbg/locale globbing (*-dev and friends) at the
image construction level so that much is possible, albeit for a quite
difference usecase atm.

Cheers,

Richard
Mikko Rapeli April 22, 2025, 10:18 a.m. UTC | #11
Hi,

On Fri, Apr 11, 2025 at 09:39:31AM -0400, Bruce Ashfield wrote:
> On Fri, Apr 11, 2025 at 9:12 AM Mikko Rapeli <mikko.rapeli@linaro.org>
> wrote:
> > On Fri, Apr 11, 2025 at 08:52:24AM -0400, Bruce Ashfield wrote:
> > > On Fri, Apr 11, 2025 at 3:48 AM Mikko Rapeli <mikko.rapeli@linaro.org>
> > > wrote:
> > > > On Thu, Apr 10, 2025 at 09:15:02AM -0400, Bruce Ashfield wrote:
> > > > > On Thu, Apr 10, 2025 at 9:00 AM Mikko Rapeli via
> > lists.openembedded.org
> > > > > <mikko.rapeli=linaro.org@lists.openembedded.org> wrote:
> > > > >
> > > > > > 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.
> > > > > >
> > > > >
> > > > > That's not quite what I said (but it is close), I said it shouldn't
> > be
> > > > > defined
> > > > > at the base with no requirement opt-in from a recipe (even if this
> > way
> > > > > of constructing an initrd with the modules is not the default). It
> > is a (
> > > > > weak)
> > > > > binding to specific kernel versions and directory layouts, but it is
> > a
> > > > > binding
> > > > > none the less. If it sits at the base in the classes no one will ever
> > > > look
> > > > > at
> > > > > it or even know that it should be considered.
> > > > >
> > > > > My suggestion was not that it should only be in linux-yocto (but I'd
> > > > > insist on overriding it or doing it slightly differently in
> > linux-yocto),
> > > > > I was saying that it I think  that the two definitions are far to
> > similar
> > > > > and even if there remain two definitions, they should be moved
> > > > > into a .inc file.
> > > >
> > > > Actually the duplication is a bug. All duplication in module.bbclass
> > can be
> > > > removed since it includes kernel-module-split.bbclass. Both
> > kernel.bbclass
> > > > and
> > > > module.bbclass include kernel-module-split.bbclass. Sorry about this.
> > > > I must have stopped half way when moving things there.
> > > >
> > > > Sending v4 with this fixed soon.
> > > >
> > > > > Any kernel recipe that wants to build an initrd like this can opt-in
> > by
> > > > > including the .inc, and/or creating their own definition.
> > > >
> > > > This I don't get. I think the kernel.bbclass and module.bbclass should
> > > > work out of the box with sane defaults. The kernel recipes can override
> > > > and adjust these as they see fit. Yes there is a dependency to some
> > kernel
> > > > APIs (kernel module install paths) which can change, but those have
> > been
> > > > stable for, over 25 years (as long as I have been compiling kernels)?
> > > >
> > > > For full control, initrd recipe maintainers can define the exact set
> > > > of kernel and other binary packages to install which makes the recipe
> > > > kernel config and machine specific.
> > > >
> > > > I don't think moving the definitions to a linux-yocto side .inc file
> > > > and then using that as basis in non-core kernel recipes is good. The
> > > > kernel.bbclass and module.bbclass would not work independently anymore
> > > > and require meta/recipes-kernel/linux/ side .inc file for working
> > defaults.
> > > > Or should the .inc file live in meta/conf/distro/include?
> > > >
> > >
> > > Let me be clear. I am not saying "linux-yocto" here. I said a ".inc"
> > file.
> > >
> > > Put that .inc file in a common directory and call it something like
> > > initrd-kernel-<foo>.inc, recipes include that .inc file to opt into the
> > > behaviour and get the base definition if they want it.
> >
> > Ok I will do this in v5.
> >
> > > This modular based initrd isn't going to be the default, so it has
> > > to be opt-in anyway. So put the opt-in and the definitions in a .inc
> > > file, a recipe including it, opts-in.
> >
> > I think this should be the default on most machines which use
> > core-image-initramfs-boot in oe-core.
> 
> 
> I'll disagree on that point, but in the end, it isn't a hill that
> is worth climbing (for me). If that's the way the default policy
> goes, I'll just roll with it.
> 
> > genericarm64, beagleplay etc machines already for install of
> > "kernel-modules"
> > to all images, including core-image-initramfs-boot:
> >
> > $ git grep MACHINE_EXTRA_RRECOMMENDS meta/conf/machine
> > meta-yocto-bsp/conf/machine/ | grep kernel-modules
> > meta-yocto-bsp/conf/machine/beaglebone-yocto.conf:MACHINE_EXTRA_RRECOMMENDS
> > = "kernel-modules"
> > meta-yocto-bsp/conf/machine/genericarm64.conf:MACHINE_EXTRA_RRECOMMENDS +=
> > "kernel-modules"
> > meta-yocto-bsp/conf/machine/include/genericx86-common.inc:MACHINE_EXTRA_RRECOMMENDS
> > += "kernel-modules linux-firmware"
> > meta/conf/machine/include/loongarch/qemuloongarch.inc:MACHINE_EXTRA_RRECOMMENDS
> > += " kernel-modules"
> > meta/conf/machine/include/riscv/qemuriscv.inc:MACHINE_EXTRA_RRECOMMENDS +=
> > " kernel-modules"
> > meta/conf/machine/qemuppc64.conf:MACHINE_EXTRA_RRECOMMENDS += "
> > kernel-modules"
> >
> Right, and that was by design.
> 
> The philosophy has been that the kernel provider should understand
> and control its configuration (since we are talking about embedded
> devices here). Sure, those examples took the simplest path, and that
> was their decision / tradeoff.
> 
> We package all the modules individually (I'm stating the obvious,
> since we all know this) so that they can be individually installed
> and required for something that really wants to control the configuration
> tightly.
> 
> In any machine / BSP that I build, the configuration is on purpose
> and if I want to install individual modules, I'll do that, otherwise,
> I trust my configuration and take all the modules.
> 
> What you have is something in the middle, and why I still think it
> needs to be opt-in. BSP creators need to understand their
> configuration and tune it. Having something down at the packaging
> level pick and choose which modules on their behalf means that
> they are relying on something that needs to be discovered and
> tweaked (versus the "all of it" or "you chose your own" as it was
> before).

By making the kernel-initrd-modules meta package optional and opt-in,
we again make the initrd image recipe depend on the opt-in feature.

I need to bind the initrd recipe to a distro level feature and
then the same for kernel side changes because the "kernel-initrd-modules"
meta package may not exist and thus it can break the build. Solution
is another abstraction in distro features. I think producing the
"kernel-initrd-modules" meta package should be default in the kernel
bbclasses. It may not get used but the overhead is really small.

This is similar to "kernel-modules" meta package. It is always there
and can safely be in MACHINE_EXTRA_RRECOMMENDS without any additional
guards like a machine or distro feature. Also BSP layer image recipes
use this.

This is the interface between kernel recipes providing kernel and module
packages and the image recipe consuming them. I'd like the image recipe
consumer to be simpler and less dependent kernel config and driver packaging
details.

> > Some qemu machines don't and that causes issues since
> > initrd is not flexible to boot even slightly different configurations,
> > like block device emulation moved from scsi to virtio.
> > This causes issues with oeqa selftests when small kernel or qemuboot
> > differences break tests.
> >
> 
> And we'll continue to do that, as all the boot methods and kernels
> need to be tested. But I agree, there are pros and cons to the
> various methods.
> 
> > initrd itself is optional, but in core-image-initramfs-boot I made
> > including "kernel-initrd-modules" the default. To me this makes sense.
> >
> > Kernels for different machines can enable drivers as modules or as built-in
> > but the initrd config stays the same and will mostly just work. I think
> > this is a good default.
> >
> >
> It is just that behaviour which is why I'm saying it should be
> explicit and opt-in. If they change their configuration it should
> be with a direct line of sight to how the various components
> consume it.
> 
> Preferably not "I have a custom driver, I need it to boot, I'm
> now building it as a module" .. and then wondering why it isn't
> picked up in the initrd. If they had to opt-in, they'll already be
> aware of the mechanism that is selecting their modules over
> and above what their kernel configuration dictates.

If the custom and vendor specific driver installs to correct paths
which fall into block etc driver regex then these already get picked up by the
initrd regex then everything will just work by default. Compiling the driver
built-in or as module will just work with the default core-image-initramfs-boot
initrd and core-image-base etc images. Boot without initrd may fail but with it
things just work.

If this feature is opt-in or specific to linux-yocto recipe, it again makes the
initrd's machine and kernel config specific. The opt-in setup needs to be made
for kernel and for initrd.

For real products all details need to be reviewed and customized but developers
need "good enough and simple" starting points and that's where the
"kernel-modules" and "kernel-initrd-modules" meta packages help.

They can more easily boot the generic images, see what drivers got loaded at boot
and remove all the rest. Then move that setup into kernel config etc. They can
also test different block devices and file systems.

The amount of optimisation done depends on what the priorities are. Gain vs effort.

> > And then "kernel-initrd-modules" are much smaller than "kernel-modules".
> > Still too big for real products but better than nothing. For
> > genericarm64 this reduced initrd image size from 200 Mb to 54 Mb.
> 
> Definitely a valid point / improvement. I'm again back to saying it
> just has to be explicit. The same way that many (most?) people
> don't want or use linux-yocto as production, we have to design
> our configurations as something to be opt-in and something that
> is clear it needs to be tweaked for production.
> 
> We aren't far off in our view on this.  Most of this looks really
> good to me, and is a good step forward. I think that our
> different point of view is about the breadth of the types of
> kernels, machines, boot methods, products, etc, that are built
> on top and how to enable this mechanism.

If this feature is opt-in and not the default in kernel.bbclass, then IMO
the result is again machine/build/config specific initrd image recipes
which I wanted to avoid.

Cheers,

-Mikko
Bruce Ashfield April 23, 2025, 12:48 p.m. UTC | #12
On Tue, Apr 22, 2025 at 6:18 AM Mikko Rapeli <mikko.rapeli@linaro.org>
wrote:

> Hi,
>
> On Fri, Apr 11, 2025 at 09:39:31AM -0400, Bruce Ashfield wrote:
> > On Fri, Apr 11, 2025 at 9:12 AM Mikko Rapeli <mikko.rapeli@linaro.org>
> > wrote:
> > > On Fri, Apr 11, 2025 at 08:52:24AM -0400, Bruce Ashfield wrote:
> > > > On Fri, Apr 11, 2025 at 3:48 AM Mikko Rapeli <
> mikko.rapeli@linaro.org>
> > > > wrote:
> > > > > On Thu, Apr 10, 2025 at 09:15:02AM -0400, Bruce Ashfield wrote:
> > > > > > On Thu, Apr 10, 2025 at 9:00 AM Mikko Rapeli via
> > > lists.openembedded.org
> > > > > > <mikko.rapeli=linaro.org@lists.openembedded.org> wrote:
> > > > > >
> > > > > > > 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.
> > > > > > >
> > > > > >
> > > > > > That's not quite what I said (but it is close), I said it
> shouldn't
> > > be
> > > > > > defined
> > > > > > at the base with no requirement opt-in from a recipe (even if
> this
> > > way
> > > > > > of constructing an initrd with the modules is not the default).
> It
> > > is a (
> > > > > > weak)
> > > > > > binding to specific kernel versions and directory layouts, but
> it is
> > > a
> > > > > > binding
> > > > > > none the less. If it sits at the base in the classes no one will
> ever
> > > > > look
> > > > > > at
> > > > > > it or even know that it should be considered.
> > > > > >
> > > > > > My suggestion was not that it should only be in linux-yocto (but
> I'd
> > > > > > insist on overriding it or doing it slightly differently in
> > > linux-yocto),
> > > > > > I was saying that it I think  that the two definitions are far to
> > > similar
> > > > > > and even if there remain two definitions, they should be moved
> > > > > > into a .inc file.
> > > > >
> > > > > Actually the duplication is a bug. All duplication in
> module.bbclass
> > > can be
> > > > > removed since it includes kernel-module-split.bbclass. Both
> > > kernel.bbclass
> > > > > and
> > > > > module.bbclass include kernel-module-split.bbclass. Sorry about
> this.
> > > > > I must have stopped half way when moving things there.
> > > > >
> > > > > Sending v4 with this fixed soon.
> > > > >
> > > > > > Any kernel recipe that wants to build an initrd like this can
> opt-in
> > > by
> > > > > > including the .inc, and/or creating their own definition.
> > > > >
> > > > > This I don't get. I think the kernel.bbclass and module.bbclass
> should
> > > > > work out of the box with sane defaults. The kernel recipes can
> override
> > > > > and adjust these as they see fit. Yes there is a dependency to some
> > > kernel
> > > > > APIs (kernel module install paths) which can change, but those have
> > > been
> > > > > stable for, over 25 years (as long as I have been compiling
> kernels)?
> > > > >
> > > > > For full control, initrd recipe maintainers can define the exact
> set
> > > > > of kernel and other binary packages to install which makes the
> recipe
> > > > > kernel config and machine specific.
> > > > >
> > > > > I don't think moving the definitions to a linux-yocto side .inc
> file
> > > > > and then using that as basis in non-core kernel recipes is good.
> The
> > > > > kernel.bbclass and module.bbclass would not work independently
> anymore
> > > > > and require meta/recipes-kernel/linux/ side .inc file for working
> > > defaults.
> > > > > Or should the .inc file live in meta/conf/distro/include?
> > > > >
> > > >
> > > > Let me be clear. I am not saying "linux-yocto" here. I said a ".inc"
> > > file.
> > > >
> > > > Put that .inc file in a common directory and call it something like
> > > > initrd-kernel-<foo>.inc, recipes include that .inc file to opt into
> the
> > > > behaviour and get the base definition if they want it.
> > >
> > > Ok I will do this in v5.
> > >
> > > > This modular based initrd isn't going to be the default, so it has
> > > > to be opt-in anyway. So put the opt-in and the definitions in a .inc
> > > > file, a recipe including it, opts-in.
> > >
> > > I think this should be the default on most machines which use
> > > core-image-initramfs-boot in oe-core.
> >
> >
> > I'll disagree on that point, but in the end, it isn't a hill that
> > is worth climbing (for me). If that's the way the default policy
> > goes, I'll just roll with it.
> >
> > > genericarm64, beagleplay etc machines already for install of
> > > "kernel-modules"
> > > to all images, including core-image-initramfs-boot:
> > >
> > > $ git grep MACHINE_EXTRA_RRECOMMENDS meta/conf/machine
> > > meta-yocto-bsp/conf/machine/ | grep kernel-modules
> > >
> meta-yocto-bsp/conf/machine/beaglebone-yocto.conf:MACHINE_EXTRA_RRECOMMENDS
> > > = "kernel-modules"
> > >
> meta-yocto-bsp/conf/machine/genericarm64.conf:MACHINE_EXTRA_RRECOMMENDS +=
> > > "kernel-modules"
> > >
> meta-yocto-bsp/conf/machine/include/genericx86-common.inc:MACHINE_EXTRA_RRECOMMENDS
> > > += "kernel-modules linux-firmware"
> > >
> meta/conf/machine/include/loongarch/qemuloongarch.inc:MACHINE_EXTRA_RRECOMMENDS
> > > += " kernel-modules"
> > >
> meta/conf/machine/include/riscv/qemuriscv.inc:MACHINE_EXTRA_RRECOMMENDS +=
> > > " kernel-modules"
> > > meta/conf/machine/qemuppc64.conf:MACHINE_EXTRA_RRECOMMENDS += "
> > > kernel-modules"
> > >
> > Right, and that was by design.
> >
> > The philosophy has been that the kernel provider should understand
> > and control its configuration (since we are talking about embedded
> > devices here). Sure, those examples took the simplest path, and that
> > was their decision / tradeoff.
> >
> > We package all the modules individually (I'm stating the obvious,
> > since we all know this) so that they can be individually installed
> > and required for something that really wants to control the configuration
> > tightly.
> >
> > In any machine / BSP that I build, the configuration is on purpose
> > and if I want to install individual modules, I'll do that, otherwise,
> > I trust my configuration and take all the modules.
> >
> > What you have is something in the middle, and why I still think it
> > needs to be opt-in. BSP creators need to understand their
> > configuration and tune it. Having something down at the packaging
> > level pick and choose which modules on their behalf means that
> > they are relying on something that needs to be discovered and
> > tweaked (versus the "all of it" or "you chose your own" as it was
> > before).
>
> By making the kernel-initrd-modules meta package optional and opt-in,
> we again make the initrd image recipe depend on the opt-in feature.
>
>
That's exactly what I'm looking for and consider it a good thing :)

I need to bind the initrd recipe to a distro level feature and
> then the same for kernel side changes because the "kernel-initrd-modules"
> meta package may not exist and thus it can break the build. Solution
> is another abstraction in distro features. I think producing the
> "kernel-initrd-modules" meta package should be default in the kernel
> bbclasses. It may not get used but the overhead is really small.
>
> This is similar to "kernel-modules" meta package. It is always there
> and can safely be in MACHINE_EXTRA_RRECOMMENDS without any additional
> guards like a machine or distro feature. Also BSP layer image recipes
> use this.
>

Except that it is much different in that it is not the BSP kernel
configuration
that is controlling what is chosen for the meta-package. It is not the
meta package itself that I have an issue with.


>
> This is the interface between kernel recipes providing kernel and module
> packages and the image recipe consuming them. I'd like the image recipe
> consumer to be simpler and less dependent kernel config and driver
> packaging
> details.
>

It is the selection mechanism that I disagree with. This is one
area that we need to be very explicit and have that fine grained control.


>
> > > Some qemu machines don't and that causes issues since
> > > initrd is not flexible to boot even slightly different configurations,
> > > like block device emulation moved from scsi to virtio.
> > > This causes issues with oeqa selftests when small kernel or qemuboot
> > > differences break tests.
> > >
> >
> > And we'll continue to do that, as all the boot methods and kernels
> > need to be tested. But I agree, there are pros and cons to the
> > various methods.
> >
> > > initrd itself is optional, but in core-image-initramfs-boot I made
> > > including "kernel-initrd-modules" the default. To me this makes sense.
> > >
> > > Kernels for different machines can enable drivers as modules or as
> built-in
> > > but the initrd config stays the same and will mostly just work. I think
> > > this is a good default.
> > >
> > >
> > It is just that behaviour which is why I'm saying it should be
> > explicit and opt-in. If they change their configuration it should
> > be with a direct line of sight to how the various components
> > consume it.
> >
> > Preferably not "I have a custom driver, I need it to boot, I'm
> > now building it as a module" .. and then wondering why it isn't
> > picked up in the initrd. If they had to opt-in, they'll already be
> > aware of the mechanism that is selecting their modules over
> > and above what their kernel configuration dictates.
>
> If the custom and vendor specific driver installs to correct paths
> which fall into block etc driver regex then these already get picked up by
> the
> initrd regex then everything will just work by default. Compiling the
> driver
> built-in or as module will just work with the default
> core-image-initramfs-boot
> initrd and core-image-base etc images. Boot without initrd may fail but
> with it
> things just work.
>

That vendor needs to understand what they are relying on. The same
way that their packages from any other recipe don't automatically get
built and used in an image with them explicitly asking for them in their
image recipes.

That is my point, I don't think this should just "automatically work". It
should have a simple way to opt-in, but behind the scenes magic in
this particular area is just going to cause support issues.


> If this feature is opt-in or specific to linux-yocto recipe, it again
> makes the
> initrd's machine and kernel config specific. The opt-in setup needs to be
> made
> for kernel and for initrd.


> For real products all details need to be reviewed and customized but
> developers
> need "good enough and simple" starting points and that's where the
> "kernel-modules" and "kernel-initrd-modules" meta packages help.
>

After 14 years of working for an OSV, I'm familiar with how a real
product is put together. I've also supported many customers through
the issues I'm describing above. I'm not just describing this theoretically,
I've also spent the hours trying to figure out silent boot death, and
the zillion variations of that.


> They can more easily boot the generic images, see what drivers got loaded
> at boot
> and remove all the rest. Then move that setup into kernel config etc. They
> can
> also test different block devices and file systems.
>
> The amount of optimisation done depends on what the priorities are. Gain
> vs effort.
>
> > > And then "kernel-initrd-modules" are much smaller than
> "kernel-modules".
> > > Still too big for real products but better than nothing. For
> > > genericarm64 this reduced initrd image size from 200 Mb to 54 Mb.
> >
> > Definitely a valid point / improvement. I'm again back to saying it
> > just has to be explicit. The same way that many (most?) people
> > don't want or use linux-yocto as production, we have to design
> > our configurations as something to be opt-in and something that
> > is clear it needs to be tweaked for production.
> >
> > We aren't far off in our view on this.  Most of this looks really
> > good to me, and is a good step forward. I think that our
> > different point of view is about the breadth of the types of
> > kernels, machines, boot methods, products, etc, that are built
> > on top and how to enable this mechanism.
>
> If this feature is opt-in and not the default in kernel.bbclass, then IMO
> the result is again machine/build/config specific initrd image recipes
> which I wanted to avoid.
>

Having a distro feature that enables it, and then having the defaults
kick in, shouldn't be too high of a bar for someone to look, read the
descriptions and decide that's what they want. After that opt-in, everything
should look pretty much like you are proposing.

Bruce


> Cheers,
>
> -Mikko
>
diff mbox series

Patch

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"