[v3,1/3] classes: Add initramfs class

Message ID 20210114101156.243184-1-hws@denx.de
State Superseded, archived
Headers show
Series [v3,1/3] classes: Add initramfs class | expand

Commit Message

Harald Seiler Jan. 14, 2021, 12:11 a.m. UTC
Add a new "image" class for generating a custom initramfs.  It works
like this: A new minimal debian rootfs is bootstrapped and all
dependency packages for the new initramfs are installed.  Then, an
initramfs is generated from this rootfs and deployed like usual.

This new initramfs.bbclass "image" class should be pulled in by an
"initramfs image" recipe.  Said recipe then specifies all dependencies
of the initramfs via INITRAMFS_INSTALL and INITRAMFS_PREINSTALL (which
are analogous to the respective IMAGE_* variables).

initramfs.bbclass intentionally does _not_ expose a mechanism to change
/etc/initramfs-tools/initramfs.conf and /etc/initramfs-tools/modules.
Changes to their settings are better done via packages that deploy
conf-hooks to /usr/share/initramfs-tools/conf-hooks.d/ and module
fragment files to /usr/share/initramfs-tools/modules.d/.

Signed-off-by: Harald Seiler <hws@denx.de>
---

Notes:
    I had this idea while searching for a way to build an initramfs that
    uses dm-verity to assert integrity of the rootfs.  To me, this feels
    like a much cleaner solution than anything else I tried and I'm happy to
    report that, using this approach, I got everything working nicely in the
    original project.
    
    In my opinion, this design has a number of advantages over the previous
    solutions we have seen so far:
    
     - It does not suffer any kind of initramfs pollution, caused by
       packages installed into a rootfs.  This is a big problem when trying
       to generated an initramfs from e.g. `buildchroot-target` as many
       unrelated packaged could be installed there which would all get
       pulled into the initrd (if they install hooks/scripts).
    
       This also means, with this new approach, the integrator has maximum
       control over the contents of the initramfs.
    
     - There are no needs to change the initramfs generation process in any
       way, the debian tooling can be used exactly like its meant to.
    
     - As most isar-generated images will never regenerate the initramfs
       from the running system, all initramfs related packages are dead-weight
       to the image.  This is a problem when trying to generate the initramfs
       from the actual image rootfs.
    
       When it is necessary to rebuild the initramfs in a running system,
       the packages designed for this new class could just be installed into
       the rootfs, without any changes necessary.  This means, any generic
       initramfs module packages can be used both with the in-rootfs mechanism
       and initramfs.bbclass.
    
     - Because of this complete isolation and independence, implementation
       of complex logic is much easier:  For example dm-verity needs
       a root-hash that is only available after the rootfs has been cast into
       a filesystem image.  With this new approach, this can be modelled with
       a simple task dependency.
    
    Changes in v2:
    - None (just added examples in new patches)
    
    Changes in v3:
    - None

 meta/classes/initramfs.bbclass | 41 ++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 meta/classes/initramfs.bbclass

Comments

Florian Bezdeka Jan. 17, 2021, 11:11 p.m. UTC | #1
On Thu, 2021-01-14 at 11:11 +0100, Harald Seiler wrote:
> Add a new "image" class for generating a custom initramfs.  It works
> like this: A new minimal debian rootfs is bootstrapped and all
> dependency packages for the new initramfs are installed.  Then, an
> initramfs is generated from this rootfs and deployed like usual.
> 
> This new initramfs.bbclass "image" class should be pulled in by an
> "initramfs image" recipe.  Said recipe then specifies all dependencies
> of the initramfs via INITRAMFS_INSTALL and INITRAMFS_PREINSTALL (which
> are analogous to the respective IMAGE_* variables).
> 
> initramfs.bbclass intentionally does _not_ expose a mechanism to change
> /etc/initramfs-tools/initramfs.conf and /etc/initramfs-tools/modules.
> Changes to their settings are better done via packages that deploy
> conf-hooks to /usr/share/initramfs-tools/conf-hooks.d/ and module
> fragment files to /usr/share/initramfs-tools/modules.d/.
> 
> Signed-off-by: Harald Seiler <hws@denx.de>
> ---
> 
> Notes:
>     I had this idea while searching for a way to build an initramfs that
>     uses dm-verity to assert integrity of the rootfs.  To me, this feels
>     like a much cleaner solution than anything else I tried and I'm happy to
>     report that, using this approach, I got everything working nicely in the
>     original project.
>     
> 
> 
> 
>     In my opinion, this design has a number of advantages over the previous
>     solutions we have seen so far:
>     
> 
> 
> 
>      - It does not suffer any kind of initramfs pollution, caused by
>        packages installed into a rootfs.  This is a big problem when trying
>        to generated an initramfs from e.g. `buildchroot-target` as many
>        unrelated packaged could be installed there which would all get
>        pulled into the initrd (if they install hooks/scripts).
>     
> 
> 
> 
>        This also means, with this new approach, the integrator has maximum
>        control over the contents of the initramfs.
>     
> 
> 
> 
>      - There are no needs to change the initramfs generation process in any
>        way, the debian tooling can be used exactly like its meant to.
>     
> 
> 
> 
>      - As most isar-generated images will never regenerate the initramfs
>        from the running system, all initramfs related packages are dead-weight
>        to the image.  This is a problem when trying to generate the initramfs
>        from the actual image rootfs.
>     
> 
> 
> 
>        When it is necessary to rebuild the initramfs in a running system,
>        the packages designed for this new class could just be installed into
>        the rootfs, without any changes necessary.  This means, any generic
>        initramfs module packages can be used both with the in-rootfs mechanism
>        and initramfs.bbclass.
>     
> 
> 
> 
>      - Because of this complete isolation and independence, implementation
>        of complex logic is much easier:  For example dm-verity needs
>        a root-hash that is only available after the rootfs has been cast into
>        a filesystem image.  With this new approach, this can be modelled with
>        a simple task dependency.
>     
> 
> 
> 
>     Changes in v2:
>     - None (just added examples in new patches)
>     
> 
> 
> 
>     Changes in v3:
>     - None
> 
>  meta/classes/initramfs.bbclass | 41 ++++++++++++++++++++++++++++++++++
>  1 file changed, 41 insertions(+)
>  create mode 100644 meta/classes/initramfs.bbclass
> 
> diff --git a/meta/classes/initramfs.bbclass b/meta/classes/initramfs.bbclass
> new file mode 100644
> index 000000000000..8af9b4b379a5
> --- /dev/null
> +++ b/meta/classes/initramfs.bbclass
> @@ -0,0 +1,41 @@
> +# This software is a part of ISAR.
> +
> +# Make workdir and stamps machine-specific without changing common PN target
> +WORKDIR = "${TMPDIR}/work/${DISTRO}-${DISTRO_ARCH}/${PN}-${MACHINE}/${PV}-${PR}"
> +STAMP = "${STAMPS_DIR}/${DISTRO}-${DISTRO_ARCH}/${PN}-${MACHINE}/${PV}-${PR}"
> +STAMPCLEAN = "${STAMPS_DIR}/${DISTRO}-${DISTRO_ARCH}/${PN}-${MACHINE}/*-*"
> +
> +INITRAMFS_INSTALL ?= ""
> +INITRAMFS_PREINSTALL ?= ""
> +INITRAMFS_ROOTFS ?= "${WORKDIR}/rootfs"
> +INITRAMFS_IMAGE_FILE = "${DEPLOY_DIR_IMAGE}/${INITRAMFS_FULLNAME}.initrd.img"
> +
> +# Install proper kernel
> +INITRAMFS_INSTALL += "${@ ("linux-image-" + d.getVar("KERNEL_NAME", True)) if d.getVar("KERNEL_NAME", True) else ""}"
> +
> +# Name of the initramfs including distro&machine names
> +INITRAMFS_FULLNAME = "${PN}-${DISTRO}-${MACHINE}"
> +
> +DEPENDS += "${INITRAMFS_INSTALL}"
> +
> +ROOTFSDIR = "${INITRAMFS_ROOTFS}"
> +ROOTFS_FEATURES = ""
> +ROOTFS_PACKAGES = "initramfs-tools ${INITRAMFS_PREINSTALL} ${INITRAMFS_INSTALL}"
> +
> +inherit rootfs
> +
> +do_generate_initramfs() {
> +    rootfs_do_mounts
> +    rootfs_do_qemu
> +
> +    sudo -E chroot "${INITRAMFS_ROOTFS}" \
> +        update-initramfs -u -v
> +
> +    if [ ! -e "${INITRAMFS_ROOTFS}/initrd.img" ]; then
> +        die "No initramfs was found after generation!"
> +    fi
> +
> +    rm -rf "${INITRAMFS_IMAGE_FILE}"
> +    cp "${INITRAMFS_ROOTFS}/initrd.img" "${INITRAMFS_IMAGE_FILE}"

${INITRAMFS_IMAGE_FILE} references ${DEPLOY_DIR_IMAGE}, which may not
exist yet. So I guess we should add something like 

do_generate_initramfs[dirs] = "${DEPLOY_DIR_IMAGE}"

otherwise you have fix the dependency with some kind of "intermediate
task" in the recipe using this class.
 
> +}
> +addtask generate_initramfs after do_rootfs before do_build
> -- 
> 2.29.2
>
Harald Seiler Jan. 18, 2021, midnight UTC | #2
Hi Florian,

On Mon, 2021-01-18 at 09:11 +0000, florian.bezdeka@siemens.com wrote:
> On Thu, 2021-01-14 at 11:11 +0100, Harald Seiler wrote:
> > Add a new "image" class for generating a custom initramfs.  It works
> > like this: A new minimal debian rootfs is bootstrapped and all
> > dependency packages for the new initramfs are installed.  Then, an
> > initramfs is generated from this rootfs and deployed like usual.
> > 
> > This new initramfs.bbclass "image" class should be pulled in by an
> > "initramfs image" recipe.  Said recipe then specifies all dependencies
> > of the initramfs via INITRAMFS_INSTALL and INITRAMFS_PREINSTALL (which
> > are analogous to the respective IMAGE_* variables).
> > 
> > initramfs.bbclass intentionally does _not_ expose a mechanism to change
> > /etc/initramfs-tools/initramfs.conf and /etc/initramfs-tools/modules.
> > Changes to their settings are better done via packages that deploy
> > conf-hooks to /usr/share/initramfs-tools/conf-hooks.d/ and module
> > fragment files to /usr/share/initramfs-tools/modules.d/.
> > 
> > Signed-off-by: Harald Seiler <hws@denx.de>
> > ---
> > 
[...]
> > +
> > +do_generate_initramfs() {
> > +    rootfs_do_mounts
> > +    rootfs_do_qemu
> > +
> > +    sudo -E chroot "${INITRAMFS_ROOTFS}" \
> > +        update-initramfs -u -v
> > +
> > +    if [ ! -e "${INITRAMFS_ROOTFS}/initrd.img" ]; then
> > +        die "No initramfs was found after generation!"
> > +    fi
> > +
> > +    rm -rf "${INITRAMFS_IMAGE_FILE}"
> > +    cp "${INITRAMFS_ROOTFS}/initrd.img" "${INITRAMFS_IMAGE_FILE}"
> 
> ${INITRAMFS_IMAGE_FILE} references ${DEPLOY_DIR_IMAGE}, which may not
> exist yet. So I guess we should add something like 
> 
> do_generate_initramfs[dirs] = "${DEPLOY_DIR_IMAGE}"
> 
> otherwise you have fix the dependency with some kind of "intermediate
> task" in the recipe using this class.

Yeah, I actually did this exact change in a downstream version of the
recipe but somehow forgot to add it here ... Will fix!

Harald

> > +}
> > +addtask generate_initramfs after do_rootfs before do_build
> > -- 
> > 2.29.2
> > 
>

Patch

diff --git a/meta/classes/initramfs.bbclass b/meta/classes/initramfs.bbclass
new file mode 100644
index 000000000000..8af9b4b379a5
--- /dev/null
+++ b/meta/classes/initramfs.bbclass
@@ -0,0 +1,41 @@ 
+# This software is a part of ISAR.
+
+# Make workdir and stamps machine-specific without changing common PN target
+WORKDIR = "${TMPDIR}/work/${DISTRO}-${DISTRO_ARCH}/${PN}-${MACHINE}/${PV}-${PR}"
+STAMP = "${STAMPS_DIR}/${DISTRO}-${DISTRO_ARCH}/${PN}-${MACHINE}/${PV}-${PR}"
+STAMPCLEAN = "${STAMPS_DIR}/${DISTRO}-${DISTRO_ARCH}/${PN}-${MACHINE}/*-*"
+
+INITRAMFS_INSTALL ?= ""
+INITRAMFS_PREINSTALL ?= ""
+INITRAMFS_ROOTFS ?= "${WORKDIR}/rootfs"
+INITRAMFS_IMAGE_FILE = "${DEPLOY_DIR_IMAGE}/${INITRAMFS_FULLNAME}.initrd.img"
+
+# Install proper kernel
+INITRAMFS_INSTALL += "${@ ("linux-image-" + d.getVar("KERNEL_NAME", True)) if d.getVar("KERNEL_NAME", True) else ""}"
+
+# Name of the initramfs including distro&machine names
+INITRAMFS_FULLNAME = "${PN}-${DISTRO}-${MACHINE}"
+
+DEPENDS += "${INITRAMFS_INSTALL}"
+
+ROOTFSDIR = "${INITRAMFS_ROOTFS}"
+ROOTFS_FEATURES = ""
+ROOTFS_PACKAGES = "initramfs-tools ${INITRAMFS_PREINSTALL} ${INITRAMFS_INSTALL}"
+
+inherit rootfs
+
+do_generate_initramfs() {
+    rootfs_do_mounts
+    rootfs_do_qemu
+
+    sudo -E chroot "${INITRAMFS_ROOTFS}" \
+        update-initramfs -u -v
+
+    if [ ! -e "${INITRAMFS_ROOTFS}/initrd.img" ]; then
+        die "No initramfs was found after generation!"
+    fi
+
+    rm -rf "${INITRAMFS_IMAGE_FILE}"
+    cp "${INITRAMFS_ROOTFS}/initrd.img" "${INITRAMFS_IMAGE_FILE}"
+}
+addtask generate_initramfs after do_rootfs before do_build