NanoPi M1 Plus OpenWRT挂载NFS rootfs

学习了韦东山老师的视频才知道能够经过设置内核启动参数来从NFS 挂载rootfs ,因而我在NanoPi M1 Plus 开发板上实际试了下,过程当中也终于到一些问题,这里整理一下:linux

1.服务端要安装 nfs-kernel-server 并开启服务

apt-get install nfs-kernel-server
/etc/init.d/nfs-kernel-server start

能够在 /etc/exports 里修改可挂载的目录 ,修改后记得重启服务web

/home *(rw,sync,no_subtree_check)

如上表示/home 可挂载,* 表示全部ip 均可以挂载shell

2.内核要开启对NFS 的支持

Location:
-> Kernel modules
–> Filesystems
—> kmod-fs-nfs <y>
—> kmod-fs-nfs-v3 <y>
—> kmod-fs-nfs-v4 <y>less

3.内核要开启对KERNEL_ROOT_NFS 的支持

K1
已看出KERNEL_ROOT_NFS 依赖于KERNEL_IP_PNP
K2
因此 在Global build settings -> Kernel build options 里选中 Compile the kernel with rootfs on NFS 便可。dom

4.设置内核启动参数

由于OpenWRT里会根据 openwrt\package\boot\uboot-sunxi\uEnv-default.txt 生成boot.scr ,因此内核启动参数在这里修改。svg

修改openwrt\package\boot\uboot-sunxi\uEnv-default.txt
root=/dev/mmcblk0p2 rootwait
改成
root=/dev/nfs nfsroot=172.16.10.67:/home/lql/my_rootfs/rootfs ip=172.16.10.69:172.16.10.67:172.16.0.1:255.255.0.0::eth0:off rootwaitoop

这里的172.16.10.67:/home/lql/my_rootfs/rootfs 是我从 build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/root-sunxi 里copy过来学习

参考:linux/Documentation/filesystems/nfs/nfsroot.txt 里面有对nfsroot 的参数说明测试

root=/dev/nfs
This is necessary to enable the pseudo-NFS-device. Note that it’s not a
real device but just a synonym to tell the kernel to use NFS instead of
a real device.
nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>]
ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>:<dns0-ip>:<dns1-ip>ui

5.编译后测试

[    6.408050] dwmac-sun8i 1c30000.ethernet eth0: Link is Up - 100Mbps/Full - flow control rx/tx
[    6.437281] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[    6.467345] IP-Config: Complete:
[    6.470578]      device=eth0, hwaddr=00:00:00:f0:08:80, ipaddr=172.16.10.69, mask=255.255.0.0, gw=172.16.0.1
[    6.480414]      host=172.16.10.69, domain=, nis-domain=(none)
[    6.486240]      bootserver=172.16.10.67, rootserver=172.16.10.67, rootpath=
[    6.493634] vcc3v0: disabling
[    6.496605] vcc5v0: disabling
[    6.499592] ALSA device list:
[    6.502555]   No soundcards found.
[    6.507254] NOHZ: local_softirq_pending 80
[    6.511363] NOHZ: local_softirq_pending 88
[    6.520386] VFS: Mounted root (nfs filesystem) readonly on device 0:10.
[    6.529150] Freeing unused kernel memory: 2048K
[    6.537255] NOHZ: local_softirq_pending 80
[    6.541361] NOHZ: local_softirq_pending 88
[    6.547269] NOHZ: local_softirq_pending 08
[    6.557257] NOHZ: local_softirq_pending 80
[    6.567261] NOHZ: local_softirq_pending 08
[    6.577251] NOHZ: local_softirq_pending 82
[    6.583300] random: fast init done
[    6.597265] NOHZ: local_softirq_pending 82
[    6.617266] NOHZ: local_softirq_pending 08
[    6.652067] init: Console is alive
[    6.655694] init: - watchdog -
[    6.828851] kmodloader: loading kernel modules from /etc/modules-boot.d/*
[    6.850805] JFS: nTxBlock = 8049, nTxLock = 64399
[    6.866231] kmodloader: done loading kernel modules from /etc/modules-boot.d/*
[    6.882747] init: - preinit -
[    7.058118] random: jshn: uninitialized urandom read (4 bytes read)
[    7.094100] random: jshn: uninitialized urandom read (4 bytes read)
[    7.118780] random: jshn: uninitialized urandom read (4 bytes read)
ip: RTNETLINK answers: File exists
Press the [f] key and hit [enter] to enter failsafe mode
Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level
[   10.269838] mount_root: mounting /dev/root
[   10.283215] urandom-seed: Seed file not found (/etc/urandom.seed)
[   19.447267] nfs: server 172.16.10.67 not responding, still trying

坑1:nfs: server 172.16.10.67 not responding, still trying
缘由分析:
设备ip配置的是172.16.10.69,ping 172.16.10.69 结果

root@localhost:~# ping 172.16.10.69
PING 172.16.10.69 (172.16.10.69) 56(84) bytes of data.
From 172.16.6.128 icmp_seq=1 Destination Host Unreachable
From 172.16.6.128 icmp_seq=2 Destination Host Unreachable
From 172.16.6.128 icmp_seq=3 Destination Host Unreachable
From 172.16.6.128 icmp_seq=4 Destination Host Unreachable
From 172.16.6.128 icmp_seq=5 Destination Host Unreachable
From 172.16.6.128 icmp_seq=6 Destination Host Unreachable
From 172.16.6.128 icmp_seq=7 Destination Host Unreachable
From 172.16.6.128 icmp_seq=8 Destination Host Unreachable
From 172.16.6.128 icmp_seq=9 Destination Host Unreachable
64 bytes from 172.16.10.69: icmp_seq=10 ttl=64 time=972 ms
64 bytes from 172.16.10.69: icmp_seq=11 ttl=64 time=0.657 ms
64 bytes from 172.16.10.69: icmp_seq=12 ttl=64 time=0.546 ms
64 bytes from 172.16.10.69: icmp_seq=13 ttl=64 time=0.653 ms
64 bytes from 172.16.10.69: icmp_seq=14 ttl=64 time=0.646 ms
From 172.16.6.128 icmp_seq=66 Destination Host Unreachable
From 172.16.6.128 icmp_seq=67 Destination Host Unreachable

发现中途链接成功了,后面又断开了,猜想是设备ip 变动致使。
结合前面打印,init: - preinit - 以后开始感受不太对劲。
跟踪一下 preinit ,就是个启动脚本,位于
172.16.10.67:/home/lql/my_rootfs/rootfs/etc/preinit
首行添加 set -xv ,这样能够展开命令行,方便跟踪.
重新上电后,发现卡在这里。

install_bin() {
        local src files
        src=$1
        files=$1
        [ -x "$src" ] && files="$src $(libs $src)"
        install_file + '[' -e  ]
+ return 1
+ boot_hook_shift preinit_mount_root fu+ return
+ uci -q get 'system.@system[0].urandom_seed'
+ SEED=
+ '['  '==' / -a  '!=' /etc/urandom.seed ]
+ boot_hook_shift preinit_main func
+ local 'hook=preinit_main_hook'
+ local 'rv+ local netdev vid
+ netdev=eth0
+ vid=eth0
+ '[' eth0 '=' et+ ip link set dev eth0 down
[   20.480996] nfs: server 172.16.10.67 not responding, still trying
root@debian:rootfs# grep "ip link set dev" . -rn 
./lib/netifd/wireless/mac80211.sh:513:          ip link set dev "$ifname" address "$macaddr"
./lib/netifd/wireless/mac80211.sh:670:  ip link set dev "$ifname" up || {
./lib/netifd/wireless/mac80211.sh:729:          ip link set dev "$wdev" down 2>/dev/null
./lib/preinit/10_indicate_preinit:21:   ip link set dev $netdev up
./lib/preinit/10_indicate_preinit:133:          ip link set dev $netdev down

查看rootfs/lib/preinit/10_indicate_preinit 发现里面确实对eth0 有down 操做。这里须要修改
我修改后的 rootfs/lib/preinit/10_indicate_preinit

118 
119 preinit_ip_deconfig() {
120         #boot from NFS,should return here
121         return 0
122         [ -n "$pi_ifname" ] && grep -q "$pi_ifname" /proc/net/dev && {
123                 local netdev vid
124 
125                 netdev=${pi_ifname%\.*}
126                 vid=${pi_ifname#*\.}
127 
128                 if [ "$vid" = "$netdev" ]; then
129                         vid=
130                 fi
131 
132                 ip -4 address flush dev $pi_ifname
133                 ip link set dev $netdev down
134 
135                 if [ -n "$vid" ]; then
136                         ip link delete $pi_ifname
137                 fi
138         }
139 }

从新上电,运行OK。

BusyBox v1.28.3 () built-in shell (ash)

  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 -----------------------------------------------------
 OpenWrt 18.06.1, r7258-5eb055306f
 -----------------------------------------------------
root@172:/# 
root@172:/# 
root@172:/# ifconfig -a
eth0      Link encap:Ethernet  HWaddr xx:xx:xx:35:4A:71  
          inet addr:172.16.10.69  Bcast:172.16.255.255  Mask:255.255.0.0
          inet6 addr: fd45:3a5d:aef5::d813:14ff:fe35:4a71/64 Scope:Global
          inet6 addr: fe80::d813:14ff:fe35:4a71/64 Scope:Link
          inet6 addr: fdd0:b256:b6ca::d813:14ff:fe35:4a71/64 Scope:Global
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2616 errors:0 dropped:5 overruns:0 frame:0
          TX packets:1268 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:2470844 (2.3 MiB)  TX bytes:196349 (191.7 KiB)
          Interrupt:34 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

root@172:/# [  190.176558] random: crng init done
[  190.179978] random: 4 urandom warning(s) missed due to ratelimiting

root@172:/# 
root@172:/#

遇到过的坑:

坑1:failed: Protocol not supported

root@OpenWrt:/# mount -t nfs -o nolock 172.16.10.67:/home /mnt/nfs/
mount: mounting 172.16.10.67:/home on /mnt/nfs/ failed: Protocol not supported

缘由分析:nfs 有多种协议 nfs-v3 nfs-v4 等,内核支持的协议不匹配
解决办法:配置内核时,增长 kmod-fs-nfs-v3 kmod-fs-nfs-v4 的支持

坑2:VFS: Unable to mount root fs via NFS, trying floppy

[  110.565339] VFS: Unable to mount root fs via NFS, trying floppy.
[  110.571675] VFS: Cannot open root device "nfs" or unknown-block(2,0): error -6

解决办法:配置内核时,开启对KERNEL_ROOT_NFS 的支持
已经KERNEL_ROOT_NFS =y ? 仍有上述问题? 须要制定 nfs version

root=/dev/nfs nfsroot=172.16.10.67:/home/lql/my_rootfs/rootfs,vers=3   xxxx

总结:

挂载NFS 根文件系统必需要使用静态ip,挂载成功后也不容许ip 发生更改,不然就会报nfs: server 172.16.10.67 not responding 的错误。