Raspberry Pi: (non-ext) USB rootfs

To put the root file system of the RPi on the SD Card might decrease the lifetime of the card due:

  • the offical RPi kernel misses a build-in flash aware file system:
    • nilfs2 is only available as kernel module
    • jffs2 and f2fs are missing at all
  • no initrd support → unable to use non-build-in file systems as rootfs

This might result in dramaticly reduced lifetime of the flash storage (SD card). This might be workarounded by using a read-only rootfs and create a writeable /var partition using i.e. nilfs2.

Another approach is to put the idea of an initrd onto the SD card and use any supported file system for the rootfs (built-in and by modules). This enables to use an usb-storage device for the rootfs, too. This article shows howto move a Raspian or Debian Wheezy installation onto an usb-storage devices using any file system supported by the stock kernel.


partitioning scheme

partitioning scheme

As the stock boot-loader and kernel does not support using an initrd we use a init partition. From with-in this partition the init of the rootfs is launched after the rootfs has been mounted.

root file system type

Choosing the right file system is not that easy. Using a log-structured file system for flash based storage might be a good choice. The only log-structed file system supported by the stock kernel is nilfs2. This solution does not depend on any particular root file system - any file system which works as a rootfs in general should work with this approach. USB storage devices might show up under different device nodes if multiple USB storage devices are attached to a host. Therefore the file system should be identified by it’s UUID or LABEL.

base system

The base system might be installed by debootrap, Raspian’s prepared root file systems or Raspian’s SD card images. The package busybox-static is required to be installed on the system. This might be done from within the running base system, from within the debootraped root file system using qemu-user-static or by downloading and extracting the package manually.

The init partition uses a small C program as it’s own stub init process. Therefore the packages git, gcc and make might be installed to fetch the sources and build the stub init process on the target’s CPU architecture.


There is a small git repository containing all stuff used to setup the init partition. It should be cloned somewhere on the rootfs:

    /usr/src# git clone https://github.com/liske/rpi-initp.git
    Cloning into 'rpi-initp'...
    remote: Counting objects: 49, done.
    remote: Compressing objects: 100% (37/37), done.
    remote: Total 49 (delta 21), reused 36 (delta 12)
    Unpacking objects: 100% (49/49), done.
    Checking connectivity... done
    /usr/src# cd rpi-initp/
    /usr/src/rpi-initp# git submodule init
    Submodule 'busybox' (git://busybox.net/busybox.git) registered for path 'busybox'
    /usr/src/rpi-initp# git submodule update
    Cloning into 'busybox'...
    remote: Counting objects: 89183, done.
    remote: Compressing objects: 100% (20694/20694), done.
    remote: Total 89183 (delta 69811), reused 86693 (delta 67954)
    Receiving objects: 100% (89183/89183), 21.20 MiB | 534.00 KiB/s, done.
    Resolving deltas: 100% (69811/69811), done.
    Checking connectivity... done
    Submodule path 'busybox': checked out 'e73f3c1d3d83699b723251f7e6a981021ce75475'
    /usr/src/rpi-initp# make
    gcc -Wall -static sinit.c -o sinit
    cp blkid.config busybox/.config
    cd busybox && make install
    make[1]: Entering directory `/usr/src/rpi-initp/busybox'

The repository has the busybox git repository as a submodule. It is used to build a staticly linked blkid binary. Debian Wheezy’s busybox version does not contain the blkid functionality - the busybox version is just to old. You might skip the busybox stuff if you have a more recent busybox version (>= 1.21) shipped with your distribution.

Moving to USB

After moving / onto the new storage the following steps are required (done from within the new rootfs; adjust device names as need):

  • create mount point for the init partition:

    # mkdir /initp
  • mount the init partition:

    # mount /dev/mmcblk0p2 /initp
  • move the kernel modules onto the init partition:

    # mkdir /initp/lib
    # mv /lib/modules /initp/lib/
    # ln -s ../initp/lib/modules /lib/modules
  • install the required files from the rpi-initp:

    /usr/src/rpi-initp# make install
    cp pinit-stub "/lib/init/"
    cp update.sh "/initp/"
    mkdir -p "/initp/sbin"
    cp pinit "/initp/sbin/"
    cp sinit "/initp/sbin/"
    cp blkid "/initp/bin/"
  • run update.sh (copies busybox and creates some directories)

    /initp# ./update.sh
  • configure the kernel cmdline (/boot/cmdline.txt on Raspberry Pi) parameters:

Parameter Description
root=/dev/mmcblk0p2 device node of the init partition file system (required)
rootfstype=ext3 file system of the init partition (required)
pivot=UUID=0bbc4207-1ffe-42fd-9123-a6dh3fb2dbb3 device identifier (UUID or LABEL value) of the root partition (defaults to LABEL=rootfs)
pivotflags= mount flags for the root partition (optional)
init=/sbin/sinit rpi-initp specific init (required)
ro kernel mounts rootfs r/o - should always be added (highly recommended)



  1. kernel will mount the init partition
  2. kernel spawns init using /sbin/sinit
  3. sinit execs the /sbin/pinit shell script
  4. pinit tries to discover the root partition, probing every 5 seconds, up to 12 times
  5. pinit mounts the root partition and swaps the mountings using pivot_root
  6. pinit execs /lib/init/pinit-stub, releasing all open file handles on the /initp mount point
  7. pinit-stub umounts /initp
  8. pinit-stub execs /sbin/init of the root partition
  9. classic boot-up begins


Uncompressing Linux... done, booting the kernel.
[    0.000000] Booting Linux on physical CPU 0
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Linux version 3.6.11+ (dc4@dc4-arm-01) (gcc version 4.7.2 20120731 (prerelease) (crosstool-NG linaro-1.13.1+bzr2458 - Linaro GCC 2012.08) ) #545 PREEMPT Fri Sep 20 23:57:55 BST 2013
[    0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
[    0.000000] Machine: BCM2708
[    0.000000] cma: CMA: reserved 16 MiB at 1e000000
[    0.000000] Memory policy: ECC disabled, Data cache writeback
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 125984
[    0.000000] Kernel command line: dma.dmachans=0x7f35 bcm2708_fb.fbwidth=656 bcm2708_fb.fbheight=512 bcm2708.boardrev=0xe bcm2708.serial=0x5fa250c4 smsc95xx.macaddr=B8:27:EB:C2:70:A9 sdhci-bcm2708.emmc_clock_freq=100000000 vc_mem.mem_base=0x1fa00000 vc_mem.mem_size=0x20000000  smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 root=/dev/mmcblk0p2 rootfstype=ext3 pivot=UUID=0bbc4207-1ffe-42fd-9123-a6dh3fb2dbb3 init=/sbin/sinit televator=deadline rootwait console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 ro


[    2.074588] Waiting for root device /dev/mmcblk0p2...
[    2.084590] Indeed it is in host mode hprt0 = 00021501
[    2.227228] mmc0: read SD Status register (SSR) after 9 attempts
[    2.241644] mmc0: new high speed SDHC card at address aaaa
[    2.247846] mmcblk0: mmc0:aaaa SU08G 7.40 GiB 
[    2.254515]  mmcblk0: p1 p2
[    2.303515] EXT4-fs (mmcblk0p2): mounting ext3 file system using the ext4 subsystem
[    2.324482] usb 1-1: new high-speed USB device number 2 using dwc_otg
[    2.331488] Indeed it is in host mode hprt0 = 00001101
[    2.337798] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
[    2.354459] VFS: Mounted root (ext3 filesystem) readonly on device 179:2.
[    2.377260] devtmpfs: mounted
[    2.380719] Freeing init memory: 132K
[    2.555226] usb 1-1: New USB device found, idVendor=0424, idProduct=9514
[    2.563474] usb 1-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[    2.571712] hub 1-1:1.0: USB hub found
[    2.575654] hub 1-1:1.0: 5 ports detected
Looking for rootfs UUID=0bbc4207-1ffe-42fd-9123-a6dh3fb2dbb3 (#1)
rootfs is not here, yet...
[    3.002137] smsc95xx v1.0.4
[    3.069209] smsc95xx 1-1.1:1.0: eth0: register 'smsc95xx' at usb-bcm2708_usb-1.1, smsc95xx USB 2.0 Ethernet, b8:27:eb:c2:80:a5
[    3.174627] usb 1-1.3: new high-speed USB device number 4 using dwc_otg
[    3.298307] usb 1-1.3: New USB device found, idVendor=2101, idProduct=8500
[    3.305224] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[    3.312528] usb 1-1.3: Product: USB2.0 Hub
[    3.316648] usb 1-1.3: Manufacturer: Action Star
[    3.322414] hub 1-1.3:1.0: USB hub found
[    3.326921] hub 1-1.3:1.0: 5 ports detected
[    3.614802] usb 1-1.3.1: new high-speed USB device number 5 using dwc_otg
[    3.718199] usb 1-1.3.1: New USB device found, idVendor=2101, idProduct=8501
[    3.725289] usb 1-1.3.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[    3.732765] usb 1-1.3.1: Product: USB HID
[    3.736799] usb 1-1.3.1: Manufacturer: Action Star
[    3.746741] hid-generic 0003:2101:8501.0001: hiddev0,hidraw0: USB HID v1.11 Device [Action Star USB HID] on usb-bcm2708_usb-1.3.1/input0
[    3.834827] usb 1-1.3.4: new high-speed USB device number 6 using dwc_otg
[    3.935893] usb 1-1.3.4: New USB device found, idVendor=12d1, idProduct=1f01
[    3.942945] usb 1-1.3.4: New USB device strings: Mfr=2, Product=1, SerialNumber=0
[    3.950457] usb 1-1.3.4: Product: HUAWEI Mobile
[    3.955035] usb 1-1.3.4: Manufacturer: HUAWEI
[    3.962217] scsi0 : usb-storage 1-1.3.4:1.0
[    4.965915] scsi 0:0:0:0: CD-ROM            HUAWEI   Mass Storage     2.31 PQ: 0 ANSI: 2
Looking for rootfs UUID=0bbc4207-1ffe-42fd-9123-a6dh3fb2dbb3 (#2)
rootfs is not here, yet...
[    9.824928] usb 1-1.3.5: new high-speed USB device number 7 using dwc_otg
[    9.925708] usb 1-1.3.5: New USB device found, idVendor=152d, idProduct=2329
[    9.932760] usb 1-1.3.5: New USB device strings: Mfr=1, Product=2, SerialNumber=5
[    9.940277] usb 1-1.3.5: Product: USB to ATA/ATAPI bridge
[    9.945701] usb 1-1.3.5: Manufacturer: JMicron
[    9.950144] usb 1-1.3.5: SerialNumber: C61B04728410
[    9.956583] usb-storage 1-1.3.5:1.0: Quirks match for vid 152d pid 2329: 8020
[    9.963864] scsi1 : usb-storage 1-1.3.5:1.0
[   10.965477] scsi 1:0:0:0: Direct-Access     INTEL SS DSA2M040G2GC     2CV1 PQ: 0 ANSI: 2 CCS
[   10.975368] sd 1:0:0:0: [sda] 78163247 512-byte logical blocks: (40.0 GB/37.2 GiB)
[   10.986142] sd 1:0:0:0: [sda] Write Protect is off
[   10.991726] sd 1:0:0:0: [sda] No Caching mode page present
[   10.997340] sd 1:0:0:0: [sda] Assuming drive cache: write through
[   11.006486] sd 1:0:0:0: [sda] No Caching mode page present
[   11.011979] sd 1:0:0:0: [sda] Assuming drive cache: write through
[   11.020104]  sda: sda1 sda2
[   11.026738] sd 1:0:0:0: [sda] No Caching mode page present
[   11.032235] sd 1:0:0:0: [sda] Assuming drive cache: write through
[   11.038365] sd 1:0:0:0: [sda] Attached SCSI disk
Looking for rootfs UUID=0bbc4207-1ffe-42fd-9123-a6dh3fb2dbb3 (#3)
Device found, trying to switchover...
[   12.874972] EXT4-fs: Warning: mounting with data=journal disables delayed allocation and O_DIRECT support!
[   12.908742] EXT4-fs (sda2): mounted filesystem with journalled data mode. Opts: data=journal; (null)
<F8><F8>INIT: <F8>version 2.88 booting<F8>CC<85><F8>[info] Using makefile-style concurrent boot in runlevel S.
[....] Starting the hotplug events dispatcher: udevd[   14.775631] udevd[207]: starting version 175
[ ok .
[....] Synthesizing the initial hotplug events...[ ok done.
[....] Waiting for /dev to be fully populated...[ ok done.
[....] Activating swap...[   18.489442] Adding 976556k swap on /dev/sda1.  Priority:-1 extents:1 across:976556k 
[ ok done.
[   18.628833] EXT4-fs (sda2): re-mounted. Opts: (null)
[....] Checking root file system...fsck from util-linux 2.20.1
rootfs: clean, 35124/2383872 files, 429225/9526009 blocks
[ ok done.
[   18.959210] EXT4-fs (sda2): re-mounted. Opts: data=journal
[....] Cleaning up temporary files... /tmp[ ok .

Comments !