概念
NFS是Network File System的縮寫及網絡文件系統。要功能是通過局域網絡讓不同的主機系統之間可以共享文件或目錄。NFS系統和Windows網絡共享、網絡驅動器類似, 只不過windows用於局域網, NFS用於企業集群架構中, 如果是大型網站, 會用到更復雜的分布式文件系統FastDFS,glusterfs,HDFS
介紹
nfs實現原理
當用戶讀寫有關的nfs下的目錄, 最終由內核解析完成后驅動硬件,完成相應的操作。
1.用戶進程訪問NFS客戶端,使用不同的函數對數據進行處理
2.NFS客戶端通過TCP/IP的方式傳遞給NFS服務端。
3.NFS服務端接收到請求后,會先調用portmap進程進行端口映射。
4.nfsd進程用於判斷NFS客戶端是否擁有權限連接NFS服務端。
5.Rpc.mount進程判斷客戶端是否有對應的權限進行驗證。
6.idmap進程實現用戶映射和壓縮
7.最后NFS服務端會將對應請求的函數轉換為本地能識別的命令,傳遞至內核,由內核驅動硬件。
rpc是一個遠程過程調用,那么使用nfs必須有rpc服務
使用nfs的作用
1.實現多台服務器之間數據共享
2.實現多台服務器之間數據的一致
3.在嵌入式開發中,避免頻繁地對存儲介質進行讀寫,減少時間的同時保證了存儲介質的壽命。
NFS存儲優點
1.NFS文件系統簡單易用、方便部署、數據可靠、服務穩定、滿足中小企業需求。
2.NFS文件系統內存放的數據都在文件系統之上,所有數據都是能看得見。
NFS存儲缺點
1.存在單點故障, 如果構建高可用維護麻煩。(web-》nfs()-》backup)
2.NFS數據明文, 並不對數據做任何校驗。
3.客戶端掛載無需賬戶密碼, 安全性一般(內網使用)
配置uboot指定nfs掛載根文件系統
嵌入式系統Linux內核對nfs文件系統的支持
-> Networking support
-> Networking options
[*] IP: kernel level autoconfiguration
-> File systems
[*] Network File Systems
<*> NFS client support
<*> NFS client support for NFS version 3
[*] NFS client support for the NFSv3 ACL protocol extension
[*] Root file system on NFS
開啟nfs服務(開發機)
安裝nfs服務(ubuntu為例)
sudo apt-get install nfs-kernel-server -y
配置好 /etc/exports
$ sudo cat /etc/exports
...
/fs_path/fs *(rw,sync,no_root_squash,no_subtree_check)
重啟nfs-kernel-server或者重啟機器,使修改生效
sudo service nfs-kernel-server restart
uboot修改bootargs
最好是備份好bootargs
setenv bootargs 'root=/dev/nfs nfsroot=${serverip}:/xxx/fs,tcp rw ip=${ipaddr}:${serverip}:${gatewayip}:${netmask} ::eth0:on init=/linuxrc console=ttyAMA0,115200'
saveenv
注:
${ipaddr} 開發板本身的地址
${serverip} tftp及nfs目錄所在系統的地址
${gatewayip} 網關
${netmask} 子網掩碼
其中:
root=/dev/nfs
/dev/nfs並非真的設備,而是一個告訴內核要通過網絡取得根文件系統。
nfsroot=<server-ip>:<root-dir>
參數nfsroot這個參數告訴內核以哪一台機器的哪個目錄以及哪個網絡文件系統選項作為根文件系統使用。
<server-ip> 指定網絡文件系統服務端的IP地址。如果沒有指定定,則使用nfsaddrs變量指定的值。
<root-dir> 服務端上要作為根文件系統要掛載的目錄名稱。
ip=<my-ip>:<serv-ip>:<gw-ip>:<netmask>:<name>:<dev>:<auto>
參數ip設定網絡通訊所需的各種網絡接口地址。
如果沒有給定這個參數,則內核核會試着使用反向地址解析協議或是啟動協議(BOOTP)以找出這些參數。
<ipaddr> 客戶端的IP地址。
<serverip> 網絡文件系統服務端的IP地址。
<gatewayip> 網關(gateway)的IP地址。
<netmask> 本地網絡的網絡掩碼。如果為空白,則掩碼由客戶端的IP地址導出。
<name> 客戶端的名稱。如果空白,則使用客戶端IP地址的ASCII標記值。
<dev> 要使用的網絡設備名稱。如果你只有一個設備,那么你可以不管它。一般指定為eth0
<auto> 用以作為自動配置的方法。,可以是on可以是off
init=/linuxrc 指定初始化文件
console=ttySAC2,115200 控制台選擇
至此,kernel通過nfs方式加載了根文件系統rootfs,此時在rootfs文件是在宿主機上,此時控制器和宿主機之間的網絡不能出現故障,否則在控制器終端就不能訪問文件系統了,所以在啟動腳本中不能修改使用nfs掛載根文件系統的網卡IP地址(或者改動一致)。
常見問題
Q:掛載以后 ls -al
發現權限異常權限變成了 ???
A:一般是因為:nfs服務器的配置問題
Q:掛載以后只讀內核提示了 : VFS: Mounted root (nfs filesystem) readonly on device.
,而且在文件系統中無法進行寫操作(包括修改/刪除文件,創建/刪除目錄)
A1:要么是 nfs服務器的配置中,權限與網段之間多了一個空格
/arm/fs * (rw,sync,no_root_squash,no_subtree_check) # 錯誤的
/arm/fs *(rw,sync,no_root_squash,no_subtree_check) # 正確的
A2:要么是 bootargs 沒有指定rw權限
root=/dev/nfs nfsroot=192.168.10.150:/xxx/fs,tcp rw ip=192.168.10.110:192.168.10.150:192.168.10.1:255.255.255.0::eth0:on
附錄:nfs參數詳解
關於nfs部分,在內核文檔里(Documentation/filesystems/nfs/nfsroot.txt)有詳細說明,摘取部分如下:
所述的參數最終都變成了Kernel command line,傳遞給linux內核,內核解析Kernel command line的內容,做相應處理
2.) Kernel command line
-------------------
When the kernel has been loaded by a boot loader (see below) it needs to be
told what root fs device to use. And in the case of nfsroot, where to find
both the server and the name of the directory on the server to mount as root.
This can be established using the following kernel command line parameters:
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>]
If the `nfsroot' parameter is NOT given on the command line,
the default "/tftpboot/%s" will be used.
<server-ip> Specifies the IP address of the NFS server.
The default address is determined by the `ip' parameter
(see below). This parameter allows the use of different
servers for IP autoconfiguration and NFS.
<root-dir> Name of the directory on the server to mount as root.
If there is a "%s" token in the string, it will be
replaced by the ASCII-representation of the client's
IP address.
<nfs-options> Standard NFS options. All options are separated by commas.
The following defaults are used:
port = as given by server portmap daemon
rsize = 4096
wsize = 4096
timeo = 7
retrans = 3
acregmin = 3
acregmax = 60
acdirmin = 30
acdirmax = 60
flags = hard, nointr, noposix, cto, ac
ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>
This parameter tells the kernel how to configure IP addresses of devices
and also how to set up the IP routing table. It was originally called
`nfsaddrs', but now the boot-time IP configuration works independently of
NFS, so it was renamed to `ip' and the old name remained as an alias for
compatibility reasons.
If this parameter is missing from the kernel command line, all fields are
assumed to be empty, and the defaults mentioned below apply. In general
this means that the kernel tries to configure everything using
autoconfiguration.
The <autoconf> parameter can appear alone as the value to the `ip'
parameter (without all the ':' characters before). If the value is
"ip=off" or "ip=none", no autoconfiguration will take place, otherwise
autoconfiguration will take place. The most common way to use this
is "ip=dhcp".
<client-ip> IP address of the client.
Default: Determined using autoconfiguration.
<server-ip> IP address of the NFS server. If RARP is used to determine
the client address and this parameter is NOT empty only
replies from the specified server are accepted.
Only required for NFS root. That is autoconfiguration
will not be triggered if it is missing and NFS root is not
in operation.
Default: Determined using autoconfiguration.
The address of the autoconfiguration server is used.
<gw-ip> IP address of a gateway if the server is on a different subnet.
Default: Determined using autoconfiguration.
<netmask> Netmask for local network interface. If unspecified
the netmask is derived from the client IP address assuming
classful addressing.
Default: Determined using autoconfiguration.
<hostname> Name of the client. May be supplied by autoconfiguration,
but its absence will not trigger autoconfiguration.
If specified and DHCP is used, the user provided hostname will
be carried in the DHCP request to hopefully update DNS record.
Default: Client IP address is used in ASCII notation.
<device> Name of network device to use.
Default: If the host only has one device, it is used.
Otherwise the device is determined using
autoconfiguration. This is done by sending
autoconfiguration requests out of all devices,
and using the device that received the first reply.
<autoconf> Method to use for autoconfiguration. In the case of options
which specify multiple autoconfiguration protocols,
requests are sent using all protocols, and the first one
to reply is used.
Only autoconfiguration protocols that have been compiled
into the kernel will be used, regardless of the value of
this option.
off or none: don't use autoconfiguration
(do static IP assignment instead)
on or any: use any protocol available in the kernel
(default)
dhcp: use DHCP
bootp: use BOOTP
rarp: use RARP
both: use both BOOTP and RARP but not DHCP
(old option kept for backwards compatibility)
Default: any
nfsrootdebug
This parameter enables debugging messages to appear in the kernel
log at boot time so that administrators can verify that the correct
NFS mount options, server address, and root path are passed to the
NFS client.
rdinit=<executable file>
To specify which file contains the program that starts system
initialization, administrators can use this command line parameter.
The default value of this parameter is "/init". If the specified
file exists and the kernel can execute it, root filesystem related
kernel command line parameters, including `nfsroot=', are ignored.
A description of the process of mounting the root file system can be
found in:
Documentation/early-userspace/README
附錄:內核打印信息參考
## Booting kernel from Legacy Image at 42000000 ...
Image Name: Linux-3.18.20
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 3954962 Bytes = 3.8 MiB
Load Address: 40008000
Entry Point: 40008000
Loading Kernel Image ... OK
OK
Starting kernel ...
Booting Linux on physical CPU 0x0
Initializing cgroup subsys cpu
Linux version 3.18.20 (root@ubuntu) (gcc version 4.9.4 20150629 (prerelease) (Hisilicon_v500_20170922) ) #6 SMP Mon Oct 21 14:41:20 CST 2019
CPU: ARMv7 Processor [414fc091] revision 1 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine model: Hisilicon HI3531D DEMO Board
Memory policy: Data cache writealloc
PERCPU: Embedded 9 pages/cpu @dfbd9000 s5696 r8192 d22976 u36864
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 130048
Kernel command line: root=/dev/nfs nfsroot=192.168.1.16:/home/schips/arm/fs ip=192.168.1.11:192.168.1.16:192.168.1.1:255.255.255.0::eth0:on init=/linuxrc console=ttyAMA0,115200
hi_gmac_v200 100a0000.ethernet eth0: Link is Up - 1Gbps/Full - flow control rx/tx
IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
IP-Config: Complete:
device=eth0, hwaddr=1a:ea:05:46:af:7c, ipaddr=192.168.10.111, mask=255.255.255.0, gw=192.168.10.1
host=192.168.10.111, domain=, nis-domain=(none)
bootserver=192.168.10.106, rootserver=192.168.10.106, rootpath=
VFS: Mounted root (nfs filesystem) on device 0:12.
Freeing unused kernel memory: 256K (c0700000 - c0740000)