嵌入式系统中的线性Flash文件系统设计
作者: WuYJ@263.net.cn
摘要:设计一种能够在典型嵌入式环境下应用的线性文件系统,为嵌入式系统Flash空间的管理提供一种非常有效的手段。它包装和通用文件系统类似的API接口,设计的实现独立于实时操作系统(RTOS)和具体的Flash典型,可方便移植到不同的嵌入式应用中。
在嵌入式系统中,为了便于对闪存(Flash)空间进行管理,会采用文件的形式来访问Flash。目前,可以购买到的Flash文件系统一般都是兼容DOS的文件系统(Flash File System,FFS),这对需要一个具有复杂的目录层次,并且DDS文件兼容的系统来说是必要的;但是对大多数的嵌入式应用来说,这种文件系统太过奢侈。笔者在参与嵌入式系统项目的时候,设计了一种线性文件系统,它适用于大多数的嵌入式应用对Flash文件系统的需求。
线性文件系统设计基于三个目标:一是提供给应用程序通过文件名而不是物理地址访问系统Flash的能力;二是文件系统的设计独立于实时操作系统(RTOS),这样可以很容易移植到不同的嵌入式应用中;三是设计统一的底层接口,适应不同的Flash类型。本文设计的线性文件系统为典型的嵌入式系统提供了所需的类文件系统能力。需要注意的是,本文件系统不支持复杂的Flash扇区擦写次数均衡算法,没有目录层次,并且和其它的文件系统不兼容。
1 线性文件系统
线性文件系统的设计思路是这样的:文件分为文件头和文件数据区两个部分,每个文件按照顺序存放在Flash中,以单向链表来链接文件。文件的起始部分是文件头,包含文件的属性、指向下一个文件头的指针、文件头和文件数据区的32位循环冗余校验和(CRC32)等。文件头用一个32位的字来表示文件属性,每位表示一种属性,如数据文件或者是可执行文件,是否已删除的文件等,具体可以根据应用的需要来定义文件的属性;文件头和文件数据区维护独立的CRC32校验,使文件系统能更精确检测文件的完整性。文件的起始地址没有特殊需求,分配给文件系统的Flash大小限制了文件的大小。另外,线性文件系统作为嵌入式系统的一个功能模块,它为应用程序提供与标准文件系统类似的API接口,如:read()、write()、open()、close()、stat()和seek()等。对于同时在多片Flash的系统而言,每片Flash相当于一个目标,文件都可存储在任何一片中(当然受物理空间限制),但不能跨片存储。
图1 Flash文件系统空间
在第一个文件创建之前,必须进行初始化,将所有分配给文件系统的Flash空间擦除。当创建第一个文件时,起始位置从文件系统的起始地址开始,文件头指针指向下一个空文件的起始位置(链表尾部);第二个文件的位置从当前的链表尾部开始,同时文件头中的链表指针指向新的尾部。删除文件时,仅仅是简单地把文件头的标识位中的活动文件标识位置0,表示删除。这样,在经过多次删除之后,就有必要运行碎片整理模块来进行文件系统Flash空间的碎片整理。碎片整理模块还需要在文件系统Flash空间尾部留一个扇区来数据备份,以便当碎片整理被打断时(如下电或者复位)可以恢复文件系统。这个保留的扇区称空闲扇区。它必须放在文件系统空间之后,这样可以保证文件系统的所有文件在所占用的Flash空间是连续的。整个文件空间的分配如图1所示。
阴影部分是文件头,数据结构如下:
struct hdr{
unsigned short hdrsize; /*文件头字节数*/
long filsize; /*文件头版本*/
long filsize; /*文件大小*/
long flags; /*描述文件的标识*/
unsigned long filcrc; /*文件数据的CRC32的值*/
unsigned long hdrcec; /*文件的最后修改时间*/
struct hdr *next; /*指向下一个文件头的指针*/
char name[NAMESIZE]; /*文件名*/
char info[INFOSIZE]; /*文件描述信息*/
《嵌入式系统中的线性Flash文件系统设计》