Investigations into significantly reducing size of /boot/initrd.img files

The default action of Ubuntu's initramfs-tools is to include almost all the available kernel modules and supporting firmware files in the initialramfs file-system regardless of if those modules or firmware are actually used by the system.

Typically this results in the /boot/initrd.img-... files being larger than 60MB. This has to be read into memory by the bootloader along with the kernel (/boot/vmlinuz-...) which can result in a significant delay during start-up for the read and then the kernel having to uncompress it into memory. The time taken to build the initrd.img also causes relatively long delays when installing linux-image-... package upgrades.

It is possible to reduce the file size to around 20MB or less with no loss of functionality with additional patches I've developed for initramfs-tools and the Linux kernel.

ASCIInema demo

Benefits of reduction

Here is an overview:

# default
MODULES=most
-rw------- 1 root root 62714412 Jan  4 13:40 /boot/initrd.img-4.18.0-13-lowlatency
# dependencies only
MODULES=dep
-rw------- 1 root root 44797560 Jan  4 14:11 /boot/initrd.img-4.18.0-13-lowlatency
# dependencies + module pruning
MODULES=dep
PRUNE=true
No Kernel firmware_loaded list
-rw------- 1 root root 32342468 Jan  4 18:49 /boot/initrd.img-4.18.0-13-lowlatency
# dependencies +module pruning + firmware pruning
MODULES=dep
PRUNE=true
Kernel firmware_loaded list
-rw------- 1 root root 22148830 Jan  4 14:12 /boot/initrd.img-4.18.0-13-lowlatency

Existing initramfs-tools configuration options

The list of files to be included is controlled by /etc/initramfs-tools/initramfs.conf and the parameter:

MODULES=most

By changing this to:

MODULES=dep

only modules required by the system will be included. This can typically result in ~30% reduction in size (to around 40MB).

Plymouth package

At this point there are still many modules and firmware included that are not required. Some of this is due to a badly written plymouth (the boot-time splash-screen/input handler) hook script that forces all DRM modules for every GPU to be included. Removing this shotgun-approach reduces the size considerably.

Firmware

Additionally, many firmware files (from /lib/firmware/) are included although they don't match the system's hardware. This is due to kernel modules that manage many different devices declaring all the firmware files they may need and all those firmware files are included in the initialramfs even when they do no match the installed hardware.

The Linux kernel does not currently provide a way to identify which firmware files have been loaded even though it has a dedicated firmware_loader class that modules use. By adding additional functionality to this code it is possible for userspace to obtain a list of the loaded firmware files and use that to control which files are included in the initialramfs.

I've investigated three approaches to adding interfaces to the Linux firmware loader. For now I've put aside the first two as being too complicated and invasive:

  1. Add a sysfs interface under /sys/firmware/ of the form /sys/firmware/module//firmware_loaded
  2. Add a procfs interface as /proc/firmware_loaded with a single text file list of the form " "
  3. Write to the kernel log using pr_info() and dev_info() with the text "Firmware loaded: "

The current experiment uses option (3) which isn't preferred but proves the efficiacy of being able to obtain the list of loaded firmware. With more work it may be possible to make the procfs option work.

Removing modules (and therefore firmware files) not required during initialramfs operation

There is scope to identify and ommit kernel modules that are not required to mount the real root file-system, which is the only task the initialramfs is supposed to be doing.

This would entail adding a script that can capture the list of loaded modules just before the /init script switches to the real root file-system and using that when the initialramfs is built.

I intend to explore this option further.