Booting Linux from USB

If you have a system that can boot from USB (like most modern PC systems), you can run a Linux system entirely from a pendrive or USB disk.

The Linux installation can be done as usual, using Grub or LILO or whatever, but the kernel has to be modified slightly in most versions.

Firstly, the code that mounts the root filesystem has to be modified to give the kernel time to detect the USB disk before it tries to mount it. In ini/do_mounts.c is a function called do_mount_root(), which looks like this in version 2.6.18.2:

  static int __init do_mount_root(char *name, char *fs, int flags, void *data)
  {
        int err = sys_mount(name, "/root", fs, flags, data);
        if (err)
                return err;
 
        sys_chdir("/root");
        ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
        printk("VFS: Mounted root (%s filesystem)%s.\n",
               current->fs->pwdmnt->mnt_sb->s_type->name,
               current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY ?
               " readonly" : "");
        return 0;
  }
We modify this so that it tries over and over again, and rests between attempts:
  static int __init do_mount_root(char *name, char *fs, int flags, void *data)
  {
        int i=20, err=-1;
        while (i-- && (err = sys_mount(name, "/root", fs, flags, data))!=0)
        {
                set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(HZ);
        }
        if (err)
                return err;
 
        sys_chdir("/root");
        ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
        printk("VFS: Mounted root (%s filesystem)%s.\n",
               current->fs->pwdmnt->mnt_sb->s_type->name,
               current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY ?
               " readonly" : "");
        return 0;
  }

This is a context diff that you can use to patch the kernel:

diff --git a/init/do_mounts.c b/init/do_mounts.c
index dc1ec08..8aa013d 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -14,6 +14,7 @@
 #include <linux/nfs_fs_sb.h>
 #include <linux/nfs_mount.h>
 
+#include <linux/delay.h>
 #include "do_mounts.h"
 
 extern int get_filesystem_list(char * buf);
@@ -268,7 +269,12 @@ static void __init get_fs_names(char *page)
 
 static int __init do_mount_root(char *name, char *fs, int flags, void *data)
 {
-       int err = sys_mount(name, "/root", fs, flags, data);
+       int i=20, err=-1;
+       while (i-- && (err = sys_mount(name, "/root", fs, flags, data))!=0)
+       {
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ);
+       }
        if (err)
                return err;

Apart from this, the kernel has to be configured to support SCSI and SCSI disks (since USB disks are accessed through the SCSI sub system), as well as USB and USB storage. All of these have to be linked into the kernel rather than built as modules.

CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y  # (eller nĂ¥gon annan HCD)
CONFIG_USB_STORAGE=y

The disk will probably be called /dev/sda, so the root device will most likely be /dev/sda1.

Don't allocate any swap space on the flash drive, since they usually have a limit to the number of writes they can handle.

You can also do this with an initrd, if you want to use modules instead of linking the drivers into the kernel, or if you want to avoid modifying the kernel.