Flash memory在存储之前需要擦除,所以flash mem文件系统需要做异地更新。
Flash memory的擦除过程比较耗时,选择异地更新会比较明智,往一个已经擦除好的block上写
比拿到脏块擦除后再写要快得多。
要做异地更新,那自然有做擦除脏数据块的机制,即垃圾收集机制。写数据只需要往擦除过的block写,
GC则需要回收丢弃的block并擦除之。
文件系统需要能够标识存储在erase block上的数据,让GC机制工作。FS是用过文件名来找到所属文件的数据,
而GC则是通过data找到是否属于某个文件。
文件的metadata和data保存在一起,称之为node,每一个node记录了所属文件,以及什么数据保存在该node中
在这一点上,jffs2与ubifs相同,都是基于node设计。在读取eraseblock的数据时可以直接决定是否搬运到其他EB上,亦或丢弃。
jffs2与ubifs最大的不同之处在于,ubifs把文件index存储在Flash上,而jffs2则把index建立在内存中。
这会导致jffs2支持的尺寸有限制,mount时间与内存消耗都会随flash mem size正比增长。
存储index到flash中非常麻烦,index也需要做异地更新,引用index的index也需要更新。解决这种依赖更新的办法是使用Wandering tree。
ubifs的游离树是使用B+树,树的叶子节点保存文件信息,其他节点为index nodes。
对叶子节点的更新,会引起父节点的更新,知道根节点,更新的inex nodes的数目显然等于树的高度。
树的根节点需要存在固定的位置,即masternode中,会有两个LEB(ubifs使用的逻辑擦除块)LEB1/LEB2中各保存一份。
使用两个LEB保存两份master node是为了出现损坏时以便恢复。有两种情况会导致master node损坏,1,写master node时断电,
2,flash介质本身出现损坏。第一种情况可以使用前一版本的master node来恢复,而第二种情况则无法判断哪个是有效的master node。
第二种情况比较麻烦,需要readback数据来重建或找到问题所在。
UBIFS在创建的时候有6个areas是固定的,
UBI device上的第一个LEB是LEB0,保存superblock node,保存文件系统基本不变的参数。
Master node存在LEB1,LEB2,
LOG area,
LEB properties tree aera
orphan area
main area
superblock与mater node前面都有提到了。
LOG是UBIFS日志的一部分,用来降低falsh index更新频率。
更新文件系统的叶子节点,需要地递归更新其父节点,可能会频繁的做这样的动作,以至效率低下。
UBIFS通过日志,仅仅写叶子节点,并不立即更新flash上的index,当然内存中的index会立即更新,当日志系统认为日志满了,进行提交。
提交过程包括写入memory index以及相应的master node。
日志的数据总是比falsh的index相比更新,在mount的时候会replay日志中的index。
日志的size是在mkfs.ubifs确定,缺省情况下,ubifs不使用fask unmount,在unmount前执行一次commit。
这会让日志几乎为空,下次mount会非常快。
commit过程本身不会从日志中移动叶子节点,而是修改日志本身,即修改日志的位置。
log中包含两类节点,commit start node记录一个commit一斤刚开始,reference nodes记录组成journal的LEBs的序号。
这些LEBs叫做buds,日志包含log和buds,log的尺寸是固定的,可认为是一个circular buffer。
待续。。。

被折叠的 条评论
为什么被折叠?



