基于29LV160TE芯片存储器的嵌入式文件系统设计与实现
摘要:针对Flash存储器的固有缺陷设计一种基于Flash存储器的嵌入式文件系统。在文件读写时,极大减少了Flash存储器擦写的次数,提高了效率。
关键词:Flash 存储器 嵌入式
引言
Flash存储器(FlashMemory)是一种高可靠性、高密度固态存储器件。嵌入式系统通常用它作为存储设备。但也存在缺陷:一是重写之前必须进行擦除,当一个块提前达到擦除上限时,将导致整个存储器无法使用。目前PC机上很多成熟基于磁盘的文件系统在Flash存储器上使用都存在着不足。而日志文件系统(Log-StructuredFileSystem)在数据更新时无需将数据写入原存储区域,适应Flash存储器无法进行重写特点。目前,针对Flash存储器缺陷而设计Linux下的JFFS文件系统,采用简化的日志文件系统,它将磨损均衡集成于清除机制之中,在带掉电可恢复功能的同时,大大减少了块擦除的次数,提高了存取速度和效率。
一、嵌入式文件系统原理
在日志文件系统中,一个文件被修改后不是被写入到原来存储空间,而是被加到所有内容后面,象日志一样被更新,这就是日志文件系统基本原理。由于同一个文件在文件系统中会留下不同版本,系统需要设置一张表标注文件最新与以前版本。该系统采用了日志文件系统的设计原理,以及JFFS文件系统将磨损均衡集成于清除机制之中的方法。该系统将一个可擦写块平分为多个簇,文件的读写以簇为单位进行。簇的状态有3种:脏、干净和空。脏表示所存内容已被置为无效;干净表示所存数据有效:空表示可以写入数据。文件和目录在该系统中被作为节点,一个节点占用若干个簇,节点中的内容连续存储,但不能越过块边界存储。该系统设置一个索引节点,保存整个系统的信息,其中包含保存有各簇状态的簇状态表。
每一次文件更新后内容都将被添加至末尾处,索引节点也被更新,总是占用最末尾干净簇;回收脏簇时,将所要擦除块中干净簇重写到空簇中,再进行块擦除;当内容写至存储体末端,则从头部重新开始循环存储。
二、嵌入式文件系统设计
1.Flash存储器中的存储结构
存储结构见图1。存储器中每个簇第一个字作为簇状态字,表示此簇是否为一个节点首簇或空簇。每个节点首部存放此节点属性(文件/目录/索引节点)和节点标识号。其中,索引节点存放该文件系统大部分信息,包括32位索引节点更新号、一张簇状态表、下一个要被擦除块的块号、给下一个新建节点(文件或目录)编号、系统根目录信息表。系统每一次更新都会产生新索引节点,索引节点更新号加1。按使用寿命10年计算,需要每秒更新136次以上,才能达到索引节点更新号上限,所以认为拥有最大更新号索引节点为最新的索引节点。簇状态表中对应每一个簇有两个Bit位,表示各个簇状态(干净01,脏11,空00)。根目录信息表存放根目录下各个目录项,每个目录项包括:属性(文件0x1/目录0x0)、文件名或目录名、节点编号、此文件(或目录)对应节点的起始簇地址、根目录表的大小可变;目录节点存放内容有:目录名,目录项个数,及所有目录项信息。
图1Flash存储器中的存储结构
2.内存数据结构及基本操作
该文件系统载入(Mount)后,会在内存中建立一个系统映象。该映象包括:索引节点中的信息、目录及文件信息、每个可擦写块中包含的节点信息、未存盘的节点信息。簇状态表、索引节点更新号、新节点编号、下一擦除块号等索引节点中的内容,在内存中均作为不同变量,内存中为每个文件和目录都建立了映象。
内存中的文件节点不包含文件真正的数据,而使用指针。文件被打开时,在内存中创建一块新存储区域存放数据,数据指针便指向此存储区,未被打开时,此指针指向空。存储地址保存文件或目录在Flash中的地址。文件和目录都被存在上一级目录下,所属目录指针即指向上一级目录在内存中的数据结构,根目录的所属目录指针即为空。对于同目录下不同节点,在内存中使用链表将其串联,同目录文件指针即联成链表。链表的首指针保存在上一级目录中,首目录项指针即指向链表的首项。该文件系统载入(mount)时,首先顺序扫描Flash中的每个索引节点,查找出最大的索引节点更新号,此更新号对应的索引节点即为最新的索引节点。查找到最新索引节点后,将簇状态表等信息映射到内存的数据结构中。依据索引节点中的根目录信息,遍历所有节点,建立内存中的目录文件结构,并将节点添加到对应的擦写块队列中。对一个文件编辑并保存。
文件打开时,先在内存中分配一块空间作为数据区,将内容写入,并定位文件节点数据指针指向该内存中的数据区。如果文件内容被修改,就将文件节点添加到未存盘队列,依次写入Flash存储器中,并修改簇状态表。保存时将内存中数据区内容写入Flash中,释放申请的内存空间,修改节点中的数据指针和簇状态表,再将文件的所有上级目录重新写入Flash,最后将更新后的索引节点内容写入Flash。如果文件未被修改,则只需修改数据指针即可。节点加入未存盘队列的顺序按照目录层数的大小排列,文件节点排在队列首,目录层数最大的排在其后,目录层数为1的排在队列末尾,根目录不加入未存盘队列。
3.嵌入式文件系统特殊处理机制
一是均衡擦写机制,为了避免任意一个可擦除块因擦写次数过多而过早报废;二是断电错误处理机制,当系统遭遇断电重新启动后,索引节点中的信息会与系统中的状态不符,这时便需要错误处理机制;三是多任务处理机制,该文件系统允许同时打开多个文件,在多任务操作系统下,为了避免冲突建立了多任务处理机制。处理方法是设立Flash写入保护区,方法是建立一个初始值为1的信号量,当一个节点需要Flash写入时,首先申请信号量,完成后再释放信号量;四是无目录文件系统的优化许多嵌入式系统设计中虽没有目录管理的要求,但是对执行效率和资源消耗的要求较高。对于不要求有目录管理的精简文件系统,在设计时也进行了优化。
三、嵌入式文件系统实现及性能分析
采用了分层方法,分为3层4个部分即应用程序接口、文件系统核心、操作系统调用接口、Flash存储器驱动。实现平台中RTOS为μC/OSOII实时操作系统,CPU用三星S4510B,Flash芯片为FUJITSU29LV160TE。针对不同实时操作系统和Flash芯片要实现不同操作系统接口和Flash存储器驱动。针对μC/OSOII编写操作系统调用接口,包括5个函数:①系统调用接口初始化FS_Sys_Interface_Init(),创建互斥信号量和内存分区;②Flash写入关闭FS_Sys_Write_Lock(),禁止Flash写入操作,调用μC/OS-II中OSMutePend();③Flash写入打开FS_Sys_Write_Unlock(),重新允许Flash写入操作,调用μC/OS-II中OSMutePost();④内存空间申请FS_Sys_Mem_Alloc()和内存空间添加FS_Sys_Mem_Add(),都调用OSMemGet()来完成;⑤内存空间释放FS_Sys_Mem_Free(),调用OSMemPut()完成,将申请的内存块全部释放。针对本次存储器芯片,定义一个FlashDef结构体的全局变量,用于存储器件信息,并且编写块擦写函数FS_Device_Sector_Erase()和数据写入函数FJFS_Device_Write()。
完成设计后,进行了运行调试,测试应用程序接口(API),应提供的各部分功能,并在突然断电情况下,测试文件系统恢复情况。无目录管理的精简文件系统的载入,可在2μs内完成,完整文件系统载入时,需建立内存中映象,耗时根据文件数量多少而不同,一般为10μs,产生代码段大小为11K。系统写入效率较高,在无目录管理配置下尤其明显。试验中系统在多次断电的情况下,系统仍能恢复至上次存盘的状态,虽会导致个别文件未更新,但不会导致文件系统崩溃。
针对Flash存储器的固有缺陷设计了一种基于Flash存储器的嵌入式文件系统。此系统代码精简,运行时占用内存资源少,运行效率高,而且有断电保护,有较高的安全性和应用价值。
参考文献
[1]陈智育.嵌入式系统中Flash的文件系统[J].单片机与嵌入式系统应用,2003(2)
[2]昊雨俊.嵌入式中的线性Flash文件系统设计[J].单片机与嵌入式系统应用,2003(10)
[3]钟忻,幂春棣.基于闪存的文件系统的买现[J].汁算机工程与应用,2008(24)