Skip to main content
RunBook Academy

LinuxLXV · Rolling Kernel UpgradesRollback

Kernel rollback - getting back to the kernel that worked

Advanced⏱ ~12 mingrubbydracutupdate-initramfs

What you'll learn

  • Distinguish the running kernel from the installed and default kernels
  • Choose between a one-shot boot and a persistent default change
  • Roll back a kernel from the console when the host will not boot
  • Rebuild an initramfs and version-lock a bad kernel

Prerequisites

Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-11

Not yet marked complete on this device.

A kernel upgrade is the one change on a Linux host that cannot be validated before it takes effect and cannot be undone without a second reboot. Rollback therefore has to be planned before the upgrade, not discovered afterwards.

The whole discipline rests on one idea: the kernel you are running, the kernels you have installed, and the kernel the bootloader will pick next time are three different things. Confusing them is why “I rolled it back” is so often followed by the same panic on the next reboot.

Three different kernels

uname -r                       # RUNNING - loaded at the last boot
rpm -q kernel                  # INSTALLED - every version on disk (RHEL family)
dpkg -l 'linux-image-*'        # INSTALLED (Debian family)
sudo grubby --default-kernel   # DEFAULT  - what the next boot will use
ls /boot/vmlinuz-*             # what is physically present

A host can be running 6.6.0, have 6.6.0 and 6.6.9 installed, and be set to boot 6.6.9 next time. Nothing is wrong with that state - it is exactly what a host looks like between dnf update and its reboot. It becomes a problem when someone reads uname -r, sees the old good version, and concludes the upgrade has not happened.

Where boot entries live

Modern RHEL-family and many Debian-family systems use the Boot Loader Specification: one small file per kernel under /boot/loader/entries/, rather than a monolithic grub.cfg stanza.

ls /boot/loader/entries/
cat /boot/loader/entries/*-6.6.9.conf
title Rocky Linux (6.6.9-1.el9.x86_64) 9.4
version 6.6.9-1.el9.x86_64
linux /vmlinuz-6.6.9-1.el9.x86_64
initrd /initramfs-6.6.9-1.el9.x86_64.img
options root=/dev/mapper/rl-root ro crashkernel=1G-4G:192M rhgb quiet

The practical consequence: an entry can be present and selectable while the file it points at is missing or truncated. A host that boots to a grub> prompt or fails with “error: file not found” usually has an entry whose linux or initrd path no longer resolves - most often because /boot filled up during the upgrade and the initramfs was written incompletely.

df -h /boot                                    # the usual culprit
ls -l /boot/vmlinuz-* /boot/initramfs-*        # sizes near zero are the giveaway

Rolling back

One-shot: boot the old kernel exactly once

Use this when you want to test whether the new kernel is the cause without committing to anything.

# RHEL family
sudo grub2-reboot "Rocky Linux (6.6.0-1.el9.x86_64) 9.4"
sudo reboot

# Debian family - index into the submenu, then reboot once
sudo grub-reboot "1>2"
sudo reboot

Both write a one-time entry to the GRUB environment. The setting is consumed by the next boot and then forgotten, so the boot after that returns to the default.

That is the feature: if the old kernel also fails to boot, you have learnt something and nothing is left in a strange state. It is also the trap: a one-shot rollback that fixes production is not a rollback, it is a reprieve.

Persistent: change the default

Use this once you have decided the new kernel is bad.

sudo grubby --set-default /boot/vmlinuz-6.6.0-1.el9.x86_64
sudo grubby --default-kernel        # verify BEFORE rebooting
sudo reboot

On Debian family without grubby, set GRUB_DEFAULT to the entry’s identifier and regenerate the configuration:

sudo grep -E '^menuentry|^submenu' /boot/grub/grub.cfg | head
sudoedit /etc/default/grub          # GRUB_DEFAULT="gnulinux-advanced-.../gnulinux-6.6.0-..."
sudo update-grub

Verify before rebooting, every time. grubby --set-default against a path that does not exist fails quietly enough that people miss it, and the next reboot returns to the kernel you were trying to escape.

From the console, when the host will not boot

You do not get a shell to run any of the above. At the GRUB menu:

  1. Press a key during the countdown to stop the timer.
  2. Select Advanced options.
  3. Choose the previous kernel version.
  4. Boot it.

Once the host is up, make the change persistent immediately - before anything else, and before anyone is tempted to reboot again.

Rebuild the initramfs when it is the problem

A kernel that panics with “Unable to mount root fs” or drops to an initramfs shell usually has a bad initramfs rather than a bad kernel: a missing storage driver, an absent LVM or multipath module, or a truncated image from a full /boot.

# RHEL family - rebuild for a specific kernel version
sudo dracut --force /boot/initramfs-6.6.9-1.el9.x86_64.img 6.6.9-1.el9.x86_64

# Debian family
sudo update-initramfs -u -k 6.6.9-1.el9.x86_64

# Confirm the driver you need is actually in there
sudo lsinitrd /boot/initramfs-6.6.9-1.el9.x86_64.img | grep -E 'nvme|megaraid|dm-'

Do this from a working kernel or a rescue environment, and check df -h /boot first - rebuilding into a full filesystem produces exactly the truncated image that caused the failure.

Version-lock the bad kernel

A rollback that leaves the bad version installable is temporary. The next patch run reinstalls it, usually unattended, usually at the weekend.

# RHEL family
sudo dnf versionlock add 'kernel-6.6.9*'
sudo dnf versionlock list

# Debian family
sudo apt-mark hold linux-image-6.6.9-1-amd64
apt-mark showhold

Record why the lock exists and who removes it. An undocumented hold is discovered eighteen months later by someone auditing why a host is four kernels behind.

The rollback plan, written before the upgrade

Before the upgrade
  uname -r                    -> record the known-good version
  grubby --default-kernel     -> record the current default
  rpm -q kernel               -> confirm at least 2 kernels installed
  df -h /boot                 -> at least 200 MB free
  installonly_limit >= 3

After the upgrade, before reboot
  grubby --default-kernel     -> is it the NEW kernel, as intended?
  ls -l /boot/vmlinuz-* /boot/initramfs-*  -> non-zero sizes

After the reboot
  uname -r                    -> the NEW version is running
  systemctl --failed          -> empty
  dmesg -l err,crit           -> nothing new
  storage, network and the application all verified

If it fails
  console -> Advanced options -> previous kernel
  grubby --set-default /boot/vmlinuz-<good>
  grubby --default-kernel     -> verify
  dnf versionlock add 'kernel-<bad>*'
  record the reason

Knowledge check

Knowledge check · 4 questions

  1. Q1. After dnf update installs a new kernel but before rebooting, what does uname -r report?

  2. Q2. grub2-reboot (or grub-reboot) sets a one-shot entry that the next boot consumes and then forgets.

  3. Q3. A host fails to boot after a kernel upgrade with "Unable to mount root fs". Which are plausible causes? Select all that apply.

  4. Q4. A 6.6.9 kernel panics on boot on one node of a cluster. You recover it from the console by selecting the previous kernel in Advanced options, the node comes back, and you return it to service. What must you still do before the maintenance can be considered closed, and what happens if you skip each step?

Passing score: 75%. Answers are checked in this browser.