Update, January 29th, 2006. If you are using a kernel newer than 2.6.12, don’t use initrd-tools. It’s unmaintained and may not work. What follows may be useful for systems still using initrd-tools. For newer systems, you might want to read about other options, such as initramfs-tools or Yaird.
–
When I started booting a box with multiple SCSI adapters, I wanted to keep the device ordering sane. I find it’s best when the boot ordering matches the order in which Linux initializes the drivers for each controller. One effective way to handle this under Debian GNU/Linux with one of the stock kernels is to create a custom initrd image.
To create your own initrd under Debian, you will want to install the initrd-tools package. You can then customize to your heart’s content using the /etc/mkinitrd configuration directory.
The most important file, /etc/mkinitrd/modules, is the list of modules you want included in the image and loaded, in the order specified, at boot time. The listed modules should be the ones necessary to initialize the actual root device. You must list the modules in dependency order. The kernel will not have the benefit of modprobe at boot time.
Within the mkinitrd.conf file you can change the MODULES option to dep to pack a minimal set of kernel modules in your initrd image. DELAY is also useful when things don’t work out. Before the initrd image tries to pivot to the new root filesystem, a brief delay will allow you to see just which modules loaded and in what order, to help debug any problems you many encounter.
# /etc/mkinitrd/modules: Kernel modules to load for initrd. # # This file should contain the names of kernel modules and their arguments # (if any) that are needed to mount the root file system, one per line. # Comments begin with a `#', and everything on the line after them are ignored. # # You must run mkinitrd(8) to effect this change. # # Examples: # # ext2 # wd io=0x300 scsi_mod sd_mod aic7xxx 3w-xxxx jbd ext3
To build your initrd, you will want to use mkinitrd, specifying the file to write the image to and what your root device is. You can allow mkinitrd to probe for your root device, but that is not always wise. For example, if you just installed a SCSI controller and your new boot device is attached to that controller, but your current root device is an IDE disk, the probe will not include the SCSI drivers you will need at next boot. The DELAY option mentioned above will help track down some of these issues. Finally, the -k option instructs mkinitrd to retain its working directory. You can then check to see if it built the image according to your wishes. Optionally, you can include the kernel version string for a kernel other than your running kernel as the last argument to mkinitrd to build an initrd for a non-running kernel. (The correct version string is the directory name in /lib/modules.)
mkinitrd -k -o /boot/initrd.img -r /dev/sda1
The newly created initrd image is actually a cramfs filesystem, which you can mount on the loopback device. Cramfs has officially been a part of the v2.4 kernel series starting with 2.4.22 and it is in v2.6 as of v2.6.3 and above. If you are compiling your own kernel, you must compile in support for using an initrd, whether your kernel supports cramfs or not.
Mark Alexander, in an email, offered some additional information if you’re using a kernel that does not support cramfs, which includes kernels downloaded directly from kernel.org through 2.6.2. Cramfs was officially merged into 2.6 starting with v2.6.3. To create a regular ext2 filesystem and use it as an initrd image, Mark suggests the following procedure. Edit /etc/mkinitrd/mkinitrd.conf and use the following binary for creating the imagine:
MKIMAGE='/usr/local/sbin/mkext2fs %s %s > /dev/null'
Next, create /usr/local/sbin/mkext2fs. (This was originally posted by Fabian Franz to the debian-knoppix mailing list. He explained to me that you may have issues with images greater than 2MB, so you should specify ramdisk_size=100000 or a value larger than your initrd image when you boot your kernel with your bootloader of choice. Thanks!)
#!/bin/bash # similar to mkcramfs (for use with debian mkinitrd) # mkext2fs dirname outfile # # no options are parsed # # Written by: Fabian Franz# GPL v.2 - See: `locate gpl.txt` if [ $# -lt 2 ] then echo "Usage: $(basename $0) dirname outfile" exit 1 fi TMPDIR=/tmp/$(basename $0).$$ mkdir $TMPDIR function clean_exit { umount $TMPDIR 2>/dev/null rm -rf $TMPDIR } trap clean_exit EXIT COUNT=$[$(du -s $1 | awk '{ print $1 }' )*2+1000] dd if=/dev/zero of=$TMPDIR/image count=$COUNT mke2fs -F $TMPDIR/image mount -o loop $TMPDIR/image $TMPDIR cp -a $1/* $TMPDIR umount $TMPDIR cat $TMPDIR/image | gzip - > $2
If you built a cramfs image, you can mount it on the loopback device and investigate to verify its loading the modules you instructed it to. (You can do the same with the ext2 image, but remember its compressed with As indicated above, after the SCSI subsystem loads, the driver for the SCSI controller with the boot device is loaded, followed by the 3Ware controller’s driver, which acts like a SCSI device driver. Now you can easily change the ordering, if need be. A quick look inside the image should confirm, before you waste a reboot, that the modules you instructed Now, that wasn’t so painful, was it?
sarah:/etc/mkinitrd# mount -t cramfs
-o loop /boot/initrd.img-2.4.22-xfs-386 /mnt
sarah:/etc/mkinitrd# ls /mnt
bin dev2 etc linuxrc loadmodules proc script sys usr
dev devfs lib linuxrc.conf mnt sbin scripts tmp var
sarah:/etc/mkinitrd# cat /mnt/loadmodules
modprobe -k scsi_mod
modprobe -k sd_mod
modprobe -k aic7xxx
modprobe -k 3w-xxxx
modprobe -k jbd
modprobe -k ext3
modprobe -k vesafb > /dev/null 2>&1
modprobe -k fbcon 2> /dev/null
modprobe -k unix 2> /dev/null
mkinitrd to load are being loaded and in the correct order. The careful reader will also verify the modules actually exist in the imagine itself as well. (And don’t forget to include any modules necessary to actually mount and read from your root filesystem; I loaded the ext3 module for ext3 below.)
sarah:/# find /mnt -name '*.o' -print |
perl -ne 's/.*kernel/(.*)/$1/;print'
drivers/scsi/3w-xxxx.o
drivers/scsi/aic7xxx/aic7xxx.o
drivers/scsi/scsi_mod.o
drivers/scsi/sd_mod.o
drivers/video/fbcon-cfb16.o
drivers/video/fbcon-cfb24.o
drivers/video/fbcon-cfb32.o
drivers/video/fbcon-cfb8.o
drivers/video/vesafb.o
fs/ext3/ext3.o
fs/jbd/jbd.o
net/unix/unix.o