[RFC] classes: Add initramfs class

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

Commit Message

Harald Seiler Sept. 21, 2020, 2:42 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.

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

Comments

Jan Kiszka Sept. 21, 2020, 11:25 a.m. UTC | #1
On 21.09.20 12:42, 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.
> 
>   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}"
> +}
> +addtask generate_initramfs after do_rootfs before do_build
> 

I think the public would also benefit from a use / test case, i.e. some 
recipe that inherits this and generates an own initramfs with 
extensions. For merging this, that will be mandatory anyway.

Quirin, what is your impression of this approach?

Jan
Harald Seiler Sept. 22, 2020, 2:34 a.m. UTC | #2
On Mon, 2020-09-21 at 21:25 +0200, Jan Kiszka wrote:
> On 21.09.20 12:42, 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.
> > 
> >   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}"
> > +}
> > +addtask generate_initramfs after do_rootfs before do_build
> > 
> 
> I think the public would also benefit from a use / test case, i.e. some 
> recipe that inherits this and generates an own initramfs with 
> extensions. For merging this, that will be mandatory anyway.

Makes sense.  What do you think would be a good and upstream-viable
example for this?  I can't think of anything trivial _and_ generic that
would still be a sensible use-case - the whole reason for this bbclass is
cases where the a custom initramfs is needed, after all ...

One idea would be to get the remaining dm-verity recipes upstream as well.
This would definitely be quite a bit of work as the ones I have right now
are not entirely generic yet ... Though you mentioned that you're
interested in making them available at some point anyway, so maybe this is
the way to go?

Otherwise (or in addition), I could add a dummy recipe that e.g. just
prints something during boot to meta-isar, to show how it works ...
Jan Kiszka Sept. 22, 2020, 3:04 a.m. UTC | #3
On 22.09.20 12:34, Harald Seiler wrote:
> On Mon, 2020-09-21 at 21:25 +0200, Jan Kiszka wrote:
>> On 21.09.20 12:42, 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.
>>>
>>>    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}"
>>> +}
>>> +addtask generate_initramfs after do_rootfs before do_build
>>>
>>
>> I think the public would also benefit from a use / test case, i.e. some
>> recipe that inherits this and generates an own initramfs with
>> extensions. For merging this, that will be mandatory anyway.
> 
> Makes sense.  What do you think would be a good and upstream-viable
> example for this?  I can't think of anything trivial _and_ generic that
> would still be a sensible use-case - the whole reason for this bbclass is
> cases where the a custom initramfs is needed, after all ...
> 
> One idea would be to get the remaining dm-verity recipes upstream as well.
> This would definitely be quite a bit of work as the ones I have right now
> are not entirely generic yet ... Though you mentioned that you're
> interested in making them available at some point anyway, so maybe this is
> the way to go?
> 
> Otherwise (or in addition), I could add a dummy recipe that e.g. just
> prints something during boot to meta-isar, to show how it works ...
> 

That would have been exactly my suggestion as well. Can still be 
replaced later on when we upstream things like dm-verity generation.

Jan
Quirin Gylstorff Sept. 22, 2020, 4:10 a.m. UTC | #4
On 9/21/20 9:25 PM, Jan Kiszka wrote:
> On 21.09.20 12:42, 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.
>>
>>   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}"
>> +}
>> +addtask generate_initramfs after do_rootfs before do_build
>>
> 
> I think the public would also benefit from a use / test case, i.e. some 
> recipe that inherits this and generates an own initramfs with 
> extensions. For merging this, that will be mandatory anyway.
> 
> Quirin, what is your impression of this approach?
> 
> Jan
> 

 From the first look of it, looks good to me.

Did you test what happens if you try to install a custom kernel module?
Harald Seiler Sept. 22, 2020, 4:18 a.m. UTC | #5
Hi,

On Tue, 2020-09-22 at 14:10 +0200, Gylstorff Quirin wrote:
> 
> On 9/21/20 9:25 PM, Jan Kiszka wrote:
> > On 21.09.20 12:42, 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.
> > > 
> > >   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}"
> > > +}
> > > +addtask generate_initramfs after do_rootfs before do_build
> > > 
> > 
> > I think the public would also benefit from a use / test case, i.e. some 
> > recipe that inherits this and generates an own initramfs with 
> > extensions. For merging this, that will be mandatory anyway.
> > 
> > Quirin, what is your impression of this approach?
> > 
> > Jan
> > 
> 
>  From the first look of it, looks good to me.
> 
> Did you test what happens if you try to install a custom kernel module?

You'll need to add the package for the custom module to INITRAMFS_INSTALL
or INITRAMFS_PREINSTALL as well of course.  If you do that, I don't see
a reason why it shouldn't work (that would be a bug) but I did not test
this so far.

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