Home Blog Certs Knowledge Base About

LPIC-2 201.2 โ€” Compiling the Linux Kernel

Exam weight: This topic carries 3 points on the LPIC-2 201 exam. Focus on make targets, the paths /usr/src/linux/.config and /lib/modules/kernel-version/, and the commands mkinitrd, mkinitramfs, and depmod.


Directory Layout

PathPurpose
/usr/src/linux/Symbolic link to the current kernel source tree
/usr/src/linux-<version>/Actual directory containing source for a specific version
/usr/src/linux/.configKernel configuration file
/boot/vmlinuz-<version>Compiled kernel image
/boot/System.map-<version>Symbol table for kernel debugging
/boot/initrd-<version>.imgInitial RAM disk image
/lib/modules/<version>/Kernel modules for a specific version
/lib/modules/<version>/modules.depModule dependency file, generated by depmod

Note: /usr/src/linux is a symbolic link. Create it manually with ln -s /usr/src/linux-4.x.x /usr/src/linux. Never place sources directly under /usr/src/linux.


Getting the Kernel Source

All kernel versions are available from kernel.org. Extract the downloaded archive into /usr/src/:

# Download the archive (example for version 4.3.3)
wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.3.3.tar.xz

# Extract
tar xvf linux-4.3.3.tar.xz -C /usr/src/

# Create the symbolic link
ln -s /usr/src/linux-4.3.3 /usr/src/linux

# Enter the source directory
cd /usr/src/linux

Tip: You need at least 1 GB of free space to compile. Before building, ensure gcc, make, and the development headers are installed: apt-get install build-essential (Debian) or yum groupinstall "Development Tools" (RHEL).


Cleaning the Source Tree

Cleaning happens at three levels:

# Level 1: removes most object files but keeps enough for external module builds
make clean

# Level 2: removes the current config (.config) and all object files
make mrproper

# Level 3: same as mrproper, plus editor backups, patch remnants, and other junk
make distclean

Running make mrproper before each new configuration and build is good practice.

Warning: make mrproper deletes .config completely. If your configuration took significant time, copy .config somewhere safe before running this command.


Creating the .config File

Before compiling, the kernel must be configured: choose which features to build in directly (=y), which to compile as modules (=m), and which to exclude (=n). The result is saved to /usr/src/linux/.config.

.config is a plain text file where each line describes one option:

CONFIG_64BIT=y
CONFIG_SMP=y
CONFIG_MODULES=y
CONFIG_EXT4_FS=m
# CONFIG_BTRFS_FS is not set

Warning: Editing .config by hand is strongly discouraged. Use one of the make configuration targets instead.


make Configuration Targets

TargetInterfaceDependenciesNotes
make configSequential text promptsNoneCannot go back. Hundreds of questions in a row. Works on any terminal
make menuconfigncurses pseudo-graphicslibncursesMenu with navigation. Can save at any point
make nconfigncurses (dark theme)libncursesAlternative to menuconfig with a different colour scheme
make xconfigQt GUIQt dev libs, X11Mouse navigation. Requires a working X Window System
make gconfigGTK GUIGTK+ 2.x dev libs, X11Same as xconfig but GTK-based
make oldconfigText, new options onlyExisting .configCarries over old settings, asks only about new options
make defconfigNo questionsNoneCreates a default configuration for the detected system type
make mrproperNoneNoneRemoves .config and all object files
# Enter the kernel source root
cd /usr/src/linux

# Launch the text menu (most common)
make menuconfig

# Update config when upgrading from 4.3 to 4.4
cp /path/to/old/.config /usr/src/linux/.config
make oldconfig

How make oldconfig handles .config

When make oldconfig runs, the old .config is copied to .config.old and a new .config is built from it. For every option not present in the old file, the system asks a question. All previously chosen values are preserved without prompting.

Note: make xconfig, make gconfig, and make menuconfig also automatically pick up an existing .config from /usr/src/linux/. New options receive default values.

Exam tip: A common exam question is the difference between make config, make menuconfig, and make oldconfig. Remember: menuconfig is an ncurses interface with navigation; oldconfig updates an existing config asking only about new options; make config is the most primitive โ€” no going back.


Compiling the Kernel

After creating .config, start the build:

# Compile the compressed kernel image (recommended)
make bzImage

# Compile the uncompressed kernel image
make zImage

# Compile modules only
make modules

# Compile everything: kernel + modules
make all

# Create an RPM source package
make rpm-pkg

# Create a binary RPM package
make binrpm-pkg

# Create a .deb package
make deb-pkg

The resulting bzImage is located at:

/usr/src/linux/arch/x86/boot/bzImage

Note: bzImage is the compressed kernel image (b = “big”, z = zipped). It differs from zImage in that it supports sizes over 512 KB. Always use bzImage on modern systems.


make Build Targets

TargetDescription
allBuild the kernel and all modules
bzImageCompressed kernel image (Big zImage)
zImageUncompressed kernel image (limited to 512 KB)
modulesCompile modules only
modules_installInstall modules to /lib/modules/<version>/
cleanRemove object files (.config is preserved)
mrproperFull clean, including .config
rpm-pkgCreate an RPM package with sources and kernel
binrpm-pkgCreate a binary RPM package
deb-pkgCreate a .deb package for Debian systems

Installing the New Kernel

The full build and install sequence:

# 1. Clean up previous build artifacts
make clean

# 2. Build the kernel image
make bzImage       # or make zImage for very old systems

# 3. Build modules
make modules

# 4. Install modules to /lib/modules/<version>/
#    The directory is created automatically if it doesn't exist
make modules_install

After building, copy the kernel and related files to /boot/. The path to bzImage depends on the architecture:

# x86_64
cp /usr/src/linux/arch/x86_64/boot/bzImage /boot/vmlinuz-2.6.31

# i386
cp /usr/src/linux/arch/i386/boot/bzImage /boot/vmlinuz-2.6.31

# Copy the symbol table (optional, needed for debugging)
cp /usr/src/linux/System.map /boot/System.map-2.6.31

# Rebuild the module dependency file
depmod -a

Including the version in the filename allows multiple kernels to coexist in /boot/ so you can roll back if something goes wrong.

After copying the files, update the bootloader (GRUB):

# GRUB 2
update-grub                               # Debian/Ubuntu
grub2-mkconfig -o /boot/grub2/grub.cfg   # RHEL/CentOS

Important: If the bootloader doesn’t see the new kernel, check two things: the kernel file is in /boot/ and the GRUB config has been updated. The exam tests this.


Kernel Modules

Kernel modules are .ko object files loaded into the kernel on demand. All modules live in a directory hierarchy under /lib/modules/<kernel-version>/.

/lib/modules/4.3.3/
โ”œโ”€โ”€ kernel/
โ”‚   โ”œโ”€โ”€ drivers/
โ”‚   โ”‚   โ”œโ”€โ”€ net/        # Network drivers
โ”‚   โ”‚   โ”œโ”€โ”€ scsi/       # SCSI drivers
โ”‚   โ”‚   โ””โ”€โ”€ block/      # Block devices
โ”‚   โ””โ”€โ”€ fs/             # Filesystems
โ””โ”€โ”€ modules.dep         # Dependency file

modules.dep lists the dependencies of each module. It is generated by depmod:

# Regenerate modules.dep for the running kernel
depmod -a

# Regenerate for a specific kernel version
depmod -a 4.3.3

Example line from modules.dep:

/lib/modules/2.6.31/kernel/drivers/acpi/thermal.ko: \
  /lib/modules/2.6.31/kernel/drivers/thermal/thermal_sys.ko

Note: modprobe reads modules.dep and automatically loads all module dependencies. insmod does not handle dependencies.


Initial RAM Disk โ€” initrd and initramfs

At boot time, the kernel cannot access the disk if the disk driver is compiled as a module. This creates a chicken-and-egg problem: to load the module you need the disk, but to access the disk you need the module. The solution is the initial RAM disk (initrd).

initrd is an image of a minimal root filesystem in RAM. The bootloader (GRUB or LILO) passes it to the kernel along with the kernel image. The kernel mounts initrd as a temporary root filesystem, loads the required modules, then mounts the real root filesystem from disk. After switching root, the old initrd either moves to /initrd or is unmounted.

Checking the format of an existing initrd

Old kernels use a tar archive internally; newer ones use cpio. To find out the format:

zcat /boot/initrd-2.6.18-348.6.1.el5.img | file -
# /dev/stdin: ASCII cpio archive (SVR4 with no CRC)

Building initrd manually

If mkinitrd is unavailable, build the image by hand using a block device โ€” a RAM disk (/dev/ram0) or a loopback device:

# 1. Create a filesystem on the RAM disk (300 blocks)
mke2fs -m0 /dev/ram0 300

# 2. Mount it
mount -t ext2 /dev/ram0 /mnt

# 3. Create necessary device nodes and directories
mkdir /mnt/dev
mknod /mnt/dev/tty1 c 4 1

# 4. Create /linuxrc โ€” the kernel runs this first
#    For a test, a symlink to /bin/sh is enough
ln -s /bin/sh /mnt/linuxrc

# 5. Copy required modules, scripts, binaries

# 6. Unmount the RAM disk
umount /dev/ram0

# 7. Copy its contents into an image file
dd if=/dev/ram0 bs=1k count=300 of=/boot/initrd

# 8. Free the RAM disk
freeramdisk /dev/ram0

Connect the image to the bootloader. Example entry in GRUB Legacy config:

title=initrd test entry
root (hd0,0)
kernel /vmlinuz-2.6.28
initrd /initrd

Note: /linuxrc is the initrd entry point. The kernel finds and runs it immediately after mounting the image. In real systems it is a script that loads modules and mounts the real root.

mkinitrd (RPM-based systems)

# Create an initrd image
mkinitrd /boot/initrd-4.3.3.img 4.3.3

# Useful options
mkinitrd --version                    # Show version
mkinitrd -f /boot/initrd.img 4.3.3   # Overwrite existing file
mkinitrd --omit-scsi-modules ...      # Exclude SCSI modules

mkinitramfs (Debian-based systems)

# Create an initramfs image
mkinitramfs -o /boot/initrd.img-4.3.3 4.3.3

# Specify an alternative config directory
mkinitramfs -d /etc/initramfs-tools -o /boot/initrd.img 4.3.3

The mkinitramfs config file is at /etc/initramfs-tools/initramfs.conf.

Important: The exam tests knowledge of both tools: mkinitrd for RPM-based systems (Red Hat, SUSE), mkinitramfs for Debian-based systems (Debian, Ubuntu). Both produce a gzip-compressed cpio archive.


Patching the Kernel

Note: Kernel patching is no longer in the LPIC-2 exam objectives, but it is useful background for working with kernel sources.

A patch file is the output of diff -u old_file new_file. It consists of change blocks called hunks. Each hunk contains context lines โ€” unchanged lines surrounding the edit. The patch tool uses this context to locate the right place in the file. Lines to remove are marked -, lines to add are marked +. If the context in the file doesn’t match the context in the patch, patch cannot apply that hunk and saves it to a .rej file.

--- a/drivers/net/foo.c   2024-01-01
+++ b/drivers/net/foo.c   2024-01-02
@@ -42,7 +42,7 @@
     int ret;
     /* init */
-    ret = old_init();
+    ret = new_init();
     if (ret < 0)
# 1. Place the patch file in /usr/src/
# 2. Enter /usr/src/
cd /usr/src

# 3. Decompress the patch (if in xz format)
unxz patch-4.3.4.xz

# 4. Apply the patch
patch -p1 < patch-4.3.4

# 5. Check for .rej files (rejected hunks)
find /usr/src/linux -name "*.rej"

The -p<n> option controls how many leading path components to strip. git diff writes paths as a/drivers/net/foo.c โ€” without stripping, patch looks for that literal path and fails. -p1 strips the first component (a/ or b/), leaving the real relative path:

OptionPath from patchResult
-p0a/drivers/net/foo.ca/drivers/net/foo.c โ€” unchanged
-p1a/drivers/net/foo.cdrivers/net/foo.c โ€” a/ stripped
-p2a/drivers/net/foo.cnet/foo.c โ€” a/drivers/ stripped

For kernel patches the standard is -p1.

Useful patch options:

OptionDescription
-p<n>Strip n leading path components
-sSilent mode, show errors only
-RReverse the patch (undo)
-EDelete empty files after patching

Reverting a patch

patch -R -p1 < patch-2.6.28
# If patch detects it was already applied:
# Reversed (or previously applied) patch detected! Assume -R? [n] y

DKMS

DKMS (Dynamic Kernel Module Support) was developed by Dell in 2003. The problem was concrete: Dell supported customers running Linux, and every kernel update broke modules for proprietary hardware. DKMS solves this by decoupling module sources from the kernel tree and automatically rebuilding them on kernel upgrades.

When the package manager updates the kernel on a DKMS-enabled system, a hook checks which modules need rebuilding for the new kernel. It also works in reverse: a new module installs without being tied to a specific kernel version.

# 1. Install the DKMS package (sources land in /usr/src/<module-version>/)
apt-get install flashcache-dkms

# 2. Add the module to the DKMS tree
dkms add -m flashcache -v 3.1.1

# 3. Build the module for the current kernel
dkms build -m flashcache -v 3.1.1

# 4. Install the module
dkms install -m flashcache -v 3.1.1

# 5. Check status
dkms status

# 6. Remove the installed module
dkms uninstall -m flashcache -v 3.1.1

Each DKMS module is described by a dkms.conf file in /usr/src/<module-version>/:

BUILT_MODULE_NAME="flashcache"
DEST_MODULE_LOCATION="/kernel/drivers/block"
PACKAGE_NAME="flashcache"
PACKAGE_VERSION="3.1.1+git20140801"
AUTOINSTALL="yes"
REMAKE_INITRD="yes"
MAKE="KERNEL_TREE=$kernel_source_dir make modules"

Key dkms.conf directives:

DirectiveRequiredPurpose
BUILT_MODULE_NAMEWhen 2+ modulesName of the compiled module
DEST_MODULE_LOCATIONYes*Install path, always starts with /kernel
PACKAGE_NAMEYesPackage name
PACKAGE_VERSIONYesPackage version
AUTOINSTALLNoyes โ€” install the module on every new kernel boot
REMAKE_INITRDNoyes โ€” rebuild initrd after module install (default no)
MAKENoBuild command; if unset, DKMS uses the default make

* DEST_MODULE_LOCATION is not required on Fedora Core 6+, RHEL 5+, SuSE Linux ES 10+, and Ubuntu โ€” they use distribution directories.

Warning: The REMAKE_INITRD directive reads only the first character of the value โ€” all others are ignored. The first character is treated as “yes” only if it is y or Y. yes and YES behave identically; so do no and nope.

Working with module archives

DKMS can work with tar archives, which is useful for transferring modules between systems:

# Create a tarball from the current modules on this system
dkms mktarball -m flashcache -v 3.1.1

# Import the tarball into the DKMS tree on another system
dkms ldtarball /path/to/flashcache-3.1.1.tar.gz

The archive must contain a valid dkms.conf.

Example config locations

Debian:    /usr/share/doc/dkms/examples/
Red Hat:   /usr/share/doc/dkms/

Important: DKMS requires kernel headers to be installed: apt-get install linux-headers-$(uname -r) or yum install kernel-devel.

Note: Global DKMS configuration is in /etc/dkms/framework.conf. The source_tree variable there tells DKMS where to look for dkms.conf directories.


Dracut

Dracut is a utility for creating initramfs images that supports multiple distributions and can work in event-driven mode. Similar to how DKMS reacts to kernel upgrades and rebuilds modules, dracut reacts to changes and automatically rebuilds the initramfs image.

# Create initramfs for the running kernel
dracut /boot/initramfs-$(uname -r).img $(uname -r)

# Force recreate (overwrite existing image)
dracut --force /boot/initramfs-$(uname -r).img $(uname -r)

Note: The LPIC-2 exam only requires knowing that dracut exists and what it does โ€” automatic initramfs creation when needed. Deep configuration is not tested.


Exam Cheat Sheet

Key Paths

/usr/src/linux/           โ€” symbolic link to kernel sources
/usr/src/linux/.config    โ€” kernel configuration file
/boot/vmlinuz-<ver>       โ€” kernel image
/boot/System.map-<ver>    โ€” symbol table
/boot/initrd-<ver>.img    โ€” initial RAM disk
/lib/modules/<ver>/       โ€” kernel modules
/lib/modules/<ver>/modules.dep  โ€” dependency file
/etc/dkms/framework.conf  โ€” DKMS configuration
/etc/initramfs-tools/initramfs.conf โ€” mkinitramfs configuration

Key Commands

make mrproper              # Full clean + remove .config
make clean                 # Remove object files only
make menuconfig            # Text configurator (ncurses)
make oldconfig             # Update .config for new kernel options
make bzImage               # Build compressed kernel image
make modules               # Build modules only
make modules_install       # Install modules to /lib/modules/
depmod -a                  # Regenerate modules.dep
mkinitrd /boot/img.img <ver>          # Create initrd (RPM)
mkinitramfs -o /boot/img.img <ver>    # Create initramfs (Debian)
dkms status                # DKMS module status
dkms add/build/install     # DKMS module lifecycle
update-grub / grub2-mkconfig          # Update GRUB config

Common Exam Mistakes

  • make mrproper deletes .config; make clean does not.
  • mkinitrd is for RPM-based systems; mkinitramfs is for Debian.
  • After make modules_install, run depmod -a.
  • The compiled bzImage is at arch/x86/boot/bzImage relative to the source tree root.
  • DEST_MODULE_LOCATION in dkms.conf must start with /kernel.

Practice Questions

Q1. An admin downloaded kernel sources 4.3.3 and extracted them to /usr/src/linux-4.3.3. Which command makes /usr/src/linux point to these sources?

A) cp -r /usr/src/linux-4.3.3 /usr/src/linux B) ln -s /usr/src/linux-4.3.3 /usr/src/linux C) mount --bind /usr/src/linux-4.3.3 /usr/src/linux D) mv /usr/src/linux-4.3.3 /usr/src/linux

Answer: B. Use a symbolic link. Option A duplicates files; D renames the directory and breaks the version reference.


Q2. An admin wants to update the kernel config from 4.3 to 4.4, keeping all existing settings and only answering questions about new options. Which make target should they use?

A) make config B) make defconfig C) make oldconfig D) make menuconfig

Answer: C. make oldconfig reads the existing .config and asks only about new options. make config asks everything from scratch.


Q3. After compiling the kernel on an x86_64 system, where is the resulting bzImage?

A) /usr/src/linux/bzImage B) /usr/src/linux/arch/x86/boot/bzImage C) /boot/bzImage D) /usr/src/linux/kernel/bzImage

Answer: B. The file is created at arch/x86/boot/bzImage relative to the source tree root.


Q4. Which command creates /lib/modules/<version>/modules.dep?

A) modprobe --update B) insmod --deps C) depmod -a D) ldconfig

Answer: C. depmod -a scans all modules in /lib/modules/<version>/ and writes the dependency file modules.dep.


Q5. An admin on a Debian system wants to create an initramfs image for kernel version 4.3.3. Which command should they use?

A) mkinitrd /boot/initrd-4.3.3.img 4.3.3 B) dracut /boot/initrd.img 4.3.3 C) mkinitramfs -o /boot/initrd.img-4.3.3 4.3.3 D) mkinitrfs 4.3.3 /boot/initrd.img

Answer: C. mkinitramfs is the Debian tool. mkinitrd is for RPM-based systems (Red Hat, SUSE).


Q6. Which file must be present in a DKMS module directory under /usr/src/?

A) Makefile B) dkms.conf C) module.spec D) .config

Answer: B. dkms.conf contains the directives for DKMS and is mandatory for the framework to function.


Q7. An admin wants to completely reset the kernel configuration and remove all previously compiled object files. Which command should they use?

A) make clean B) make distclean C) make mrproper D) make reset

Answer: C. make mrproper removes both object files and .config. make clean removes only object files, preserving .config.


Q8. After installing a new kernel and running make modules_install, the admin notices modprobe cannot load the new module, complaining about a missing dependency file. What fixes this?

A) Restart udevd B) Run depmod -a C) Run ldconfig D) Rebuild the kernel with make all

Answer: B. depmod -a creates the modules.dep file that modprobe reads to resolve dependencies.