Booting Linux off of a USB drive.
Last update: January 23, 2005.
Author: Simon Ilyushchenko (simonf@simonf.com)
Contents:
- Instructions for Fedora Core 3
- Instructions for both FC3 and older distrubutions
- Using USB boot and Systemimager.
- Instructions for Fedora Core 2 by Allen Benusa (external).
- Intructions for Debian by Geoff Soutter (external)
- Intructions for RHEL 4 by Lijian Liu (external)
(With the 2.6 kernel and Fedora 2,
make sure you either run 2.6.8-1 or later kernel or disable USB 2.0
support in the kernel configuration, as some 2.6 kernels were reported
freezing intermittently.)
Warning: I am not a USB expert. Feel free to email me if you do not understand the instructions or have corrections, but if you understood and followed them, but the drive still would not boot, I WILL NOT be able to help you. Try the usb-devel mailing list instead.
Here is how to use a small USB pen drive as the primary hard drive for Linux. This information floats on the net in bits and pieces, so I figured I'd put it together. You can also do this with a kernel patch listed here (look for boot-usb.patch). However, the initrd way, while longer to set up initially, is easier to reuse when you upgrade the kernel.
You have to first install Linux (I used Redhat 9.0, with which
you might need to go into the "linux expert" mode) on your hard drive.
Then, when it won't boot, use the rescue CD. Make sure your motherboard
supports booting off of USB. You
might need to enable USB in the BIOS. Try all USB slots (one out of two
did not work for me).
Instructions for Fedora Core 3
You still may need to use the longer instructions below if this simple way does not work.
1. Boot off of a rescue CD. If you use Redhat/Fedora, type
chroot /mnt/sysimage
mount /dev/sda3 /mnt/sysimage
mount /dev/sda1 /mnt/sysimage/boot
chroot /mnt/sysimage
2. You'll need to create a custom initrd image. Fortunately, FC3 can
do it for you (thanks to David Chalmers for pointing this out and to Mike Marmar for coming up with the idea):
mkinitrd --preload=ehci-hcd --preload=usb-storage --preload=scsi_mod --preload=sd_mod /boot/usbinitrd.img 2.6.9-1.667smp
Warning: this did not work for me on FC3, probably because the sleep call (see below) was not there, and I was not
able to create a custom initrd using the steps below. But my hardware is pretty flaky. Other people reported success with this.
Stanislav Umansky made some corrections to the default mkinitrd script. He writes:
The mkinitrd command wasn't okay, because it lacked sleeps and some
other commands, so we've changed it a little. The main thing is having
sleeps and running sfdisk on
/dev/sdb, /dev/sdc and /dev/sdd. When you boot on some systems
with the primary SATA drive, /dev/sda is that SATA drive. Our USB
drives become /dev/sdb,
/dev/sdc...
As we installed FC3, it used volume labels to find a disk when
booting (ROOT in our case), but when we tried to boot on a system where
Linux had already been installed on the primary hard drive, the system
found two
ROOT-labeled partitions and didn't boot successfully, so we had to
change the labels to ROOT_USB, etc and modify grub.conf.
3. Update your lilo.conf or grub.conf to use the new usbinitrd.gz
with the same kernel that you grabbed the modules from. Run lilo
or grub-install.
Instructions for both FC3 and older distributions
If you are doing this on Fedora Core 3, note a couple of differences mentioned below.
1. If your rescue CD would not mount the partitions (for some reason, mine did not), you have to mount them manually and then change root to the hard disk's filesystem. In my case,
mount /dev/sda3 /mnt/source
mount /dev/sda1 /mnt/source/boot
chroot /mnt/source
2. You'll need to create a custom initrd image. Take your current image from /boot (see /etc/lilo.conf or /etc/grub.conf for the exact name). I'll call it initrd.img. (Use mkinitrd to create an initrd image if you don't have one.)
cp /boot/initrd.img /tmp/initrd.gz
3.
gunzip /tmp/initrd.gz
4.
mkdir /tmp/a
5.
mount -o loop /tmp/initrd /tmp/a
If this step fails, there is no loopback device support in your
kernel. You might be able to load the module with "modprobe loop". If
it does not work, you have to compile it in.
On Fedora Core 3, you should do
cd /tmp/a
cpio -i < /tmp/initrd
6. The file /tmp/a/linuxrc (/tmp/b/init on Fedora Core 3) is the script that runs before the root partition is mounted. We need to make sure it can mount a USB partition. If you use Redhat, replace /tmp/a/linuxrc with this (edit your script otherwise) :
#!/bin/nash
echo "Loading jbd.o module"
insmod /lib/jbd.o
echo "Loading ext3.o module"
insmod /lib/ext3.o
echo Mounting /proc filesystem
mount -t proc /proc /proc
echo "Loading usb modules"
insmod /lib/usbcore.o
insmod /lib/scsi_mod.o
insmod /lib/sd_mod.o
insmod /lib/usb-storage.o
insmod /lib/usb-uhci.o
/bin/sleep 5
echo Creating block devices
mkdevices /dev
echo Creating root device
mkrootdev /dev/root
/bin/sfdisk -R /dev/sda
echo 0x0100 > /proc/sys/kernel/real-root-dev
echo Mounting root filesystem
mount -o defaults --ro -t ext3 /dev/root /sysroot
pivot_root /sysroot /sysroot/initrd
umount /initrd/proc
The lines before "Loading usb modules" and after "sfdisk", as well as mkdevices an mkrootdev are probably already there, so you just need to insert the extra stuff. First the script loads all the necessary kernel modules, then waits five seconds in order for the USB code to recognize the disk, then runs sfdisk to reread the partition table.
Note: Alan Deehr reported that usb-uhci.o did not see his USB 2.0 external disk. He used usb/host/ehci-hcd.o instead.
7. Copy kernel modules into the initrd image. For example, if you are running kernel 2.4.22 (uname -r to find out),
cd /lib/modules/2.4.22/kernel/drivers
cp usb/usbcore.o /tmp/a/lib
cp usb/usb-uhci.o /tmp/a/lib
cp usb/storage/usb-storage.o /tmp/a/lib
cp scsi/scsi_mod.o /tmp/a/lib
cp scsi/sd_mod.o /tmp/a/lib
8. Find out what libraries sleep and sfdisk use from the output of ldd:
ldd /bin/sleep
ldd /sbin/sfdisk
Copy the libraries into /tmp/a/lib. In my case it was:
mkdir /tmp/a/lib/tls
cp /lib/tls/libm.so.6 /tmp/a/lib/tls
cp /lib/tls/libpthread.so.0 /tmp/a/lib/tls
cp /lib/tls/libc.so.6 /tmp/a/lib/tls
cp /lib/librt.so.1 /tmp/a/lib
cp /lib/ld-linux.so.2 /tmp/a/lib
9. Copy the executables over:
cp /bin/sleep /tmp/a/bin
cp /sbin/sfdisk /tmp/a/bin
10.
umount /tmp/a
On Fedora Core 3, docd /tmp
mkcramfs /tmp/a initrd
11.
gzip /tmp/initrd
Alternatively, on Fedora Core 3, instead of steps 10 and 11 you can do: (thanks to Angela Jean)cd /tmp
find . | cpio -c -o | gzip -9 > /boot/usbinird.img
12.
cp /tmp/initrd.gz /boot/usbinird.gz
13. Update your lilo.conf or grub.conf to use the new usbinitrd.gz with the same kernel that you grabbed the modules from. Run lilo or grub-install.
14. Tom Haux reported that he successfully booted a RH 9 box in this way, but then X would not start due to some hardware errors. He had to disable kudzu to get it working.
/sbin/chkconfig --level 5 kudzu off
P.S. Presumably you can also patch the kernel to add a delay before a USB device is mounted at boot time.
Using USB boot and Systemimager.
If you want to use Systemimager to auto-install your nodes (which you should - it's a great tool), beware of some differences. Systemimager works by taking an image of a working node, booting into its own temporary kernel on another node and copying all the files over. Obviously, we want to make sure that the temporary kernel can see the USB drive, or there will not be a place to copy files to.
The differences with the process above:
- The initrd file is included into the RPM package systemimager-i386boot-standard. On my system its files are in /usr/share/systemimager/boot/i386/standard.
- The initrd file is cramfs, not loopback filesystem. This means
that you can't edit a mounted file, you have to
cp -r
the whole mounted directory (let's call the new directory mydir), change its contents and thenmkcramfs mydir initrd
gzip -f initrd
cp -f initrd.gz /tftpboot/initrd.img
- As you can see from the previous step, initrd.img is usually placed into /tftpboot. That's where the boot files for the systemimager kernel live.
- The same RPM package systemimager-i386boot-standard includes the necessary USB kernel modules. Untar boel_binaries.tar.gz and copy the USB modules into mydir/lib.
- As luck would have it, one of the modules (usb-storage.o) was missing. I had to install the systemimager source RPM, change the kernel configuration file (CONFIG_USB_STORAGE=m) and "make modules".
- The script that is run by initrd is /etc/init.d/rcS. It's more complicated than the usual initrd scripts. Put the section that loads modules in the beginning of the control flow (before switch_root_to_tmpfs) and the sfdisk call after get_boel_binaries_tarball.
- Note that the temporary systemimager kernel uses devfs, not the regular dev filesystem. If everything goes well, you don't need to know that, but it can make debugging interesting.