Linux UBI子系统设计初探
问题领域
flash存储设备存在如下特点:
- 存在坏块
- 使用寿命较短
- 存储介质不稳定
- 读写速度慢
- 不支持随机访问(nand)
- 只能通过擦除将0改成1
- 最小读写单位为page or sub-page
- 便宜
针对flash设备的特点,flash文件系统的核心功能需求和质量需求需包括如下这几个方面:
- 读写
- 性能
- 可靠性
- 持久性
针对这些需求,可分析得出flash文件系统需要满足如下属性要求:
- 数据保护
- 坏块管理
- 垃圾回收
- 磨损均衡
- 分区管理
- 文件管理
- 性能优化
在ubifs文件系统中,这7条属性中的数据保护、坏块管理、垃圾回收、磨损均衡、分区管理等需求由ubi子系统实现,也是此次分析的重点。
架构模型
ubi是ubifs的一个子系统,其位于MTD之上,ubifs之下,如图所示。

ubi子系统内部又细分多个模块(如下),每个模块后面逐个展开介绍。

其设计架构如下:

为了管理架构栈中的各个子系统,ubi在用户态导出多个控制接口,以便于对模型进行控制管理。
/dev/mtd0:
mtd对象,对mtd设备操作的实体
/dev/ubi_ctrl:
ubi控制对象,用于ubi与mtd的映射与解映射(attach and detach)
/dev/ubi0:
ubi 抽象层对象,对ubi操作的实体
/dev/ubi0_0:
ubi volume对象,对ubi volume操作的实体
UBI数据模型
数据是建模和设计的核心,UBI有2个顶层数据对象:ubi_attach_info和ubi_volume_desc。其数据关系模型如下:


UBI数据持久化设计
因为磨损均衡、逻辑块管理、分卷管理等需要,ubi自身支持这些功能的元数据需要持久化存储,如:块擦除次数、LEB/PEB映射、volume/LEB映射、分卷表、fastmap等数据,具体的数据结构有:
OOB
ubi_ec_hdr - UBI erase counter header
ubi_vid_hdr - on-flash UBI volume identifier header
ubi_vtbl_record - a record in the volume table.
ubi_fm_sb - UBI fastmap super block
ubi_fm_hdr - header of the fastmap data set
ubi_fm_scan_pool - Fastmap pool PEBs to be scanned while attaching
ubi_fm_ec - stores the erase counter of a PEB
ubi_fm_volhdr - Fastmap volume header
ubi_fm_eba - denotes an association beween a PEB and LEB
其中ubi_ec_hdr、ubi_vid_hdr、ubi_vtbl_record、OOB的数据结构定义、存储位置和数据示例如下:
ubi_ec_hdr,存放在每个PEB(1MB)的page 0,每个page(8K)一段OOB(0x1C0);
ubi_vid_hdr,对于已分配到volume中的PEB,vid hdr存放在PEB page 1(8K) or page 0 sub-page 1(2K);
ubi_vtbl_record,作为UBI_LAYOUT_VOLUME_ID的数据,LEB0,LEB1相互备份,从PEB的page 2 开始存放。

每个PEB块有个OOB区,OOB前面几个字节是坏块标记(橙色标示),尾部一段字节为ECC数据(绿色标示),如果中间有多余字节,则闲置不用(黄色标示)。各段的大小依赖于页格式、ecc位数、各flash厂商定义的坏块标记形式而定。

UBI attaching子系统
attaching子系统的核心任务就是创建并初始化ubi设备,其核心数据是ubi_attch_info对象,对照上一节的数据模型,这个过程包括创建ubi_ainf_volume对象;扫描所有PEB的ec header和vid header,读取OOB区坏块标记,统计坏块个数,初始化ai->bad_peb_count;如果attaching时PEB的ec header为无效值,此时会有平均的ec值初始化其ec header;如果发现2个PEB具有相同的lnum,选用seqnum大的PEB,seqnum小的PEB放入 ai->erase链表。
校验每个块的ec header、vid header和data,并对其错误类型进行分类,对可纠正的错误,放入ai->erase表,对于无法纠正的错误,放入ai->corr或ai->alien表;对于没有错误的块,放入ai->free表。具体分类规则请参照下表。
错误类型:
- UBI_IO_FF: 全0xFF;
- UBI_IO_FF_BITFLIPS: 全0xFF,但是有可纠正的ECC错误;
- UBI_IO_BAD_HDR: EC或VID头损坏(如magic number错误或者CRC错误)
- UBI_IO_BAD_HDR_EBADMSG: 由不可纠正的ECC错误导致的EC或VID头损坏
- UBI_IO_BITFLIPS: 有可纠正的ECC错误;
PEB分类:
- free:正常块;
- erase:擦除块,需要进行擦除;
- corr:损坏块,不再参与磨损均衡;
- alien:异常块,不再参与磨损均衡;
- scrub:擦洗块,数据搬移到正常快上,并对其进行擦除,确认没有问题;
- torture:拷问块,数据搬移到正常快上,并对其反复多次读写擦除,确认没有问题;

UBI EBA子系统
EBA子系统主要提供如下功能:
- LEB/PEB的映射表管理:上层只看到LEB,不再关心块的读写错误处理、替换等细节;
- LEB的sequence counter管理:seq counter主要是为了标记顺序,解决LEB/PEB的映射冲突;
- LEB访问接口封装:如read, write, copy, check, unmap, atomic change等;
- LEB访问保护:每一个LEB的并发访问都由读写信号量锁rwsem进行保护;
EBA提供了2种写方式:ubi_eba_write_leb和ubi_eba_atomic_leb_change。ubi_eba_write_leb用于对块的write,ubi_eba_atomic_leb_change用于对块的modify或者append。ubi_eba_write_leb写后会做读校验,如果有-EIO错误,将老PEB上的数据移动到新的PEB上,并将新数据也写到新的PEB中,对老PEB进行torture。ubi_eba_atomic_leb_change为了避免破坏已有数据,采用异地更新的方式来实现原子写,并加一个ubi->alc_mutex来进行串行化保护,其具体流程如下:
- 读取leb数据(ubifs内完成)
- 检查写数据长度是否为0,为0时,unmap leb
- 分配初始化vid_hdr
- 分配新的peb(ubi_wl_get_peb)
- 新peb中写入vid_hdr
- 新peb中写入老leb数据+新增数据
- 回收老的peb(ubi_wl_put_peb)
- 更新leb map(vol->eba_tbl)
UBI wear-leveling子系统
磨损均衡是UBI的核心功能之一,负责管理PEB的分配、回收、擦除、scrub、磨损均衡等。其中scrub、擦除, 磨损均衡功能由UBI后台线程进行异步调度管理。
UBI磨损均衡基于PEB的擦除次数实现,采用静态磨损均衡策略。对于静态磨损均衡,建立在如下假设上:擦除次数(ec)少的PEB比擦除次数多的PEB稳定,将ec大的PEB数据交换到ec小的PEB上,达到磨损均衡的目的。
PEB的分配、回收、擦除、scrub都会触发磨损均衡检查。为了避免频繁磨损均衡,进一步加重磨损情况,磨损均衡的触发频率通过UBI_WL_THRESHOLD控制,UBI_WL_THRESHOLD值不宜太小。但这种策略也存在一些问题,为了避免极端情况下对某些特定块反复擦除,通过磨损均衡_FREE_MAX_DIFF (2*UBI_WL_THRESHOLD)来控制挑选最坏的free PEB范围。
根据attaching时的PEB分类,磨损均衡模块初始化时,启动对erase块的擦除,对torture块的拷问,构建磨损均衡块红黑树,scrub红黑树等。PEB的分配通过ubi_wl_get_peb接口实现,分配具有平均擦除次数的free PEB。PEB的回收通过ubi_wl_put_peb接口实现,回收后调度erase_worker擦除。
UBI IO子系统
IO子系统主要为上层模块提供统一的读写接口,这主要包含:
PEB读写接口的统一封装,包括mtd read/write 封装;参数检查;读写检查(read io check, write verify check), 通过ubi->dbg.chk_io控制,默认没有使能。
ubi ec/vid hdr的读写接口的统一封装,包括有效性验证;支持非对齐存储;支持vid存于sub-page。
UBI fastmap子系统
缩短ubi初始化(attach)时间,使attach时间复杂度是个常数,不随PEB个数成线性增长。(Experimental feature,产品中暂未使能,未研究)
参考资料
Linux kernel 3.14-rc6 source code
http://en.wikipedia.org/wiki/Wear_leveling
www.linux-mtd.infradead.org
--EOF--
Linux UBI子系统设计初探的更多相关文章
- Linux ubi子系统原理分析
本文思维导图总纲: 综述 关于ubi子系统,早已有比较正式的介绍,也提供非常形象的介绍ubi子系统ppt 国内的前辈 alloysystem 不辞辛劳为我们提供了部分正式介绍的中文译文,以及找不到原文 ...
- Linux时间子系统之六:高精度定时器(HRTIMER)的原理和实现
转自:http://blog.csdn.net/droidphone/article/details/8074892 上一篇文章,我介绍了传统的低分辨率定时器的实现原理.而随着内核的不断演进,大牛们已 ...
- Linux输入子系统(转)
Linux输入子系统(Input Subsystem) 1.1.input子系统概述 输入设备(如按键,键盘,触摸屏,鼠标等)是典型的字符设备,其一般的工作机制是低层在按键,触摸等动作发生时产生一个中 ...
- 【转】 linux iio子系统
原文网址:http://blog.csdn.net/tsy20100200/article/details/47101661 最近由于工作的需要,接触了Linux iio子系统,对于这个目录其实以前是 ...
- 【转】linux IO子系统和文件系统读写流程
原文地址:linux IO子系统和文件系统读写流程 我们含有分析的,是基于2.6.32及其后的内核. 我们在linux上总是要保存数据,数据要么保存在文件系统里(如ext3),要么就保存在裸设备里.我 ...
- Linux中断子系统:级联中断控制器驱动
Linux中断子系统 Linux中断子系统是个很大的话题,如下面的思维导图所示,包含硬件.驱动.中断上半部.中断下半部等等.本文着眼于中断控制器(PIC),特别是级联中断控制器驱动部分,对驱动的设计和 ...
- linux iio子系统
//============================================================================\\ || 系 统:W ...
- Linux input子系统分析
输入输出是用户和产品交互的手段,因此输入驱动开发在Linux驱动开发中很常见.同时,input子系统的分层架构思想在Linux驱动设计中极具代表性和先进性,因此对Linux input子系统进行深入分 ...
- Linux时间子系统之(二):软件架构
专题文档汇总目录 Notes:从框架上讲解了时间子系统,从底向上包括CPU Local TImer.Global Counter.Clock Souce/Clock Events模块管理.Tick D ...
随机推荐
- [NHibernate]组件之依赖对象
目录 写在前面 文档与系列文章 组件之依赖对象 一个例子 总结 写在前面 周一至周四一直在成都出差,也一直没有更新博客了,一回到家第一件事就是扒一扒最近博客园更新的文章,然后把想看的收藏了,大概有20 ...
- CF451E Devu and Flowers (隔板法 容斥原理 Lucas定理 求逆元)
Codeforces Round #258 (Div. 2) Devu and Flowers E. Devu and Flowers time limit per test 4 seconds me ...
- AndroidStudio导入Library
1.把它像Module一样导入. File >New >ImportModule(选择你要导入的Library). 如果出现了下面的情况,意思是跟项目中的Module重名,改个名字就行了. ...
- tyvj1195 最后的晚餐
背景 话说zhangbh001给盖子编的Windows 2012超时了(- -!),所以他不得不在自己家门口亲眼见证这个电影般的场景.虽然他不想错过这个美妙的时刻,但是他的肚子一再抗议,要求先吃完这最 ...
- 【piu~】制作一只变形小鸡~
在http://codepen.io/pick上看到的,,,具体是谁忘了,反正我只截了最萌的一段,作者越改越不萌ಥ_ಥ 谷哥哥随便一搜就有很多好玩的,度娘就...(  ̄ ▽ ̄)o╭╯☆#╰ _─﹏─) ...
- mysql数据库 中文乱码
看到一篇很好的文章,转录于此 中文乱码似乎是程序编写中永恒的一个话题和难点,就比如MySQL存取中文乱码,但我想做任何事情,都要有个思路才行,有了思路才知道如何去解决问题,否则,即使一时解决了问题,但 ...
- PHP常量详解:define和const的区别
常量是一个简单值的标识符(名字).如同其名称所暗示的,在脚本执行期间该值不能改变(除了所谓的魔术常量,它们其实不是常量).常量默认为大小写敏感.通常常量标识符总是大写的. 可以用 define() 函 ...
- word20161214
MAC, Message Authentication Code / 消息验证代码 MAC address / MAC 地址 machine-centric / 机器中心的 Macintosh-acc ...
- 基于python的文件处理
二.文件操作方法大全 1.os.mknod("test.txt") 创建空文件2.fp = open("test.txt",w) 直接打开一个文件,如果文件不存 ...
- 深入解析PHP中的(伪)多线程与多进程
本篇文章是对PHP中的(伪)多线程与多进程进行了详细的分析介绍,需要的朋友参考下 (伪)多线程:借助外力利用WEB服务器本身的多线程来处理,从WEB服务器多次调用我们需要实现多线程的程序.QUOTE: ...