Rebuilding the Linux ramdisk
A New Beginning
After moving your hard disk to a new system, the Linux system suddenly fails to boot. Often this happens because of missing drivers in the ramdisk, which the kernel needs to boot the system. In this article, I take a closer look at the handling of the initramfs
file and introduces dracut
[1] as a practical helper.
Many users only see the initramfs
(initial random access memory filesystem) archive file as yet another file in the boot
directory. It is automatically created when a new kernel is installed and deleted again when the kernel is removed from the system. But this initial ramdisk plays an important role, since it ensures that the root filesystem can be accessed after the computer has been restarted, to be able to access all the tools that are necessary for the computer to continue booting.
The GRUB2 bootloader, used in most cases today, is responsible for loading the Linux kernel (vmlinuz
) and a ramdisk (initramfs
) into memory at boot time. The kernel then mounts the ramdisk on the system as a root volume and then starts the actual init
process. On current Linux systems, this is typically systemd. The init
process can then use the drivers and programs provided by initramfs
to gain access to the root volume itself. The root volume is usually available on a local block device but can also be mounted over the network, if required. For this to work, all the required drivers must, of course, be available in the initramfs
.
These can be drivers for LVM, RAID, the filesystem, the network, or a variety of other components. The details of this depend on the individual configuration of the system. For example, if the root filesystem is located on an encrypted partition, the tools for accessing it must be available within the ramdisk.
When installing a new kernel, the ramdisk is automatically created and installed based on the system properties. On RPM-based distributions, for example, the new-kernel-pkg
tool is used; it is called automatically as part of the kernel installation. By default, the ramdisk resides alongside the kernel in the /boot
directory, and a new entry for the bootloader is created so that, after a reboot, the new kernel loads with the appropriate initramfs
.
You can view the contents of the disk with the cpio
tool. The associated file is simply a cpio
archive, but lsinitrd
gives you a more elegant and convenient approach:
lsinitrd /boot/initramfs-$(uname -r).img | less
If you are only interested in the kernel drivers provided by this ramdisk, you can restrict the output:
lsinitrd /boot/initramfs-$(uname -r).img | grep -o '/kernel/drivers/.*xz'
The command in Listing 1 tells the tool to display only the available network card drivers.
Listing 1
Available Network Card Drivers
lsinitrd /boot/initramfs-$(uname -r).img | grep -o '/kernel/drivers/net/.*xz' /kernel/drivers/net/ethernet/broadcom/bnx2x/bnx2x.ko.xz /kernel/drivers/net/ethernet/broadcom/cnic.ko.xz /kernel/drivers/net/mdio.ko.xz
Support from dracut
In some cases, you may now need to create a new ramdisk manually. For example, if you want it to support new hardware or allow access to a newly encrypted volume, you have no alternative but to create a new initramfs
for the current kernel. The easiest way to do this is to use the dracut
tool, which is a framework that provides specific functions within an initial ramdisk based on modules. On a Fedora system these modules are located in the /usr/lib/dracut/modules.d/
directory. For Linux veterans, dracut
also offers a wrapper named mkinitrd
, but it is far less flexible than calling dracut
directly. To create a new initramfs
archive, just run the following command in the simplest case:
dracut --force /boot/initramfs-$(uname -r).img
The tool uses host-only mode by default and overwrites the existing initramfs
file if the --force
option is set. In this mode, dracut
only uses the modules and drivers needed for the operation of the local system. If you plan to use the hard disk in a new system in the future, disable host-only mode as follows:
dracut --no-hostonly /boot/initramfs-$(uname -r)-new.img
The fact that dracut
now writes far more data into the initramfs
file is easily seen by comparing the sizes of the two files (Listing 2).
Listing 2
File Size Comparison
ls -ls /boot/initramfs-$(uname -r)*.img 24350 -rw-------. 1 root root 24932655 Apr 16 16:01 /boot/initramfs-4.20.10-200.fc29.x86_64.img 69242 -rw-------. 1 root root 70901695 Apr 16 16:04 /boot/initramfs-4.20.10-200.fc29.x86_64-new.img
The following command shows which modules – and thus functions – dracut
provides:
dracut --list-modules
If you want to use a new ramdisk on a system on which the Clevis encryption framework is required to enable access to the root partition, the matching dracut
module needs to be included in the initramfs
file. The output from dracut --list-modules
should first confirm that dracut
is familiar with the Clevis module. If this is the case, include the module in the initramfs
archive as follows:
dracut --add clevis /boot/initramfs-$(uname -r)-clevis.img
The following call should confirm that the files belonging to the Clevis module are now part of the initramfs
:
lsinitrd /boot/initramfs-$(uname -r)-clevis.img|grep clevis
To include a specific kernel driver in the initramfs
, you can use the command:
dracut --add-drivers bnx2x /boot/initramfs-$(uname -r)-bnx2x.img
Here, too, the call to lsinitrd
should confirm that the drivers are in place in the archive. Which drivers or modules are required, of course, depends on the system on which the initramfs
is to be used.
By default, dracut
always creates an initramfs
archive for the kernel currently in use. In some cases, it may be necessary to create the archive file for a different kernel version. This is easily done if the desired kernel version is specified with the --kver
option when calling dracut
(Listing 3).
Listing 3
Specify Kernel Version
dracut --kver 3.10.0-957.el7.x86_64 /boot/initramfs-$(uname -r)-other-kernel.img ls -l /boot/initramfs-3.10.0-957.el7.x86_64.img -rw-------. 1 root root 22913501 Apr 14 11:00 /boot/initramfs-3.10.0-957.el7.x86_64.img
Troubleshooting the Shell
If the system does not boot as usual and access to the root volume is not possible, dracut
provides a shell for troubleshooting, if required. It is a good idea to make the following changes to the bootloader configuration to facilitate troubleshooting. In the bootloader configuration you need to remove the rhgb
and quiet
entries, if present, to ensure that messages are displayed on the screen when booting.
Additionally, add the rd.shell
and rd.debug
entries to the kernel line of the bootloader so that dracut
starts a corresponding shell in case of an error and outputs further debug messages. The dracut
tool also writes the messages to the /run/initramfs/rdsosreport.txt
file. Both changes can be made either statically in the bootloader configuration file or by dynamically editing the boot menu entry.
Conclusions
Thanks to dracut
, all the major Linux distributions provide a framework for creating an initial ramdisk. The framework is very flexible, supports booting a system from many different sources, and enables block device abstractions like RAID, LVM device mapper, FCoE, iSCSI, NBD, and NFS. Thanks to its modular structure, the tool can be easily combined with other frameworks to enable, say, automatic decryption of LUKS volumes through Clevis integration.
Infos
Buy this article as PDF
(incl. VAT)