NFS檔案系統製作和移植
*****************************************************************************************************************
核心版本:linux-3.0
u-boot :u-boot-2010.09
作 者:fulinux <[email protected]>
描 述:希望大家能與我交流學習和討論
*****************************************************************************************************************1.NFS檔案系統簡介:
2.在核心中新增對nfs的支援:NFS是由Sun開發並發展起來的一項在不同機器、不同作業系統之間通過網路共享檔案的技術。在嵌入式Linux系統的開發除錯階段,可以利用該技術在主機上建立基於NFS 的根檔案系統,掛載到嵌入式裝置,可以很方便地修改根檔案系統的內容。以上討論的都是基於儲存裝置的檔案系統(memory-based file system),它們都可用作Linux的根檔案系統。實際上,Linux還支援邏輯的或偽檔案系統(logical or pseudo file system),例如procfs(proc檔案系統),用於獲取系統資訊,以及devfs(裝置檔案系統)和sysfs,用於維護裝置檔案。
3.參考根檔案系統製作的文件,製作用於系統啟動的NFS檔案系統:Networking --->
Networking options --->
[*] IP: kernel level autoconfiguration
[ ] IP: DHCP support
[ ] IP: BOOTP support
[ ] IP: RARP support
File systems --->
Network File Systems --->
<*> NFS file system support
[ ] Provide NFSv3 client support
[ ] Provide NFSv4 client support (EXPERIMENTAL)
[ ] Allow direct I/O on NFS files
< > NFS server support
[*] Root file system on NFS
注:對於nfs檔案系統,上面紅色標註的要選上,其餘選項根據自身的情況而言。
[[email protected] opt]$ ls rootfs
apps bin dev home init linuxrc media opt root stat tmp var
backup data etc info lib logs mnt proc sbin sys usr
[[email protected] opt]$
確認並安裝NFS服務依賴軟體包
一般NFS伺服器要提供服務,必須啟動inet,nfs, mount,portmap或rpcbind這些守護程序並保持在後臺狀態執行. 這裡需要提示的是從RHEL6開始, 系統使用rpcbind替換了以前早期版本中NFS依賴的portmap服務。
在使用NFS共享檔案之前,我們首先使用rpm命令確認我們安裝了這些應用程式。如果沒有安裝,則從安裝光碟中找到他們並安裝,或者使用yum安裝。下面顯示我們在安裝系統時,已經選擇安裝了NFS服務相關軟體
[[email protected] opt]$ rpm -qa | grep nfs
nfs4-acl-tools-0.3.3-6.el6.x86_64
nfs-utils-lib-1.1.5-4.el6.x86_64
nfs-utils-1.2.3-36.el6.x86_64
[[email protected] opt]$ rpm -qa | grep rpcbind
rpcbind-0.2.0-11.el6.x86_64
[[email protected] opt]$
修改主機上的NFS配置檔案,匯出/opt目錄使用NFS共享:
backup data etc info lib logs mnt proc sbin sys usr xxx
[[email protected] opt]$ sudo vim /etc/exports
/opt/ *(rw,sync,no_root_squash)
下面是一些NFS共享的常用引數:
ro 只讀訪問
rw 讀寫訪問
sync 所有資料在請求時寫入共享
async NFS在寫入資料前可以相應請求
secure NFS通過1024以下的安全TCP/IP埠傳送
insecure NFS通過1024以上的埠傳送
wdelay如果多個使用者要寫入NFS目錄,則歸組寫入(預設)
no_wdelay 如果多個使用者要寫入NFS目錄,則立即寫入,當使用async時,無需此設定。
hide 在NFS共享目錄中不共享其子目錄
no_hide 共享NFS目錄的子目錄
subtree_check 如果共享/usr/bin之類的子目錄時,強制NFS檢查父目錄的許可權(預設)
no_subtree_check 和上面相對,不檢查父目錄許可權
all_squash 共享檔案的UID和GID對映匿名使用者anonymous,適合公用目錄。
no_all_squash 保留共享檔案的UID和GID(預設)
root_squash root使用者的所有請求對映成如anonymous使用者一樣的許可權(預設)
no_root_squas root使用者具有根目錄的完全管理訪問許可權
anonuid=xxx 指定NFS伺服器/etc/passwd檔案中匿名使用者的UID
anongid=xxx 指定NFS伺服器/etc/passwd檔案中匿名使用者的GID
關於/etc/exports檔案的更加詳細的配置說明,我們可以使用man exports命令來檢視幫助手冊。
重新啟動rpcbind或portmap和nfs服務
使用root許可權執行“service rpcbind restart”(RHEL高於6.0版本)或“service portmap restart”(RHEL5及以下版本)命令重啟NFS依賴的服務:
[[email protected] opt]$ sudo service rpcbind restart
Stopping rpcbind: [ OK ]
Starting rpcbind: [ OK ]
使用root許可權執行“service nfs restart”命令重啟NFS服務,讓其生效:
[[email protected] opt]$ sudo service nfs restart
Shutting down NFS daemon: [ OK ]
Shutting down NFS mountd: [ OK ]
Shutting down NFS quotas: [ OK ]
Shutting down NFS services: [ OK ]
Starting NFS services: [ OK ]
Starting NFS quotas: [ OK ]
Starting NFS mountd: [ OK ]
Starting NFS daemon: [ OK ]
[[email protected] opt]$
使用service rpcbind status命令和“service nfs status”命令檢視相關服務的執行狀態,同時可以使用“showmount –e”命令可以檢視我們通過NFS服務共享的檔案:
[[email protected] opt]$ service rpcbind status
rpcbind (pid 3719) is running...
[[email protected] opt]$ service nfs status
rpc.svcgssd is stopped
rpc.mountd (pid 7935) is running...
nfsd (pid 7962 7961 7960 7959 7958 7957 7956 7955) is running...
rpc.rquotad (pid 7931) is running...
[[email protected] opt]$ showmount -e
Export list for localhost.localdomain:
/opt *
/usr/local/src *
[[email protected] opt]$
測試NFS訪問
在另外一個Linux機器上,或者在本機上通過mount命令掛載並測試如下:
[[email protected] opt]$ sudo mkdir -p /mnt/nfs
[[email protected] opt]$ sudo mount -t nfs 192.168.1.3:/opt /mnt/nfs
[[email protected] opt]$ mount
/dev/sda2 on / type ext4 (rw)
proc on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
devpts on /dev/pts type devpts (rw,gid=5,mode=620)
tmpfs on /dev/shm type tmpfs (rw)
none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw)
nfsd on /proc/fs/nfsd type nfsd (rw)
192.168.1.2:/var/ftp/pub on /opt/pub type nfs (rw,nolock,vers=4,addr=192.168.1.2,clientaddr=192.168.1.3)
192.168.1.3:/opt on /mnt/nfs1 type nfs (rw,vers=4,addr=192.168.1.3,clientaddr=192.168.1.3)
[[email protected] opt]$ ls /mnt/nfs/
buildroot-2012.08 mtd pub rootfs
[[email protected] opt]$ ls /mnt/nfs1/rootfs/
apps bin dev home init linuxrc media opt root stat tmp var
backup data etc info lib logs mnt proc sbin sys usr xxx
[[email protected] opt]$ ls /opt/rootfs/
apps bin dev home init linuxrc media opt root stat tmp var
backup data etc info lib logs mnt proc sbin sys usr xxx
[[email protected] opt]$ rm /mnt/nfs1/rootfs/xxx
rm: remove write-protected regular empty file `/mnt/nfs1/rootfs/xxx'? y
[[email protected] opt]$ ls /mnt/nfs/rootfs/
apps bin dev home init linuxrc media opt root stat tmp var
backup data etc info lib logs mnt proc sbin sys usr
[[email protected] opt]$ ls /opt/rootfs/
apps bin dev home init linuxrc media opt root stat tmp var
backup data etc info lib logs mnt proc sbin sys usr
[[email protected] opt]$
4.uboot設定和映像燒錄啟動
[ [email protected] ]# set bootcmd_rootfs 'nand read 30008000 100000 400000;bootm 30008000'
[ [email protected] ]# set bootcmd 'run bootcmd_rootfs'
注:下面這個設定只為儲存nfs的啟動bootargs引數
[ [email protected] ]# set bootargs_nfs 'noinitrd console=ttyS0,115200 init=/linuxrc mem=64M loglevel=7 root=/dev/nfs rw nfsroot=192.168.1.3:/opt/rootfs ip=192.168.1.111:192.168.1.3:192.168.1.1:255.255.255.0:localhost.com:eth0:off'
[ [email protected] ]# set bootargs 'noinitrd console=ttyS0,115200 init=/linuxrc mem=64M loglevel=7 root=/dev/nfs rw nfsroot=192.168.1.3:/opt/rootfs ip=192.168.1.111:192.168.1.3:192.168.1.1:255.255.255.0:localhost.com:eth0:off'
注:上面的設定中ip=<my-ip>:<serv-ip>這兩個是必須在bootargs中出現,不然可能無法啟動。
initrd, noinitrd:
當你沒有使用ramdisk啟動系統的時候,你需要使用noinitrd這個引數,但是如果使用了的話,就需要指定initrd=r_addr,size, r_addr表示initrd在記憶體中的位置,size表示initrd的大小。console:
console=tty 使用虛擬串列埠終端裝置 .
console=ttyS[,options] 使用特定的串列埠,options可以是這樣的形式bbbbpnx,這裡bbbb是指串列埠的波特率,p是奇偶位(從來沒有看過使用過),n是指的bits。
console=ttySAC[,options] 同上面。看你當前的環境,有時用ttyS,有時用ttySAC,網上有人說,這是跟核心的版本有關,2.4用ttyS,2.6用ttySAC,但實際情況是官方文件中也是使用ttyS,所以應該是跟核心版本沒有關聯的。可以檢視Documentation/serial-console.txt找到相關描述。
init:
init指定的是核心啟起來後,進入系統中執行的第一個指令碼,一般init=/linuxrc, 或者init=/etc/preinit,preinit的內容一般是建立console,null裝置節點,執行init程式,掛載一些檔案系統等等操作。請注意,很多初學者以為init=/linuxrc是固定寫法,其實不然,/linuxrc指的是/目錄下面的linuxrc指令碼,一般是一個連線罷了。如果核心找不到linurc檔案,將會依次搜尋/sbin/init,/etc/init,/bin/init,/bin/sh.
mem:
指定記憶體大小,不是必須的
root:
用來指定rootfs的位置, 常見的情況有:
root=/dev/ram rw
root=/dev/ram0 rw
請注意上面的這兩種設定情況是通用的,我做過測試甚至root=/dev/ram1 rw和root=/dev/ram2 rw也是可以的,網上有人說在某些情況下是不通用的,即必須設定成ram或者ram0,但是目前還沒有遇到,還需要進一步確認,遇到不行的時候可以逐一嘗試。
root=/dev/mtdx rw
root=/dev/mtdblockx rw
root=/dev/mtdblock/x rw
root=31:0x
上面的這幾個在一定情況下是通用的,當然這要看你當前的系統是否支援,不過mtd是字元裝置,而mtdblock是塊裝置,有時候你的挨個的試到底當前的系統支援上面那種情況下,不過root=/dev/mtdblockx rw比較通用。此外,如果直接指定裝置名可以的話,那麼使用此裝置的裝置號也是可以的。
root=/dev/nfs,並非真的裝置,而是一個告訴核心經由網路取得根檔案系統的旗標。
在檔案系統為基於nfs的檔案系統的時候使用。當然指定root=/dev/nfs之後,還需要指定nfsroot,nfsroot這個引數告訴核心以哪一臺機器,哪個目錄以及哪個網路檔案系統選項作為根檔案系統使用。引數的格式如下:
nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>]
如果指令列上沒有給定 nfsroot 引數,則將使用‘/tftpboot/%s’預設值。其它選項如下:
<server-ip> --指定網路檔案系統服務端的網際網路地址(IP address)。如果沒有給定此欄位,則使用由 nfsaddrs 變數(見下面)所決定的值。此引數的用途之一是允許使用不同機器作為反向地址解析協議(RARP) 及網路檔案系統服務端。通常你可以不管它(設為空白)。
<root-dir> -- 服務端上要作為根掛入的目錄名稱。如果字串中有個‘%s’ 符記(token),此符記將代換為客戶端網際網路地址之ASCII表示法。
<nfs-options> -- 標準的網路檔案系統選項。所有選項都以逗號分開。如果沒有給定此選項欄位則使用下列的預設值:
port = as given by server portmap daemon
rsize = 1024
wsize = 1024
timeo = 7
retrans = 3
acregmin = 3
acregmax = 60
acdirmin = 30
acdirmax = 60
flags = hard, nointr, noposix, cto, ac
引數nfsaddrs設定網路通訊所需的各種網路介面地址。如果沒有給定這個引數,則核心核會試著使用反向地址解析協議以及/或是啟動協議(BOOTP)以找出這些引數。其格式如下:
ip:
下面是U-boot官方文件提供的IP引數解析:
setenv bootargs ${bootargs}
ip=${ipaddr}:${serverip}:/
${gatewayip}:${netmask}:/
${hostname:${netdev}:off
注意,上面換行的地方均有空格。其中 192.168.2.6是開發板的IP,192.168.2.125
是PC端(或虛擬機器)的 IP,上面的IP根據自己的實際情況修改,不要弄錯了。
nfsaddrs=<my-ip>:<serv-ip>:<gw-ip>:<netmask>:<name>:<dev>:<auto>
<my-ip> -- 客戶端的網際網路地址。如果沒設,此地址將由反向地址解析協議(RARP)或啟動協議來決定。使用何種協議端視配置核心時開啟的選項以及 引數而定。如果設定此引數,就不會使用反向地址解析協議或啟動協議。
<serv-ip> -- 網路檔案系統服務端之網際網路地址。如果使用反向地址解析協議來決定客戶端地址並且設定此引數,則只接受從指定之服務端傳來的迴應。要使用不同的機器作為反向地址解析與網路檔案系統服務端的話,在此指定你的反向地址解析協議服務端(保持空白)並在 nfsroot 引數(見上述)中指定你的網路檔案系統服務端。如果此專案空白則使用回答反向地址解析協議或啟動協議之服務端的地址。
<gw-ip> -- 閘道器(gateway)之網際網路地址,若服務端位於不同的子網路上時。如果此專案空白則不使用任何閘道器並假設服務端在本地的(local)網路上,除非由啟動協議接收到值。
<netmask> -- 本地網路介面的網路掩碼。如果為空白,則網路掩碼由客戶端的網際網路地址匯出,除非由啟動協議接收到值。
<name> -- 客戶端的名稱。如果空白,則使用客戶端網際網路地址之 ASCII-標記法,或由啟動協議接收的值。
<dev> -- 要使用的網路裝置名稱。如果為空白,所有裝置都會用來發出反向地址解析請求,啟動協議請求由最先找到的裝置發出。網路檔案系統使用接收到反向地址解析協議或啟動協議迴應的裝置。如果你只有一個裝置那你可以不管它。
<auto> -- 用以作為自動配置的方法。如果是 `rarp' 或是 `bootp' 則使用所指示的協議。如果此值為`both' 或空白,若配置核心時有開啟這兩種協議則都使用。 `none' 表示不使用自動配置。這種情況下你必須指定前述欄位中所有必要的值。
此引數可以作為 nfsaddrs 的引數單獨使用(前面沒有任何 `:` 字元),這種情況下會使用自動配置。然而,此種情況不能使用`none'作為值。
[ [email protected] ]# set bkr 'tftp 30008000 linuxrom-fulinux.bin;nand erase 100000 400000;nand write 30008000 100000 400000'
[ [email protected] ]# pri
bbl=nand erase 0 100000;tftp 30008000 u-boot-$cpu.bin;nand write 30008000 0 $filesize
norbbl=erase bank 1;tftp 30008000 u-boot-$cpu.bin;cp.b 30008000 0 $filesize
bkr=tftp 30008000 uImage-$cpu.gz;nand erase 100000 400000;nand write 30008000 100000 $filesize
bootcmd_rootfs=nand read 30008000 100000 400000;bootm 30008000
tpb=tftp 30008000 uImage-$cpu.gz;tftp 30800000 ramdisk-$cpu.gz;bootm 30008000
mtdids=nand0=nand0
mtdparts=mtdparts=nand0:[email protected](u-boot),[email protected](kernel),[email protected](ramdisk),[email protected](cramfs),[email protected](yaffs2),[email protected](ubifs),-(users)
bootdelay=1
baudrate=115200
ethaddr=08:00:3e:26:0a:6b
ethact=dm9000
bcramfs=tftp 30800000 rootfs.cramfs;nand erase f00000 600000;nand write 30800000 f00000 600000
bjffs2=tftp 30008000 rootfs.jffs2;nand erase 1e00000 1400000;nand write.jffs2 30008000 1e00000 1400000
bootargs_jffs2=noinitrd root=/dev/mtdblock4 rootfstype=jffs2 init=/linuxrc console=ttyS0,115200
bootargs_cramfs=noinitrd root=/dev/mtdblock3 rootfstype=cramfs init=/linuxrc console=ttyS0,115200
bootargs_ubifs=console=ttyS0,115200 mem=64M ubi.mtd=6 root=ubi0:rootfs rootwait rootfstype=ubifs rw
bubifs=tftp 30008000 ubifs-$cpu.img;nand erase 6e00000 900000;nand write 30008000 6e00000 900000
cpu=arm920t
brdfs=tftp 30008000 ramdisk.gz;nand erase 500000 a00000;nand write 30008000 500000 500000
filesize=4B065C
fileaddr=30008000
netmask=255.255.255.0
ipaddr=192.168.1.111
serverip=192.168.1.3
bootcmd_ramdisk=nand read 30008000 100000 400000;nand read 30800000 500000 500000;bootm 30008000
bootargs_ramdisk=console=ttyS0,115200 mem=64M initrd=0x30800000,16M root=/dev/ram0 rw loglevel=7
ip=192.168.1.111:192.168.1.3:192.168.1.1:255.255.255.0:localhost.com:eth0:off
bootcmd=run bootcmd_rootfs
bootargs_nfs=noinitrd console=ttyS0,115200 init=/linuxrc mem=64M loglevel=7 root=/dev/nfs rw nfsroot=192.168.1.3:/opt/rootfs ip=192.168.1.111:192.168.1.3:192.168.1.1:255.255.255.0:localhost.com:eth0:off
bootargs=noinitrd console=ttyS0,115200 init=/linuxrc mem=64M loglevel=7 root=/dev/nfs rw nfsroot=192.168.1.3:/opt/rootfs ip=192.168.1.111:192.168.1.3:192.168.1.1:255.255.255.0:localhost.com:eth0:off
注:也可以是下面這樣
bootargs=noinitrd console=ttyS0,115200 init=/linuxrc mem=64M loglevel=7 root=/dev/nfs rw nfsroot=192.168.1.3:/opt/rootfs ip=192.168.1.111:192.168.1.3
stdin=serial
stdout=serial
stderr=serial
Environment size: 2123/131068 bytes
[ [email protected] ]#
上面的bootargs引數解析:
initrd, noinitrd:
當你沒有使用ramdisk啟動系統的時候,你需要使用noinitrd這個引數,但是如果使用了的話,就需要指定initrd=r_addr,size, r_addr表示initrd在記憶體中的位置,size表示initrd的大小。
console=ttyS?[,options] 使用特定的串列埠,options可以是這樣的形式bbbbpnx,這裡bbbb是指串列埠的波特率,p是奇偶位,n是指的bits。不過我們一般預設會使用console=ttyS0,115200作為引數;有時,在s3c24x0的u-boot環境變數中,我們會看到
console=ttySAC0,115200,這時因為在Linux-2.6以後的某個版本開始(如我們移植的linux-2.6.24),將drivers/serial/s3c2410.c中設定:
#define S3C24XX_SERIAL_NAME "ttySAC"
另外,在struct uart_driver s3c24xx_uart_drv中定義
.dev_name = "s3c2410_serial",
這時,我們將上面的兩處定義分別修改為下面值就OK了:
#define S3C24XX_SERIAL_NAME "ttyS"
static struct uart_driver s3c24xx_uart_drv = {
{
****
.dev_name = "ttyS",
****
}
init指定的是核心啟起來後,進入系統中執行的第一個指令碼,一般init=/linuxrc, 或者init=/etc/preinit,preinit的內容
一般是建立console,null裝置節點,執行init程式,掛載一些檔案系統等等操作。請注意,很多初學者以為init=/linuxrc
是固定寫法,其實不然,/linuxrc指的是/目錄下面的linuxrc指令碼,一般是一個連線罷了。如果核心找不到linurc檔案,
將會依次搜尋/sbin/init,/etc/init,bin/init,/bin/sh