ubifs 和 jffs2 根文件系统
根文件系统就是基于flash的文件系统,与传统的文件系统ext2、ext3、ext4不同,他们都是针对不同的硬件而诞生的,不同的根文件系统性能指标不同,那么ubifs和jffs2就是比较常见的用的比较多的根文件系统,jffs2是很早期的根文件系统,ubifs是linux内核2.6之后才产生的一种新型根文件系统。
-
jffs2 专门针对Norflash设计的文件系统,小页的Nandflash也可以使用,只是效率不高;因为根文件系统存放在Flash上,所以根文件系统路径下的文件修改后掉电仍然存在;
-
(顺带一提)yaffs2 早期专门针对大页Nandflash设计的文件系统,他的源码独立于Linux内核维护着,所以可以在单片机等裸机环境下使用(只有该文件系统可以),linux内核想用它必须要打上补丁;在分区较大时,nandflash的挂载时间较长,现在逐渐被ubifs广泛替代;
-
ubifs 是专门针对Nandflash设计的一种文件系统,他在内核的MTD一层上面又建立了UBI一层,挂载速度、磨损均衡、读写速度非常快,目前nandflash上应用得最广的一种根文件系统;
ubifs详情:https://blog.csdn.net/yedushu/article/details/79767099
VFS虚拟文件系统,这个文件系统保证了linux下多种文件类型的统一,文件系统、根文件系统、网络文件系统、ram文件系统就是通过VFS的机制实现不同层文件系统的标准统一。
mtd-utils工具
mtd-utils编译依赖lzo、zlib和libuuu(e2fsprogs)这几个库,所以我们在编译它之前先要编译这些库。另外,为了在运行mkfs.jffs2和mkfs.ubifs这些命令时不依赖这些动态库,我们采用静态编译、然后静态链接生成这两个命令。
创建/x86_tools/mtd_utils目录
下载我们工具所需要的库lzo和zlib
lzo库:http://www.oberhumer.com/opensource/lzo/download/lzo-2.10.tar.gz
zlib库:wget https://github.com/madler/zlib/archive/v1.2.10.tar.gz -O zlib-1.2.10.tar.gz
e2fsprogs库:wget
https://github.com/tytso/e2fsprogs/archive/v1.43.7.tar.gz -O e2fsprogs-1.43.7.tar.gz
lzo库解压缩之后配置编译参数
./configure --prefix=`pwd`…/install --enable- static --disable-shared
–prefix指定安装路径 --enable-static指定生产静态库 --disable- shared 指定不要生成动态库,指定我们编译的参数。然后make && make install
配置zlib库
配置e2fsprogs库 编译make ; make install-libs
接下来就是编译mdt-utils
源码:ftp://ftp.infradead.org/pub/mtd-utils/mtd-utils-1.5.2.tar.bz2
解压缩后设置环境变量:
export CFLAGS+=" -I…/install/include/ "
export LDFLAGS+=" -L…/install/lib/ - static "
内核调整nandflash分区
分区表
vim arch/arm/plat-s3c24xx/common-smdk.c
/* NAND parititon from 2.4.18-swl5 */
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,
}
};
......
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"
mtdX为可读写的字符设备,总共产生了六个分区。
jffs2文件系统
JFFS2全名是 Journalling Flash File System Version2,是Redhat公司开发的Flash的文件系统,其前身是JFFS, 最早只支援Norflash, 自2.6版以后开始支援NAND Flash,其功能就是管理在MTD设备上实现的日志型文件系统,极适合使用于嵌入式系统。与其他的存储设备存储方案相比,JFFS2并不准备提供让传统文件系统也可以使用此类设备的转换层。它只会直接在MTD设备上实现日志结构的文件系统。JFFS2会在安装的时候,扫描MTD设备的日志内容,并在RAM中重新建立文件系统结构本身。除了提供具有断电可靠性的日志结构文件系统,JFFS2还会在它管理的MTD设备上实现“损耗平衡”和“数据压缩”等特性。下面是JFFS2的不足之处:
- JFFS2 的挂载(mount)过程需要对Flash从头到尾的扫描,这个过程是很慢的,我们在测试中发现,挂载一个 16M 的闪存有时需要半分钟以上的时间。
- JFFS2 在分区的空间使用率比较大后,数据的读写非常缓慢。
- JFFS2 对磨损平衡是用概率的方法来解决的,这很难保证磨损平衡的确定性。在某些情况下,可能造成对擦写块不必要的擦写操作;在某些情况下,又会引起对磨损平衡调整的不及时。
- JFFS2没有write-back机制,不能将资料暂存于缓存(cache), 以致于flash I/O的动作频繁。
- JFFS2是针对早起的Norflash和小页(页大小<4K)的Nandflash设计的,并不适合大页的Nandflash。
jffs2镜像文件制作
使用之前的mtd-utils中的mkfs.jffs2工具来制作,mkfs-jffs2 -h可以查看工具的使用方法
xiaobaicai@xiaobaicai:~/fl2440/linux$ mkfs.jffs2 -n -s 2048 -e 128KiB -d ./rootfs -o rootfs-jffs2.bin --pad=0xa00000
-n 指明不填充清除标记
-s 指定nandflash页的大小2k
-e 指定nandflash擦除块大为128k
-d 指定目录树路径
-o 指定镜像文件的名字
–pad=0xa00000 将制作的根文件系统镜像(rootfs-jffs2.bin)文件大小用0xFF填充为–pad指定的值。如果在制作根文件系统的不填充的话,Linux挂载启动根文件系统时将会出现下面警告信息。
我们在之前的Linux内核Nandflash分区修改里将rootfs分区大小设置为40M,所以这里的–pad值应该为0x280000。但如果使用0x2800000,则根文件系统镜像的大小就为40M,这样u-boot下载烧录的时间较长,另外如果在Nandflash上烧录该镜像文件的分区存在坏块的话,则在u-boot里用nand
write烧录时会跳过坏块溢出到下一个分区空间中去,从而占用了下一个空间的使用,系统就会出错。这里我们将填充大小值设置为10M是也可以解决上面jffs2_scan_eraseblock抛出的警告信息,之所以将填充大小设置为10M是因为不进行填充时制作的根文件系统镜像大小为6.3M,这个值的大小根据分区大小和根文件系统目录树的实际大小进行调整。
内核配置和编译
1.General setup —>
2.File systems —>
2.1 CD-ROM/DVD Filesystems —>
该选项下都取消掉
2.2 DOS/FAT/NT Filesystems —>
2.3 Pseudo filesystems —>
2.4 [*]Miscellaneous filesystems —>
2.5 [*]Network File Systems —>
2.6 Partition Types —>
2.7 Native language support —>
选上<*> Codepage 437 (United States, Canada)
<*> Simplified Chinese charset (CP936, GB2312)
<*> Traditional Chinese charset (Big5)
<*> ASCII (United States)
<*> NLS ISO 8859-1 (Latin 1; Western European Languages)
<*> NLS UTF-8
u-boot环境变量配置和系统烧录
jffs2文件系统镜像是单独存在的,他的加载需要依靠u-boot传bootargs环境变量告诉内核jaffs2的镜像位置,所以我们需要配置环境变量。
- u-boot的烧录地址应该是 0,大小不超过1M。该分区对应Linux内核分区
表的/dev/mtdblock0; - Linux内核的烧录地址应该是0x100000(1M的偏移量处),大小不超过15M。该分区对应Linux内核分区表的/dev/mtdblock1;
- 根文件系统镜像的烧录地址应该是0x1000000(16M的偏移量处),大小不超过40M。该分区对应Linux内核分区表的/dev/mtdblock2;
bootcmd和bootargs
bootcmd是内核地址参数,bootargs是根文件系统地址参数,uboot根据bootcmd参数加载内核镜像文件,uboot传参给内核,让内核加载跟文件系统镜像文件
设置如下:
我们内核编译完的大小只有2.4M
xiaobaicai@xiaobaicai:~/fl2440/linux/linux-3.0$ du -sh linuxrom-s3c2440.bin
2.4M linuxrom-s3c2440.bin
bootcmd=nand read 30008000 100000 400000;bootm 30008000
bootargs=console=tty0 console=ttyS0,115200 root=/dev/mtdblock2
rootfstype=jffs2 init=/linuxrc mem=64M rw noinitrd loglevel=7
bootargs的参数解析如下:
console=tty0 指定内核控制终端为LCD,内核启动信息输出到LCD上;
console=ttyS0,115200 指定内核控制终端也为第一个串口,使用波特率115200,这样内核启动信息也打印到第一个串口上;
root=/dev/mtdblock2 指定根文件系统存放在mtdblock2上,该值应该与u-boot烧录位置、Linux内核分区保持一致;如果错误则Linux内核会因找不到根文件系统而启动失败;
rootfstype=jffs2 指定根文件系统类型为jffs2,如果该参数错误则内核启动失败;
init=/linuxrc 指定init进程执行/linuxrc这个程序,他会解析并执行/etc/inittab下的命令;
mem=64M u-boot告诉Linux内核有64M的内存;
rw 根文件系统以读写的形式挂载;
noinitrd 没有使用initrd;
loglevel=7 定义内核printk的打印级别为7,即所有信息都通过console打印出来;
设置快捷烧录方式
blx=tftp 30008000 linuxrom-s3c2440.bin;nand erase 100000 F00000;nand write 30008000 100000 400000
jffs2=tftp 30008000 rootfs-jffs2.bin;nand erase 1000000 2800000;nand write 30008000 1000000 b00000
boot启动
启动测试没有问题
jffs2挂载
查看内核分区
~ >: dmesg | grep mtdblock
Kernel command line: console=tty0 console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=jffs2 init=/linuxrc mem=64M rw noinitrd loglevel=7
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/partitions
major minor #blocks name
31 0 1024 mtdblock0
31 1 15360 mtdblock1
31 2 40960 mtdblock2
31 3 81920 mtdblock3
31 4 81920 mtdblock4
31 5 40960 mtdblock5
查看分区对应的块设备
~ >: ls -l /dev/mtdblock*
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
这里我们以 mtdblock5 为例将其以jffs2文件系统格式挂载到 /info 挂载点上:
先擦除分区mtdblock5
~ >: flash_eraseall /dev/mtd5
Erasing 128 Kibyte @ 2800000 - 100% complete.
没有flash_eraseall命令就去busybox下配置
挂载并查看分区
mount -t jffs2 /dev/mtdblock5 /info/
~ >: mount
rootfs on / type rootfs (rw)
/dev/root on / type jffs2 (rw,relatime)
proc on /proc type proc (rw,relatime)
usbfs on /proc/bus/usb type usbfs (rw,relatime)
tmpfs on /dev type tmpfs (rw,relatime)
ramfs on /tmp type ramfs (rw,relatime)
sysfs on /sys type sysfs (rw,relatime)
devpts on /dev/pts type devpts (rw,relatime,mode=600)
/dev/mtdblock5 on /info type jffs2 (rw,relatime)
但是这样重启之后,挂载会恢复,要想开机自动挂载,就要配置/etc/fstab文件,控制上机文件系统自动挂载