UBIFS文件系统概述及制作步骤

版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/wteruiycbqqvwt/article/details/90610718

什么是UBIFS文件系统

UBIFS是UBI file system的简称,用于裸的flash设备,作为jffs2的后继文件系统之一。UBIFS通过UBI子系统处理与MTD设备之间动作。UBIFS文件系统更适合MLCNAND FLASH。需要注意的是UBIFS并不是为SSD,MMC,SD,Compact Flash等之类的基于flash的存储设备,其是针对于裸flash设备。

裸flash有以下特点:

①其包含的块被称为可擦除块,而对于SSD这类的设备,并无可擦除块的概念,取而代之的是扇区的概念。

②包括读、写、擦除可擦除块三种操作。

③ 硬件并不管理坏的可擦除块,而SSD之类的设备则具有专门的控制器处理坏块。

④ 可擦除块的读写寿命从几千到几十万之间不等。

图0.1中给出的设备是MMC、SD类型的,该设备具有flash转换层的硬件控制器,该硬件控制器的损耗平衡算法属于商业秘密,华为的dorado 系列高端存储器的文档对其损耗平衡(动态和静态)原理讲解的非常透彻,感兴趣的可以自己找找。对于UBIFS使用的场景,通常只有NANDFLASH那一个模块,其和控制器的接口通常是专门的NAND flash接口。由于这类设备的速率比较慢,所以通常用在相对而言比较低端的嵌入式设备,追求加载速度快一点嵌入式设备通常会选择使用emmc存储器,其文件系统通常会选择UFS。

       

MTD(Memory Technology Devices)对闪存存储器提供了一个抽象,隐藏了特定flash的独特之处,提供统一的API存取各种类型的flash。

MTD在内核层的API是struct mtd_device而用户空间的API接口是/dev/mtd0,这些接口提供了设备信息,读写可擦除块,擦除一个可擦除块,标记一个可擦除块是坏块,检查可擦除块是否是坏块。MTD的API并不隐藏坏的可擦除块也不做任何损耗平衡。

UBI(Unsorted Block Images)的内核API是include/mtd/ubi-user.h,用户空间的则是/dev/ubi0,提供损耗平衡,隐藏坏块,允许运行时容量创建、删除和修改,有点类似LVM功能。UBI线性扩展,在初始化时会读取所有的可擦除块头,所以当flash容量越大,初始化所花费的时间越多,但是就可扩展性而言比JFFS2要好很多。

LEB(logic eraseblock),PEB(physical erase block);将LEB映射到PEB,任何一个LEB可能映射到任何一个PEB,可擦除块头存储的是映射信息以及擦除计数值。

ubifs的制作

1️⃣、配置内核,使其支持ubifs文件系统

1)Device Drivers  --->Memory Technology Device (MTD) support  --->UBI - Unsorted block images  --->Enable UBI     

2)File systems  --->Miscellaneous filesystems  --->UBIFS file system support

2️⃣、制作ubifs格式的根文件系统镜像

先说明一下,板子上既有NorFlash,又有NandFlash,其中根文件系统和应用程序放在NandFlash上,uboot和kernel放在NorFlash上,而根文件系统所在的mtd设备为mtd2,分区大小为34MiB

uboot kernel rootfs=34MiB app

3️⃣、./mkfs.ubifs -v -r ./rootfs -o rootfs.img -m 2048 -e 129024 -c 272

   -r:制定文件内容的位置      -m:页面大小      -e:逻辑擦除块大小      -c:最大的逻辑擦除块数量

mkfs.ubifs -m 2048 -e 129024 -c 1984 -o rootfs.ubifs -x none

-m 2048   (Minimum input/output unit size: 2048 bytes)
-e 129024 (Default UBI LEB size:           129024 bytes, 126.0 KiB)
-c 1984   (Amount of eraseblocks:          1984 (260046848 bytes, 248.0 MiB))
-o rootfs.ubifs (output file)
-x none   (no compression)

mkfs.ubifs生成的image可以用来在linux kernnel里面更新ubi volume。
其使用方法如下:
mkfs.ubifs -r root-tree -F -m 4096 -e 258048 -c 362 -o ti.ubifs
-r   后面跟文件系统的tree
-F --space-fixup, 如果要基于ti.ubifs来制作使用u-boot来烧写的ubi.img,这个flag一定要选啊
-m   min i/o size
-e   logical 擦除块的大小
-c   逻辑擦除块的数目
-o   目标生成文件

下面是使用ti.ubifs更新ubi vlomue的例子:
flash_eraseall /dev/mt7
ubiattach /dev/ubi_ctrl -m 7
ubimkvol /dev/ubi0 -N rootfs -s 85MiB
ubiupdatevol /dev/ubi0_0 ti.ubifs

mount /dev/ubi0_0 /mnt/ubi0
就可以看到ubifs的内容了

4️⃣、./ubinize -v -o rootfs.ubi -m 2048 -p 128KiB -s 2048 hi.cfg

     -p:物理擦除块大小 ; -m:页面大小;-s: 最小的硬件输入输出页面大小,如:k9f1208为256(上下半页访问)

ubinize用来制作u-boot下烧写用的ubifs的image。
其使用方法如下:
ubinize -o ubi.img -m 4096 -p 256KiB -s 1024 ubinize.cfg
-o 后跟目标image文件名,这个ubi.img可以在u-boot里面进行烧写
-m minimum io size
-p 物理擦除块的大小
-s subpage的大小
ubinize.cfg 是生成ubi.img的配置文件,内容如下。
#cat ubinize.cfg
[ubifs]
mode=ubi
image=ti.ubifs
vol_id=0
vol_size=80MiB
vol_type=dynamic
vol_name=rootfs
vol_flags=autoresize
其中
"image=ti.ubifs"指明使用上文所述的ti.ubifs作为输入。
"vol_name=rootfs"指明volume的name.
"vol_size=80MiB"指明fs的总大小。

下面是u-boot烧写ubi.img的方法
当前是写48MB, 需要根据实际调整.
U-Boot# mw.b 0x82000000 0xFF 0x3000000 
U-Boot# tftp 0x82000000  ubi.img
U-Boot# nand erase 0x1000000  0x7000000 /* 将整个mtd都擦掉了  */
U-Boot# nand write 0x82000000 0x1000000 0x3000000 

在kernel里面也可以将ubi.img烧写到mtd分区里。
#ubiformat /dev/mtd7 -f ubi.img -s 4096 

5️⃣、配置文件ubi.cfg如下:

[ubifs] mode=ubi image=rootfs.img vol_id=0 vol_size=34MiB vol_type=dynamic vol_alignment=1 vol_name=rootfs vol_flag=autoresize

 6️⃣、然后修改uboot的环境变量:

setenv bootargs 'mem=288M console=ttyAMA0,115200 root=ubi0:rootfs rw rootflags=sync rootfstype=ubifs ubi.mtd=2 mtdparts=hi_sfc:5M(boot),1M(picture);hinand:34M(rootfs),8M(config),86M(app)';

root@localhost:/mnt# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00040000 00040000 "NAND.dt"
mtd1: 00040000 00040000 "NAND.dt.backup"
mtd2: 00080000 00040000 "NAND.hardinfo"
mtd3: 000c0000 00040000 "NAND.u-boot"
mtd4: 00040000 00040000 "NAND.u-boot-env"
mtd5: 00800000 00040000 "NAND.userdata"
mtd6: 00600000 00040000 "NAND.kernel"
mtd7: 07000000 00040000 "NAND.file-system"
mtd8: 08000000 00040000 "NAND.hmidata"
mtd9: 10000000 00040000 "NAND.prjdata"

需要在bootargs中指出使用的内核ubiattach使用哪一个mtd
如:ubi.mtd=NAND.file-system,1024  其中“NAND.file-system”是mtd7的名字, “1024”是vid header的偏移。
也可以不用mtd的名字,而是使用mtd的编号,如:ubi.mtd=7,1024  其中7是mtd的编号
或者不指定header的偏移,如:ubi.mtd=7

需要在bootargs中指出使用的内核使用的ubi volume name,如root=ubi0:rootfs, 这个rootfs是在ubinize.cfg中指明的。ubimkvol中也会指明volume的name。也可以写成root=ubi0_0
例1:
"setenv bootargs console=ttyS0,115200n8 root=ubi0:rootfs rw ubi.mtd=NAND.file-system,1024 rootfstype=ubifs rootwait=1;tftp 0x82000000 zImage; tftp 0x88000000 snd.dtb; bootz 0x82000000 - 0x88000000"
例2:
"setenv bootargs console=ttyS0,115200n8 root=ubi0:rootfs rw ubi.mtd=7,1024 rootfstype=ubifs rootwait=1;tftp 0x82000000 zImage; tftp 0x88000000 snd.dtb; bootz 0x82000000 - 0x88000000"
例3:
"setenv bootargs console=ttyS0,115200n8 root=ubi0:rootfs rw ubi.mtd=7 rootfstype=ubifs rootwait=1;tftp 0x82000000 zImage; tftp 0x88000000 snd.dtb; bootz 0x82000000 - 0x88000000"

7️⃣、保存环境变量,执行如下命令

setenv ipaddr 192.168.253.132;

setenv serverip 192.168.253.130;

setenv ethaddr 40:61:86:67:33:47;

mw.b 82000000 ff 2200000;

tftp 82000000 rootfs.ubi;

nand erase 0 2200000;

nand write 82000000 0 $(filesize);

sf probe 0;

sf read 0x82000000 0x100000 0x400000;

bootm 0x82000000

说明:

其实从上面的烧写命令可以看出,ubifs格式的镜像中是不包含oob信息的。 

参见:http://www.cnblogs.com/pengdonglin137/p/3399071.html

8️⃣、问题分析

出现如下错误信息:

UBI: attaching mtd2 to ubi0 UBI: physical eraseblock size: 131072 bytes (128 KiB) UBI: logical eraseblock size: 126976 bytes UBI: smallest flash I/O unit: 2048 UBI: VID header offset: 2048 (aligned 2048) UBI: data offset: 4096 UBI: max. sequence number: 0 UBI error: vtbl_check: volume table check failed: record 0, error 9 UBI error: ubi_init: cannot attach mtd2Fixed MDIO Bus: probed

原因:参考     http://wiki.linpert.de/index.php?title=UBIFS#record_0.2C_error_9  

             http://lists.infradead.org/pipermail/linux-mtd/2009-April/025127.html

原因就是:在配置文件中,volume设为34MiB,太大了,因为整个mtd2分区总共才34MiB。

解决办法:将配置文件改为:

[ubifs] mode=ubi image=rootfs.img vol_id=0 vol_size=32MiB vol_type=dynamic vol_alignment=1 vol_name=rootfs vol_flag=autoresize

说明:vol_id  表示volume的编号,一个ubi设备中可以有多个volume。(这种情况下,/dev下会出现 ubi0 和 ubi0_0)

vol_size 表示ubi0_0的大小,即volume0的大小;vol_type 表示volume0的类型,分为dynamic和static两种,其中dynamic类型的设备表示可以读写,static类型的设备表示只读;vol_name 表示volume0的名称,在挂载ubi分区是会使用到,如在bootargs中的root=ubi0:rootfs

然后重新执行:   ./ubinize -v -o rootfs.ubi -m 2048 -p 128KiB -s 2048 hi.cfg

当再次重启后,又出现如下错误信息:

UBIFS: parse sync UBIFS error (pid 1): validate_sb: LEB size mismatch: 129024 in superblock, 126976 real UBIFS error (pid 1): validate_sb: bad superblock, error 1

原因:

参考:http://www.linux-mtd.infradead.org/faq/ubifs.html#L_lebsz_mismatch

原因是:逻辑块的大小与实际的大小不符

解决办法:

将-e选项的值由129024改成126976

重新执行:

 ./mkfs.ubifs -v -r ./rootfs -o rootfs.img -m 2048 -e 126976 -c 272

 ./ubinize -v -o rootfs.ubi -m 2048 -p 128KiB -s 2048 hi.cfg

重新烧写并重启。

还有一个需要注意的问题是,如果将-s选项的值搞错,如将2048写成了512,那么会有如下错误信息

UBI error: validate_ec_hdr: bad VID header offset 512, expected 2048 UBI error: validate_ec_hdr: bad EC header UBI error: ubi_io_read_ec_hdr: validation failed for PEB 0 UBI error: ubi_init: cannot attach mtd2 Fixed MDIO Bus: probed

从错误提示中就可以看到解决方法:将-s选项的值改为2048即可

参考:http://www.cnblogs.com/pengdonglin137/p/3404685.html

也就是说,对于上面的例子,如果有subpage(可以到/sys/class/mtd/其中的一个目录下使用cat命令去查看某个mtd设备的subpagesize参数),如果是512B,这有如下参数搭配(对于块大小是128KiB,页大小是2KB的NandFlash来说):

 ./mkfs.ubifs -v -r ./rootfs -o rootfs.img -m 2048 -e 129024 -c 272 

 ./ubinize -v -o rootfs.ubi -m 2048 -p 128KiB -s 512 hi.cfg

 其中 -e表示的是逻辑块的大小,因为subpagesize大小是512(也就是-s选项的值),第一页的前512存放EC(实际用了前64B),接下来的512B(前64B)存放UBI headers,逻辑块的大小就是128KiB-2KiB=126KiB,转化成十进制就是129024。

 假如没有subpagesize,那么有如下搭配:

 ./mkfs.ubifs -v -r ./rootfs -o rootfs.img -m 2048 -e 126976 -c 272 

 ./ubinize -v -o rootfs.ubi -m 2048 -p 128KiB -s 2048 hi.cfg

 其中,逻辑块的大小:128KiB-2KiB-2KiB=124KiB,转换成10进制就是126976,-s后面的值为页大小,即2048B。

猜你喜欢

转载自blog.csdn.net/wteruiycbqqvwt/article/details/90610718