UBI文件系统-----UBI文件系统概念、UBI文件系统开销、UBI文件系统使用方法

参考资料:

衷心感谢网友的分享:

UBI系统原理分析
http://blog.chinaunix.net/uid-28236237-id-4164656.html

Ubifs文件系统和mkfs.ubifs以及ubinize工具的用法
https://blog.csdn.net/wjjontheway/article/details/8977871

Linux ubi子系统原理分析
https://www.cnblogs.com/gmpy/p/10874475.html

 

一、UBI文件系统的概念:

1、UBI文件系统:无排序区块镜像文件系统(Unsorted Block Image File System, UBIFS)是用于固态存储设备上,并与LogFS相互竞争,作为JFFS2的后继文件系统之一。

2、UBIFS涉及三个子系统

1)MTD子系统:flash驱动直接操作设备,而MTD在flash驱动之上,向上呈现统一的操作接口。所以MTD子系统的使命是:屏蔽不同flash的操作差异,向上提供统一的操作接口;对应drivers/mtd;

2)UBI子系统:UBI子系统是基于MTD子系统的,在MTD上实现nand特性的管理逻辑,向上屏蔽nand的特性;对应drivers/mtd/ubi;

3)UBIFS文件系统:是基于UBI子系统的文件系统,实现文件系统的所有基本功能。例如文件的实现,日志的实现;对应fs/ubifs;

4)ubi文件系统的结构:

UBI文件系统-----UBI文件系统概念、UBI文件系统开销、UBI文件系统使用方法_第1张图片


 

3、nand flash的特性:

1)操作最小单元为页(Page)/块(Block):nand flash不同于nor flash,nor可以以字节为单位操作flash,但是nand的最小读写单元是页,擦除最小单元是块。

2)擦除寿命限制:nand flash的物理性质决定了其每个块都有擦除寿命的限制,因此驱动必须做到磨损平衡。

3)位翻转(bit-filps):nand物理性质使其可能会在使用、保存过程中出现位翻转现象。所以要不在nand flash的内部,要不在nand flash控制器都会存在ecc校正模块,在位翻转后校正。然而ecc并不是万能的,其校正能力有限,所以驱动必须在位翻转数量进一步变多之前把数据搬移到其它快。ecc都已经校正了,为什么还要搬移?因为ecc校正是从flash读到内存中的数据,而不是flash本身存储的数据,此时flash中的数据依然是错的,如果不搬移,随着翻转的位数量积累,ecc就校验不了,此时就相当于永久丢失正确数据。

4)存在坏块(Bad Block)
制作工艺和nand本身的物理性质导致在出厂和正常使用过程中都会产生坏块。


4、UBI与Block Layer
Block Layer是适用于常见块设备的通用块层,其本质上来讲并不是块设备。UBIFS的IO操作并不通过通用块设备。

5、UBI与FTL
FTL(Flash Translation Layer)是一个"黑盒子",其跟UBI非常像,都是对nand特性进行封装。
UBI子系统屏蔽nand特性是为了对接UBIFS,而FTL则是为了对接Block Layer。

6、UBI Volume 与 UBI Device
在UBI中有两个概念:UBI卷与UBI设备
UBI设备相当于磁盘设备(sda、mmcblk0);
UBI卷相当于磁盘上对应分区(sda1,mmcblk0p1);
UBI设备是在MTD设备上创建出来的设备,而UBI卷则是从UBI设备上划分出来的分区;

7、LEB与PEB
LEB:Logical Erase Block,即逻辑擦除块,简称逻辑块,表示逻辑卷中的一个块;
PEB:Physical Erase Block,即物理擦除块,简称物理块,表示nand中的一个块;

8、UBI子系统的作用:
UBI子系统就是UBIFS与MTD子系统的中间层,其向下连接MTD设备,实现nand特性管理,向上呈现无坏块的卷;
所以UBI子系统的作用主要包括两点:
1)屏蔽nand特性(坏块管理、磨损平衡、位翻转);
2)UBI卷实现;

9、UBI头部:
UBI子系统需要往每个物理块开头写入两个关键数据,这两个关键数据组成了UBI头部;
这两个关键数据分别是此物理块擦除次数和次物理块的逻辑卷标记头,也分别称为EC头(Erase Count)和VID头(Volume IDentifier)。
EC头和VID头,都是64Bytes,分别记录于物理块的第一页和第二页;

1)为什么要有两个头:
nand每个block都有擦除寿命限制,因此需要记录擦除次数,以实现磨损平衡,因此需要EC头;为了实现卷,必须记录物理块与逻辑块之间的映射关系,因此需要VID头;

2)为什么不合并成一个头?
两者写入时机不同,导致两个头必须分开写入。EC头在每次擦除后,必须马上写入以避免丢失,而VID头只有在卷映射后才会写入。

3)不管是EC头还是VID头都是64Bytes,为什么要用俩个Page?
使用两个Page是对nand来说的,因为nand的最小读写单元是Page;对于NOR FLASH,最小读写单元使Byte,因此对于Nor可以只使用64Bytes.

4)在记录擦除次数时掉电等,导致丢失实际擦除次数怎么办?
取所有物理块擦除次数的平均数;

10、UBI卷表(UBI Volume Table):
UBI子系统有个对用户隐藏的特殊卷,叫层卷(layout volume),用来记录卷表。我们可以把卷表等价于分区表,记录各个卷的信息。
卷表大小为两个逻辑擦除块,每个逻辑擦除块记录一份卷表。即UBI子系统为了保证卷表的可靠性,用了两个逻辑卷记录两份卷表信息;
由于层卷的大小是固定的,导致能保存的卷信息受限,所以最大支持的卷数量是随着逻辑块的大小改变的。但最多不超过128个;
保存卷表的结构体:
struct ubi_vtbl_record {                                                         
        __be32  reserved_pebs; //物理块数量
        __be32  alignment; //卷对齐
        __be32  data_pad;                                                        
        __u8    vol_type; //静态卷or动态卷标识
        __u8    upd_marker; //更新标识
        __be16  name_len; //卷名长度
        __u8    name[UBI_VOL_NAME_MAX+1]; //卷名
        __u8    flags; //常用语自动重分配大小标记
        __u8    padding[23]; //保留区域
        __be32  crc; //卷信息的CRC32校验值
} __packed;

卷信息是被CRC232保护的。

11、动态卷和静态卷

1)vol_type记录了卷的类型,在创建卷时指定,可选动态卷和静态卷。

2)动态卷:是可读可写的,数据的完整性由文件系统保证;

3)静态卷:静态卷是只读的,是UBI子系统试用CRC232来校验保护整个卷的数据;

12、flags是否自动分配大小标识
在首次运行时自动resize卷,让卷大小覆盖所有未使用的逻辑块。
例如Flash大小是128M,在烧录的镜像中分配的所有卷加起来只用了100M,如果有卷被表示为autoresize,那么在首次运行时,那个卷会自动扩大,把剩余的28M囊括在内。
注意:只允许一个卷设置autoresize标志;

13、坏块标记:

1)有两个场景可能会识别坏块,分别是在写失败和擦除失败,擦除失败且返回EIO,则直接标记坏块。

2)写失败坏块判断逻辑:

a. 擦除嫌疑坏块

b. 读取擦除后的值,判断是否都是0xFF(擦除后理应全为0xFF)

c. 写入特定数据

d. 读取并校验写入的数据

e. 以不同的数据模式重复步骤1-4

以上步骤如果出问题则标记坏块,详细实现参考torture_peb()。

 

二、UBI管理开销

什么是管理开销?为了管理nand的空间,实现磨损平衡、坏块管理等功能,必须占用一部分空间来存储关键数据,就好像文件系统的元数据。管理占用的空间是不会呈现给用户使用的,这个空间即为管理开销;

对nand来说,UBI管理开销主要包括5部分:

1)层卷(卷表),占用两个物理块;

2)磨损平衡,占用一个物理块;

3)逻辑块修改原子操作,占用一个物理块;

4)坏块管理,默认每1024个块预留20个块作为坏块处理(内核参数:CONFIG_MTD_UBI_BEB_LIMIT)。

5)UBI头:物理块总数*2页;

UBI管理开销计算:
UBI管理开销 = UBI特性开销 + UBI头开销
其中:
坏块预留 = MAX(出厂坏块数量,坏块管理预留数量)
特性开销 = (坏块预留 + 1磨损平衡开销 + 2卷表开销 + 1原子操作开销)* 物理块大小(物理块字节数,假设一个物理块是128KB)
UBI头开销 = 2 * 页大小 * (含坏块的总块数 - 坏块预留 - 1个磨损平衡开销 - 1个原子操作开销 - 2个层卷开销)
UBI管理总开销 = (坏块预留 + 4)* 物理块大小 + 2 * 页大小 * (含坏块的总块数 - 坏块预留 - 4)

例子:
总大小:128M(1Gbit)
页大小:2K bytes
块大小:128K
块数量:1024
假设是完全无坏块的片子,其管理开销为:

UBI管理开销 = (20 + 4) * 128K + 2 * 2K * (1024 - 20 - 4) = 7072K ≈ 7M


三、UBI文件系统的使用

1、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设备的信息

2、制作ubi镜像文件范例
1)mkfs.ubifs的用法 
Usage: mkfs.ubifs [OPTIONS] target 
Make a UBIFS file system image from an existing directory tree 
Examples: 
Build file system from directory /opt/img, writting the result in the ubifs.img file 
        mkfs.ubifs -m 512 -e 128KiB -c 100 -r /opt/img ubifs.img 
The same, but writting directly to an UBI volume 
        mkfs.ubifs -r /opt/img /dev/ubi0_0 
Creating an empty UBIFS filesystem on an UBI volume 
        mkfs.ubifs /dev/ubi0_0 
Options: 
-r, -d, --root=DIR               build file system from directory DIR 
-m, --min-io-size=SIZE       minimum I/O unit size,最小输入输出大小 
-e, --leb-size=SIZE        logical erase block size逻辑可擦出块大小 
-c, --max-leb-cnt=COUNT    maximum logical erase block count最大逻辑可擦出块数目 
-o, --output=FILE        output to FILE输出文件名 
-j, --jrn-size=SIZE      journal size 
-R, --reserved=SIZE      how much space should be reserved for the super-user 
-x, --compr=TYPE        compression type - "lzo", "favor_lzo", "zlib" or 
                                  "none" (default: "lzo") 
-X, --favor-percent       may only be used with favor LZO compression and defines 
                                how many percent better zlib should compress to make 
                                mkfs.ubifs use zlib instead of LZO (default 20%) 
-f, --fanout=NUM         fanout NUM (default: 8) 
-F, --space-fixup         file-system free space has to be fixed up on first moun
                          (requires kernel version 3.0 or greater) 
-k, --keyhash=TYPE       key hash type - "r5" or "test" (default: "r5") 
-p, --orph-lebs=COUNT     count of erase blocks for orphans (default: 1) 
-D, --devtable=FILE       use device table FILE 
-U, --squash-uids         squash owners making all files owned by root 
-l, --log-lebs=COUNT     count of erase blocks for the log (used only for debugging) 
-v, --verbose             verbose operation 
-V, --version             display version information 
-g, --debug=LEVEL         display debug information (0 - none, 1 - statistics, 2 - files, 3 - more details) 
-h, --help               display this help text 
例: 
mkfs.ubifs -x lzo -m 2KiB -e 124KiB -c 720 -o system_ubifs.img -d $path_to_system 
-x压缩格式为lzo 
-m最小输入输出大小为2KiB(2048bytes),一般为页大小 
-e逻辑可擦除块大小为124KiB=(每块的页数-2)*页大小=(64-2)*2KiB=124KiB 
-c最多逻辑可擦除块数目为720(720*128KiB=90MiB),这个可根据ubi volume来设置,实际上是设置此卷的最大容量。 
通过此命令制作的出的UBIFS文件系统镜像可在u-boot下使用ubi write命令烧写到NAND FLASH上。
========================================================================================

2)ubinize的用法
Usage: ubinize [-o filename] [-p ] [-m ] [-s ] [-O ] [-e 
][-x  ]  [-Q  ]  [-v]  [-h]  [-V]  [--output=
[--peb-size=]  [--min-io-size=]  [--sub-page-size=
[--vid-hdr-offset=]  [--erase-counter=]  [--ubi-ver=
[--image-seq=] [--verbose] [--help] [--version] ini-file 
Example: ubinize -o ubi.img -p 16KiB -m 512 -s 256 cfg.ini - create UBI image 
         'ubi.img' as described by configuration file 'cfg.ini' 
-o, --output=     output file name 
-p, --peb-size=       size of the physical eraseblock of the flash 
                             this UBI image is created for in bytes, 
                              kilobytes (KiB), or megabytes (MiB) 
                              (mandatory parameter)物理可擦出块大小 
-m, --min-io-size=    minimum input/output unit size of the flash 
                             in bytes 
-s, --sub-page-size=  minimum input/output unit used for UBI 
                             headers, e.g. sub-page size in case of NAND 
                             flash (equivalent to the minimum input/output 
                             unit size by default)子页大小 
-O, --vid-hdr-offset=   offset if the VID header from start of the 
                              physical eraseblock (default is the next 
                             minimum I/O unit or sub-page after the EC 
                             header)VID头部偏移量,默认是512 
-e, --erase-counter=    the erase counter value to put to EC headers (default is 0) 
-x, --ubi-ver=           UBI version number to put to EC headers  (default is 1) 
-Q, --image-seq=        32-bit UBI image sequence number to use 
                             (by default a random number is picked) 
-v, --verbose                be verbose 
-h, --help                   print help message 
-V, --version                print program version 
例: 
ubinize –o ubi.img -m 2KiB -p 128KiB -s 2048 $system_cfg_file –v 
-m最小输入输出大小为2KiB(2048bytes),一般为页大小 
-p物理可擦出块大小为128KiB=每块的页数*页大小=64*2KiB=128KiB 
-s用于UBI头部信息的最小输入输出单元,一般与最小输入输出单元(-m参数)大小一样。 
此命令生成的ubi.img可直接使用NAND FLASH的烧写命令烧写到FLASH上(带有UBI文件系统镜像卷标)。

3)ubinize需要指定一个配置文件$system_cfg_file,内容如下: 
[rootfs-volume]  
mode=ubi  
image=system_ubifs.img  
vol_id=0  
vol_size=90MiB  
vol_type=dynamic 
vol_name=system 
======================================================================
配置文件说明 
INI-file format. 
The input configuration ini-file describes all the volumes which have to 
be included to the output UBI image. Each volume is described in its own 
section which may be named arbitrarily. The section consists on 
"key=value" pairs, for example: 
 
[jffs2-volume] 
mode=ubi 
image=../jffs2.img         mkfs.ubi生成的源镜像 
vol_id=1                   卷序号 
vol_size=30MiB             卷大小 
vol_type=dynamic           动态卷 
vol_name=jffs2_volume      卷名 
vol_flags=autoresize      
vol_alignment=1 

This example configuration file tells the utility to create an UBI image with one volume with ID 1, volume size 30MiB, the volume is dynamic, has name "jffs2_volume", "autoresize" volume flag, and alignment 1. The "image=../jffs2.img" line tells the utility to take the contents of the volume from the "../jffs2.img" file. The size of the image file has to be less or equivalent to the volume size (30MiB). The "mode=ubi" line is mandatory and just tells that the section describes an UBI volume - other section modes may be added in the future. 
Notes: 
  * size in vol_size might be specified kilobytes (KiB), megabytes (MiB),  gigabytes (GiB) or bytes (no modifier); 
  * if "vol_size" key is absent, the volume size is assumed to be equivalent to the size of the image file (defined by "image" key); 
  * if the "image" is absent, the volume is assumed to be empty; 
  * volume alignment must not be greater than the logical eraseblock size; 
  * one ini file may contain arbitrary number of sections, the utility will put all the volumes which are described by these section to the           output UBI image file. 


3、写入镜像
将ubi.img镜像写入到nand flash上

1)使用open(),write()等系统调用函数将镜像写入到/dev/xxx_ubi卷上;

2)或者使用ubiupdatevol更新卷,更新镜像中的卷;
例如,把/dev/ubi1_x的内容同步到/dev/ubi0_x
dd if=/dev/ubi1_x of=xxx.ubi
ubiupdatevol /dev/ubi0_x  xxx.ubi

3)手动写入:按照设备启动过程中加载ubi卷这一节中的1)~ 4)步骤操作;

4、设备启动过程中加载ubi卷

1)格式化mtd设备然后写入镜像(如果是手动写入ubi卷需要加这一步操作):
擦除:flash_eraseall /dev/mtd2或ubiformat /dev/mtd2
写入:nandwrite  -p /dev/mtd2 xxx.ubi

2)链接MTD设备到UBI并且创建相应的UBI设备:
ubiattach -m mtd2 -d 2   

3)从UBI设备上创建UBI卷:
ubimkvol /dev/ubi0 -N user1 -s 100MiB 
在UBI设备/dev/ubi0上创建UBI卷ubix_x,第一个卷为ubix_0,user1为ubi卷名。ubix_0与ubix:user1是等价的。

4)mount将ubi卷挂载到文件系统中某个目录下,可以通过操作这个目录下的文件来实现ubi读写:
mount -t ubifs ubi0_0 /mnt/ubi或mount -t ubifs ubi0:user1 /mnt/ubi
将ubi0_0卷以ubi文件系统的格式挂载到/mnt/ubi目录下,-t指定挂载的文件系统格式。

你可能感兴趣的:(linux)