学习了韦东山老师的视频才知道可以通过设置内核启动参数来从NFS 挂载rootfs ,于是我在NanoPi M1 Plus 开发板上实际试了下,过程中也终于到一些问题,这里整理一下:
apt-get install nfs-kernel-server
/etc/init.d/nfs-kernel-server start
可以在 /etc/exports 里修改可挂载的目录 ,修改后记得重启服务
/home *(rw,sync,no_subtree_check)
如上表示/home 可挂载,* 表示所有ip 都可以挂载
Location:
-> Kernel modules
–> Filesystems
—> kmod-fs-nfs
—> kmod-fs-nfs-v3
—> kmod-fs-nfs-v4
已看出KERNEL_ROOT_NFS 依赖于KERNEL_IP_PNP
所以 在Global build settings -> Kernel build options 里选中 Compile the kernel with rootfs on NFS 即可。
因为OpenWRT里会根据 openwrt\package\boot\uboot-sunxi\uEnv-default.txt 生成boot.scr ,所以内核启动参数在这里修改。
修改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 rootwait
这里的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=[:] [, ]
ip=: : : : : : : :
[ 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:/#
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 的支持
[ 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 的错误。