Step-by-step NFS-mounted Root File System

From odroid US
Jump to: navigation, search

This tutorial is for Developers. It is written to work with the odroidu2-ubuntu or odroidu2-debian SD-Card images [is this specific enough?]

It is not for Android developers.


A common technique for embedded development is to NFS-mount your root file system. This means that all files are actually on a host. The host is configured to export the filesystem. The target (odroid) mounts the filesystem at boot time and uses it as its own. All files are visible on the host.

As targets have increased in storage capacity and speed, the need for NFS-mounting root file systems will decrease. The technique is still useful when bringing up a new port or you have a lot of files that need to change together.

It is common to check in a whole root file system into a source control system for quality control.


  • You MUST have access to the serial console -- use the USB/Serial adapter [check actual Hardkernel name]
  • You need to be able to edit files on the odroid, or how to move them to a host and back for editing
  • You need to know how to build a kernel. There are many ways to do it. This tutorial walks through a native kernel build: Step-by-step Native Compiling a Kernel
  • You need to know how to abort booting at the u-boot console. Abort Boot
  • You will need some patience... NFS exporting and mounting can be frustrating


    We are going to:

  • Add some u-boot environment variables to steer the boot process
  • Mount the boot partition read/write
  • Compile a custom u-boot script to add parameters to the kernel command line
  • Replace the standard boot.scr with our custom one
  • Setup the root file system directory
  • Configure NFS-exports
  • Test the NFS server
  • reboot and see that we actually are running from files living on the host


    Since the kernel sources and configuration do change, there is an archived set of files here [1]. At this point, you may not understand what all these files are for, but when you get stuck, a complete solution can be nice to have.

    boot-nfs.scr				compiled u-boot script that will use u-boot ${bootdev} to mount NFS root file system
    boot-nfs.txt				u-boot script source
    boot-sdcard.scr				compiled u-boot script
    boot-sdcard.txt				u-boot script source.  Compare to boot-nfs.txt		kernel source used in the tutorial
    odroidu2_ubuntu_defconfig		configuration at the time of the snapshot
    odroidu2_ubuntu_nfs_defconfig		configuration needed to boot 
    odroidu2_ubuntu_nfs_defconfig.patch	Patch to take the original configuration to odroidu2_ubuntu_nfs_defconfig
    zImage.nfs				Kernel compiled with odroidu2_ubuntu_nfs_defconfig, ready to run

    Add U-boot Environment Variables

    Power-up the odroid and abort the boot at u-boot console

    Exynos4412 #

    Replace value of nfsserverip with the ip address below with the ip address of the host you want to NFS-mount. This address must be on the same subnet as your odroid -- no routes are in place so early in the boot, and neither is DNS

    Replace home/karlo/targetrfs value of rfspath with the host absolute path of the directory you mean to use for the odroid root file system. This can be a symlink, but NFS must be able to resolve it (it must be on the same filesystem)

    The setnfs macro may be used as 'run setnfs' at the u-boot prompt to turn on NFS mounting

    The unsetnfs macro may be used as 'run unsetnfs' at the u-boot prompt to turn off NFS mounting

    saveenv saves the u-boot environment variables we just set

    Copy/paste the following text to a text editor. You need to make changes as explained above. After making the changes, you can paste the text into u-boot console. Of course, you could just type the individual lines on the u-boot console.

    set nfsserverip
    set rfspath home/karlo/targetrfs
    set setnfs 'set bootdev root=/dev/nfs rw nfsroot=${nfsserverip}:/${rfspath}; saveenv;'
    set unsetnfs 'set bootdev root=/dev/mmcblk0p2 ro rootwait; saveenv '

    Now boot the odroid, nothing we did so far is going to change the boot.

    run bootcmd

    Mounting the Boot Partition

    Mount the boot partition read-write, if it is not already mounted. The Debian images do not mount the boot partition (at this time)

    mount /dev/mmcblkp1 /boot
    cd /boot

    Compiling Custom U-boot Script

    This is the current boot.scr (yours may be different):

    setenv initrd_high "0xffffffff"
    setenv fdt_high "0xffffffff"
    setenv bootcmd "fatload mmc 0:1 0x40008000 zImage; fatload mmc 0:1 0x42000000 uInitrd; bootm 0x40008000 0x42000000"
    setenv bootargs "console=tty1 console=ttySAC1,115200n8 root=/dev/mmcblk0p2 rootwait ro mem=2047M"

    Copy the existing boot script:

    cp boot.txt boot-nfs.txt

    Edit boot-nfs.txt. Change the bootargs line to give the following: (Adding ${bootdev} and ip=dhcp are key)

    setenv initrd_high "0xffffffff"
    setenv fdt_high "0xffffffff"
    setenv bootcmd "fatload mmc 0:1 0x40008000 zImage; fatload mmc 0:1 0x42000000 uInitrd; bootm 0x40008000"
    setenv bootargs "${bootdev} console=tty1 console=ttySAC1,115200n8 rootwait ip=dhcp mem=2047M"

    You will need the mkimage app from the uboot-mkimage package. Install it like this (Debian-based distros)

    sudo apt-get install  u-boot-tools

    Compile to a u-boot script like this:

    mkimage -T script -A arm -C none -n 'odroid-u2.Boot NFS-mounted RFS' -d boot-nfs.txt boot-nfs.scr 

    If that works, replace your existing script with the one we just made. If not, you do not have the prerequisites to build a kernel. mkimage comes from a u-boot package, listed in prerequisites for kernel building.

    mv boot.scr boot.scr.orig
    cp boot-nfs.scr boot.scr

    Custom Kernel

    Now we need a kernel configured to be able to NFS-mount the root file system and the network driver needs to be built-in, not a kernel module. Maybe it is easiest to just pick up the configuration I used... Or you could look at the patch. Browse here: Example files

    You need to somehow get the configuration to the area you are building the kernel. If it is on the target, it would be /usr/src/linux.

    cd /usr/src/linux
    mv odroidu2_ubuntu_nfs_defconfig arch/arm/configs
    # now use the new configuration
    make odroidu2_ubuntu_nfs_defconfig
    # build the kernel
    make -j8 zImage
    # copy it out to the boot partition
    cp arch/arm/boot/zImage /boot

    To keep in sync with the released kernel versions, it may be better to just patch the released configuration -- this step is an alternative to just copying one that may not have your favorite kernel modules selected. This example is based on the default config, you would patch your own selections to add NFS mounted root file system capability.

    # In the kernel source directory, get the NFS-mounting root file system configuration patch
    # Set up to build the kernel
    make odroidu2_ubuntu_defconfig
    # now our .config file matches the default configuration selected above.  Apply the patch
    patch < odroidu2_ubuntu_nfs_defconfig.patch 
    # Save this new configuration for future use.
    cp .config arch/arm/configs/odroidu2_ubuntu_nfs_defconfig

    At this point, you can still boot normally. The capability to NFS mount the kernel will not stop you from mounting the flash-located root file system.

    Setting up Target Root File System

    # go home
    cd ~
    # make a place to hold the target root file system
    mkdir targetrfs
    chmod 777 targetrfs
    cd targetrfs
    # You need to expand the RFS image as root, or you will lose the required device nodes
    sudo tar -xvzf ../odroidu2_20130104-debian-wheezy-2-rootfs.tgz
    cd ..

    Setting up NFS export

    # configure to export the target root file system with no restrictions
    sudo echo "/home/$USER/targetrfs  *(rw,no_root_squash,no_subtree_check)" >> /etc/exports
    # On Debian/Ubuntu host:
    sudo /etc/init.d/nfs-kernel-server restart
    # On a SuSE 11.4 host, it looks like this:
    # sudo /etc/init.d/nfsserver restart

    Testing NFS Export

    # go home
    cd ~
    # create a mount point and set permissions
    mkdir mnt
    chmod 777 mnt
    sudo mount -t nfs localhost:/home/$USER/targetrfs mnt
    # test to make sure we have write access
    echo xyx > mnt/test.txt
    sudo umount mnt

    Selecting NFS-mount

    Abort booting at the u-boot console

    # select the nfs-mounted RFS configuration.  You would use run unsetnfs to go back to normal mount
    run setnfs
    === Testing NFS-mounted Root File System ===
    Reboot the target and watch the boot progress.  You can power-cycle or do 'run bootcmd' at the u-boot prompt.
    Once you see the IP-Config lines, you know you succeeded.
    Begin: Loading essential drivers ... done.
    Begin: Running /scripts/init-premount ... done.
    Begin: Mounting root file system ... Begin: Running /scripts/nfs-top ... done.
    [    5.399441] ADDRCONF(NETDEV_UP): eth0: link is not ready
    [    6.975337] ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
    [    6.976319] smsc95xx 1-2:1.0: eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1
    IP-Config: eth0 hardware address ce:dd:54:19:96:0b mtu 1488 DHCP RARP
    IP-Config: no response after 2 secs - giving up
    IP-Config: eth0 hardware address ce:dd:54:19:96:0b mtu 1488 DHCP RARP
    IP-Config: eth0 guessed broadcast address
    IP-Config: eth0 complete (dhcp from
     address:     broadcast:     netmask:   
     gateway:         dns0     :        dns1   :       
     domain :                                             
     rootserver: rootpath: 
     filename  : k2000.0
    Begin: Running /scripts/nfs-premount ... done.
    Begin: Running /scripts/nfs-bottom ... done.
    Begin: Running /scripts/init-bottom ... done.
    INIT: version 2.88 booting

    Here is more proof:

    root@odroidu2-1:~# mount
    sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
    proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
    udev on /dev type devtmpfs (rw,relatime,size=10240k,nr_inodes=168964,mode=755)
    devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620)
    tmpfs on /run type tmpfs (rw,nosuid,noexec,relatime,size=203124k,mode=755)
    ''' on / type nfs (rw,relatime,vers=3,rsize=1048576,wsize=1048576,namlen=255,hard,nolock,proto=tcp,port=2049)'''
    tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
    tmpfs on /run/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=406240k)

    Nice to have a lot of disk space:

    root@odroidu2-1:~# df -h
    Filesystem                         Size  Used Avail Use% Mounted on
    rootfs                             1.9T  713G  1.1T  41% /
    udev                                10M     0   10M   0% /dev
    tmpfs                              199M  204K  199M   1% /run  1.9T  713G  1.1T  41% /
    tmpfs                              5.0M     0  5.0M   0% /run/lock
    tmpfs                              397M     0  397M   0% /run/shm