一、UBI文件系统的概述
UBIFS是由诺基亚工程师在塞格德大学的帮助下开发的一种新的闪存文件系统。在某种程度上,UBIFS可以被认为是JFFS2文件系统的下一代。
UBI 意思是"Unsorted Block Images未排序的块镜像"。UBIFS是一个flash文件系统。UBIFS与Linux中的传统文件系统如Ext2,XFS,JFS等完全不同。UBIFS 表示一类单独的文件系统,它们与 MTD 设备(而不是块设备)一起使用。此类的另一个 Linux 文件系统是 JFFS2。
JFFS2 文件系统与UBIFS文件系统的区别在于:JFFS2在 MTD 设备之上工作,但 UBIFS 在 UBI 卷之上工作,不能在 MTD 设备上运行
二、UBIFS涉及三个子系统
解释 | |
MTD子系统 | MTD子系统用于屏蔽不同flash的操作差异,向上提供统一的操作接口,对应kernel的代码位于drivers/mtd。MTD在flash驱动之上,向上呈现统一的操作接口 |
UBI子系统 | UBI子系统基于MTD子系统之上,在MTD上实现nand特性的管理逻辑,向上屏蔽nand的特性;对应drivers/mtd/ubi |
UBIFS文件系统 | 基于UBI子系统的文件系统,实现文件系统的所有基本功能。例如文件的实现,日志的实现等;对应kernel的代码位于fs/ubifs |
三、UBIFS的功能列表
1、可扩展项。UBIFS相对于闪存大小具有良好的可扩展性。挂载时间,内存消耗和I / O速度不取决于闪存大小。UBIFS应该可以在数百GiB的flash上正常工作。UBI / UBIFS堆栈的扩展性比JFFS2好得多
2、快速安装。UBIFS几毫秒就能安装,安装不取决于闪存大小,但UBI初始化时间与闪存大小相关
3、写回支持。JFFS2是直写,UBIFS提高了许多工作负载中文件系统的吞吐量
4、容忍不干净的重启。UBIFS是一个日志文件系统,它容忍突然崩溃和不干净的重新启动。在遇到不干净的重启时,挂载时间稍慢,因为需要重放日志,但 UBIFS 不需要扫描整个介质,因此挂载 UBIFS 无论如何都需要几分之一秒的时间
5、快速I/O。在同步I/O中与JFFS2竞争是极其困难的,因为JFFS2不在闪存上维护索引数据结构,因此它没有维护开销,而UBIFS需要。但是UBIFS仍然很快,因为UBIFS提交日志的方式——不会将数据从一个地方物理移动到另一个地方,而是将相应的信息添加到文件系统索引中,并为新日志选择不同的擦除块,还有其他技巧,如多头日记,这些特性使得UBIFS I/O速度表现良好
6、动态压缩。数据以压缩形式存储在闪存介质上,这与JFFS2非常相似。UBIFS还允许在每个inode的基础上打开/关闭压缩,这非常灵活。
7、可恢复性。如果索引信息损坏,UBIFS 可能会被完全恢复。UBIFS中的每条信息都有一个描述该信息段的标头,并且可以通过扫描闪存介质完全重建文件系统索引,这与JFFS2非常相似。
8、完整性。UBIFS(以及UBI)会校验写入闪存的所有内容以保证数据完整性,UBIFS不会让数据或元数据损坏被忽视(同JFFS2)。默认情况下,UBIFS在从flash读取时仅检查元数据CRC,而不检查数据CRC,但是也可以使用其中一个 UBIFS 挂载选项强制 CRC 检查数据
四、UBI文件系统的制作
制作UBI文件系统时常用的命令有:
工具 | 作用 |
ubinfo | 提供ubi设备和卷的信息 |
ubiattach | 链接MTD设备到UBI并且创建相应的UBI设备 |
ubidetach | ubiattach相反的操作,将MTD设备从UBI设备上去链接 |
ubimkvol | 从UBI设备上创建UBI卷 |
ubirmvol | 从UBI设备上删除UBI卷 |
ubiblock | 管理UBI卷上的block |
ubiupdatevol | 更新卷,例如OTA直接更新某个分区镜像 |
ubicrc32 | 使用与ubi相同的基数计算文件的crc32 |
ubinize | 制作UBI镜像 |
ubiformat | 格式化空的Flash设备,擦除Flash,保存擦除计数,写入UBI镜像到Flash |
mtdinfo | 报告从系统中找到的UBI设备的信息 |
五、制作ubi镜像
制作ubi镜像时分两步:
1、创建一个UBIFS映像
2、创建UBI映像
下面我将在一个设备中手动创建一个卷并将其挂载:
在我的设备中,userdata分区包含了/cache和/data两个目录,挂载分区的脚本是/etc/init.d/find_partitions.sh,先将其中的/data和/cache的挂载注释掉,然后使用fastboot将此分区擦干净
本来设备里面的挂载情况:
修改之后的挂载情况:
/dev/ubi2_0就是我的userdata分区,被我擦除掉了。那么接下来我们要在原始的userdata的区域创建一个新的UBI文件系统,并将其挂载为/cache:
首先要知道userdata是mtd的第几个设备:
使用ubiformat将/dev/mtd15设备进行格式化,可以从下图中看到/dev/mtd15设备总共有311个擦除块,总共大小为38.9MiB,I/O size为2048 bytes
本来可以从/dev/下看到ubi设备只有一个,使用ubiattach命令链接mtd15,并创建相应的ubi设备,此处创建的新设备为/dev/ubi2设备
使用ubimkvol工具从ubi设备上创建UBI卷
同样,再将/data也挂载过来:
如此,就创建了一个新的UBIFS,并将其成功挂载了。
六、两个工具 mkfs.ubifs和ubinize
1、mkfs.ubifs工具。此工具用于创建 UBIFS 镜像。
2、ubinize工具。此工具用于根据UBIFS镜像创建UBI镜像。
UBI和UBIFS制作时,他们依赖于flash的各项参数,例如:
MTD分区大小,闪存物理擦除块的大小,最小flash 输入/输出单元大小,NAND flash的子页大小,逻辑擦除块大小等等
例如需要给一个256MiB NAND flash chip,128KiB物理擦除快(PEB),2048bytes NAND pagesize,flash允许对同一NAND页面执行4*512字节的写入的一个设备生成只有一个存储UBIFS文件系统的UBI卷:
$ mkfs.ubifs -q -r rootfs/ -m 2048 -e 126976 -c 2146 -o ubifs.img
$ ubinize -o ubi.img -m 2048 -p 128KiB -s 2048 $(TOOLS_DIR)/ubinize.cfg
在使用mkfs.ubifs命令时,后面跟的参数各自的含义为:
参数 | 作用 |
-q | 网上没搜到,也没在mkfs.ubifs -h里面看到,估计应该是quite的作用,加不加影响不大 |
-r rootfs/ | 创建的UBIFS镜像将具有与rootfs/目录下相同的内容 |
-m 2048 | 此 UBIFS 镜像的闪存的最小输入/输出单元大小为 2048 字节(在本例中为 NAND 页大小) |
-e 126976 | 此镜像的 UBI 卷的逻辑擦除块大小(逻辑块,LEB, Logical Erase Block),126976即124KiB,即62pages * 2 KiB/page |
-c 2146 | 逻辑擦除块中指定最大文件系统大小,生成的FS最大可达259MiB(2146 * 126976) |
-o ubifs.img | 最后生成的文件名为ubifs.img |
在使用ubinize命令时,后面跟的参数各自的含义为:
参数 | 作用 |
-o ubi.img | 最后生成的文件为ubi.img |
-m 2048 | 最小输入/输出单元大小,单位为byte |
-p 128KiB | 物理擦除快的大小(物理擦除块,PEB, Physical Erase Block),表示NAND中的一个块。至于物理擦除块为什么比逻辑擦除块要多2KiB,我想应该是oobsize(页外带的大小) |
-s 2048 | 用作UBI头部的最小输入/输出单元大小 |
$(TOOLS_DIR)/ubinize.cfg | 配置文件 |
其中,ubinize.cfg文件的内容为:
[ubifs]
mode=ubi
image=ubifs.img
vol_id=0
vol_size=200MiB
vol_type=dynamic
vol_name=rootfs
vol_flags=autoresize
这个文件告诉工具,要创建一个叫做ubifs.img的UBI镜像,该镜像具有一个ID为0,大小为200MiB,名为“rootfs”的动态卷,大小还是可自动调整的(vol_flags=autoresize)。
vol_flags=autoresize这个标记位意味着UBI首次运行时会尝试最大可能的大小。
此外,还可以在一个UBI镜像中包含两个UBIFS。例如: