记录nand相关知识,主要是mtd和ubi
它是一种flash管理方式
flash是一系列连续的物理擦除块组成的。
UBI卷是一系列连续的逻辑擦除块(eraseblock),每一块都可以被映射到物理分区,这种映射是由UBI管理的。
UBI是靠什么来管理这些物理擦除块的呢??
首先要区分一些层次:
UBI全称Unsorted Block Images,是一种原始flash设备的卷管理系统。这个系统能在一个物理的flash设备上管理操纵多个卷并且能在整个flash芯片上实现损耗均衡。
从某种意义上说,UBI和LVM有点相似,LVM将逻辑扇区映射到物理扇区上面,UBI映射逻辑擦除块到物理擦除块。但是除了映射,UBI还实现了全局的损耗均衡和透明的I/O错误处理。
NAND Flash在读写的时候可能会出现bit翻转,bit翻转可以被ECC校验来纠正,但是这种现象长期积累会导致数据丢失。UBI将出现bit翻转块上的数据转移到其它块上面。这种机制叫做冲刷,冲刷过程在后台完成,对上层软件是透明的。
下面是UBI特性的列表
UBI提供一种卷的机制,可以动态创建、删除、重设置卷大小等操作
UBI在整个Flash设备上提供了损耗平衡的机制,你可以不断的对某一个逻辑擦除块进行擦除,UBI会将你的操作均匀分散到其它各个物理块上面。
UBI透明的处理Flash上面的坏块
UBI通过冲刷机制最大限度的减小数据丢失的几率
UBI和MTD分析对比,有如下的特点。
两者都由擦除块组成,在UBI中是逻辑擦除块,在MTD分区中是物理擦除块。
两者都支持三种基本的擦做,read、write和erase
UBI卷没有擦除块损耗均衡的限制,用户层软件不需要关注损耗均衡,简化了用户层软件的设计
UBI卷没有坏块的情况需要考虑,这也使得上层软件设计简单
UBI卷可以被动态创建、删除和重新分配大小,而MTD分区是静态的。
UBI能处理bit翻转的情况,用户层软件不需要考虑bit翻转
UBI提供了卷升级操作,这样可以简单的探测软件升级的中断并且予以恢复
UBI提供了原子逻辑擦除块更换操作,这个操作允许更改逻辑擦除块中的内容过程中如果遇到了断电重启等情况不会丢失原来逻辑擦除块中的内容。这个功能对上层软件比如文件系统特别有用。
UBI提供un-map操作,这种操作只是将逻辑块和物理块之间的映射去除掉,然后调度物理块进行后台擦除操作,这个过程非常迅速,上层软件不需要等待较长的擦除时间。
UBI 对外提供一种块设备,允许随机访问,块适应的文件系统挂载在UBI卷上面。实现这种功能的主要原因是UBI卷不需要考虑坏块。
另外UBI还额外提供一种叫做gluebi的驱动来在UBI卷上模拟MTD设备,这种做法看起来有一点奇怪,因为UBI本身工作在MTD设备上面,而gluebi又要在UBI上模拟一个MTD设备。但是这种做法实际是可行的,这样可以在UBI上运行诸如jffs2之类的软件。尽管如此,新软件还是能充分利用UBI的特性,让UBI来处理Flash技术引入的一些问题。
下面列举了UBI相关的一些工具 ubinfo - 提供从系统中找到的UBI设备、UBI卷的相关信息
ubiattach - 链接MTD设备(MTD设备描述原始Flash设备)到UBI并且创建相应的UBI设备;
ubidetach - ubiattach相反的操作,将MTD设备从UBI设备上去链接;
ubimkvol - 从UBI设备上创建UBI卷;
ubirmvol - 从UBI设备上删除UBI卷;
ubiblock - 管理UBI卷上的block;
ubinize - 制作UBI镜像;
ubiformat - 格式化恐的Flash设备,擦除Flash,保存擦除计数,写入UBI镜像到Flash;
mtdinfo - 报告从系统中找到的UBI设备的信息.
UBI存储两个64字节的文件头在每一个非坏块的起始位置
擦除计数头(或者称为EC头)包含物理擦除块的擦除次数以及其它一些不太重要的信息
卷标记头(或者称为VID头)包含了属于这块物理擦除块的卷ID和逻辑块号,另外包含了其它一些不太重要的信息
所有的UBI头都使用CRC-32校验来保护,用户可以参考/drivers/mtd/ubi/ubi-media.h文件获得更加详细的文件头内容的信息。
当UBI链接一个MTD设备时,UBI系统会扫描整个MTD设备,读取所有的文件头,并且校验CRC-32的校验值。之后UBI系统会记录每个物理擦除块的擦除操作计数,同时建立逻辑块到物理块的映射到内存中。用户可以参考后面相关的章节了解这个过程的详细描述。
当UBI系统擦除了一个物理块,它会在这个物理块上写入一个EC头并且增加擦除计数。这意味着物理擦除块除了在擦除物理块到写入EC头的这段短暂时间内总有一个EC头,如果在上述短暂时间内系统发生了断电等情况,EC头会丢失或者损坏,这种情况下UBI系统重新写入一个EC头并且使用一个整个扫描计算得到的UBI的平均擦除计数作为EC头的擦除计数。
逻辑擦除块的去映射操作只是将逻辑块从映射的物理块去映射然后调度物理块进行擦除操作。擦除操作中EC头会被直接写入物理块中,而VID头并不写入物理块
逻辑擦除块的映射操作以及当往一个还没有映射的逻辑块中写入内容的时候。UBI寻找一个合适的物理块并且向其中写入VID头(此前EC头已经被写入到物理块中了)。需要注意的是如果向一个已经映射的逻辑块中写入内容的话只直接写入数据到映射到的物理块而不需要操作UBI头。
UBI系统为每一个物理块维护了两个文件头,主要的原因是UBI需要在不同的时间向Flash中写入不同的信息。这两个不同的时间点如下面所述。
当一个物理块被擦除后,UBI需要迅速向物理块中写入EC头记录这个物理块的擦除次数。以免这个擦除计数由于断电重启而被丢失的概率。
当UBI映射一个物理块到逻辑块时,VID头会被写入到物理块中。
当EC头被写入到物理块中的时候,UBI还不清楚这个物理块将要对应的卷ID和以后将要被映射的逻辑块号。这就是UBI需要使用两个分立的文件头的原因。
卷表示UBI系统保存在Flash上的一个数据结构,这个数据结构保存了一个UBI设备上面每一个卷的信息。一个卷表是每个卷记录信息的数组。每个卷记录信息包含了下面的具体内容:
UBI使用下面的算法来更新卷表记录项。
当UBI链接MTD设备的时候,必须确保两份卷表内容一致。如果两份卷表的内容不一致,就用LEB0逻辑块的卷标拷贝覆盖LEB1逻辑块的内容。如果其中某一份的内容损坏了,就用那份完整的拷贝覆盖损坏的内容。
UBI使用了一种抽象的Flash模型,简而言之就是,UBI将MTD设备看成事由一个个擦除块组成的,擦除块分为好块和坏块。好块可以进行读取,写入,擦除操作。
对Flash的读写操作都只能以最小擦除块的大小进行,这个大小取决于Flash的类型
NOR Flash通常的最小IO大小事1字节,NOR Flash通常允许单字节的对Flash进行读写操作,NOR Flash甚至可以对设备上单比特进行操作
NAND Flash通常以512、2048、4096字节作为设备IO的最小单位,一般这个最小单位就是NAND Flash的一页的大小。NAND Flash将每一页的ECC校验值存储到OOB区中,这就意味着整个NAND Flash的一页内容必须一次写入从而可以计算出整个页的ECC校验值。整个页的内容页必须一次性读出以校验ECC校验值。Flash设备的最小IO大小是一个很重要的概念,对UBI系统有很多影响,比如说:
UBI系统中VID头部的位置就取决于Flash设备的最小IO大小,还有UBI系统中逻辑擦除块的大小也取决于Flash设备的最小IO大小。一般来说,最小IO值越大,逻辑擦除块反而会越小,原因是UBI头占用的空间会越大。
所有对逻辑擦除块的写操作都必须是和最小IO值对齐的,必须是最小IO值的整数倍。对于读操作没有这样的限制,事实上在MTD设备层面也是按照最小IO值大小进行读取的,读入到一个缓冲空间后,最后只拷贝了用户请求的字节数目给用户。
EC头都放置在擦除块的开始偏移位置,占用64字节空间。之后防止VID头,VID头要么放置在偏移最小IO大小的位置,要么放置在子页位置,也占用64字节空间。一般有如下的三种情况
对于NOR Flash情况,最小IO为1byte,所有VID头紧接着就放置在EC头的后面
对于有子页的NAND Flash的情况,VID放置在第一个页的子页上面
对于没有子页的NAND Flash情况,VID头放置在第二个页上面
UBI系统会使用一些Flash空间作为其系统管理的开销。这样就减小了UBI系统用户可用的Flash大小。一般一个UBI系统Flash系统开销有如下:
两个物理擦除块保存卷表
一个物理擦除块保留给磨损均衡使用
一个物理擦除块保留给原子改变逻辑擦除块使用
另外还有一些物理擦除块保留给坏块替换,这个只对NAND Flash是这样。保留物理擦除块多少是可以配置的,默认是1024个物理擦除块中保留20个擦除块。
在物理擦除块最开始的一部分空间还要保留出来给EC头和VID头使用。保留的这部分空间大小取决与Flash的种类。
当使用UBI的时候,非常重要的一个概念就是你必须意识到UBI保存了擦除计数在Flash介质上面。也就是每一个可用的物理块都保存了一个记录了擦除次数的EC头在物理块的开始部分。不丢失这部分数据是很重要的。这样用来操作这些物理块的工具必须是能检测到UBI的存在,MTD工具中相关的工具能正确的操作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
这一节只和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存储数据的空间
Nand Flash由于本身硬件的内在特性,会导致(极其)偶尔的出现位反转的现象。
所谓的位反转,bit flip,指的是原先Nand Flash中的某个位,变化了,即要么从1变成0了,要么从0变成1了
漂移效应指的是,Nand Flash中cell的电压值,慢慢地变了,变的和原始值不一样了。
此现象有时候也叫做,过度编程效应(over-program effect)。
对于某个页面的编程操作,即写操作,引起非相关的其他的页面的某个位跳变了。
此效应是,对一个页进行数据读取操作,却使得对应的某个位的数据,产生了永久性的变化,即Nand Flash上的该位的值变了。
如果只是对于单个位的跳变,也许问题看起来并不是很严重。然而,如果恰巧是某个重要文件的某位变化了,那么问题就严重了。
如果位反转,只是读取数据出来时候报告出来的位反转,那么很简单,只需要重新再去读取一次数据,即可解决此问题。
但是,如果是Nand Flash物理上的某个位真正的翻转了,那么需要通过对应的ECC校验去解决。
相对Nor Flash来说,Nand Flash中,位反转的现象,相对更加容易发生。因此,Nand Flash厂家都推荐,在使用Nand Flash的时候,最好要应用ECC算法。
当Nand Flash应用于多媒体信息,比如存储音视频文件,那么位反转所造成的问题,并不严重。
当用于存储操作系统,配置文件和其他敏感信息的时候,必须要用ECC,以实现数据的校验,保证数据的正确性。
MTD,Memory Technology Device即内存技术设备
字符设备和块设备的区别在于前者只能被顺序读写,后者可以随机访问;同时,两者读写数据的基本单元不同。
字符设备,以字节为基本单位,在Linux中,字符设备实现的比较简单,不需要缓冲区即可直接读写,内核例程和用户态API一一对应,用户层的Read函数直接对应了内核中的Read例程,这种映射关系由字符设备的file_operations维护。
块设备,则以块为单位接受输入和返回输出。对这种设备的读写是按块进行的,其接口相对于字符设备复杂,read、write API没有直接到块设备层,而是直接到文件系统层,然后再由文件系统层发起读写请求。
同时,由于块设备的IO性能与CPU相比很差,因此,块设备的数据流往往会引入文件系统的Cache机制。
MTD设备既非块设备也不是字符设备,但可以同时提供字符设备和块设备接口来操作它。
MTD总概述
Linux中MTD的所有源码位于/drivers/mtd子目录下,
http://www.linux-mtd.infradead.org/doc/ubi.html
http://www.crifan.com/order_nand_flash_bit-reversed_bit_flipped/
http://blog.chinaunix.net/uid-28236237-id-4217118.html
http://blog.csdn.net/bugouyonggan/article/details/9167213