Linux-文件系统-学习笔记(14):根文件系统原理与nfs搭建方法
一、根文件系统
1、根文件系统简介
为什么需要根文件系统?
(1)init进程的应用程序在根文件系统上,因此向用户态切换时根文件系统必不可少。
(2)根文件系统提供了根目录/ ,相当于一个数根、起点,通过这个能够找到你想要找的那个位置。
(3)内核启动后的应用层配置(etc目录)在根文件系统上。几乎可以认为:发行版=内核+rootfs。
(4)shell命令程序在根文件系统上。譬如ls、cd等命令(这些shell命令都在/bin下)。
总结:一套linux体系,只有内核本身是不能工作的,必须要rootfs(上的etc目录下的配置文件、/bin /sbin等目录下的shell命令,还有/lib目录下的库文件等···)相配合才能工作。
根文件系统的实质
(1)根文件系统是特殊用途的文件系统。相对于文件系统来说根文件系统能够提供根目录。
(2)根文件系统也必须属于某种文件系统格式。rootfstype=
(3)由于存储设备(块设备,像硬盘、flash等)是分块(扇区)的,物理上底层去访问存储设备时是按照块号(扇区号)来访问的。文件系统是一些代码,是一套软件,这套软件的功能就是对存储设备的扇区进行管理,将这些扇区的访问变成了对目录和文件名的访问。我们在上层按照特定的目录和文件名去访问一个文件时,文件系统会将这个目录+文件名转换成对扇区号的访问。底层还是按扇区号来访问的,但是上层只需要操作文件名即可。
(4)不同的文件系统的差异就在于对这些扇区的管理策略和方法不同,譬如坏块管理、碎片管理。
根文件系统的形式
根文件系统有两种形式,一种是可供烧录的镜像文件形式,另一种可以下载的文件夹形式。
(1)镜像文件形式
我们可以使用专用工具软件制作的可供烧录的镜像文件。镜像文件中包含了根文件系统中的所有文件,这意味着能够看到的文件系统的所有内容都在这里面,也就是斜杠/下的那些文件。烧录此镜像类似于对相应分区格式化。镜像文件系统具有一定的格式,格式是内化的,跟文件名后缀是无关的。
镜像文件形式的根文件系统主要目的是用来烧录到块设备上,设备上的内核启动后去挂载它。镜像文件形式的根文件系统是由文件夹形式的根文件系统使用专用的镜像制作工具制作而成的。
(2)文件夹形式
根文件系统其实就是一个包含特定内容的文件夹而已。它可由任何一个空文件夹添加必要文件构成而成(先创建一个mkdir空文件夹,然后往这个文件夹中添加东西)。
最初在开发主机中随便mkdir创建了一个空文件夹,然后向其中添加一些必要的文件(包括etc目录下的运行时配置文件、/bin等目录下的可执行程序、/lib目录下的库文件等···)后就形成了一个文件夹形式的rootfs。然后这个文件夹形式的rootfs可以被kernel通过nfs方式来远程挂载使用,但是不能用来烧录块设备。我们为了将这个rootfs烧录到块设备中于是用一些专用的软件工具将其制作成可供烧录的一定格式的根文件系统镜像。
文件夹形式的rootfs是没有格式的,制作成镜像后就有了一定的rootfs格式了,格式是由我们的镜像制作过程和制作工具来决定的。每一种格式的镜像制作工具的用法都不同。
根文件系统中有什么?
(1)最重要的就是linuxrc。后面会简单介绍它。
(2)dev目录下的设备文件。在linux中一切皆是文件,因此一个硬件设备也被虚拟化成一个设备文件来访问,在linux系统中 /dev/xxx就表示一个硬件设备,我们要操作这个硬件时就是open打开这个设备文件,然后read/write/ioctl操作这个设备,最后close关闭这个设备。在最小rootfs中/dev目录也是不可少的,这里面有一两个设备文件是rootfs必须的。
(3)sys和proc目录。在最小rootfs中也是不可省略的,但是这两个只要创建了空文件夹即可,里面是没东西的,也不用有东西。这两个目录也是和驱动有关的。属于linux中的虚拟文件系统。
(4)usr是系统的用户所有的一些文件的存放地,这个东西将来busybox安装时会自动生成。比如自己安装一些库,应用程序……
(5)etc目录是很关键很重要的一个,目录中的所有文件全部都是运行时配置文件。/etc目录下的所有配置文件会直接或者间接的被/linuxrc所调用执行,完成操作系统的运行时配置。etc目录是制作rootfs的关键。
(6)lib目录也是rootfs中很关键的一个,不能省略的一个。lib目录下放的是当前操作系统中的动态和静态链接库文件。我们主要是为了其中的动态链接库。
(7)其他opt、mnt等都是一些临时文件夹。
2、动手制作ext3格式的根文件系统
制作ext2、ext3、ext4等格式的根文件系统需要一个mke2fs的应用程序,该程序在ubuntu中默认安装了。
一般用来制作各种不同格式的rootfs的应用程序的名字都很相似,类似于mkfs.xxx。
下面我们动手创建一个ext3格式的根文件系统,并将其挂载到一个目录下访问它。为什么要挂载到其他目录下呢?因为创建好的根文件系统中的内容是不能够直接操作的,我们需要对它进行挂载,相当于给它找了一个入口,通过这个入口就可以查看和修改里面的内容。
创建文件系统命令:
#创建并挂载
dd if=/dev/zero of=rootfs.ext2 bs=1024 count=2048
losetup /dev/loop1 rootfs.ext2
mke2fs -m 0 /dev/loop1 2048
mount -t ext2 /dev/loop1 ./rootfs/
#卸载
umount /dev/loop1
losetup -d /dev/loop1
注:第一步中:if表示输入文件,文件为空;of表示输出文件;block大小为1024字节,count有2048个block,所以总大小为2MB。第二步中:rootfs.ext2是根文件系统的文件名。第三步中:用mke2fs表示文件格式为ext格式。第四步中:./rootfs/表示挂载dev/loop1到当前目录的rootfs中,进rootfs中写东西就相当于给rootfs.ext2中写东西了(需要先创建好一个rootfs文件才能挂载)。
二、搭建nfs服务器
nfs是一种网络通讯协议,由服务器和客户端构成。利用nfs协议可以做出很多直接性应用,我们这里使用nfs主要是做rootfs挂载。开发板中运行kernel做nfs客户端,主机ubuntu中搭建nfs服务器。在主机ubuntu的nfs服务器中导出我们制作的文件夹形式的rootfs目录,则在开发板中就可以远程去挂载这个文件夹形式的rootfs进而去启动系统。
1、搭建nfs服务器方法
(1)安装nfs
sudo apt-get install nfs-kernel-server
sudo apt-get install nfs-common
(2)配置/etc/exports
#打开这个文本
sudo vi /etc/exports
#在文本中添加挂载的目录路径,我这里路径为/root/porting_x210/rootfs/rootfs
/root/porting_x210/rootfs/rootfs *(rw,sync,no_root_squash,no_subtree_check)
#执行命令
chmod 777 -R /root/porting_x210/rootfs/rootfs
sudo showmount -e
#第一次会报错clnt-create : RPC : Program not registered,重启
sudo exportfs -r
sudo showmount localhost -e
#重启nfs服务
sudo /etc/init.d/nfs-kernel-server restart
#挂载,
mount -t nfs -o nolock localhost:/root/porting_x210/rootfs/rootfs /opt
挂载完成后,进入到/opt文件夹下即可看到rootfs中的内容。
2、配置内核以支持nfs作为rootfs
(1)首先要配置内核支持nfs启动方式。通过make menuconfig中实现配置。
Networking support
Networking options
TCP/IP networking
IP: kernel level autoconfiguration
[*] IP: DHCP support
[*] IP: BOOTP support
File systems --->
Network File Systems --->
<*> NFS client support
[*] NFS client support for NFS version 3
[*] NFS client support for the NFSv3 ACL protocol extension
[*] NFS client support for NFS version 4 (EXPERIMENTAL)
[] NFS client support for NFSv4.1 (DEVELOPER ONLY)
[*] Root file system on NFS
(2)设置uboot中的bootargs。
setenv bootargs root=/dev/nfs nfsroot=192.168.1.141:/root/porting_x210/rootfs/rootfs ip=192.168.1.20:192.168.1.141:192.168.1.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC2,115200
启动内核后发现,开发板上的内核远程挂载到主机上的rootfs,但是未能执行其中的/linuxrc文件。标志着我们制作的简易版rootfs远程挂载成功。
注:当出现bash: cd: mnt: Stale file handle问题时,尝试umount -f /mnt。
三、linuxrc
1、什么是linuxrc?
上一步我们进行到了挂载根文件系统成功,但是显示不能执行linuxrc。那么什么是linuxrc呢?
(1)/linuxrc是一个可执行的应用程序,是应用层的,和内核源码一点关系都没有。
(2)/linuxrc在开发板当前内核系统下是可执行的。因此在ARM SoC的linux系统下,这个应用程序就是用arm-linux-gcc编译链接的;如果是在PC机linux系统下,那么这个程序就是用gcc编译连接的。
(3)/linuxrc如果是静态编译连接的那么直接可以运行;如果是动态编译连接的那么我们还必须给他提供必要的库文件才能运行。但是因为我们/linuxrc这个程序是由内核直接调用执行的,因此用户没有机会去导出库文件的路径,因此实际上这个 /linuxrc没法动态连接,一般都是静态连接的。
2、linuxrc的作用是什么?
(1)/linuxrc执行时引出用户界面。操作系统启动后在一系列的自己运行配置之后,最终会给用户一个操作界面(也许是cmdline,也许是GUI),这个用户操作界面就是由/linuxrc带出来的(由于linuxrc的运行使得它们才能运行)。
(2)用户界面等很多事并不是在/linuxrc程序中负责的,用户界面有自己专门的应用程序,但是用户界面的应用程序是直接或者间接的被/linuxrc调用执行的。用户界面程序和其他的应用程序就是进程2、3、4·····,而linuxrc属于进程1(init进程),所以说进程1是其他所有应用程序进程的祖宗进程。
(3)/linuxrc负责系统启动后的配置。由于操作系统启动起来后不能直接使用,需要先进行配置。操作系统启动后的应用层的配置(一般叫运行时配置,英文简写etc)是为了让我们的操作系统用起来更方便,更适合我个人的爱好或者实用性。
(4)/linuxrc在嵌入式linux中一般就是busybox。busybox其实是一个用C语言写的项目,我们用arm-linux-gcc来编译busybox就会得到一个可以在开发板linux内核上运行的应用程序。busybox这个程序开发出来就是为了在嵌入式环境下构建rootfs使用的,也就是说他就是专门开发的init进程应用程序。
busybox为当前系统提供了一整套的shell命令程序集。譬如vi、cd、mkdir、ls等。在桌面版的linux发行版(譬如ubuntu、redhat、centOS等)中vi、cd、ls等都是一个一个的单独的应用程序。但是在嵌入式linux中,为了省事我们把vi、cd等所有常用的shell命令集合到一起构成了一个shell命令包,起名叫busybox,它所做的就是linuxrc要做的。
四、补充:VFS
1、VFS简介
VFS是linux内核的一种设计理念、设计机制。VFS就是vitrual file system,叫虚拟文件系统。
具体的一些文件系统如FAT、NTFS、ext2、ext3、jffs2、yaffs2、ubi等主要设计目的是为了管理块设备(硬盘、Nand···)。VFS是借鉴了文件系统的设计理念(通过文件系统将底层难以管理的物理磁盘扇区式访问,转换成目录+文件名的方式来访问),将硬件设备的访问也虚拟化成了对目录+文件的访问。所以有了VFS后我们可以通过设备文件(目录+文件名,譬如/dev/mmcblk0p2)的方式来访问系统中的硬件设备。
2、VFS作用
(1)将对硬件设备的访问和对普通文件的访问给接口统一化了(linux中一切届是文件)。
(2)将操作系统上层(应用层)对下层不同文件系统类型的访问细节给屏蔽掉了。因此如果没有VFS那我们写cp命令(其他命令也一样)的时候就不得不去考虑你cp的这个文件在什么文件系统类型下。所以cp命令非常复杂,因此要考虑具体的文件系统类型。有了VFS后情况就不同了。VFS成了一个隔离层,隔离了下层的不同文件系统的差异性,对上层应用提供一个统一的接口。它就像一个万能钥匙,通过VFS我们可以用相同的方法访问各种不同类型的文件系统。
(3)VFS将不同文件系统和下层硬件设备(块设备)驱动之间的细节也给屏蔽了。不同类型的文件系统在本身设计时是不用考虑各种不同的硬件设备的具体操作差异的,这里有一个类似于VFS的设计理念。