| Lesson 8 | Configure a Modern Linux Kernel Build |
| Objective | Create and review a kernel configuration while preserving boot requirements and a unique release identity. |
This lesson prepares an upstream Linux source build for an x86-64 RHEL 10 lab VM. Start with the verified source and tools from Lesson 7, work as an ordinary user, and keep the vendor kernel available for recovery. A locally compiled upstream kernel is outside Red Hat's supported kernel build; it does not become a RHEL kernel by using a RHEL configuration.
The result of this lesson is a reviewed .config and a recorded, distinct kernel release name. Installation, initramfs creation, and boot-entry verification follow in Lessons 9–11.
Inspect the running system before changing configuration. RHEL 10's x86 platform requires x86-64-v3 CPU capabilities; uname -m identifies the architecture but does not by itself verify that CPU level. For a VM, check the capabilities exposed by the hypervisor.
uname -r
uname -m
findmnt -no SOURCE,FSTYPE,OPTIONS /
lsblk -o NAME,TYPE,FSTYPE,MOUNTPOINTS
cat /proc/cmdline
if [ -d /sys/firmware/efi ]; then
printf 'Booted through UEFI\n'
else
printf 'No EFI runtime directory detected\n'
fi
sudo grubby --default-kernel
sudo grubby --info=DEFAULT
Record the root filesystem, storage layers, disk controller, console, and working boot entry. A root filesystem on encrypted LVM has different requirements from a plain virtual disk. Keep the current command line for comparison later; do not automatically copy every argument into a new boot entry.
Use the same source release and paths as Lesson 7. The placeholder must be replaced with your actual extracted release. These steps assume the output directory does not already contain a configuration you need to keep. Stop and preserve existing work before starting again in a used directory.
version='REPLACE_WITH_SELECTED_RELEASE'
src="$HOME/kernel-lab/linux-$version"
build="$HOME/kernel-lab/build-$version-lab1"
running_release=$(uname -r)
test -f "$src/Makefile" && test -f "$src/Kconfig"
test -r "/boot/config-$running_release"
test ! -e "$build/.config"
Continue only if all three checks succeed. Then copy and preserve the seed configuration:
mkdir -p "$build"
cp "/boot/config-$running_release" "$build/.config"
cp "$build/.config" "$build/config.before"
make -C "$src" O="$build" olddefconfig
Check each command's result. olddefconfig uses defaults for newly introduced options; it does not prove that vendor settings transfer correctly to upstream code. oldconfig is the interactive alternative. An architecture default is another starting point for an experienced builder, but it is not a substitute for reviewing this VM's requirements.
Keep O="$build" on every subsequent make command. A fresh, clean source/output pair does not require a ritual make mrproper; that target can erase configuration and generated state. There is no separate make dep preparation step in this workflow.
Use CONFIG_LOCALVERSION for this lab's suffix. Change the final counter for each build you intend to install alongside an earlier one; a date alone is not unique. Evaluate the date once, then leave the stored suffix unchanged through compilation and installation.
lab_suffix="-lab.$(date +%Y%m%d).1"
"$src/scripts/config" --file "$build/.config" \
--set-str LOCALVERSION "$lab_suffix"
"$src/scripts/config" --file "$build/.config" \
--disable LOCALVERSION_AUTO
make -C "$src" O="$build" olddefconfig
scripts/config edits settings; the following make command reconciles their dependencies. Review the result rather than assuming every requested setting survived.
localversion* files in the source/output directories contribute additional text. Do not duplicate your suffix in a “backup” file with that name.LOCALVERSION also adds text; it does not replace CONFIG_LOCALVERSION. Avoid mixing naming mechanisms in this lab.CONFIG_LOCALVERSION_AUTO suppresses the full automatic Git suffix, but some Git-tree states can still produce a trailing +. Use the exact kernelrelease output, not a hand-assembled prediction.make -C "$src" O="$build" menuconfig
Use search and the help text for your selected source version. Options may be built in (y), modular (m), or disabled (n) where supported. Any driver required to reach the real root filesystem must be built in or supplied, with its dependencies, in the early-boot initramfs. A module stored only on an inaccessible root filesystem cannot provide that initial access.
| Review area | Match it to this machine |
|---|---|
| Architecture and modules | Check CONFIG_X86_64 and module support. CONFIG_MODULE_UNLOAD controls unloading; it is not a universal boot prerequisite. |
| Initramfs | Retain CONFIG_BLK_DEV_INITRD and decompression support matching the image that will actually be generated. |
| Storage and root filesystem | Keep the disk-controller and root-filesystem drivers. Review device mapper for LVM, encryption support for encrypted storage, and RAID support where used. |
| VM devices | Match the actual virtual hardware. A virtio-scsi disk needs a different driver path from a virtio-blk disk; do not assume that every guest uses the same devices. |
| Userspace services | Preserve the working configuration's procfs, sysfs, tmpfs, device-management, cgroup, namespace, and security facilities required by the installed userspace. |
| Firmware, console, and recovery | Match the EFI/boot path and console. Preserve crash-dump support if the lab uses kdump; review its configuration separately. |
This is a review guide, not a universal list of symbols to force to y. For example, filesystem drivers may be modules when the initramfs contains everything required. Keeping a crashkernel= argument alone does not establish that kdump works.
A simple inspection helper can show selected settings, including disabled or undefined options:
for symbol in X86_64 MODULES BLK_DEV_INITRD DEVTMPFS CGROUPS; do
printf '%s: ' "$symbol"
"$src/scripts/config" --file "$build/.config" --state "$symbol"
done
Extend the review to the actual storage, filesystem, network, and console drivers you identified. The helper does not test bootability. Avoid localmodconfig as a shortcut here: currently unloaded drivers can still be needed by removable devices, recovery, or later workloads.
A vendor configuration may refer to certificate files absent from an upstream tree. Inspect these settings in the configuration editor before building:
| Setting | Review decision |
|---|---|
CONFIG_SYSTEM_TRUSTED_KEYSCONFIG_SYSTEM_REVOCATION_KEYS | Supply the intended certificates, or clear an unavailable additional certificate list only when the lab's trust policy permits omitting it. Do not disable the whole keyring to fix a missing filename. |
CONFIG_MODULE_SIG_KEY | For module signing, use a valid key/certificate pair. The upstream default certs/signing_key.pem supports automatic key generation when absent; an empty string is not an equivalent default. |
CONFIG_MODULE_SIG_FORCECONFIG_MODULE_SIG_ALL | Retain the required signature policy and plan how all required modules will be signed. Do not switch enforcement off as a routine configuration step. |
A module-signing key does not automatically make the kernel image trusted by firmware or shim. Resolve the Secure Boot trust and image-signing plan before installation. Protect private keys; archive the configuration and public build information separately.
After saving the interactive review, reconcile the configuration and inspect the differences:
make -C "$src" O="$build" olddefconfig
python3 "$src/scripts/diffconfig" \
"$build/config.before" "$build/.config"
target_release=$(make -s -C "$src" O="$build" kernelrelease)
printf 'Running: %s\nTarget: %s\n' \
"$running_release" "$target_release"
Stop if a command fails, the target is empty, or the difference report contains unexplained changes. Check that the proposed identity does not reuse the running kernel or an installed kernel's paths:
if [ -z "$target_release" ] ||
[ "$target_release" = "$running_release" ] ||
[ -e "/lib/modules/$target_release" ] ||
[ -e "/boot/vmlinuz-$target_release" ]; then
printf 'STOP: select an unused release identity and repeat the review.\n'
else
printf 'No collision found in the checked release paths.\n'
fi
Also inspect the installed boot entries and the installation layout used by this VM. After the checks pass, preserve the configuration and release name:
cp "$build/.config" "$build/config.reviewed"
printf '%s\n' "$target_release" > "$build/kernelrelease.reviewed"
sha256sum "$build/config.reviewed"
Keep the source release, seed configuration, intentional changes, storage requirements, signing plan, and fallback kernel with this record. Recheck the identity after any configuration or source change. The running uname -r changes only when you boot the new kernel.
Continue to Lesson 9: building and installing the kernel. Verify the resulting initramfs in Lesson 10 and the boot entry in Lesson 11. Installation helpers use distribution-specific hooks; this configuration review does not guarantee that they create the required files or a correct boot entry.