UBIFS是Unsorted Block Image File System的简写,用于固态存储设备上,是JFFS2的后继文件系统之一。目前u-boot和Linux中都提供了很好的支持。
一. ubi的几个概念
在阅读ubi相关的文档时,需要区分几个不同的名称
ubi device(设备)
这是指绑定了某个MTD分区的ubi逻辑设备,一般简称ubi。
系统中使用ubi0表示第一个ubi设备,ubi1表示第二个设备。
ubi volume(卷)
这是指在ubi设备上创建的文件卷 (volume),每个ubi设备可以创建1个或多个卷。一个ubi卷的表示方法是ubi0:0或ubi0:volume。
ubifs(文件系统)
这是指在ubi卷上建立的文件系统。
二. ubi的Header
ubi在每个block中存放了2个Header结构,一个存放了物理擦写块(PEB)擦写计数的信息,称为Erase Counter Header(EC),另一个存放了卷标和这个物理擦写块(PEB)所属的逻辑擦写块(LEB)信息,称为Volume Identifier Header(VID)。
EC通常放在每个块最开始的位置上,也就是offset 0的位置,使用64字节,而VID存放在第二个I/O操作的单位上,也占据64字节。具体来说:
如果是NOR Flash且最小I/O单位是1 byte的话,则VID存放在Offset=64的位置上;
如果是NAND Flash且没有子页的话,VID存放在第2个页上,offset=2048 (假定一页是2048字节)。
如果是NAND Flash且支持子页的话,VID存放在第2个子页上,offset=512 (通常每个子页512字节)。
三. Linux中创建ubi镜像
如果在嵌入系统中使用ubifs作为根文件系统,通常在Linux中创建ubi的镜像文件,然后在uboot中使用ubi命令将镜像文件写入NAND。
Linux中创建ubi镜像文件的命令是
mkfs.ubifs -r <源目录> -o <目标文件> -m <页大小> -e <LEB大小> -c <LEB个数>
源目录是已经准备好的根文件系统所在的目录;
目标文件是需要生成的镜像文件名称;
页的大小是NAND芯片Page的大小;
LEB大小是逻辑块的大小,等于物理块的大小减去存放Header信息页的大小。
LEB个数等于NAND分区中物理块的个数。
举例来说,
假定NAND芯片每个Page 2048字节,每个Block 128Kb,支持子页,NAND分区176M(1408 Block),则Head信息占据1个Page,LEB的大小 = 128K – 2048 = 129024,镜像生成命令是
mkfs.ubifs –r ./rootfs –o rootfs.img –m 2048 –e 129024 –c 1408
同样参数,但不支持子页,则Head信息需要占用2个Page,LEB的大小 = 128K – 4096 = 126976,镜像生成命令是
mkfs.ubifs –r ./rootfs –o rootfs.img –m 2048 –e 126976 –c 1408
上面涉及到的一些重要参数,可在Linux或uboot中通过挂载MTD分区获得
uboot使用ubi命令
ubi part <MTD分区>
显示内容:
Creating 1 MTD partitions on "nand0":
0x000005000000-0x000010000000 : "mtd=6"
ubi0: attaching mtd1
ubi0: scanning is finished
ubi0: empty MTD device detected
ubi0: attached mtd1 (name "mtd=6", size 176 MiB)
ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 129024 bytes
ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size 512
ubi0: VID header offset: 512 (aligned 512), data offset: 2048
ubi0: good PEBs: 1407, bad PEBs: 1, corrupted PEBs: 0
ubi0: user volume: 0, internal volumes: 1, max. volumes count: 128
ubi0: max/mean erase counter: 1/0, WL threshold: 4096, image sequence number: 0
ubi0: available PEBs: 1364, total reserved PEBs: 43, PEBs reserved for bad PEB handling: 39
Linux中使用
ubiattach /dev/ubi_ctrl -m 6
ubi1: attaching mtd6
ubi1: scanning is finished
ubi1: empty MTD device detected
ubi1: attached mtd6 (name "NAND.User-space", size 176 MiB)
ubi1: PEB size: 131072 bytes (128 KiB), LEB size: 129024 bytes
ubi1: min./max. I/O unit sizes: 2048/2048, sub-page size 512
ubi1: VID header offset: 512 (aligned 512), data offset: 2048
ubi1: good PEBs: 1407, bad PEBs: 1, corrupted PEBs: 0
ubi1: user volume: 0, internal volumes: 1, max. volumes count: 128
ubi1: max/mean erase counter: 0/0, WL threshold: 4096, image sequence number: 3078332594
ubi1: available PEBs: 1364, total reserved PEBs: 43, PEBs reserved for bad PEB handling: 39
ubi1: background thread "ubi_bgt1d" started, PID 77
可以看到显示的内容与u-boot中基本一样。
其中
PEB size: 物理擦写块的大小,物理上块的字节数
LEB size: 逻辑擦写块的大小,物理擦写块的大小 减去 两个 Header 后剩余的大小
I/O unit sizes: 输入输出大小,也就是一个Page的大小
sub-page size: 说明能够支持sub-page的访问
VID header offset: VID (Volume IDentifier) 的偏移位置
data offset: 块中开始存放数据的偏移位置
四. uboot中写入镜像
在上一节Linux中生成的ubifs.img文件,可以在uboot中通过ubi命令写入NAND分区
首先将ubifs.img文件读入内存,假定存放的位置是0x82000000,长度2E000。
然后绑定MTD分区NAND.rootfs
ubi part NAND.rootfs
在ubi的分区上创建文件卷rootfs
ubi create rootfs -
后面使用”-“表示将创建的卷使用整个ubi的分区。如果想在这个ubi分区上建立两个或两个以上的文件卷,需要指定size大小。
最后将已载入内存的镜像文件写入ubi的卷中
ubi write 0x82000000 rootfs 2e000
五. 设置Linux启动命令
将Linux的启动参数设置为
bootargs = "console=ttyO0,115200n8 root=ubi0:rootfs ubi.mtd=5 rootfstype=ubifs rw";
关于上面与ubi有关的参数中,
root=ubi0:rootfs
表示根文件系统是ubi0设备的rootfs卷中,这个rootfs的名称与上一节使用ubi create命令创建ubi文件卷时设置的名称相对应。
ubi.mtd=5
表示ubi0设备使用的是MTD分区中第5个设备,也就是在上一节ubi part命令绑定分区时所对应的分区。
有些文档的这个参数写为
ubi.mtd=5,2048
这是在不支持subpage的ubi中,VID偏移位置在2048(第2个page处)。如果不写则表示缺省偏移位置在512(第2个subpage处)。
rootfstype=ubifs
这是指定根文件系统的类型是ubifs
六. u-boot中ubi的命令
ubi detach
detach ubi from a mtd partition
将ubi从MTD分区上分离。
ubi part [part] [offset]
显示当前ubi绑定的mtd分区,或设置ubi需要绑定的MTD分区。在设置分区时,可以同时指定VID头的偏移位置。
ubi info [l[ayout]]
显示当前卷的信息,以及ubi中卷的布局信息
ubi check <volumename>
检查volumename名称的卷是否存在
ubi create[vol] <volume> [size] [type] [id]
create volume name with size ('-' for maximum available size)
创建一个名称为volume的卷,这个卷的大小为size,如果使用“-”则使用最大可能的大小。
ubi write[vol] <address> <volume> <size>
Write volume from address with size
将内存地址address开始的size字节写入名称为volume的卷中
ubi read[vol] <address> <volume> [size]
Read volume to address with size
将volume卷中的内容,读取到内存address开始处,长度是size。如果不指定size则读取整个volume的内容
ubi remove[vol] <volume>
Remove volume
移除volume卷
ubifsmount <volume-name>
mount UBIFS volume
加载ubi create创建的文件卷。卷名的形式有
- ubiX_Y - 加载 ubi设备号X 卷号Y 的文件卷;
- ubiY - 加载 ubi设备号0 卷号Y 的文件卷;
- ubiX:NAME - 加载 ubi设备号X 卷名NAME 的文件卷;
- ubi:NAME - 加载 ubi设备号0 卷名NAME 的文件卷
ubifsload <addr> <filename> [bytes]
load file from an UBIFS filesystem
从加载的ubifs卷中读取filename文件,写入addr开始的内存地址,如果不指定bytes,则读取整个文件,否则读取bytes字节数。
ubifsls [directory]
list files in a directory
显示ubifs卷中的文件,如果不指定directory,则显示根目录下的文件,否则显示指定目录的文件
ubifsumount
unmount UBIFS volume
卸载当前的ubifs卷