转自:http://blog.chinaunix.net/uid-28236237-id-4217118.html
UBI 文件头位置
EC头都放置在擦除块的开始偏移位置,占用64字节空间。之后防止VID头,VID头要么放置在偏移最小IO大小的位置,要么放置在子页位置,也占用64字节空间。一般有如下的三种情况
对于NOR Flash情况,最小IO为1byte,所有VID头紧接着就放置在EC头的后面
对于有子页的NAND Flash的情况,VID放置在第一个页的子页上面
对于没有子页的NAND Flash情况,VID头放置在第二个页上面
Flash空间的开销
UBI系统会使用一些Flash空间作为其系统管理的开销。这样就减小了UBI系统用户可用的Flash大小。一般一个UBI系统Flash系统开销有如下:
两个物理擦除块保存卷表
一个物理擦除块保留给磨损均衡使用
一个物理擦除块保留给原子改变逻辑擦除块使用
另外还有一些物理擦除块保留给坏块替换,这个只对NAND Flash是这样。保留物理擦除块多少是可以配置的,默认是1024个物理擦除块中保留20个擦除块。
在物理擦除块最开始的一部分空间还要保留出来给EC头和VID头使用。保留的这部分空间大小取决与Flash的种类。
保留擦除计数
当使用UBI的时候,非常重要的一个概念就是你必须意识到UBI保存了擦除计数在Flash介质上面。也就是每一个可用的物理块都保存了一个记录了擦除次数的EC头在物理块的开始部分。不丢失这部分数据是很重要的。这样用来操作这些物理块的工具必须是能检测到UBI的存在,MTD工具中相关的工具能正确的操作UBI系统上的物理擦除块。
UBI 文件头位置
EC头都放置在擦除块的开始偏移位置,占用64字节空间。之后防止VID头,VID头要么放置在偏移最小IO大小的位置,要么放置在子页位置,也占用64字节空间。一般有如下的三种情况
对于NOR Flash情况,最小IO为1byte,所有VID头紧接着就放置在EC头的后面
对于有子页的NAND Flash的情况,VID放置在第一个页的子页上面
对于没有子页的NAND Flash情况,VID头放置在第二个页上面
Flash空间的开销
UBI系统会使用一些Flash空间作为其系统管理的开销。这样就减小了UBI系统用户可用的Flash大小。一般一个UBI系统Flash系统开销有如下:
两个物理擦除块保存卷表
一个物理擦除块保留给磨损均衡使用
一个物理擦除块保留给原子改变逻辑擦除块使用
另外还有一些物理擦除块保留给坏块替换,这个只对NAND Flash是这样。保留物理擦除块多少是可以配置的,默认是1024个物理擦除块中保留20个擦除块。
在物理擦除块最开始的一部分空间还要保留出来给EC头和VID头使用。保留的这部分空间大小取决与Flash的种类。
保留擦除计数
当使用UBI的时候,非常重要的一个概念就是你必须意识到UBI保存了擦除计数在Flash介质上面。也就是每一个可用的物理块都保存了一个记录了擦除次数的EC头在物理块的开始部分。不丢失这部分数据是很重要的。这样用来操作这些物理块的工具必须是能检测到UBI的存在,MTD工具中相关的工具能正确的操作UBI系统上的物理擦除块。
UBI镜像和擦除相关
下面的步骤就是擦除UBI镜像的一般过程
首先,扫描整个UBI分区,收集每个擦除块上面的EC值,也就是读出没一个PEB的VID header,检查CRC-32校验,并且记录擦除计数到内存中,一般这个过程没有必要读取VID Header。遇到坏快就跳过去。
计算出平均的EC 记述值,这个值会被用来重新写入到EC Header丢失或者坏掉的PEB块上面。这种EC Header丢失或者损坏的情况出现在掉电重启等情况下。这样的PEB不会很多。
如果只是单纯的擦除掉flash,没一个PEB块会被擦除,合适的EC 头会被写入到PEB的起始位置。EC Header中擦除计数应该相应的加1,坏块应该跳过,对于NandFlash,擦除和写入过程中如果遇到了IO错误,相应的块就应该被标记为坏快。
如果是烧写UBI镜像,相应的过程如下
首先将一块PEB大小的镜像读入到内存buffer中,将buffer中余下的空间全部设置成0xff,擦除PEB,修改EC Header的buffer空间,增加EC counter计数,重新计算CRC-32的校验值。
将buffer写入到物理擦除块中。
通常,如果遇到坏快的话需要跳过坏快,在擦除和写入Flash过程中如果遇到了坏块就需要将相应的Flash块标记为坏块。
通常来说,UBI的镜像会比Flash要大一些,所以擦除程序需要将UBI镜像区域正确的写入,并且将多余的Flash区域正确的擦除
需要了解的是,当写入一个UBI镜像的时候,没有必要关心UBI镜像写到擦除块上面的顺序,地一个输入块可以写如到地一个物理块,也可以写入到第二个,第三个上面。
如果你为产线上写一个擦除程序,你没有必要关心去改变EC Header的擦除计数的增加,因为,产线上的Flash基本上都是新的,擦除计数可以认为是0
UBI标记擦除块为坏块
这一节只和NANDflash相关,因为只有NAND Flash才存在坏块。有两种情形UBI会标识擦除块为坏块。
一种情况是写擦除块操作失败,这个时候UBI将数据从这个物理块写入到其它物理块,进行数据恢复,并将发生写错误的物理块传递到后台进行测试判定是否为坏块。
如果是擦除操作发射IO错误,直接将这个物理块标记为坏块。
坏块拷问(bad block
torturing)是在系统后台进行的,目的是为了检测物理块是否真的是坏块。因为发生写错误会有多种原因,比如驱动程序写得有问题,或者上层软件写得有问题,对同一块Flash区域进行了多次写入。所以坏块拷问是很有必要的,避免坏块的误判。坏块的拷问过程如下:
擦除物理块
重新读入擦除块,检查是不是全0xFF字节
写入测试模式的字节
将数据读回并检查测试字节
检查多个测试式样的字节(0xA5,0x5A,0x00)
如果上面的坏块拷问过程都能顺利通过,那么这个物理块不会被标识为坏块。在坏快拷问过程中如果出现了bit反转,则这个块就被标记为坏块。torture_peb()函数就是坏块拷问的具体过程。
可扩展性问题
非常遗憾,UBI的初始时间和Flash擦除块多少成正比。这意味着Flash越大,UBI系统初始化的时间就越长。从linux V3.7开始UBi系统推出了一个新的特性叫做FastMap,这个特性使得系统链接初始化UBI的时间是一个常数。
UBI链接一个MTD设备的时候,首先去扫描这个MTD设备,从每一块物理块中读取EC和VID头,也就是从norflash中读取头128字节,或者从NandFlash中读取每个擦除块的头两页(对于有子页的就是读取头两个子页)。不管怎么样,这都要比jffs2挂载mtd设备读取的内容少很多。UBI链接一个mtd设备比jffs挂载一个mtd设备要快很多倍。
UBI要为没一个EC头和VID头做CRC校验,这会花费一定的cpu运算时间,但是和Flash的IO时间相比是非常微小的。
UBI的实现细节
要实现UBI的功能,UBI系统必须管理三张表,如下
第一张表就是 volume table,这个表记录了和卷相关的一些信息,比如卷大小,标记flag等等。这个表直接记录在Flash上面。
第二张表就是eraseblock association
table,这个表的作用就是记录逻辑卷到物理卷的映射,当上层软件操作写一个逻辑卷的时候,UBI系统首先将逻辑卷号转换为物理卷号,然后将内容写入到对应的物理卷上面。这个表只存在于内存中,并没有记录在Flash上面,内存生成这种表的方法是在UBI初始化的时候对系统中的所有物理块进行扫描,然后形成这张表。
第三张表就是物理块上擦除计数的表,这个表主要是在损耗均衡系统中使用到。这个表也不是存在flash上,而是UBI系统初始化的时候通过扫描物理块建成的。
UBI系统中每个擦除块都要花费掉两个page来记录EC header和VID header,这中额外的花费会损耗掉Flash存储数据的空间,在UBI2中,EC header和VID header都会被存储到OOB区域,因为不会损耗Flash存储数据的空间