Sunday, August 16, 2009

NFS Mounting AVR3NGW 100

To get nfs mounting to work, following steps are needed:

  1. change router / dhcp settings so that board / server can work with each other. In my case, I just chose a static setup because it makes life easy. My server is located at 192.168.1.101 (both tftp and nfs) while the avr device is located at 192.168.1.103. The gumstix stays at 192.168.1.100. Router gateway is at 192.168.1.1. The "static"-ness is achieved by setting appropriate rules on the router's dhcp server.
  2. expose appropriate root file system from a nfs mountable point on the build-server
  3. modify avr32ngw100's kernel so that nfs is created as part of the kernel image and not as a module change uboot to boot from tftp instead of on board flash / sd-card
  4. change uboot arguments to pass root as nfs to linux kernel.
  5. ensure that root is not mounted on /dev/mtdblock, since it will already have been specified as bootargs to the kernel
  6. disable any dhcp or other disruptive network setup, since eth0 would already have been setup by uboot


Modifying avr32kernel



Under gumstix, this was simply done by the following set of commands:


cd build_arm_nofpu
cd linux-gum-2.6.21
make ARCH=arm menuconfig


However, under avr32, this is a little different. Actually, NFS support is built in to the kernel by default. This can be checked by inspecting the .config file in the kernel directory:


# grep --ignore-case nfs \
buildroot-avr32-v2.3.0/project_build_avr32/atngw100/linux-2.6.27.6/.config

CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
CONFIG_ROOT_NFS=y
CONFIG_NFSD=m
CONFIG_NFSD_V3=y
# CONFIG_NFSD_V3_ACL is not set
# CONFIG_NFSD_V4 is not set
CONFIG_NFS_COMMON=y


The NFS_FS=y and the CONFIG_ROOT_NFS=y imply that this is all setup nice and proper. We can also use the menuconfig method to check if things are setup as we want them:

in the linux-2.6.27.6/ dir above, do

make ARCH=avr32 CROSS_COMPILE=avr32-linux- menuconfig


this should bring up the familiar menu. Browse to File Systems | Network File Systems ensure that “NFS Client support (for NFS v3)” and “Root file system on NFS” are built in (denoted by '*'. denotes that they are loaded as modules. We don't want modules, but want built in since at boot up the kernel won't have an opportunity to load modules because no file-system would exist at that point to locate and provide the said modules).

Since the default command contains this, it is good to know and keep around:

make ARCH=avr32 CROSS_COMPILE=avr32-linux- atngw100_defconfig


Also when booting over TFTP, the kernel image must be provided. Avr32 Buildroot generally produces a kernel image called uImage (same as gumstix). However, this is then copied over to the binaries folder, found at

buildroot-avr32-v2.3.0/binaries/atngw100/atngw100-linux-2.6.27.6.gz


That this file is the same as uImage produced by the kernel may be verified using the cksum command:

cksum $(find ./ -iname uImage -print)
127785873 1252230 ./arch/avr32/boot/images/uImage

cksum ~/work/buildroot-avr32-v2.3.0/binaries/atngw100/atngw100-linux-2.6.27.6.gz
127785873 1252230 ~/work/buildroot-avr32-v2.3.0/binaries/atngw100/atngw100-linux-2.6.27.6.gz


So all that remains now is to set the appropriate commands in u-boot, copy over files to proper places and have this thing going!

Preparing the root-fs



Since both the NGW100 and gumstix are buildroot systems they have a lot in common. However, the differences are significant enough to warrant independent and complete documentation.

Firstly, the NGW100's root file system is typically produced as a tar file. Also it's generated root file system is present in a different path as compared with gumstix. In particular, the NGW100's root filesystem is located at:


/buildroot-avr32-v2.3.0/project_build_avr32/atngw100/root

we copy this over to ~/avr32ngw100/work/nfsroot

cp -a buildroot-avr32-v2.3.0/project_build_avr32/atngw100/root/* ~/avr32ngw100/work/nfsroot

Ensure that the target file system has /dev/null and /dev/console. Sometimes, tar does not have the permission to create these nodes.

touch ~/avr32ngw100/work/nfsroot/dev/null
touch ~/avr32ngw100/work/nfsroot/dev/console

chmod 666 ~/avr32ngw100/work/nfsroot/dev/null ~/avr32ngw100/work/nfsroot/dev/console


Ideally /dev/null and /dev/console are character special devices created by mknod


sudo mknod ~/avr32ngw100/work/nfsroot/dev/console c 5
sudo mknod ~/avr32ngw100/work/nfsroot/dev/null c 1 3
sudo chown hypo ~/avr32ngw100/work/nfsroot/dev/console ~/avr32ngw100/work/nfsroot/dev/null
sudo chmod 666 ~/avr32ngw100/work/nfsroot/dev/console ~/avr32ngw100/work/nfsroot/dev/null


However, this kept giving me problems. Also sometimes i would get a message "could not open initial console" on the serial terminal, so i went back to simply touching the files.

U-boot settings



There are some good instructions at:
http://support.atmel.no/knowledgebase/avr32studiohelp/com.atmel.avr32.tool.ngw100/html/filesystem_over_nfs_for_avr32_linux.html

However, once the tftp server is up and serving files, i ran in to an unhandled exception error and an endless loop of the board trying to restart. Turns out that the expanded kernel was trampling over the downloaded data. I computed the appropriate location to download the kernel to so that it won't get trampled over by the expanded kernel.


perl -e '{my $image = 1.2 * 1024 * 1024; my $top_mem = 0x10000000 + 32 * 1024 * 1024; printf("0x%x 0x%x\n", $image, $top_mem - 2*$image);}'

0x133333 0x11d99999


the second figure is the download location. After doing this, I also ran in to a couple of webpages that indicated success with downloading to an address 0x1040000

We want to leave enough space at the start of the memory section for the kernel to expand. The size computation in perl above helps us determine where to place this. We back-off twice the size of the compressed kernel from the top of the memory. My assumption was to leave the very top alone because some cpus jump to that address during startup. Also placing it close to the end gives more room in the beginning so that the expanded kernel doesn't overwrite the compressed image :)


setenv bootcmd 'set ipaddr 192.168.1.103;tftp 0x10400000 avr32ngw100/uImage-n;bootm'
or
setenv bootcmd 'set ipaddr 192.168.1.103;tftp 0x11d99999 avr32ngw100/uImage-n;bootm'


next we setup the boot args that are passed to the linux kernel. In particular, we need to setup the ethernet interface and indicated that we're booting off nfs. The Uboot interpreter on this board however, can't handle the length of the command. So, we use the askenv command:

syntax of ip command is

ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>



askenv:
/dev/nfs rw nfsroot=192.168.1.101:/home/hypo/avr32ngw100/work/nfsroot,nolock,rsize=1024,wsize=1024 console=ttyS0 ip=192.168.1.103:192.168.1.101:192.168.1.1:::eth0:off



Copying and pasting the above might not work, so type away!

Also disable network startup since this is done at boot up

cd ~/avr32ngw100/work/nfsroot
mv etc/init.d/S20network etc/init.d/s20network


Change /etc/network/interfaces so that no auto setup happens on eth0 that can disrupt the nfs mount.

# Configure Loopback
auto lo
iface lo inet loopback

# Configure Ethernet 0
# commenting out auto setup for eth0 because
# this would already have happened during nfs root
# boot up. Uncomment when not running with root over nfs

# auto eth0
# iface eth0 inet dhcp

# i don't need this just yet, but will enable it later
# Configure Ethernet 1
# auto eth1
# iface eth1 inet static
# address 10.0.0.1
# netmask 255.255.255.0
# network 10.0.0.0
# broadcast 10.0.0.255


Change /etc/fstab so that default mounting on / and /usr is disabled:

# /etc/fstab: static file system information.
#
#
#mtd1 / jffs2 defaults 0 0
# commenting out following because root-fs is now nfs mounted, so /usr is also part of that and not needed anymore
#mtd3 /usr jffs2 defaults 0 0


Server settings



TFTP settings:



Ensure that the compiled kernel image is placed in the right location. My tftp root is located at ~/tftpboot. And since it's serving both gumstix and ngw100 uImages, I've modified the tree a little bit so that it is scalabe for other targets / projects:

cd ~/tftpboot
mkdir gumstix avr32ngw100
cp ~/avr32ngw100/work/nfsroot/boot/uImage ~/tftpboot/avr32ngw100/uImage
cp ~/gumstix/uImage ~/tftpboot/gumstix/uImage


Ensure that the path above matches the path mentioned in bootcmd on the target.
Change appropriate config files on the server to ensure that the new device has access to these folders:

Change /etc/hosts.allow.

portmap: 192.168.1.100 , 192.168.1.101 , 192.168.1.103
lockd: 192.168.1.100 , 192.168.1.101 , 192.168.1.103
mountd: 192.168.1.100 , 192.168.1.101 , 192.168.1.103
statd: 192.168.1.100 , 192.168.1.101 , 192.168.1.103


NOTE: /etc/hosts.deny stays the same:

# ALL: PARANOID
lockd:ALL
mountd:ALL
rquotad:ALL
statd:ALL



/etc/exports:

# Cast of characters
# 192.168.1.100 - gumstix
# 192.168.1.101 - server
# 192.168.1.103 - avr32ngw100

# gumstix tftp boot-point
/home/hypo/gumstix/tftpboot 192.168.1.100(ro,sync) 192.168.1.101(ro,sync) 192.168.1.103(ro,sync)

# avr32ngw100 boot point
/home/hypo/avr32ngw100/work/tftpboot 192.168.1.100(ro,sync) 192.168.1.101(ro,sync) 192.168.1.103(ro,sync)

# gumstix root fs
/home/hypo/gumstix/nfsroot 192.168.1.100(rw,sync,no_root_squash) 192.168.1.101(rw,sync) 192.168.1.103(rw,sync)

# avr32ngw root fs
/home/hypo/avr32ngw100/work/nfsroot 192.168.1.100(rw,sync,no_root_squash) 192.168.1.101(rw,sync) 192.168.1.103(rw,sync,no_root_squash)


Note the rw,no_root_squash options for the development boards. this allows them to mount the paths with root privileges.

Restart tftpd and nfs-servers


sudo /etc/init.d/tftpd restart
sudo /etc/init.d/nfs-user-server restart


PS: there's probably a good reason why i'm running a user space nfs server instead of the usual kernel space version, but it eludes me at the moment. Perhaps I wanted to export heterogeneous filesystems (ntfs + ext3) under one nfs mount point. But since I didn't note my rationale, I have no idea right now. I see no reason for a kernel space nfs server to not work with this setup.


Test the tftp and nfs connections on the server before struggling with the board:


# mkdir ~/temp/test
# cd ~/temp/test
# tftp
tftp> get avr32ngw100/uImage
1 file xxx bytes
tftp> quit
# ls uImage
uImage

# rm *
# cd ../
# sudo mount -t nfs 192.168.1.101:/home/hypo/avr32ngw100/work/nfsroot/ ~/temp/test
# ls
bin etc lost+found proc tmp
boot home media root usr
config lib mnt sbin var
dev linuxrc opt sys www
# umount ~/temp/test


Ironically, it took me half a day to get the setup going and a whole day to blog about it. There's infact more I've already done, just haven't gotten around to bloggin about it :)

No comments: