嵌入式Linux根文件系统简介
根文件系统首先是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,但是相
对于普通的文件系统而言它还是内核启动时所挂载(mount)的第一个文件系统,系统引导启动程序会
在根文件系统挂载之后从中把一些初始化脚本(如inittab、rcS)和服务加载到内存中去运行。我们要
明白文件系统和内核是完全独立的两个部分。在嵌入式中移植的内核下载到开发板上,是没有办法真正
的启动Linux操作系统的,会出现无法加载文件系统的错误。
根文件系统之所以在前面加一个”根“,说明它是加载其它文件系统的”根“,既然是根的话,那么
如果没有这个根,其它的文件系统也就没有办法进行加载的。它包括了Linux启动时所必须的目录和关
键性的文件,例如Linux启动时都需要有init目录下的相关文件,在 Linux挂载分区时Linux一定会
找/etc/fstab这个挂载配置文件等,根文件系统中还包括了应用程序(如ls、mkdir、rm、ifconfig等命
令)和 GNU C 库(glibc、eglibc或uclibc)等。任何包括这些Linux 系统启动所必须的文件都可以成
为根文件系统。Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件
系统,则系统会出错而退出启动。成功之后可以自动或手动挂载其他的文件系统。因此,一个系统中可
以同时存在不同的文件系统。
在 Linux 中将一个文件系统与一个存储设备关联起来的过程称为挂载(mount)。使用 mount 命令
将一个文件系统附着到当前文件系统层次结构中(根)。在执行挂载时,要提供文件系统类型、文件系
统和一个挂载点。根文件系统被挂载到根目录下“/”上后,在根目录下就有根文件系统的各个目录,
文件:/bin /sbin /mnt等,再将其他分区挂接到/mnt目录上,/mnt目录下就有这个分区的各个目录,
文件。
Linux操作系统可以支持多种多样不同的文件系统,如windows下的FAT32、NTFS,Linux服务器使
用的ext2、ext3、ext4、btrfs、xfs、reiser4、ufs、hfs(苹果系统),Linux操作系统自身使用的伪
文件系统如swap、proc、sysfs、tmpfs等,也有一些设备的文件系统如iso9660(光盘)、nfs(网络
文件系统)等,当然还包括我们嵌入式设备上用的不同的文件系统如:initramfs(在内存中运行的文件
系统)、jffs2(一种基于Norflash的文件系统,也支持小页的nandflash)、ubifs(目前Android手机
上的Nandflash普遍使用的文件系统)、yaffs2(早期专门用来支持大页Nandflash的文件系统,具备
可移植性可在单片机裸机情况下使用)、cramfs(一种基于内存的只读的文件系统)、squashfs(在
openwrt路由器上广泛使用的俄文件系统)、romfs(一种只读、支持片上执行XIP的文件系统,在
uClinux中广泛使用)等。下面是几种常用的嵌入式根文件系统的对比:initramfs 该文件系统直接将根文件系统直接打包进Linux内核里(只有这种文件系统具有该功
能),这样内核和根文件系统绑定在一块成为一个单独的文件,他在Linux系统启动后加载到内存
中运行,所以速度快,但浪费内存,系统升级的时候内核和根文件系统一起升级比较方便。但因
为他是基于内存的文件系统,所以系统掉电后针对根文件系统下所有文件的修改掉电都会丢失,
如果要升级根文件系统只有重新编译、烧录Linux内核;jffs2 专门针对Norflash设计的文件系统,小页的Nandflash也可以使用,只是效率不高;因为
根文件系统存放在Flash上,所以根文件系统路径下的文件修改后掉电仍然存在;yaffs2 早期专门针对大页Nandflash设计的文件系统,他的源码独立于Linux内核维护着,所以
可以在单片机等裸机环境下使用(只有该文件系统可以),linux内核想用它必须要打上补丁;
在分区较大时,nandflash的挂载时间较长,现在逐渐被ubifs广泛替代;ubifs 专门针对Nandflash设计的一种文件系统,他在内核的MTD一层上面又建立了UBI一层挂载速度、磨损均衡、读写速度非常快,目前nandflash上应用得最广的一种根文件系统;
Linux操作系统之所以能够支持这么多种不同的文件系统,主要是通过叫做VFS的中间层对这些文件系
统提供了完美的支持。对于用户来说,这些文件系统几乎是透明的,在大部分情况下,用户通过libc和
kernel的VFS交互,不需要关心底层文件系统的具体实现,但是有时应用程序也需要考虑底层文件系统
限制(比如fat vfat不支持链接,比如各个文件系统支持最大文件限制不同)。VFS主要有以下特性:
1. 向上,对应用层提供一个标准的文件操作接口,如open()、read()、write()、ioct()、close()等;
2. 对下,对所有文件系统提供一个统一的标准接口,以便其他操作系统的文件系统可以方便的移植
到Linux上;
3. VFS内部则通过一系列高效的管理机制,比如inode cache, dentry cache 以及文件系统的预读
等技术,使得底层文件系统不需沉溺到复杂的内核操作,即可获得高性能;
4. 此外VFS把一些复杂的操作尽量抽象到VFS内部,使得底层文件系统实现更简单。
下图是Linux内核里文件系统的分层结构图:
mtd-utils工具源码编译
Linux内核MTD对同一Flash分区提供了两种设备文件给用户层使用,一种是/dev/mtdblockX块设
备,该设备用来建立文件系统并挂载起来使用;另外一种相对应的/dev/mtdX字符设备,其里面添加了
一些ioctl,支持很多命令,如MEMGETINFO,MEMERASE等。而mtd-util就是以这些ioctl为基础而实
现的工具,实现一些关于Flash的操作,如flash_erase、flash_eraseall、flashcp、nandwrite等命令,
此外在PC上制作根文件系统所需要的一些工具也在里面,如制作JFFS2根文件系统用的mkfs.jffs2、制
作UBIFS根文件系统工具mkfs.ubifs以及开发板上操作UBI文件系统的命令。
这里我们只介绍PC端的源码编译来获取mkfs.jffs2和mkfs.ubifs工具,如果相应的工具需要放在
ARM开发板上运行则需要使用交叉编译器编译。mtd_utils需要lzo、zlib和e2fsprogs这三个库,所以在
编译mtd_utils之前先需要编译这三个库。Linux下使用源码安装工具时,如果有Makefile则直接用
make命令编译,如果没有Makefile文件,则一般有个configure的脚本,该源码结构的编译三步曲:
./configure、make、make install
2.1 创建mtd-utils的工作路径
[email protected]:~/fl2440$ ls
3rdparty bootloader crosstool driver images linux program
[email protected]:~/fl2440$ mkdir -p x86_tools/mtd_utils
mtd-utils编译依赖lzo、zlib和libuuu这几个库,所以我们在编译它之前先要编译这些库。另外,为了
在运行mkfs.jffs2和mkfs.ubifs这些命令时不依赖这些动态库,我们采用静态编译、然后静态链接生成
这两个命令
2.2 编译lzo库
[email protected]:~/fl2440$ cd x86_tools/mtd_utils/
[email protected]:~/fl2440/x86_tools/mtd_utils$ tar -xzf lzo-2.10.tar.gz
[email protected]:~/fl2440/x86_tools/mtd_utils$ cd lzo-2.10/
[email protected]:~/fl2440/x86_tools/mtd_utils/lzo-2.10$ ls
aclocal.m4 BUGS configure.ac INSTALL Makefile.in tests
asm ChangeLog COPYING lzo2.pc.cmakein minilzo THANKS
AUTHORS CMakeLists.txt doc lzo2.pc.in NEWS util
autoconf config.hin examples lzotest README
B configure include Makefile.am src
[email protected]:~/fl2440/x86_tools/mtd_utils/lzo-2.10$ ./configure -help
//编译三部曲
[email protected]:~/fl2440/x86_tools/mtd_utils/mtd-utils-1.5.2$ ./configure --prefix=`pwd`/../install --enable-static --disable-shared //--prefix指定安装路径 --enable-static指定生产静态库 --disable- shared 指定不要生成动态库
[email protected]:~/fl2440/x86_tools/mtd_utils/lzo-2.10$ make
[email protected]:~/fl2440/x86_tools/mtd_utils/lzo-2.10$ make install
2.3 编译zlib库
[email protected]:~/fl2440/x86_tools/mtd_utils$ wget https://github.com/madler/zlib/archive/v1.2.10.tar.gz -O zlib-1.2.10.tar.gz
[email protected]:~/fl2440/x86_tools/mtd_utils$ tar -xzf zlib-1.2.10.tar.gz
[email protected]:~/fl2440/x86_tools/mtd_utils$ cd zlib-1.2.10/
[email protected]:~/fl2440/x86_tools/mtd_utils/zlib-1.2.10$ ./configure --prefix=`pwd`/../install --static
[email protected]:~/fl2440/x86_tools/mtd_utils/zlib-1.2.10$ make
[email protected]:~/fl2440/x86_tools/mtd_utils/zlib-1.2.10$ make install
2.4 编译e2fsprogs库(libuuid)
[email protected]:~/fl2440/x86_tools/mtd_utils$ wget https://github.com/tytso/e2fsprogs/archive/v1.43.7.tar.gz -O e2fsprogs-1.43.7.tar.gz
[email protected]:~/fl2440/x86_tools/mtd_utils$ tar -xzf e2fsprogs-1.43.7.tar.gz
[email protected]:~/fl2440/x86_tools/mtd_utils$ cd e2fsprogs-1.43.7/
[email protected]:~/fl2440/x86_tools/mtd_utils/e2fsprogs-1.43.7$ ./configure --prefix=`pwd`/../install --enable-elf-shlibs --enable-libuuid
[email protected]:~/fl2440/x86_tools/mtd_utils/e2fsprogs-1.43.7$ make
[email protected]:~/fl2440/x86_tools/mtd_utils/e2fsprogs-1.43.7$ make install
2.5 编译mtd-utils并安装mkfs.jffs2和mkfs.ubifs
[email protected]:~/fl2440/x86_tools/mtd_utils$ wget ftp://ftp.infradead.org/pub/mtd- utils/mtd-utils-1.5.2.tar.bz2
[email protected]:~/fl2440/x86_tools/mtd_utils$ tar -xjf mtd-utils-1.5.2.tar.bz2
//导入环境变量
[email protected]:~/fl2440/x86_tools/mtd_utils$ cd mtd-utils-1.5.2/
[email protected]:~/fl2440/x86_tools/mtd_utils/mtd-utils-1.5.2$ export CFLAGS+="I../install/include/"
[email protected]:~/fl2440/x86_tools/mtd_utils/mtd-utils-1.5.2$ export LDFLAGS+="-L../install/lib/ -static"
[email protected]:~/fl2440/x86_tools/mtd_utils/mtd-utils-1.5.2$ make WITHOUT_XATTR=1
[email protected]:~/fl2440/x86_tools/mtd_utils/mtd-utils-1.5.2$ sudo cp mkfs.jffs2 /bin/
[email protected]:~/fl2440/x86_tools/mtd_utils/mtd-utils-1.5.2$ sudo cp mkfs.ubifs/mkfs.ubifs /bin/
[email protected]:~/fl2440/x86_tools/mtd_utils/mtd-utils-1.5.2$ sudo cp ubi-utils/ubinize /bin/
内核调整Nandflash分区表
FL2440上使用K9F2G08这个256MB的Nandflash,就像PC上的硬盘一样,我们也需要对整个
Nandflash进行分区。只不过这个分区的过程是通过在Linux的源码修改来调整,接下来我们按照下面
这个分区表来调整Linux系统的分区表。
[email protected]:~/fl2440/x86_tools/mtd_utils/mtd-utils-1.5.2$ cd ../../../linux/linux-3.0/
[email protected]:~/fl2440/linux/linux-3.0$ vim arch/arm/plat-s3c24xx/common-smdk.c
static struct mtd_partition smdk_default_nand_part[] = {
[0] = {
.name = "mtdblock0 u-boot 1MB",
.offset = 0,
.size = SZ_1M*1, // 0x0000000 ~ 0x0100000
},
[1] = {
.name = "mtdblock1 kernel 15MB",
.offset = MTDPART_OFS_NXTBLK,
.size = SZ_1M*15, // 0x0100000 ~ 0X1000000
},
[2] = {
.name = "mtdblock2 rootfs 40MB",
.offset = MTDPART_OFS_NXTBLK,
.size = SZ_1M*40,
},
[3] = {
.name = "mtdblock3 apps 80MB",
.offset = MTDPART_OFS_NXTBLK,
.size = SZ_1M*80,
},
[4] = {
.name = "mtdblock4 data 80MB",
.offset = MTDPART_OFS_NXTBLK,
.size = SZ_1M*80,
},
[5] = {
.name = "mtdblock5 backup 40MB",
.offset = MTDPART_OFS_NXTBLK,
.size = SZ_1M*40,
}
};
编译linux内核重新烧录到开发板并启动,可以看到分区变化:
...
Creating 6 MTD partitions on "NAND":
0x000000000000-0x000000100000 : "mtdblock0 u-boot 1MB"
0x000000100000-0x000001000000 : "mtdblock1 kernel 15MB"
0x000001000000-0x000003800000 : "mtdblock2 rootfs 40MB"
0x000003800000-0x000008800000 : "mtdblock3 apps 80MB"
0x000008800000-0x00000d800000 : "mtdblock4 data 80MB"
0x00000d800000-0x000010000000 : "mtdblock5 backup 40MB"
...
~ >: cat /proc/mtd//登录开发板Linux后,我们也可以使用 cat /proc/mtd 命令查看分区信息
dev: size erasesize name
mtd0: 00100000 00020000 "mtdblock0 u-boot 1MB"
mtd1: 00f00000 00020000 "mtdblock1 kernel 15MB"
mtd2: 02800000 00020000 "mtdblock2 rootfs 40MB"
mtd3: 05000000 00020000 "mtdblock3 apps 80MB"
mtd4: 05000000 00020000 "mtdblock4 data 80MB"
mtd5: 02800000 00020000 "mtdblock5 backup 40MB"
~ >: ls -l /dev/mtd*//开发板Linux系统的路径下会产生相应的分区文件,其中mtdX(X为0,1,2,3....)为可读写字符设备, mtdXro为只读的字符设备, mtdblockX为mount命令挂载使用的块设备。
crw-rw---- 1 root root 90, 0 Jan 1 00:00 /dev/mtd0
crw-rw---- 1 root root 90, 1 Jan 1 00:00 /dev/mtd0ro
crw-rw---- 1 root root 90, 2 Jan 1 00:00 /dev/mtd1
crw-rw---- 1 root root 90, 3 Jan 1 00:00 /dev/mtd1ro
crw-rw---- 1 root root 90, 4 Jan 1 00:00 /dev/mtd2
crw-rw---- 1 root root 90, 5 Jan 1 00:00 /dev/mtd2ro
crw-rw---- 1 root root 90, 6 Jan 1 00:00 /dev/mtd3
crw-rw---- 1 root root 90, 7 Jan 1 00:00 /dev/mtd3ro
crw-rw---- 1 root root 90, 8 Jan 1 00:00 /dev/mtd4
crw-rw---- 1 root root 90, 9 Jan 1 00:00 /dev/mtd4ro
crw-rw---- 1 root root 90, 10 Jan 1 00:00 /dev/mtd5
crw-rw---- 1 root root 90, 11 Jan 1 00:00 /dev/mtd5ro
brw-rw---- 1 root root 31, 0 Jan 1 00:00 /dev/mtdblock0
brw-rw---- 1 root root 31, 1 Jan 1 00:00 /dev/mtdblock1
brw-rw---- 1 root root 31, 2 Jan 1 00:00 /dev/mtdblock2
brw-rw---- 1 root root 31, 3 Jan 1 00:00 /dev/mtdblock3
brw-rw---- 1 root root 31, 4 Jan 1 00:00 /dev/mtdblock4
brw-rw---- 1 root root 31, 5 Jan 1 00:00 /dev/mtdblock5
以上工作为制作jffs2和ubifs文件系统准备,下面会讲到两种文件系统的制作。