Linux: Custom Kernels Trim Fat and Tune Performance
I have some shocking news: despite the astonishing growth of Linux, there is a whole new generation of Linux users who have never, ever compiled a kernel. How to account for this sad state of affairs? Perhaps it's because the distribution maintainers are doing such fine jobs it's not necessary. Maybe users just don't know that they can. Whatever the reasons, today we're taking a tour of some of the different ways to customize the Linux kernel. First we'll learn the old reliable generic way, and then take a tour of the Fedora Way and the Debian Way of customizing kernels.
A word of warning: while building a custom kernel isn't all that difficult, it is complex and time-consuming, and when you're all finished you might be the proud parent of a non-booting kernel. The good news is you can have as many do-overs as you want without hurting your system. Any Linux system can have any number of kernels and you can choose which one to boot to, so never delete old kernels until you're certain your new one works correctly. Your system will not try to boot to a new kernel until you explicitly configure it to do so, so it can't sneak up on you. So you can go on a wild spree and build and test a whole army of new kernels if you like.
Give yourself a couple of gigabytes of disk space to play with. You'll need it to hold your kernel sources and build tools and other utilities, plus you'll need 500 megabytes just for the interim files created during the build process, and you'll need a place to keep your nice new kernels and kernel modules.
You should have the lshw and lspci commands installed in case you need to look up hardware information. Run the update-pciids command first to bring them up-to-date. cat /proc/cpuinfo displays your CPU specs.
Why would you even want to do this? For a number of reasons: to get extra functionality, to weed out unneeded features, to try for better performance, to help with testing new patches, or just because you want to know how. The last two reasons are the best ones. I wish everyone had curiosity and a desire to tinker and improve things.
Most general-purpose Linux distributions ship with kernels and sets of modules that try to please everyone and support all the hardware in the world, so you end up with a couple hundred megabytes of kernel + modules fattening your system. This raises security concerns, and some things are just plain silly such as support for infrared, ham radio, and bales of laptop-specific crud on a desktop system, to name my three personal favorite useless features. And why have all that lard in the first place? It's fun to build a kernel customized for your CPU and that supports only the hardware and other features that you want it to. You might even see a performance gain.
The Generic Way of Customizing Kernels
You can get freshly-baked kernels and the latest patches from Kernel.org. These are called vanilla kernels because this is where the original, unmodified kernels live. Then you need to assemble your build environment. Both Fedora and Debian make this easy. On Fedora, install the Development Tools package group:
# yum groupinstall 'Development Tools'
You'll also want Qt:
# yum install qt-devel
On Debian use this command:
# aptitude install build-essential libqt3-mt-dev
The Documentation/Changes file in your unpacked source tarball gives you a basic list of applications that you need for a build environment. In fact you should invest a lot of time exploring the documentation that comes in the kernel tarball- there is a wealth of knowledge squirreled away in there.
When you download and unpack your new kernel sources don't put them in /usr/src, and pay no attention to all the people who tell you to do that. Create a directory in your home directory to keep your source trees in. The kernel README itself says:
"...put the kernel tarball in a directory where you have permissions (eg. your home directory)...Do NOT use the /usr/src/linux area! This area has a (usually incomplete) set of kernel headers that are used by the library header files. They should match the library, and not get messed up by whatever the kernel-du-jour happens to be."
I use /home/carla/kernel.
Unpack your kernel tarball with tar zxvf linux-2.6.22.tar.bz2, using your correct version of course. Then change to the top-level kernel source directory and open the Makefile in your favorite text editor. Change the EXTRAVERSION = line to something unique, like EXTRAVERSION = .1-carla.
Next, let's see what options the make command has:
$ make help
This is going to spit out a lot of information. Take some time to look it over. Read the Makefile itself, which is a plain-text file. Then do a bit of housecleaning:
$ make mrproper
Read the output of make help to see what this does. It shouldn't be necessary at this stage, but it's cheap insurance and sometimes you inherit funky stuff.
Now we get to the fun part- configuring our new kernel-to-be:
$ make xconfig
You'll see something like Figure 1.
This is the part that takes a lot of time. If you don't have a config file in your kernel source tree or supply one on purpose, xconfig will use your /boot/config-2.6.* file. This isn't a problem, but a good starting point. You can change anything you want anyway. Click the Help button to see how to use xconfig. Every configuration option has a description, and next week we'll review some of them.
Once you are happy with your configuration, run the make command with no options. This will take some time, maybe up to an hour or more. Then change to root and run these commands:
# mkinitrd -o /boot/initrd-2.6.22.img
# cp ~/kernel/linux-2.6.22/arch/i386/boot/bzImage /boot/vmlinuz-2.6.22
# cp ~/kernel/linux-2.6.22/System.map /boot/System.map-2.6.22
arch/i386/boot/bzImage is your new kernel, and it must be copied to the /boot directory. Copy over the matching System.map, and your new initrd image should already be there.
Add all of this to your GRUB menu, reboot, and give it a whirl. This is an example menu.lst entry:
homebrew 2.6.22 kernel
kernel /boot/vmlinuz-2.6.22 root=UUID=b099f554-db0b-45d4-843e-0d6a1c43ba44 ro
The kernel names and initrd image names are arbitrary; you could call them anything you want, as long your menu.lst entries match. GRUB counts from zero, so /dev/hda1, which is the first partition on the first hard drive, equals (hd0,0) in menu.lst.
The root partition's UUID comes from running the blkid command:
/dev/sda1: UUID="b099f554-db0b-45d4-843e-0d6a1c43ba44" SEC_TYPE="ext2" TYPE="ext3"
/dev/hda1: UUID="1a5408ad-7d1d-4e24-b9db-d132d76e9e8e" SEC_TYPE="ext2" TYPE="ext3"
In this shiny new era of udev, you should use UUIDs to identify your block devices because /dev names are no longer static, but at the mercy of udev. You need to create an initrd image because the /dev directory is not populated until after boot, so there is no way (that I know of) to build the boot device into the kernel anymore.
Next week we'll learn the Debian and the Fedora way of customizing kernels, and review some of the meelyuns of kernel compilation options.