plane0
|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB| block0
|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB| block1
|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|
|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|
plane1
|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|
|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|
|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|
|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|
plane(n-1)
|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|
|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|
|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|
|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB|chunk|OOB| block(n-1)
#define chunkSize 2048 //一个page的大小,指存放数据的chunk最大2048字节,不包括OOB
#define spareSize 64 //OOB大小是64字节
#define pagesPerBlock 64 //每个block包含64个page,block是擦除大小,每次擦除会把这64个page一次性擦去
object_header 0x0-0x200 (512字节) 存放在chunk内,一个目录或者文件对象,就有一个object_header描述,是目录或文件的元数据
type
parent_obj_id
sum_no_longer_used
name
yst_mode
yst_udi
yst_gid
yst_atime
yst_mtime
yst_ctime
file_size_low //文件大小
equiv_id
alias
yst_rdev
win_ctime
win_atime
win_mtime
inband_shadowed_obj_id
inband_is_shrink
file_size_high
reserved
shadows_obj
is_shrink
OOB 0x800-0x840 (64字节) 每个chunk都配有一个OOB,主要用来管理数据版本,做ecc校验
chunk_used //表示这个chunk是否刚被擦除,如果已擦除,标记为unused,可以分配给新数据使用,如果未擦除,标记为used
obj_id //这个chunk的唯一id,从256开始编号
chunk_id //如果该chunk是object_header,这里是0,如果该chunk是data,这里表示第几个data chunk
n_bytes //data chunk使用,data长度
ecc_result //该chunk的ecc
block_bad
is_deleted
serial_number
seq_number //对于同一个obj_id的chunk,seq_number越大表示越新,老的chunk会被回收掉
extra_available
extra_parent_id
extra_is_shrink
extra_shadows
extra_obj_type
extra_file_size
extra_equiv_id
例如一个目录在yaffs里的占用:
|chunk|OOB|
|object_header|_____________________________|OOB|
0x0 0x200 0x800 0x840
例如一个文件在yaffs里的占用:(注意实际场景,一个文件的data可能储存在多个不连续的chunk中,组建文件表inode时,要找到该文件的所有chunk)
|chunk|OOB|
|object_header|________________|OOB|
0x0 0x200 0x800 0x840
|data|OOB|
0x840 0x1040 0x1080
|data||OOB|
0x1080 0x1880 0x18C0
特性:
1、数据读写的最小单位是page(chunk)
2、数据写入之前,写入位置需要是被擦除过了的
3、数据擦除的最小单位是block
4、block里面的page,只能按顺序写入,不能任意page写入
5、oob的数据是随着page的数据一同被写入
数据更新流程:
1、首先找到要修改的chunk,将数据读取到内存中,再对其数据进行修改,最后将修改后的数据写入到一个新的chunk
2、新的数据写入新chunk的同时,与它对应的oob数据也会被一同写入新chunk对应的oob区域,obj_id不变,seq_number+1
3、yaffs2的垃圾回收线程工作(数据更新不会调用):如果多个chunk的obj_id相同,保留最大seq_number的chunk,其他chunk按block擦除,擦除完后该chunk的chunk_used标记为unused
垃圾回收机制(yaffs2的垃圾回收线程工作):
1、主动回收:一个block中的绝大部分chunk数据都是无效的,yaffs2会触发主动回收
2、被动回收:flash已经没有干净的chunk可以继续使用,此时需要立即执行垃圾回收以释放空间。这里会把几个block中的有效数据合并到一块,腾出至少一个无效数据block以便进行整块擦除回收
3、为了平衡性能与回收功能:
1)尽可能地延迟进行垃圾回收
2)一次只处理一个block块
优点:
1、启动较快:与jffs2相比,它不需要全盘扫描flash空间,直接扫描位置固定的oob,再结合object_header,即可建立文件路径表,所以挂载所花费的时间相对较短
2、日志结构:采用日志结构的设计,在异常断电等情况下比较容易保持文件系统的一致性
3、磨损均衡:block内的chunk是按序写入,加上日志结构设备使yaffs2自带磨损平衡。但是在垃圾回收的时候,并没有提供专门的算法,所以不是严格的磨损平衡,带有一些随机性(磨损均衡优化:应该尽量按顺序找尽可能满足可擦除条件的block)
缺点:
1、无压缩功能:文件数据和元数据都未进行压缩,这个在对成本敏感的嵌入式设备中,是个劣势
2、元数据开销大:每个obj都至少需要一个chunk存储object_header,元数据的开销大,浪费存储空间
3、扩展性差:不适合大容量的存储设备,管理大规模数据时性能可能下降
yaffs2使用场景:
1、flash区分
1)nor flash:成本较高,容量较小,优点是读写数据不容易出错,比较适用于存储关键数据,比如程序固件、配置参数等,一般用jffs2
2)nand flash:成本较低,相对便宜,容量较大,但是数据比较容易出错,所以一般都需要有对应的软件或者硬件的校验算法ECC,比较适合用来储存大容量且数据安全要求不是非常严格的数据,比如照片、视频等,一般用yaffs2
2、nand flash技术还可以作为固态存储颗粒,集成到FTL(Flash Translation Layer)设备中,比如TF卡、SD卡、SSD、U盘等,这些设备不用yaffs2,而是用exFAT、ext4等
闪存文件系统分类:
VFS->FAT/NTFS/ext4->块设备->HDD/SSD
VFS->FAT/NTFS/ext4->FTL->MTD->闪存
VFS->yaffs2/jffs2/logfs(日志文件系统LFS)->MTD->闪存
VFS->ubifs->ubi->MTD->闪存