UBI子系统学习
作者:互联网
UBI子系统
UBI子系统简介
UBI子系统是运行在mtd子系统之上的一个flash管理系统,对上层屏蔽了flash的一些特性(例如坏块管理、磨损平衡等),并且提供了UBI卷(类似于分区)的概念;
UBI子系统只适用于传统的Flash(nor/nand),不适用于消费类Flash(mmc、emmc等),原因是它们都有自己的一套坏块管理和磨损平衡的机制。
相关概念
PEB和LEB
PEB(Physical Erase Block)物理擦除块是真实物理设备中的块,因为Nand Flash的擦除最小单位是块,因此叫做擦除块;以GD的flash为例 1块的大小是128K,1页大小是2048Byte+128Byte。
LEB(Logical Erase Block)逻辑擦除块是映射到物理擦除块上的,由于UBI会在每个PEB前面添加自己的UBI头,因此实际大小会比PEB要小。
UBI卷
UBI卷是一组连续的逻辑擦除块(LEB),每个LEB会动态映射到PEB上,由UBI子系统本身管理,这个管理对用户是隐藏的,当某个PEB损坏的时候,对应LEB会自动取消对这个PEB的映射,然后映射到另一个好的PEB上,这个过程用户是没有感觉的,因为它操作的还是那个LEB,并不知道底层擦写的物理块已经变了。
UBI卷有两种类型:动态卷和静态卷。静态卷是只读的卷,里面的内容由CRC-23校验码保护,并且静态卷的大小是已知的;动态卷是可以读写的,数据的完整性由文件系统保证,并且动态卷的大小不是固定的,可以重新指定大小。
磨损平衡
由于Nand Flash本身的特性,擦除次数是有限制的,通常在一个分区里面(例如userdata分区)并不会一直都是填满数据的,大部分的时间大部分空间都是空的,如果按顺序对Flash进行擦写,那么擦写的块就会集中在分区前面的block,这样造成的后果就是大大增加了前面的block的损坏概率,而后面的block又完全没用到。
UBI提供了一个磨损平衡的机制来保证分区里面的每个block的擦除次数的最大差值不会超过一定值,这样就能保证每个block都有机会被使用到;这时候逻辑块的作用就体现出来了,上层操作的还是连续的逻辑块,但是ubi将LEB映射到了不同的PEB,这样底层擦写的就是另一个物理块,实现了磨损平衡,而且上层不需要做任何其他的操作。
坏块管理
Nand Flash生产过程中或使用过程中都有可能产生坏块,这是由Flash本身的特性决定的,一个Nand Flash出厂的时候只能保证第0个block一定是好的,其它的每个块都有可能是坏块,但出厂时总的坏块数不会超过2%,在后面的使用过程中也可能会随机产生坏块。
UBI本身就是一个坏块管理的中间件,提供坏块管理的功能:
UBI在创建的时候是会预留一个坏块池,运行过程中发现一个物理擦除块变成坏块时,它就会从坏块池中拿出一个好的块替换掉这个坏的块,并将数据从这个块中迁移到好块里面。
更多的时候LEB和PEB的映射关系不会像上图那样有序,而是杂乱无章的,因为有磨损平衡的存在,当同步数据的时候,ubi就可能会对逻辑块进行re-map操作。
位翻转(bit-flips)
Nand Flash在使用过程中容易发生位翻转,发生位翻转可以由ECC校验并矫正,但ECC的纠错能力是有限的,一般512字节8位的ecc校验码,能纠正1bit位翻转,能发现2bit位翻转,更多的就不能保证发现,并且超过1位就不能纠正了。
UBI会检查每个block是否发生了位翻转,并且将数据转移到其他PEB来解决问题,这个过程称为scrubbing(擦洗)。
UBI 头(headers)
UBI在每个非坏PEB开始需要存放2个64Byte的头,分别是EC头(Erase Counter Header)和VID头(Volume Identifier Header):
- EC头,擦除计数头,主要包含该PEB的擦除计数器以及其他信息;
- VID头,卷标识头,主要包含所属卷ID和逻辑块号(lnum);
位置
EC头始终位于PEB偏移量为0处并占用64个字节,VID头则位于下一个最小IO单元开始的地方,也占用64个字节,例如:
- 对于最小IO单元为1的nor flash,则VID头位于偏移量64字节处;
- 对于没有子页的Nand Flash,则VID头位于下一个page开始处;
- 对于有字节的Nand Flash,则VID头位于下一个子页开始处;
GDFlash是没有子页的Nand Flash,并且1个page的大小为2k,因此对于GD的Flash,EC头位于每个block偏移量为0处,VID头则位于偏移量为2048(2k)处。
擦写时机
EC头和VID头位于不同IO单元是因为,EC头和VID头写入的时机并不一样。
当UBI关联到一个MTD设备的时候,会去扫描整个MTD设备,并在RAM中建立映射关系,保存在ubi_attach_info
数据结构中;第一次关联MTD设备时,还需要先将MTD设备格式化成UBI格式,也就是在每个物理擦除块前写入EC头。
UBI擦除PEB后,它就会增加擦除计数器的值,并将EC头重新写入。
当UBI将LEB和PEB映射的时候,才会将VID头写入PEB中;VID头被写入的时候,更像是这样子:
- 当进行LEB映射或者写操作一个没有映射的LEB的时候,ubi会去寻找一个合适的**空闲(free)**的PEB,然后将VID头写入(此时EC头是必须已经存在的,并且不会更改EC头);
- 当发生数据迁移的时候,LEB会取消映射PEB,并将这个PEB放进擦除(erase)链表中,PEB执行擦除完成后会立马写入EC头,并且EC头的擦除计数器+1,此时不会写入VID头;LEB会执行
1
操作,重新映射另一个PEB。
ps:
1.PEB擦除到重新写入EC头中间如果发生重启,EC头将会丢失,重启后ubi会扫描mtd设备,重新写入一个拥有平均计数器的EC头;
2.PEB的擦除和写入是异步的,也就是说可能会发生层新的LEB已经映射了新的PEB并写入了VID头,但是旧的PEB还没有被擦除,此时发生重启,就会有两个PEB被同一个LEB所映射(VID头拥有相同的卷ID和逻辑块号);此时就会选择 sqnum(全局LEB序列号) 更大的PEB
层卷(Layout Volume)
ubi层卷是必须存在的一个卷,并且这个卷对用户隐藏,使用的时候并不会发现有这个卷的存在;层卷需要占用两个块的内存空间,层卷里面保存了每个卷的信息,并且保存了两份,一个block一份,防止丢失。也就是说UBI子系统中能创建的最大卷的数量和bolck的大小是有关的,但最多不超过128个卷。
UBI子系统的主要功能
- 提供卷的概念,可以动态创建、删除或重新调整大小;
- 提供磨损平衡机制;
- 提供坏块管理;
- 会处理位翻转;
- 提供原子更改逻辑块操作,在发生unclean-reboot的时候保证数据完整性;
UBI管理开销
UBI子系统提供了这么多功能,付出的代价就是需要消耗额外的内存空间来存放这些管理信息。UBI管理产生的开销主要有以下:
- 层卷,需要2个block;
- 磨损平衡,需要消耗1个block;
- 原子更改逻辑块,需要消耗1个block;
- 坏块管理预留坏块池,需要预留20个block;
- UBI标头,每个block前都要预留空间存放2个header,所占用空间和实际UBI分区大小有关;
对Nand Flash(128M,block=128k,page=2k)来说,37M大小的UBI分区的管理开销应该为:ALL = 24 x 128k + (296 - 24) x 2 x 2k = 4160k ≈ 33 block
标签:LEB,子系统,学习,擦除,block,坏块,UBI,PEB 来源: https://blog.csdn.net/FOUREYESPIG/article/details/118944730