I need to load driver on early stage booting. For development I use LVM (logical volume manager) so I can easily revert test setups to the default image from a snapshot. For this I have to load the lvm driver before accessing the root partition. This is done with an init ramdisk (initrd or initramfs). This is also good to support custom kernel. But unlike Debian, Raspbian does not support initramfs out of the box. How can I use an init ramdisk?
5 Answers
I have found that there is a setup in
rpi ~$ cat /etc/default/raspberrypi-kernel
# Defaults for raspberrypi-kernel
# Uncomment the following line to enable generation of
# /boot/initrd.img-KVER files (requires initramfs-tools)
#INITRD=Yes
# Uncomment the following line to enable generation of
# /boot/initrd(7).img files (requires rpi-initramfs-tools)
#RPI_INITRD=Yes
The comments there are the only documentation I have found. In particular I can't find anything about rpi-initramfs-tools
. They are simply not available. So I tested with INITRD=Yes
by uncommenting it because initramfs-tools
are installed by default. Then to create an initramfs I execute
rpi ~$ sudo update-initramfs -c -k $(uname -r)
and it works like a charm. You must also do it to generate the first initramfs. It produces one for example /boot/initrd.img-4.14.71-v7+
. From now on you can simply update with:
rpi ~$ sudo update-initramfs -u
ln: failed to create hard link '/boot/initrd.img-4.14.71-v7+.dpkg-bak' => '/boot/initrd.img-4.14.71-v7+': Operation not permitted
update-initramfs: Generating /boot/initrd.img-4.14.71-v7+
As you see you will get a warning (it's not an error) from ln
. The boot partition has a fat filesystem that does not support links but it doesn't matter. The only problem is that it needs an entry in /boot/config.txt
like
initramfs initrd.img-4.14.71-v7+
(without equal sign)
Otherwise the boot loader cannot find the ramdisk and boot up fails.
With Raspbian we have also two kernel images, for example /boot/initrd.img-4.14.71
and /boot/initrd.img-4.14.71-v7+
and by default update-initramfs generates an init ramddisk for each kernel but that will not fit onto the limited space of the boot partition. So we have also to ensure that we only generate an initramfs for the running kernel.
Managing initramfs is done with the script /etc/kernel/postinst.d/initramfs-tools
. We have to modify this script as follows.
Edit /etc/default/raspberrypi-kernel
to comment out INITRD
and uncomment RPI_INITRD
instead.
Then create a file
rpi ~$ sudo editor /etc/kernel/postinst.d/rpi-initramfs-tools
with this content:
#!/bin/bash -e
# Environment variables are set by the calling script
version="$1"
bootopt=""
command -v update-initramfs >/dev/null 2>&1 || exit 0
passing the kernel version is required
if [ -z "${version}" ]; then
echo >&2 "W: initramfs-tools: ${DPKG_MAINTSCRIPT_PACKAGE:-kernel package} did not pass a version number"
exit 2
fi
exit if kernel does not need an initramfs
if [ "$RPI_INITRD" = 'No' ]; then
# delete initramfs entries in /boot/config.txt
/bin/sed -i '/^initramfs /d' /boot/config.txt
exit 0
fi
there are only two kernel types: with and without postfix "-v7+" or "-v8+"
currentversion="$(uname -r)"
get §currenttype from $currentversion
currenttype="<no currenttype>"
echo $currentversion | grep -Pq '^\d+.\d+.\d++$' && currenttype="+"
echo $currentversion | grep -Pq '^\d+.\d+.\d+-v[78]+$' && currenttype="${currentversion#*-}"
get $newtype from $version
newtype="<no newtype>"
echo $version | grep -Pq '^\d+.\d+.\d++$' && newtype="+"
echo $version | grep -Pq '^\d+.\d+.\d+-v[78]+$' && newtype="${version#*-}"
we do nothing if the new kernel is not for the same kernel type then the current
if [ "$newtype" != "$currenttype" ]; then
exit 0
fi
absolute file name of kernel image may be passed as a second argument;
create the initrd in the same directory
if [ -n "$2" ]; then
bootdir=$(dirname "$2")
bootopt="-b ${bootdir}"
fi
avoid running multiple times
if [ -n "$DEB_MAINT_PARAMS" ]; then
eval set -- "$DEB_MAINT_PARAMS"
if [ -z "$1" ] || [ "$1" != "configure" ]; then
exit 0
fi
fi
we're good - create initramfs. update runs do_bootloader
INITRAMFS_TOOLS_KERNEL_HOOK=1 update-initramfs -c -t -k "${version}" ${bootopt} >&2
delete initramfs entries in /boot/config.txt
/bin/sed -i '/^initramfs /d' /boot/config.txt
insert initramfs entry in /boot/config.txt
INITRD_ENTRY="initramfs initrd.img-${version} followkernel"
echo >&2 $(basename "$0"): insert '"$INITRD_ENTRY"' into /boot/config.txt
/bin/sed -i "1i $INITRD_ENTRY" /boot/config.txt
Make the script executable:
rpi ~$ sudo chmod 755 /etc/kernel/postinst.d/rpi-initramfs-tools
The extensions in the script ensures that an initramfs is only created for the current running kernel and that there is managed an entry in /boot/config.txt
. If you like to see the changes you can do it with diff --ignore-tab-expansion ~/initramfs-tools /etc/kernel/postinst.d/rpi-initramfs-tools
.
For manual updates we create:
rpi ~$ sudo editor /usr/local/sbin/update-rpi-initramfs
with this content:
#!/bin/bash
# This script calls default update-initramfs
# and then insert a 'initramfs' entry into /boot/config.txt if necessary
should return e.g. "update-initramfs: Generating /boot/initrd.img-4.14.79-v7+"
or "update-initramfs: Deleting /boot/initrd.img-4.14.71-v7+"
MSG=$(/usr/sbin/update-initramfs "$@")
RETCODE=$?
echo $MSG
if [[ $RETCODE -ne 0 ]]; then
echo >&2 ATTENTION! Check 'initramfs' entry in /boot/config.txt
exit "$RETCODE"
fi
CMP="update-initramfs: Deleting *"
if [[ $MSG == $CMP ]]; then
# delete initramfs entries in /boot/config.txt
/bin/sed -i '/^initramfs /d' /boot/config.txt
echo $(basename "$0"): deleted all 'initramfs' entries from /boot/config.txt
exit 0
fi
CMP="update-initramfs: Generating *"
if [[ $MSG == $CMP ]]; then
# delete initramfs entries in /boot/config.txt
/bin/sed -i '/^initramfs /d' /boot/config.txt
# exit if kernel does not need an initramfs
source /etc/default/raspberrypi-kernel
if [ "${INITRD,,}" != 'yes' ]; then
echo $(basename "$0"): no entry in /boot/config.txt \(see INITRD in /etc/default/raspberrypi-kernel\)
exit 0
fi
# insert initramfs entry in /boot/config.txt
VERSION=$(basename "$MSG")
INITRD_ENTRY="initramfs $VERSION"
echo $(basename "$0"): insert \'"$INITRD_ENTRY"\' into /boot/config.txt
/bin/sed -i "1i $INITRD_ENTRY" /boot/config.txt
exit 0
fi
echo >&2 ATTENTION! Check 'initramfs' entry in /boot/config.txt
exit 1
Set permissions:
rpi ~$ sudo chmod 755 /usr/local/sbin/update-rpi-initramfs
From now on you should only use update-rpi-initramfs
instead of update-initramfs
, for example:
rpi ~$ sudo update-rpi-initramfs -u
This ensures that you always have the right entry in /boot/config.txt
.
References:
[1] Package maintainer scripts and hooks
I can offer an alternative solution.
Instead of renaming the initramfs-image and modifying the existing /etc/kernel/postinst.d/* files, I added an initramfs hook that modifies /boot/config.txt so that it will load the initramfs with its current name.
Therefore, there is no need to rename the initramfs any longer after creation, and it can use the standard name chosen by the initramfs generation scripts (i. e. initrd.img-$KERNELRELEASE).
The script is customizable by setting variables for all important path name components at its beginning, so that all customizable settings are in one place.
The script also avoids updating config.txt if it already contains the current name of the actual initramfs image, saving the life endurance of your SD card a little.
Before you install the hook, make sure your /boot/config.txt contains the line which the hook attempts to update.
That line must have a format like the last one in the following section from my config.txt:
# Important: This value will be updated by initramfs generation scripts.
#
# Special syntax: Do not use "=" for assignment here.
initramfs initrd.img-4.19.42-v7+ followkernel
I named the hook script
/etc/initramfs-tools/hooks/update_initrd_ref_qaumv1g34z54324pbel831evd
which contains a UUID at the end of its name, so there is no danger of name collisions with existing or future scripts of the same name. However, the name does not really matter; feel free to rename it as long as you leave it in the same directory.
And here are the contents of that script:
#! /bin/sh -e
# Update reference to $INITRD in $BOOTCFG, making the kernel use the new
# initrd after the next reboot.
BOOTLDR_DIR=/boot
BOOTCFG=$BOOTLDR_DIR/config.txt
INITRD_PFX=initrd.img-
INITRD=$INITRD_PFX$version
case $1 in
prereqs) echo; exit
esac
FROM="^ *\\(initramfs\\) \\+$INITRD_PFX.\\+ \\+\\(followkernel\\) *\$"
INTO="\\1 $INITRD \\2"
T=`umask 077 && mktemp --tmpdir genramfs_XXXXXXXXXX.tmp`
trap "rm -- \"$T\"" 0
sed "s/$FROM/$INTO/" "$BOOTCFG" > "$T"
# Update file only if necessary.
if ! cmp -s "$BOOTCFG" "$T"
then
cat "$T" > "$BOOTCFG"
fi
Note that this is a script, so you need to
$ chmod +x /etc/initramfs-tools/hooks/update_initrd_ref_qaumv1g34z54324pbel831evd
after creating it.
This is actually all there is to it - run
$ update-initramfs -u
as usual, and the contents of /boot/config.txt should "automagically" match the name of your /boot/initrd.img-* file.

- 501
- 1
- 5
- 11
-
Thanks for the suggestion. I will test it in detail. Just had only a glance at it. Does this script will be triggered automatically on kernel updates like on debian by default? – Ingo Jul 03 '19 at 19:52
-
-
-
Worked quite well on this 64-bit Raspbian Bullseye install to load the
vc4
driver for early KMS! – genpfault Jan 28 '22 at 04:24 -
Elegant and concise alternative option. One enhancement could be to have
/etc/initramfs-tools/hooks/update_initrd_ref_qaumv1g34z54324pbel831evd
check if/boot/config.txt
already have the lineinitramfs initrd.img-*
. If it does, then do thesed "s/$FROM/$INTO/" "$BOOTCFG" > "$T"
else build the line from the variables you already have and insert that line in/boot/config.txt
. – Thomas Nov 18 '23 at 04:48
I've used a different solution, adding a hook in the /etc/kernel/postinst.d
directory. It has been working for a while, but I am about to make a miniscule change that I will include here that hasn't been tested because I want to include the ability to run the v8 kernel. So I added this script as /etc/kernel/postinst.d/rebuild
#!/bin/sh -e
# Rebuild initramfs{7,8}.img after kernel upgrade to include new kernel’s modules.
#
# Exit if rebuild cannot be performed or not needed.
[ -x /usr/sbin/mkinitramfs ] || exit 0
# Exit if not building kernel for this Raspberry Pi’s hardware version (assume armv7l or aarch64).
version="$1"
case "${version}" in
*-v7+) arch=7;;
*-v8+) arch=8;;
*) exit 0
esac
[ -f /boot/initramfs$arch.img ] && lsinitramfs /boot/initramfs$arch.img | grep -q "/$version$" && exit 0 # Already in initramfs.
# Rebuild.
mkinitramfs -o /boot/initramfs$arch.img "$version"
making it executable. I don't touch the the /etc/default/raspberrypi-kernel
file at all.
I do edit /boot/config.txt
to either include initramfs initramfs7.img followkernel
or initramfs initramfs8.img followkernel
and arm_64bit=1
. I don't mind making that small distinction which I think is necessary so often I can undo the arm_64bit
flag if I want. It only

- 111
- 3
the script called during the kernel installation must be slightly edited because otherwise it will exit with error code 1 if grep doesn't match
#!/bin/sh -e
# Environment variables are set by the calling script
version="$1"
bootopt=""
command -v update-initramfs >/dev/null 2>&1 || exit 0
# passing the kernel version is required
if [ -z "${version}" ]; then
echo >&2 "W: initramfs-tools: ${DPKG_MAINTSCRIPT_PACKAGE:-kernel package} did not pass a version number"
exit 2
fi
# exit if kernel does not need an initramfs
if [ "$INITRD" = 'No' ]; then
# delete initramfs entries in /boot/config.txt
/bin/sed -i '/^initramfs /d' /boot/config.txt
exit 0
fi
# there are only two kernel types: with and without postfix "-v7+" or "-v8+"
currentversion="$(uname -r)"
# get §currenttype from $currentversion
currenttype="<no currenttype>"
if [ `echo $currentversion | grep -P '^\d+\.\d+\.\d+\+$'` ]; then
[ $? -eq 0 ] && currenttype="+"
else [ `echo $currentversion | grep -P '^\d+\.\d+\.\d+-v[78]l?\+$'` ];
[ $? -eq 0 ] && currenttype="${currentversion#*-}"
fi
# get $newtype from $version
newtype="<no newtype>"
if [ `echo $version | grep -P '^\d+\.\d+\.\d+\+$'` ]; then
[ $? -eq 0 ] && newtype="+"
else [ `echo $version | grep -P '^\d+\.\d+\.\d+-v[78]l?\+$'` ];
[ $? -eq 0 ] && newtype="${version#*-}"
fi
# we do nothing if the new kernel is not for the same kernel type then the current
if [ "$newtype" != "$currenttype" ]; then
exit 0
fi
# absolute file name of kernel image may be passed as a second argument;
# create the initrd in the same directory
if [ -n "$2" ]; then
bootdir=$(dirname "$2")
bootopt="-b ${bootdir}"
fi
# avoid running multiple times
if [ -n "$DEB_MAINT_PARAMS" ]; then
eval set -- "$DEB_MAINT_PARAMS"
if [ -z "$1" ] || [ "$1" != "configure" ]; then
exit 0
fi
fi
# we're good - create initramfs. update runs do_bootloader
INITRAMFS_TOOLS_KERNEL_HOOK=1 update-initramfs -c -k "${version}" ${bootopt} >&2
# delete initramfs entries in /boot/config.txt
/bin/sed -i '/^initramfs /d' /boot/config.txt
# insert initramfs entry in /boot/config.txt
INITRD_ENTRY="initramfs initrd.img-${version} followkernel"
echo >&2 $(basename "$0"): insert \'"$INITRD_ENTRY"\' into /boot/config.txt
/bin/sed -i "1i $INITRD_ENTRY" /boot/config.txt

- 11
- 2
Not tested this but have used a similar method to add overlayfs
modules and a custom scripts to the the initramfs
to enable RO operation. If all you want is to add the LVM modules to the initramfs
I think all you need to do is:
- Add the modules you want to include to
/etc/initramfs-tools/modules
. - Add any support scripts you need to run during boot to '/etc/initramfs-tools/scripts/...'.
- Run
mkinitramfs -o /boot/initrd
to build theinitramfs
- Add
initramfs initrd followkernel
to your/boot/config.txt
to enable it. - Reboot.
EDIT:
As Ingo pointed out in the comments this method does not automatically recompile the initramfs
as a part of any system updates. You'd have to manually re-run mkinitramfs -o /boot/initrd
to compile a new image with, for example, a new LVM module to match a newly installed kernel. So, might not be suitable for what you need.

- 1,494
- 7
- 14
-
1Hi Roger, many thanks for your feedback.
I'm using an initramfs for a long time. [..] But it is a little bit dangerous because automatic updating a initramfs isn't supported by Raspbian.
More details about my motivation to make this triggered update you can read at Custom initramfs. Adding support scripts inetc/initramfs-tools/scripts/
doesn't triggerupdate-initramfs
on kernel updates. – Ingo Jan 14 '19 at 12:46 -
If the
followkernel
option is that what it looks like it would be a very useful hint to simplify my scripts. I will look at it. Btw. I also useoverlayfs
for How do I make the OS reset itself every time it boots up? but I don't need aninitframfs
for it becauseoverlayfs
is part of the kernel. – Ingo Jan 14 '19 at 13:21 -
@Ingo That's a fair comment about this method not automatically rebuilding the
initramfs
. Wasn't a consideration for what we were doing as the final disk image was more or less static once burned to the SD card (we'd not expect our users to runapt-get
). I'll amend my answer to clarify that point. Was not aware thatunionfs
was in the stock kernel but made extensive use of theinitramfs
scripts anyway to delay the boot whilst a UPS charged up and so on. – Roger Jones Jan 14 '19 at 15:23 -
I have tested
initramfs initrd followkernel
. It has no effect. The bootloader does not use an initramfs if initrd does not exactly match the name in/boot/
, e.g.initrd.img-4.14.79-v7+
. I have considered to rename the initrd to a generic name but then I have no control over tne version. Don't k now what's better ... – Ingo Jan 14 '19 at 15:26 -
@ingo Sorry, didn't read your answer properly and you're already using
sed
to editconfig.txt
. I believe thatinitramfs-tools
exports the version as a variable, can you edit yoursed
command to change theinitramfs
line to contain the new version instead? Something likesed -i "s/^initramfs\\ initrd.*/initramfs\\ initrd.img-${version}/" /boot/config.txt
? http://manpages.ubuntu.com/manpages/xenial/man8/initramfs-tools.8.html – Roger Jones Jan 14 '19 at 15:55 -
@Ingo I mean't to add a suggestion about running
sed
from the/etc/initramfs-tools/hooks/
directory to editconfig.txt
so it's a part of the compilation rather than the postinstall. Feels to me that it should be part of the compilation (so thatmkinitramfs
works too) but there's no obvious way to do it safely within the initramfs-tools environment. – Roger Jones Jan 14 '19 at 16:13
sudo mv -i /etc/kernel/postinst.d/initramfs-tools ~
, based on references to/etc/kernel/postinst.d/initramfs-tools
and than later diffing against~/initramfs-tools
(without disabling the former any other way as far as I can see). – n8henrie Mar 23 '21 at 19:20