If you’ve ever looked into recompiling your Linux kernel, you’ve probably seen advice to include critical boot drivers (for your hard disk controller and root partition’s filesystem) in the kernel itself. Omitting the boot drivers is likely to result in an inability to boot the computer. The kernel loads and begins doing some checks, but then stops because it can’t read the root filesystem.
The kernels provided by most Linux distributions, however, lack the drivers for most disk hardware. These same distributions can install and boot on all of this hardware, though. How is that possible? The answer is that the kernels use an initial RAM disk (initrd for short) to hold the relevant drivers as modules. When the computer boots, the boot loader passes the initrd to the kernel, which loads it into RAM and treats it like a disk. The kernel can then load modules stored in the RAM disk, keeping the kernel size small while still providing a wide variety of drivers.
When you compile your own kernel, it’s usually easier to bypass the initrd and instead build the relevant drivers into your main kernel file. Sometimes, though, you might want to build your own initrd. Let’s see how.
Why Use initrd?
The average desktop or server system running a custom kernel doesn’t need initrd. However, it can be useful in several situations:
*Most distributions use initrd because the distributions’ designers can’t predict what hard disk controller you’ve got.
*Using initrd enables you to design a custom emergency system or specialized boot CD-R that will run on a variety of systems. This could be handy if you want to have an emergency system for use in a work environment with many different system configurations.
*If you maintain several Linux systems, you may want to custom-build a single kernel for all of them. Rather than tweak each system’s kernel for its specific hardware or build kernels with multiple sets of disk drivers, you can place the necessary drivers as modules in initrd.
*In certain embedded and specialized Linux systems, initrd may be used as the final root filesystem. This enables Linux to run on a read/write filesystem even when the only permanent storage is read-only in nature.
*Even if you don’t want to build a completely new initrd, you might want to modify the one provided by your distribution maintainer, say, to add a new or updated driver.
Getting to Know initrd
Before delving into initrd configuration, you should understand a bit about how it works.
When a Linux system boots, the computer reads a boot loader, which in the case of an x86 or x86-64 Linux system is likely to be the Linux Loader (LILO) or the Grand Unified Boot Loader (GRUB). LILO and GRUB are both very simple programs. They can read data from the hard disk using BIOS calls, so they don’t need disk drivers such as those used by the Linux kernel. Using BIOS calls, LILO or GRUB loads the Linux kernel into memory and executes it. When given appropriate options, LILO or GRUB also loads an initrd image, which is typically stored on disk in your /boot directory along with the kernel file. When the boot loader loads an initrd image, it passes its address in memory to the kernel when it starts the kernel.
Once the kernel is running, it mounts the initrd image and executes the /linuxrc or /init program on the RAM disk. (Most initrd documentation refers to /linuxrc, but some systems expect a file called /init.) This program acts something like the normal Linux startup program (/sbin/init), in that it controls what the kernel does with the initrd contents. Typically, /linuxrc or /init is a shell script that loads the drivers necessary for accessing your hard disk, swaps out the RAM disk filesystem for the root filesystem on the hard disk, releases the memory used by the RAM disk, and then continues the boot process using the hard disk’s root filesystem. In principle, this RAM disk boot script could do much more than this, but in practice additional steps are usually performed by /sbin/init on your hard disk and the programs it calls, such as SysV startup scripts. Using on-disk programs and utilities makes for easier system maintenance.
One problem with using initrd is that the RAM disk image must be maintained using utilities. You can’t just copy files in and out of a directory. In the past, initrd image files were typically filesystem images, holding ext2, romfs, or other filesystems. Today, they’re more often compressed cpio archives. As a result, the process of creating or modifying an initrd image involves extracting data from an existing image file, replacing and modifying files, and creating a new archive with your new or changed files. You can then modify your boot loader configuration to access the new files. Chances are you’ll need to reconfigure your kernel before you do any of these things, though.
Configuring Your Kernel
In most cases, the whole point of using initrd is to slim down your kernel. Therefore, you should peruse your kernel options, changing drivers you normally build into the kernel to build as modules. Typically, such options are restricted to filesystems and hard disk drivers.
Of course, you can do the same to other drivers, such as sound card drivers, network drivers, and frame buffer video drivers; however, such drivers are not typically required to boot the computer (with the exception of network drivers for network boot configurations), so you can perform such slimming even if you don’t use initrd.
One notable caveat exists: If you intend to create an initial RAM disk as a disk image file (rather than as a cpio archive file), you must build support for the filesystem you use into your kernel. You could build a RAM disk image using ext2, romfs, the Minix filesystem, or various others. Chances are ext2 would be the most convenient, but you can use your own judgment on this matter. Creating a cpio archive instead of using a conventional filesystem enables you to build all your standard filesystems as modules.
Two options that must be present in your kernel to use an initial RAM disk are the RAM Disk Support and Initial RAM Filesystem and RAM Disk (initramfs/initrd) Support options, both of which are in the “Block Devices” subsection of the Device Drivers kernel configuration area. Be sure these options are both built into the kernel itself!
Once you’re done configuring your kernel via make xconfig, make menuconfig, or similar tools, you can compile it in the normal way. Remember to install your kernel modules via make modules_install and copy your main kernel file to /boot.
Using initrd Preparation Tools
The easiest way to create an initrd is to use a preparation tool. Most distributions include a program called mkinitrd to do this job. To use it, pass it the name of the file in which you want to store your initrd image and the kernel version number you want to use:
# mkinitrd /boot/initrd-2.6.18.cpio.gz 2.6.18
This example creates an initrd image for the 2.6.18 kernel. Here, the .cpio.gz filename extension is used because this is what it really is, but most distributions give it no extension or an .img extension instead.
Although mkinitrd and similar tools (such as yaird, http://alioth.debian.org/projects/yaird/) are handy, they’re inflexible. If you want to create an unusual initrd, you’ll need to dig into the standard file and modify it.
Preparing an initrd Image from Scratch
One way to create a custom or unusual initrd is to start with a working image. You can begin with a standard initrd image or create one with mkinitrd. Locate the original file, copy it to a convenient directory, and create a subdirectory to hold the RAM disk’s extracted files. The original file is typically called /boot/initrd-* or /boot/initrd-*.img, where * is a version number and perhaps additional distribution-specific codes. Although many distributions do not include a .gz extension in their initrd filenames, these files are almost always compressed with gzip. Thus, you should rename the copy to include a .gz extension. Suppose it’s called initrd.img.gz. If the file is a cpio archive, you can uncompress it with cpio and gunzip, after changing into the working directory for your RAM disk files:
# gunzip -c ../initrd.img.gz | cpio -iv
The result should yield a copy of the files from the initrd image file you specified.
If you’re working from a disk image rather than a cpio archive, you can uncompress the copy and mount it using the loopback device, after changing into the directory that holds the initial RAM disk image file:
# gzunip ./initrd.img.gz
# mount -o loop initrd.img ./workdir
This pair of commands makes the working files available under the workdir subdirectory of the current directory. One caveat about this approach is that initial RAM disk images may contain little or no extra space for adding files. Thus, you may need to copy these files to another subdirectory, modify them there, and then create a cpio archive from your changed files. Alternatively, you could create a larger filesystem image file and copy the files there.
In either case, you can begin modifying the RAM disk’s files. Precisely how you proceed depends on what you want to accomplish, but some things you may want to do include:
*Replace kernel modules (files with the .ko extension) in the RAM disk’s lib directory with their equivalents from your newly compiled kernel, as stored in the /lib/modules/version directory tree, where version is your kernel version number.
*Add kernel modules for any drivers or filesystems you want to have available during the boot process, perhaps including proprietary or non-standard drivers.
*Modify the init or linuxrc file to perform additional tasks. You may need to add insmod lines to load new kernel modules, for instance. This startup script is normally a shell script, so you can edit it with a text editor.
*Depending on your distribution and from where you acquired your kernel source, you may need to rename the init file to linuxrc or vice-versa. To hedge your bets, create a symbolic link so that it may be called by either name.
*More ambitious changes may require you to add programs to bin, add device nodes to dev, or make more extensive changes to the startup script. If you’re creating an emergency boot system or other standalone boot CD-R, you may want to disable the last few lines of a standard initrd startup script, which pass control over to the on-disk boot partition. Instead, substitute a call to bash or some other shell.
One potentially frustrating aspect of preparing or modifying a startup script is that it can be tricky to get the order in which you load kernel modules right. You can use the modinfo command on the kernel module files to spot dependencies, which can help you figure out what needs to be loaded first (or at all).
When you’re finished making changes, you must create a new initial RAM disk file. If you’ve used a loopback device, unmount and recompress it to do the trick:
# umount ./workdir
# gzip -9 initrd.img
If you want to create a cpio archive as your initrd carrier, you can
do so with cpio and gzip:
# cd workdir
# find ./ | cpio -o -H newc | gzip -9 > ../initrd.cpio.gz
In either case, you should probably copy your new initrd image file to /boot, perhaps renaming it with an appropriate version number.
Reconfiguring Your Boot Loader
At this point, you should have a new kernel in /boot and a new initrd image in the same location. Your task now is to reconfigure your boot loader (LILO or GRUB) to use both.
If you use LILO, load the /etc/lilo.conf file into a text editor. This file contains global options followed by a series of stanzas, each of which describes one kernel or non-Linux OS. Linux stanzas begin with a line that starts with the string image= followed by the kernel’s filename. Subsequent lines in the stanza are usually indented and describe options.
Copy your current working stanza and modify the copy to point to the new kernel. Locate the line in the stanza that begins initrd= and point it to your new initrd image file. When you’re done, save your changes and type lilo at a root prompt to re-install LILO.
In the case of GRUB, edit the file called /boot/grub/grub.conf or /boot/grub/menu.lst. Locate your current boot stanza, copy it, and modify the copy to point to the new kernel and initrd image. The relevant lines begin with the strings kernel and initrd, respectively. Once you’ve made the changes, you don’t need to re-install GRUB; this boot loader reads the configuration file from disk whenever the system boots.
Rebooting to Use Your initrd Image
At this point, you should reboot your computer to test the new kernel and initrd configuration. If all goes well, your computer will start normally, providing access to all your devices. If there’s a problem, it should show up fairly early in the boot process.
The most common problem is that the kernel can’t mount a root filesystem (either the initial RAM disk or the hard disk’s root filesystem). If this happens, you’ll see a note to that effect. Read all the kernel messages on the screen; they may provide clues about what went wrong. The usual cause is a missing or out-of-place insmod call in the initrd startup script.
Once your system is working, you can tweak it. You can add drivers to your startup script to support multiple hardware configurations, or create separate startup scripts and RAM disk images to support these configurations. Attempting to load a driver for a nonexistent device is normally not a problem, so you may be able to get by with a single RAM disk image for multiple hardware configurations. Because the kernel releases the initrd memory when it switches to the hard disk root partition, there’s no memory penalty for providing a big RAM disk with lots of drivers.
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου