view · edit · print · history

How to run Debian / NSLU2 with no Initramfs

The internal flash in a normal Debian / NSLU2 system contains a kernel and an "initramfs". The initramfs is a directory structure containing files that are run as soon as the kernel has started; this is called "early userspace". This code is responsible for mounting the real root filesystem, located on an external USB drive.

The benefit of using an initramfs is that the kernel does not need to have built-in support for all of the different hardware and filesystems that you might be using for your root. (Consider, for example, all the kernel code required to mount an NFS root.) Instead, the initramfs contains kernel modules for all of this hardware, and only the necessary modules are loaded. This results in a kernel that uses less RAM.

For a distribution like Debian, having a kernel image that supports lots of different root filesystem hardware is important. But if you compile your own kernel to run on hardware that isn't likely to change much, it could be considered overkill. My motivation for removing the initramfs is to free some space in the internal flash: the Debian initramfs image is over 3 megabytes!

To get rid of the initramfs there are two or three things that you need to do:

  1. You need to make the kernel wait for your USB device to come online before mounting it.
  2. You need to build a kernel with built-in support for the hardware and filesystem used by your root device.
  3. You may need to set a kernel command line indicating which device to use as the root.

Waiting for USB

When you plug in a USB device, some time elapses while the USB and SCSI subsystems initialise it. I think that most of this time is a deliberate delay to allow for you physically connecting it reliably. Because of this, during boot the kernel is likely to give up with a panic telling you that your root device is not available before it has been initialised.

There are two ways to avoid this. The simplest it to use the rootdelay kernel command line argument, which specifies how long the kernel should pause for, in seconds, before trying to mount the root device. See ChangeKernelCommandLine for how to set this.

Alternatively, a simple patch can be applied to make the kernel retry until the device comes online. It is available here: http://www.xenotime.net/linux/usb/usbboot-2422.patch

This patch was written for 2.4.22. I manually applied it to my 2.6.19 kernel and it works well, subject to the comments below about how you specify the root device.

Building a kernel

I'm not going to explain how to build a kernel here - mainly because I haven't got cross compilation using the Debian make-kpkg tool working properly. See BuildImage for some other instructions. The important point is that when you configure the kernel you need to enable all of the things that are required by your root filesystem as built-in code, i.e. press "y", not modules ("m"). This includes PCI support, the EHCI and OHCI USB host controller, USB storage, SCSI disks, and your chosen filesystem (ext3). Also, don't forget to disable initramfs support.

Specifying the root device

If you use the patch described above to retry until the root device is available you need to specify the root device on the kernel command line. However, the kernel will attempt to convert an alphanumeric device name (e.g. /dev/sda1) to major/minor device numbers before the USB and SCSI systems are ready, which will fail. Instead you need to use a numeric format, e.g. root=8:1. (use ls -l to find the major/minor device numbers for your root device.) You may be able to supply this as a default command line setting when you build your kernel, but I prefered to set it using APEX. Changing the kernel command line from APEX is described in ChangeKernelCommandLine.

Note that this is likely to fail if you have multiple disks since the order of initialisation is non-deterministic. Mounting by disk label is not supported at this level, though it may be possible with some more patching. Luckily I have only one disk on the slug I'm doing this to.

I'm unsure whether it's necessary to explicitly specify the root device if you use the rootdelay option, and whether it's necessary to use numeric device numbers - can someone confirm?

Installing the new kernel

Before installing the new kernel (and new APEX, if you've changed it), save a copy of your flash. You can revert to this using upslug2 if necessary.

# cat /dev/mtdblock* > /var/tmp/flash_backup.bin
# scp /var/tmp/flash_backup.bin other-computer:/somewhere/safe

I haven't managed to make a kernel-image .deb file, so I don't know if installing that will just work. Instead I manually installed the new modules and put the new kernel in /boot/vmlinux-2.6.19. To keep flash-kernel happy I created a zero-length /boot/initrd.img.2.6.19. Then just run "flash-kernel", reboot and cross your fingers!

view · edit · print · history · Last edited by Phil Endecott.
Originally by Phil Endecott.
Page last modified on September 15, 2007, at 12:24 PM