What You Will Learn
By the end of this tutorial you will clearly understand:
- Why Linux cannot directly mount the real root filesystem at boot
- What initramfs is and the problem it solves
- The difference between initrd and initramfs
- What is actually inside an initramfs image
- How to inspect and unpack an initramfs image yourself
- How modern kernels (6.x) handle initramfs compared to older kernels
No previous knowledge of the boot process is assumed. We start from zero.
Topics Covered:
initrd
Linux Boot Process
Kernel 6.x Boot
mkinitramfs
lsinitramfs
Embedded Linux
Hybrid initramfs
Root Filesystem
GRUB Bootloader
1. The Chicken-and-Egg Problem at Boot
Here is a situation every Linux developer eventually runs into when they think deeply about the boot process:
The kernel needs to mount the root filesystem to access programs. But the programs needed to mount the root filesystem live on that very same root filesystem. So which comes first?
Let’s think about what mounting a root filesystem actually involves in a real system:
- The disk might be encrypted. You need a program to ask for the password first.
- The disk might be on a RAID array. You need tools to assemble the RAID.
- The disk might be on a network (NFS). You need a network driver and NFS tools.
- The filesystem might be on an LVM volume. You need
lvmtools to activate it.
All of these tools are user-space programs. They live on the root filesystem. But the root filesystem is not yet mounted. This is the classic chicken-and-egg problem.
The kernel by itself cannot solve this. The kernel does not include password dialogs, RAID assembly tools, or LVM binaries inside it. That would make the kernel enormous and impractical. There had to be a better solution.
2. What is initramfs?
The solution is initramfs — short for initial RAM filesystem. The idea is elegant: before the kernel hands control to the real root filesystem, it mounts a small, temporary filesystem that lives entirely in RAM. This temporary filesystem contains just enough tools to get the real root filesystem ready.
Think of it like a tool kit you carry in your pocket when you go to set up a new workshop. The workshop (real root filesystem) is empty. But your pocket kit (initramfs) has a flashlight, a screwdriver, and a key to open the door. Once the workshop is set up, you put the pocket kit away.
| BIOS / UEFI | Power On → Hardware self-test → Find bootable device
+——–+———+
|
v
+——————+
| GRUB Bootloader | Loads kernel image + initramfs image into RAM
+——–+———+
|
v
+——————+
| Linux Kernel | Decompresses itself → hardware init → mounts initramfs
+——–+———+
|
v
+——————+
| initramfs | Tiny temporary root filesystem in RAM
| (RAM-based) | Runs /init script → loads drivers → mounts real disk
+——–+———+
|
v
+——————+
| Real Root FS | /sbin/init or systemd takes over
| (your hard disk) | Normal Linux boot continues
+——————+
In simple terms, initramfs gives the kernel a fully working user-space environment before the real disk is ready. The kernel does not even know or care whether it is talking to a real disk or a RAM-based filesystem initially.
3. initrd vs initramfs — What is the Difference?
You will often see both terms used. They refer to the same idea (a temporary filesystem loaded at boot) but implemented differently. Here is a clear comparison:
| Feature | initrd (old) | initramfs (modern) |
|---|---|---|
| Full name | Initial RAM Disk | Initial RAM Filesystem |
| Storage format | Block device image (like a disk image) | cpio archive compressed with gzip/lz4/zstd |
| Kernel support | Required a RAM disk driver in kernel | Built into the VFS layer, no extra driver needed |
| Transition to real root | pivot_root syscall | switch_root (or just exec into real root) |
| Used today? | Mostly obsolete (filename kept for compatibility) | Yes, all modern distros use this |
Important note: On Ubuntu, Fedora, and Debian, the file is still called initrd.img-<version> in /boot/ even though it is technically an initramfs image. The name is kept for historical compatibility. Do not get confused by this. The format inside is a cpio archive, not an old initrd block image.
4. What is Actually Inside an initramfs Image?
Think of initramfs as a tiny complete Linux system. It is not a full distro, but it has everything needed to set up the real root filesystem. Here is what you typically find:
├── bin/ ← Essential tools: sh, mount, modprobe, udevadm …
├── sbin/ ← Admin tools: fsck, blkid, dmsetup, cryptsetup …
├── lib/ ← Shared libraries: libc, libpthread, ld-linux …
│ └── modules/ ← Kernel modules needed early (disk drivers, crypto …)
├── etc/ ← Config files: udev rules, fstab, modprobe config
│ └── udev/
├── dev/ ← Device nodes
├── proc/ ← Proc filesystem mount point
├── sys/ ← Sysfs mount point
├── run/ ← Runtime state
└── init ← THE most important file: the startup script
The /init file (or /init symlink on some distros) is the first program the kernel runs inside initramfs. It is a shell script or a binary. Its job is to:
- Mount
/proc,/sys,/dev - Load any needed kernel modules (disk controllers, filesystem drivers)
- Run udev to detect hardware
- Decrypt disks if encryption is used
- Mount the real root filesystem
- Hand over control to the real system using
switch_root
On modern systems with systemd, the initramfs often contains a lightweight systemd binary that runs the same unit-file mechanism you know from normal boot, just with a minimal set of units. This is why boot troubleshooting in the initramfs stage looks and feels like normal systemd.
5. How to Inspect an initramfs Image Yourself
The best way to learn is to look inside. Let’s do that step by step.
Step 1: Find your initramfs file
On any Ubuntu/Debian system, look in /boot/:
ls -lh /boot/initrd.img-$(uname -r)
This shows you the initramfs for your currently running kernel. On kernel 6.x systems you will see a file name like initrd.img-6.8.0-51-generic.
Step 2: List its contents
On Ubuntu/Debian, use lsinitramfs:
lsinitramfs /boot/initrd.img-$(uname -r) | less
On Fedora/RHEL/CentOS, the equivalent tool is lsinitrd:
lsinitrd /boot/initramfs-$(uname -r).img | less
You will see hundreds of files — libraries, kernel modules, udev rules, scripts. All of this is what Linux needs before it can even look at your hard disk.
Step 3: Actually unpack and explore it
On Ubuntu, you can fully unpack an initramfs image using unmkinitramfs:
TMPDIR=$(mktemp -d)
unmkinitramfs /boot/initrd.img-$(uname -r) $TMPDIR
ls -la $TMPDIR
After unpacking, browse around with ls and cat. Try reading the init script:
cat $TMPDIR/main/init
This is a fascinating exercise. You will see real shell scripting that runs before systemd even starts on your machine.
Kernel 6.x note: Compression format
Older kernels used gzip compression for initramfs. Modern kernel 6.x images often use zstd (Zstandard) compression, which decompresses much faster. You can check what compression is used:
file /boot/initrd.img-$(uname -r)
You might see output like Zstandard compressed data or gzip compressed data. Both formats are fully supported by the kernel and by the unmkinitramfs tool.
6. Hybrid initramfs — The Early and Main Sections
Modern systems use what is called a hybrid initramfs. If you unpacked an initramfs image in the previous section, you probably noticed two top-level directories: early/ and main/. This is what hybrid means.
+——————————-+
| EARLY section (cpio archive) | ← CPU microcode updates (Intel/AMD)
| Loaded first by kernel | ← Decompressed BEFORE kernel init
+——————————-+
| MAIN section (cpio archive) | ← The full temporary root filesystem
| Typical initramfs content | ← /bin, /lib, /init, kernel modules, etc.
+——————————-+
The early section is special. It contains CPU microcode updates (binary patches for Intel or AMD processors). The kernel loads and applies these patches as early as possible — even before memory is fully set up — to fix hardware bugs and security vulnerabilities. On AMD systems you will see AuthenticAMD.bin inside the early section. On Intel systems you will see GenuineIntel.bin.
The main section is the actual temporary root filesystem we have been discussing throughout this tutorial.
On Ubuntu, the tool that builds this hybrid image is mkinitramfs. The higher-level wrapper you normally interact with is update-initramfs:
# Rebuild initramfs for the currently running kernel
sudo update-initramfs -u -k $(uname -r)
# Build for a specific kernel version
sudo update-initramfs -u -k 6.8.0-51-generic
On Fedora/RHEL the equivalent tool is dracut:
# Rebuild on Fedora
sudo dracut --force
7. What Changed in Kernel 6.x for initramfs?
If you are coming from tutorials written for older kernels (4.x or 5.x), here are the key differences to be aware of:
| Aspect | Older Kernels (4.x/5.x) | Kernel 6.x |
|---|---|---|
| Default compression | gzip or lz4 | zstd (on most distros) |
| Systemd inside initramfs | Optional (busybox or systemd) | systemd-based initramfs is now common |
| TPM/Secure Boot integration | Minimal | Full TPM2 and LUKS2 support in initramfs |
| Microcode loading | Early cpio section | Same, but microcode packages updated frequently |
| Debug access | Break= boot parameter | systemd.break= or rd.break= parameters |
Dropping into a shell during initramfs (debug tip)
This is very useful when troubleshooting boot issues. Add this to the kernel command line in GRUB:
# For systemd-based initramfs (Ubuntu 22.04+, Fedora, etc.)
rd.break
# This drops you into a shell before switch_root happens
# You are inside the initramfs filesystem at this point
# /sysroot is where the real root is mounted (read-only)
8. Why Does This Matter for Embedded Systems Engineers?
You might wonder: “I work on embedded Linux, not desktop Linux. Why do I need to know about initramfs?” Here is why it matters a lot:
- Custom board bring-up: When bringing up a new board, your rootfs might be on eMMC, NFS, or SD card. The initramfs handles the early detection and mounting. If something goes wrong here, the board does not boot.
- Disk encryption on embedded: Encrypting storage on an IoT device using LUKS requires a properly configured initramfs to handle decryption before the rootfs mounts.
- Factory reset and recovery: Many embedded products implement a factory reset mechanism inside the initramfs — it can wipe and re-flash the rootfs from a recovery image before systemd ever starts.
- Minimal kernel size: You might want to bake the initramfs directly into the kernel image (using
CONFIG_INITRAMFS_SOURCE) for ultra-fast boot on resource-constrained devices. - Network boot (PXE/NFS): Diskless embedded systems that boot over the network rely entirely on the initramfs to set up network connectivity before mounting a remote rootfs.
Understanding initramfs is not optional for serious embedded Linux engineers — it is fundamental.
Interview Questions — initramfs & Linux Boot
These are real questions that come up in embedded Linux and kernel developer interviews:
Q1. What problem does initramfs solve? Why can’t the kernel mount the root filesystem directly?
The kernel may need user-space programs (for decryption, RAID assembly, LVM activation, or network setup) to prepare the root filesystem for mounting. These programs cannot live in the kernel itself due to design constraints. initramfs provides a temporary user-space environment in RAM so these programs can run before the real root filesystem is available.
Q2. What is the difference between initrd and initramfs?
initrd (Initial RAM Disk) was an old approach that used a block device image mounted as a RAM disk. initramfs (Initial RAM Filesystem) is a cpio archive that the kernel extracts directly into a tmpfs filesystem. initramfs is simpler, does not require a RAM disk driver, and uses switch_root instead of pivot_root to hand off to the real root. Modern systems use initramfs even if the file is still named initrd.img.
Q3. What is the first process that runs inside initramfs?
The kernel executes /init inside the initramfs as PID 1. This is either a shell script (on minimal distros or embedded systems) or a lightweight systemd binary (on modern full distros like Ubuntu or Fedora). Its job is to prepare the real root filesystem and then call switch_root to hand control over.
Q4. What is a hybrid initramfs and what is the purpose of the early section?
A hybrid initramfs contains two concatenated cpio archives: an early section and a main section. The early section contains CPU microcode updates (Intel or AMD binary patches). The kernel applies microcode as soon as possible — before SMP is initialized — to patch hardware bugs. The main section is the actual temporary root filesystem.
Q5. How do you bake the initramfs into the kernel image itself?
Set the kernel config option CONFIG_INITRAMFS_SOURCE to the path of a directory or cpio archive containing your initramfs contents. When you build the kernel, it packages that content directly into the vmlinux image. The bootloader does not need to load a separate initramfs file — it is already inside the kernel. This is common in embedded systems for faster boot and simplified boot configuration.
Q6. You are at a job interview and the interviewer asks: “Our product uses LUKS disk encryption. Walk me through what happens at boot.” What do you say?
After the bootloader loads the kernel and initramfs, the kernel runs /init inside the initramfs. The init script (or systemd unit in initramfs) detects the LUKS-encrypted block device, runs cryptsetup to open it (prompting for a passphrase or using a key from a TPM), creates a decrypted device mapper target, mounts the decrypted filesystem as the real root, and then calls switch_root to hand control to the real system’s init.
Q7. How would you debug a system that gets stuck during the initramfs stage?
Add rd.break (systemd-based) or break=premount (older busybox-based) to the kernel command line in GRUB. This drops you into a shell inside the initramfs before the real root is mounted. You can then manually run mount, blkid, modprobe, and other commands to diagnose the issue. Increase kernel verbosity by removing quiet splash from the kernel command line and adding debug.
Q8. What compression formats does kernel 6.x support for initramfs?
Kernel 6.x supports gzip, bzip2, lzma, xz, lzo, lz4, and zstd for initramfs compression. Most modern distributions default to zstd because it offers the best balance of compression ratio and decompression speed. The kernel auto-detects the compression format — you do not need to specify it explicitly.
Up Next in Chapter 3
In Part 2, we cover GRUB Bootloader Customization — how to show the boot menu, set timeouts, add custom kernel parameters, and make your development workflow smoother.
