The Linux kernel is distinctive among major commercial UNIX variants in that the complete source code for the kernel is available and freely included in most major Linux distributions. If you are curious about a particular Linux implementation detail, you can have a look at the source. If you have a special need that requires modification of the kernel, you apply your patch and build your own special version of Linux.

This is not to say that building a kernel is a required step in the administration of a Linux system. There is no application used anywhere in this text that mandates a kernel with special features; the generic kernel put down by the installer has everything required. While older Linux implementations commonly required custom kernels (especially in the days before kernel modules), recent improvements in Linux have obviated much of the need for such system customization. A linux administrator who insists upon a custom kernel is behind the times.

However, security vulnerabilities were found in the 2.2.5 kernel shortly after Red Hat Linux 6.0 was released. Any production Linux installation on the 2.2 kernel series should upgrade to a patched kernel. This can be done with a complex set of steps involving RPM, or by building a new kernel as outlined below.

It is more important to build custom kernels for servers with Internet exposure than workstations. It is also easier, since servers generally do not have sound cards or other hardware that increases kernel complexity.

The Linux kernel is usually stored in a file called vmlinuz in the root directory of the system. However, Red Hat Linux 6.0 puts the kernel in the /boot directory, under a different name (such as vmlinuz-2.2.5-15). The kernel is loaded at boot time. As it boots, the kernel will probe the system and configure basic hardware settings, then load a program called init which continues the boot process; the boot sequence is not documented in this text. While portions of the kernel can be loaded or removed at will, the only way to switch to a completely different kernel image is to reboot.

Throughout this text, there has been an implicit understanding that the i386 architecture is in use. We now make that assertion explicit: the slight differences in preparing and booting kernels for Alpha and Sparc architectures are not discussed here.

Installing the Kernel Source

The Linux kernel is written in C and requires a C compiler in the development environment. A copy of the kernel source (version 2.2.11) is included on the CD-ROM in the /linux directory. It is encoded with the bzip2 compression utility. This bzip2 utility is not installed by default, but an RPM package which will install it is available in the standard distribtion of Red Hat Linux 6.0. If you do not know how to install such packages, you are definately not ready to build a new kernel - read the RPM section of Chapter 1 in this text.

It is very easy to make a mistake in building a kernel that will prevent a system from booting. Kernel builds are not for the inexperienced. An emergency boot disk, created at installation time, is a manditory item. For an inexperienced administrator, it is not a question of if a future kernel build will render the system incapable of booting, but when.

Assuming that the CD-ROM included with this text is mounted on the /cdrom directory, the kernel source could be unpacked with the following sequence of commands:

cd /usr/src
rm -f linux
bzip2 -cd /cdrom/linux/linux-2.2.11.tar.bz2 | tar xvf -
chown -R root.root linux
cd linux

Once the 2.2.11 kernel source is installed, check for newer versions of the kernel on-line. Two popular Linux kernel sites are http://www.kernel.org and http://www.kernelnotes.org. If there are new kernel versions available, just download and apply the patch files to bring the kernel source up-to-date. Documentation for applying the patches can be found on these sites. It should not be necessary to download the entire kernel source package. Use the patches as they are much smaller and accomplish the same effect.

The kernel source is also available in RPM format in the standard Red Hat distribution, but the use of the Linux kernel source RPMs is specifically not recommended. The RPM versions do not include the entire source distribution. Source patches will commonly fail to work properly with these versions.

FTP access to kernel.org is facilitated by the use of country codes. For example, administrators in the United States should use the ftp.us.kernel.org address to download kernel patches from the /pub/linux/kernel/v2.2 directory. Users in the United Kingdom should use ftp.uk.kernel.org, Canadians should use ftp.ca.kernel.org, etc.

Navigating “make config”

There is one valuable piece of advice for users considering the use of the make config command to configure the kernel - don't! The make config command has been supplanted by the much easier make menuconfig, which is the most flexible of the kernel build configuration utilities. make xconfig is also useful, but since it requires X-Windows, it will not be covered in this text.

Enter the following command to configure the build options for the Linux kernel:

make menuconfig

A menu similar to the following will appear:

 Linux Kernel v2.2.11 Configuration
 *****************************************************************************
  ******************************** Main Menu ********************************
  *  Arrow keys navigate the menu.  <Enter> selects submenus --->.          *
  *  Highlighted letters are hotkeys.  Pressing <Y> includes, <N> excludes, *
  *  <M> modularizes features.  Press <Esc><Esc> to exit, <?> for Help.     *
  *  Legend: [*] built-in  [ ] excluded  <M> module  < > module capable     *
  * *********************************************************************** *
  * *           Code maturity level options  --->                         * *
  * *           Processor type and features  --->                         * *
  * *           Loadable module support  --->                             * *
  * *           General setup  --->                                       * *
  * *           Plug and Play support  --->                               * *
  * *           Block devices  --->                                       * *
  * *           Networking options  --->                                  * *
  * *           SCSI support  --->                                        * *
  * *           Network device support  --->                              * *
  * *           Amateur Radio support  --->                               * *
  * *           IrDA subsystem support  --->                              * *
  * *           ISDN subsystem  --->                                      * *
  * *           Old CD-ROM drivers (not SCSI, not IDE)  --->              * *
  * *           Character devices  --->                                   * *
  * *           Filesystems  --->                                         * *
  * *           Console drivers  --->                                     * *
  * *           Sound  --->                                               * *
  * *           Kernel hacking  --->                                      * *
  * *           ---                                                       * *
  * *           Load an Alternate Configuration File                      * *
  * *           Save Configuration to an Alternate File                   * *
  * *********************************************************************** *
  ***************************************************************************
  *                    <Select>    < Exit >    < Help >                     *
  ***************************************************************************

Each menu option above composes a major subsection of the kernel configuration parameters. Within these subsections, individual options that can be enabled or disabled. For most options, as they are enabled, they cause extra code to be compiled into the kernel, which makes the binary kernel image larger.

Most of these options can be built in two ways. They can either be compiled directly into the kernel binary, or they can be built as modules which can be loaded and removed from the kernel at will. Some configuration options cannot be prepared as modules, and others can only be used as modules, but most can be used either way.

The greatest pitfall, however, are the storage options which include drivers for SCSI (Small Computer Systems Interface) and IDE (Integrated Drive Electronics). If the kernel is loaded from a SCSI drive, the driver for the SCSI controller must be available to the kernel, or the system will not boot because it does not know how to manipulate the SCSI hardware. The best way to prepare a kernel for a SCSI system is to compile the driver for the SCSI controller directly into the kernel image. This is not a reasonable solution, however, for the generic kernel provided by the installation process. In this generic kernel, the SCSI drivers are provided as modules, since drivers compiled directly into the kernel would make the kernel image very, very large. If the modules are stored on the SCSI hard drive, a chicken-and-egg situation develops. The generic kernels use an “initial ramdisk” to solve this problem. The “initrd” image holds copies of all the SCSI modules. The initrd image is loaded by LILO (or whatever loader is in use) and is available as the kernel boots. In any case, initrd images are inconvenient and it is best if custom kernels do not rely upon them.

In addition to the basic ability to access the hard drive, a few other configurations will result in a system that will not boot. Failure to provide support for ext2fs (Second Extended File System support) will clobber a system quite handily, since ext2fs is the native file system used in Red Hat Linux at this time (this situation may change with the inclusion of the XFS journaling file system in the anticipated Linux 2.4 kernel). Improper device configuration options passed as arguments to the kernel can commonly lead to a quick death at boot time. It is not difficult to find a long list of things that can go wrong, so ensure a contingency plan is in place (relating to LILO and an emergency boot diskette).

Before building a kernel, an approach to modules must be decided. When building a kernel to be used on a large number of machines, it is very convenient to disable modules and (carefully) select drivers for all required hardware to compile directly into the kernel. Copy the kernel as a single file to a remote system, run LILO, then reboot in the new kernel environment. If such a static kernel is used, it will be advisable to comment out the entry in /etc/cron.d/kmod, otherwise hourly status messages will be generated by cron concerning module manipulation failures. In any case, static kernels are much more convenient from an administration standpoint than kernels that use modules. However, there are size limitations on the kernel binary image, and some features must be compiled as modules. If circumstances demand it, use modules and be glad for them.

Before beginning a kernel configuration, it might be appropriate to examine the output of the lsmod command. lsmod will list all loaded modules in the active kernel image. Such a list will both confirm planned kernel features and list hardware drivers that might have been neglected or forgotten. Obviously, lsmod will fail if a static kernel is in use.

Not every kernel configuration option can be covered here. Being aware of the specific problem areas, the administrator must build a kernel, boot with it, then test to see if all required functionality is still available. If something important doesn't work anymore (i.e., network routing, the CD-ROM drive, etc.), then it is likely that the kernel wasn't built with everything it needed.

Now, a brief synopsis of the options in make menuconfig (help is available on any option through the menus):

Code maturity level options
This menu will allow for experimental drivers and incomplete code to be included in the build. Unless you like to live on the wild side, leave this switched off. The kernel-based NFS server, now the supported NFS server for Red Hat Linux, is classed as an experimental feature, so this option must be set to provide NFS server support.
Processor type and features
Select the type of processor for which the kernel is being built. If the kernel obtained from this process will be used on a variety of machines, build for the least common denominator. If the processor lacks the “math coprocessor” (the 386, 486sx, and NexGen processors do not include them, but all Pentiums do), be sure to enable “math emulation.” If the system has multiple processors, enable Symmetric Multi-Processing (SMP), but otherwise leave it off.
Loadable module support
If enabled, extra kernel code will be stored under /lib/modules, and kernel features that support it can be loaded as dynamic modules. Enable the kernel module loader if modules are enabled (so the old kerneld module loader isn't required). If modules aren't enabled, remember to comment out the entry in /etc/cron.d/kmod, otherwise hourly status messages will be generated by cron concerning module manipulation failures.
General setup
Basic networking, PCI bus controls (PCI is a hardware standard used in most modern PCs), the format of program binaries, and System V IPC are configured here. Make sure that most of this stuff is on. Inter-Process Communication (IPC) is used by many applications, especially the Apache web server.
Plug and Play support
Try to avoid plug and play hardware, but if you've got it, enable this feature.
Block devices
The IDE disk and CD-ROM support should probably be enabled, even if the system is SCSI-only, since IDE equipment is so cheap and plentiful. If the IDE chipset can be verified, specifically set it here (especially turn off the checks for the buggy CMD640 and RZ1000 if they are not needed). The loopback device is required for the initrd command and it is also useful in writing CD-ROMs, so it should be built into the kernel if at all possible.
Networking options
Major networking parameters including routing, firewalls and masquerade can be configured within this menu (masquerade only appears if “Network firewalls,” “TCP/IP Networking,” “IP Firewalls,” and “always defragment” options are set).
SCSI support
Support for SCSI configurations is available here. CD recorders require SCSI generic support. Individual SCSI adapters can be selected from the “SCSI low-level drivers” menu at the bottom. If your root file system is on a SCSI controller, compile the driver for the controller directly into the kernel, not as a module, or an initrd image will be required.
Network device support
Drivers for networking hardware will be found here, including ethernet, token ring, fddi, etc. Support for PPP is also configured within this menu.
Amateur Radio support
Configure Linux support for amateur radio here.
IrDA subsystem support
If you have wireless infrared devices on your computer equipment, configure them here.
ISDN subsystem
If you have an Integrated Services Digital Network adapter, configure it here.
Old CD-ROM drivers (not SCSI, not IDE)
If you have a really old CD-ROM drive which is not based on the SCSI or IDE interfaces, do us all a favor and buy something newer. IDE CD-ROM drives can be found for under $50. If you absolutely must have support for one of these older drives, configure it in this menu.
Character devices
The console and virtual terminal options in this menu probably shouldn't be changed. If you have a supported multi-port serial board, a driver for it can be configured here. Psuedo-terminal devices are also configured here. Psuedo-terminals are consumed by telnet connections, xterms, and other terminal-like services. The default is a maximum of 256 devices; increase this limit if necessary. Bus mice and PS/2 mouse support is included in this menu, as well as QIC tape support.
Filesystems
The critical entry here is the “Second extended fs support.” This is the native filesystem for Red Hat Linux 6.0. Without it, the system will not boot. CD-ROMs cannot be read without the ISO 9660 filesystem support. DOS filesystems will commonly require FAT support, plus one of the DOS filesystem types (such as MSDOS or VFAT). Support for the /proc filesystem is virtually required - its lack will break many programs. NFS client and server support can be found under the “Network File Systems” menu - NFS server support requires experimental driver support in the Code Maturity menu.
Console drivers
These include drivers for basic VGA, plus the new frame buffer.
Sound
Sound cards are configured here.
Kernel hacking
The option in this menu is only used in debugging the Linux kernel. Unless you are actively modifying code in the kernel, it is safe to leave this option unset.
Load/Save Alternate Configuration File
It is possible to save the kernel configuration to a file. This file can then be moved to another machine and loaded into a separate kernel build environment. The kernel configuration from the Red Hat kernel source packages is stored in kernel/redhat.config on the CD-ROM included with this text. It can be loaded with the above menu options. This configuration requires an initrd, so modify the SCSI configuration to compile a driver for your SCSI controller directly into the kernel if possible.

When all options have been properly configured, exit the menu. A prompt will ask if the changes to the kernel configuration should be abandoned; answer no if everything is correct.

Compiling

Compiling the Kernel

Once the kernel configuration is complete, run the following two commands to clean the source tree and generate the dependency files:

make dep
make clean

At this point, one way to generate a new kernel is with the following command:

make zlilo

This command will generate the files /vmlinuz (the zipped kernel image) and /System.map (a table of symbols from the kernel). However, because Red Hat Linux installs the kernel in the /boot directory, this new kernel will not boot. One way to use this new kernel is to modify LILO to boot from /vmlinuz. Below is an example of a stock /etc/lilo.conf which is configured to boot a kernel in the “Red Hat Way.” This LILO configuration is from an IDE system which does not use an initrd.

boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=50
image=/boot/vmlinuz-2.2.5-15
	label=linux
	root=/dev/hda5
	read-only
other=/dev/hda1
	label=dos
	table=/dev/hda

The above /etc/lilo.conf can be modified to boot /vmlinuz. The label describing the kernel in the boot directory is renamed to “linuxold” (the “label” is the keyword typed at the LILO boot prompt which selects the operating system to boot). Then, a new image “stanza” is added, describing /vmlinuz.

boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=50
image=/vmlinuz
	label=linux
	root=/dev/hda5
	read-only
image=/boot/vmlinuz-2.2.5-15
	label=linuxold
	root=/dev/hda5
	read-only
other=/dev/hda1
	label=dos
	table=/dev/hda

Once the file is reconfigured, run /sbin/lilo to reconfigure the LILO boot manager with the new kernel.

Some other operating systems place kernel images place the kernel image in a completely separate file system, such as /stand. Refrain from this behavior in Red Hat Linux.

There are two main reasons why you might not want to use “make zlilo” in this way. Either you want to follow the Red Hat convention of placing the kernel image in the boot directory, or the “make zlilo” failed, complaining that the kernel image was too large.

If the image is too large, it can be compressed further by using “make bzImage” which uses the bzip2 compression format. However, you should make certain that all unnecessary drivers have been removed from the kernel image.

After a successful run of “make bzImage,” a copy of the compressed kernel will be stored in /usr/src/linux/arch/i386/boot/bzImage and a System.map will be placed in /usr/src/linux. Move these files to the desired positions (either the root directory or /boot and reconfigure LILO accordingly).

Do not reboot the system until the modules and the initrd (if required) are installed. After booting and satisfactory testing of the new kernel, the generic kernel in /boot can be removed. Use caution, and do not delete the files required by LILO; do not touch boot.b or map in the /boot directory.

Compiling the Modules

If modules are enabled in the kernel configuration, they must be generated in a procedure separate from the kernel preparation. Enter the following command from /usr/src/linux:

make modules

Once the modules have been compiled, they can be installed with:

make modules_install

This command installs the modules under /lib/modules, in a directory that has the same name as the kernel release. When moving the kernel to another Linux system, this set of directories must be moved also, and they must be placed in the same location on the target system.

Creating the initrd

If you are using a SCSI system and you have made the (unwise) decision to prepare support for your SCSI adapter as a module, an initrd will be required. Generate it with the following command:

mkinitrd initrd 2.2.11

Below is an example /etc/lilo.conf demonstrating the use of an initrd. Note further that the generic kernel put down by the Red Hat installer has been preserved:

boot=/dev/sda
map=/boot/map
install=/boot/boot.b
prompt
timeout=50
image=/vmlinuz
	label=linux
	root=/dev/sda1
	initrd=/initrd
	read-only
image=/boot/vmlinuz-2.2.5-15smp
	label=linuxold
	root=/dev/sda1
	initrd=/boot/initrd-2.2.5-15smp.img
	read-only
image=/boot/vmlinuz-2.2.5-15
	label=linux-up
	root=/dev/sda1
	initrd=/boot/initrd-2.2.5-15.img
	read-only

Using an Errata Kernel

If you don't want to go to the trouble of building your own kernel, you can apply errata kernels that are posted by Red Hat. At the time of the publication of this text, the latest version of the kernel that Red Hat would like you to use is 2.2.5, build 22. This version replaces 2.2.5, build 15, which has a bug that allows remote users to crash it.

Red Hat, in previous Linux distributions, included a single kernel RPM, compiled for an 80386 processor, in the Red Hat Linux installation. Starting in Red Hat Linux 6.0, Red Hat now includes several kernels for different types of machines. Following are the kernel packages in the errata:

kernel-2.2.5-22.i386.rpm
For i386, i486 and other “non-Pentium” systems.
kernel-2.2.5-22.i586.rpm
For Pentium and most Pentium class CPU's.
kernel-smp-2.2.5-22.i586.rpm
For Pentium SMP boxes.
kernel-2.2.5-22.i686.rpm
For i686 (Pentium II, Celeron).
kernel-smp-2.2.5-22.i686.rpm
For i686 SMP.

Red Hat has a long list of steps to upgrade your kernel, but it really isn't that hard. We will assume that a uni-processor Pentium system is to be upgraded. You could enter the following set of commands:

/sbin/modprobe loop.o
rpm -ivh kernel-2.2.5-22.i586.rpm
/sbin/mkinitrd /boot/initrd-2.2.5-22.img 2.2.5-22

If you are really brave (or crazy), you can use the “Uvh” option of RPM, which will destroy your present kernel, and prevent LILO from booting the system unless it is reconfigured:

/sbin/modprobe loop.o
rpm -Uvh kernel-2.2.5-22.i586.rpm
/sbin/mkinitrd /boot/initrd-2.2.5-22.img 2.2.5-22

The “Uvh” option is probably more realistic for IDE, rather than SCSI users. If, for some reason, the loopback device is not available, the mkinitrd will fail.

In either case, before you attempt either of these commands, make sure that you have your boot disk handy. Lost your boot disk? You can create another, before your upgrade, with the following command:

mkbootdisk --device /dev/fd0 2.2.5-15

If I have to tell you that /dev/fd0 is the A: drive on your PC, you probably aren't ready to be doing a kernel upgrade. You should also be advised that if you use the “Uvh” option to the RPM kernel upgrade command, the loop.o kernel module won't be available on your boot disk (if the system crashes). You could get it out of an older RPM, though. In any case, don't use the “Uvh” option unless you're sure that you can get it right the first time, and you might set aside a copy of loop.o from your old kernel before you start (it lives in the /lib/modules directory).

The above mkinitrd command isn't really that important on IDE systems, but it is deadly important on SCSI systems. Without the kernel modules in the initrd, the system will not boot.

Once the new kernel is installed, the system is in a precarious state. LILO should be reconfigured immediately. A reboot between the kernel upgrade and LILO reconfiguration could range from inconvenient to disasterous. Upgrades for an IDE system are usually as simple as changing the name of the kernel image in /etc/lilo.conf:

boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=50
image=/boot/vmlinuz-2.2.5-22
	label=linux
	root=/dev/hda5
	read-only
other=/dev/hda1
	label=dos
	table=/dev/hda

Alternately, if the “Uvh” option was not used, the old kernel could be set up as a backup:

boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=50
image=/boot/vmlinuz-2.2.5-22
	label=linux
	root=/dev/hda5
	read-only
image=/boot/vmlinuz-2.2.5-15
	label=linuxold
	root=/dev/hda5
	read-only
other=/dev/hda1
	label=dos
	table=/dev/hda

This alternate configuration lets LILO boot the new kernel if “linux” is entered at the prompt, and the old kernel if “linuxold” is entered instead (in addition to the “dos” entry).

A SCSI system is a bit trickier, as the initrd must also be set:

boot=/dev/sda
map=/boot/map
install=/boot/boot.b
prompt
timeout=50
image=/boot/vmlinuz-2.2.5-22
        label=linux
        root=/dev/sda1
        initrd=/boot/initrd-2.2.5-22.img
        read-only
image=/boot/vmlinuz-2.2.5-15
        label=linuxold
        root=/dev/sda1
        initrd=/boot/initrd-2.2.5-15.img
        read-only

Once the new /etc/lilo.conf file has been written, don't forget to run the following command:

/sbin/lilo

Forgetting to rerun LILO before the reboot is a major cause of terror for Linux administrators, which nabs IDE and SCSI users alike.

If you haven't been frightened away at this point, the odds are that you are about to change your kernel. Good luck! Make sure your boot disk is good, and may your LILO never fail you!