Step-by-step NFS-mounted Root File System

From odroid US
Revision as of 19:07, 18 January 2013 by Osterluk (Talk | contribs) (Add U-boot Environment Variables)

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.

Introduction

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.


Prerequisites

  • 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: Kernel Compiling
  • You need to know how to abort booting at the u-boot console. [http://odroid.us/mediawiki/index.php?title=U-boot_Topics&action=view&section=5 Abort boot at u-boot console]
  • You will need some patience... NFS exporting and mounting can be frustrating

    Overview

    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

    Add U-boot Environment Variables

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

    Exynos4412 #
    

    Replace 10.4.124.93 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 it must 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 10.4.124.93
    set rfspath home/karlo/targetrfs
    set setnfs 'set bootdev root=/dev/nfs rw nfsroot=${nfsserverip}:/${rfspath}; saveenv;'
    set unsetnfs 'set bootdev;'
    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=UUID=e139ce78-9841-40fe-8823-96a304a09859 rootwait ro mem=2047M"
    boot
    

    Copy the existing boot script:

    cp boot.scr boot-nfs.scr
    

    Edit boot-nfs.scr. Insert ${bootdev} text to give the following:

    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 "${bootdev} console=tty1 console=ttySAC1,115200n8 root=UUID=e139ce78-9841-40fe-8823-96a304a09859 rootwait ro mem=2047M"
    boot
    

    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 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
    wget http://odroid.us/odroid/users/osterluk/nfs-mounting/odroidu2_ubuntu_nfs_defconfig
    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
    

    At this point, you can still boot normally. The capability to NFS mount the kernel will not stop 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
    <pre>
    
    === 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.
    <pre>
    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 10.4.127.255
    IP-Config: eth0 complete (dhcp from 10.1.0.219):
     address: 10.4.124.209     broadcast: 10.4.127.255     netmask: 255.255.128.0   
     gateway: 10.4.0.1         dns0     : 10.1.0.83        dns1   : 10.1.0.84       
     domain : echelon.echcorp.com                                             
     rootserver: 10.1.0.41 rootpath: 
     filename  : k2000.0
    Begin: Running /scripts/nfs-premount ... done.
    Begin: Running /scripts/nfs-bottom ... done.
    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)
    '''10.4.124.93:/home/karlo/targetrfs 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)
    root@odroidu2-1:~# 
    

    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
    10.4.124.93:/home/karlo/targetrfs  1.9T  713G  1.1T  41% /
    tmpfs                              5.0M     0  5.0M   0% /run/lock
    tmpfs                              397M     0  397M   0% /run/shm
    root@odroidu2-1:~#