嵌入式Flash文件系统的设计与实现

1  引言

    随着嵌入式系统越来越广泛的应用,嵌入式系统中有大量的数据需要存储和管理。Flash存储器具有容量大、体积小、功耗小、成本低、掉电后数据不丢失、读访问速度高、抗震性好等一系列的优点,已经成为嵌入式系统中广泛应用的存储器件。但是随着系统复杂性的增加和存储器容量的加大,如何高效地存储和管理数据从而方便用户使用,成为一个重要的课题。引入嵌入式Flash文件系统正是解决这个问题的好办法。
    基于Flash存储器本身的特性,并结合笔者所参与的嵌入式系统项目,在嵌入式操作系统μC/OS-II的基础上设计了一种嵌入式Flash文件系统,主要完成了以下几个目标:一是提供给应用程序通过文件名而不是物理地址访问系统Flash的能力;二是提供与底层存储器无关、清晰的编程接口API,使上层应用不再关心底层具体设备;三是提供一种简单的Flash扇区擦写次数均衡算法,以延长Flash的使用寿命;四是提供掉电安全机制;五是针对本项目的特殊性,将文件分类存储,同一种类的文件存储在同一个扇区内。

2  Flash存储器特点

    嵌入式系统中使用的Flash主要分为NOR和NAND两种类型,一般使用NOR技术的Flash存储器,既可以存储数据,又可以存放直接执行的代码。这里以NOR型Flash为例进行介绍。
    Flash存储器的读操作与普通的SRAM存储器类似,可以实现完全随机的字节读取,但是它的写操作就较为特殊,不能对同一内存地址写入两次,而必须先经过耗时的擦除操作后才能写入,而且Flash的擦除操作以扇区为单位(扇区大小一般为64KB)。扇区被正确擦除后,所有的位都变为“1”,即整个扇区的内容都被置为0xff。在写入操作时,可使必要的位从“1”变为“0”,但是要让位从“0”变为“1”,就需要再重复以上的“擦除——写入”过程。此外,Flash存储器数据传输中的时间瓶颈不在于读操作,而在于内部的擦写操作上,一般需要1~2s,甚至最长要10s。
    NOR型Flash每个扇区的擦除次数都有限制,当前的Flash芯片一般支持10万~100万次的擦除,而写入操作对Flash损耗不大,一般没有次数限制。

3  嵌入式Flash文件系统的要求

    基于Flash芯片本身的特性和嵌入式系统的应用环境,一般对嵌入式Flash文件系统有如下的要求:
    (1)掉电安全机制。由于嵌入式系统的运行环境一般都比较恶劣,但同时又要求系统有较高的可靠性,即在系统突然掉电或者重新启动后,不能破坏Flash中的数据,同时保持文件系统的一致性和完整性。
    (2)均衡磨损(wear_leveling)。由于Flash的擦除次数有限制,所以文件系统要均衡使用Flash的每个扇区,延长Flash的使用寿命。
    (3)垃圾回收机制。在存储器分配使用一段时间后,Flash中可能存在脏数据,这就要进行垃圾回收,将无效的数据从存储器中清除来保证高效地使用存储器。因为Flash的擦除以扇区为单位,所以垃圾回收也应该以扇区为单位进行,将有效的数据全部移动到另一个扇区后再擦除整个扇区。

4  Flash文件系统的设计

    为了使文件系统的结构清晰,便于在不同Flash存储器上的移植,本Flash文件系统提供了3个基本的操作作为与Flash存储器设备的应用接口,包括扇区擦除(sector_erase)、页面写入(page_write)、页面读出(page_read)。这样可以忽略某些Flash存储器产品的独有特性,便于文件系统的移植。此外,本Flash文件系统还向应用程序提供了统一的、标准的API接口,包括:init( )——初始化文件系统,open( )——打开一个存在的文件,close( )——关闭一个已打开的文件,read( )——读一个指定的文件到文件缓冲区中,write( )——写文件缓冲区的数据到一个指定的文件中,delete( )——删除一个指定的文件。

4.1  Flash文件系统的存储结构

    本Flash文件系统将整个存储空间分成两个部分:文件分配表和数据区域。
    (1)文件分配表(FAT,File Allocation Table)。主要反映了Flash存储器的扇区的使用情况,记录了各个扇区的状态,该扇区当前存放的文件的类型以及该扇区已经进行扇区擦除的次数。每个扇区的使用情况都在文件分配表中存有一项,每个表项占8个字节,数据结构如下所示:
struct  FAT_item{
    char sector_state;/*扇区状态*/
                   unsigned short file_type;/*该扇区中存放的文件类型*/
                   long erase_time;/*该扇区已经进行擦除的次数*/
    char reserved;/*保留*/
}
    其中扇区有5种状态分别为:
    0xff——空闲扇区;
    0xfe——扇区已被占用;
    0xfc——扇区的数据为过时数据;
    0xf8——脏扇区,可以进行整片的扇区擦除;
    0xf0——坏扇区;
    (2)数据区域(Data Area)。除了文件分配表以外的扇区都称为数据区域。该区域采用线性Flash文件系统的设计思想,文件分为文件头和文件数据区两部分。文件头的数据结构如下:
    struct file_header{
        char name[NAMESIZE];/*文件名*/
        long size;/*文件大小*/
        struct file_header *next;/*指向下一个文件头的指针*/
        char file_state;/*文件状态*/
}
    文件头中用一个变量file_state来表示该文件当前的状态,只用了它的低4位来表示文件的5种状态,主要用于掉电数据恢复和垃圾回收。这在下面将有详细讲述。此外,本Flash文件系统分配给每个文件块的空间(即块大小)为2K,故一个扇区中最多可存储32个文件。用单向链表来链接文件,若next域为0xff,说明这是分配给该文件的最后一个文件块。

4.2 提高Flash文件系统可靠性

    由于Flash存储器本身可能出现物理性坏损的情况,所以应该保证文件分配表的有效性。鉴于每个扇区的FAT项都很小,并且结合具体Flash芯片的特性,可以将Flash芯片的较小的扇区分配给FAT。本项目开发中使用的Flash芯片共39个扇区,其中有8个8K的扇区和31个64K的扇区。所以本文件系统将前3个8K的扇区存放引导程序,后5个8K的扇区分配给FAT。每次使用其中的两个扇区作为一个主FAT和一个备份FAT。当有一个扇区损坏的时候,可以从剩下的扇区中再取出一个扇区与另外的那个好的扇区重新组合成一对一主一备的FAT。只有当这5个扇区都损坏了,系统则彻底崩溃了。这样相对于只使用一个扇区或者两个扇区作为FAT来说大大提高了系统的可靠性。
    针对系统突然掉电与重启动的情况,本Flash文件系统提供了掉电安全机制。文件块的状态有5种,这些状态可以顺次修改,它们分别是:
    FREE——空闲块(0xff);
    INVALID——无效数据(0xfe);
    VALID——有效数据(0xfc);
    OBSOLETE——过时数据(0xf8);
    DIRTY——脏数据,可以擦除(0xf0)。
    文件块的初始状态为空闲FREE,当要写入一个新文件时,状态变为无效数据INVALID,当数据正确写入后,状态修改为有效数据VALID。当修改一个文件中的数据时,原文件块的状态先变为过时数据OBSOLETE,当修改成功后状态变为DIRTY,进行垃圾回收时状态为DIRTY的这块数据可以清除。这些状态可以顺次修改,即将某位从“1”变成“0”,而不需要擦除整个扇区。
   系统是按照如下方式提供掉电安全的。如果在写入一个新文件期间系统掉电或重启,在系统重新运行后检查文件头,若文件块状态标识为INVALID,说明该文件没有被正确写入,则将状态由INVALID修改为DIRTY,放弃该块,再重新申请一个空闲块写该文件。修改一个文件时,原文件块状态由VALID修改为OBSOLETE,然后在另一个文件块中写入修改后的文件。若修改正确,则将原文件块状态由OBSOLETE修改为DIRTY,说明该块可以删除。若在修改期间系统掉电,系统重新运行后,扫描整个Flash存储器,查找状态为OBSOLETE的文件块,如果存在与其重名的有效文件块,则将其状态标识为DIRTY;如果没有与其重名的有效文件块,则将需要修改的文件重新写到一个新块中,并将原文件块状态由OBSOLETE修改为DIRTY。

4.3 垃圾回收

    由于Flash的底层技术不支持Flash的任意空间被删除,而必须是以扇区为单位删除,所以在删除一个文件的时候,仅仅是在文件头的标识里作一个删除标识,而该文件依然保留在Flash空间中并标识它为脏数据DIRTY。这样导致系统在运行一段时间后,Flash中累积着大量的脏数据,这就有必要对这些脏空间进行回收,来有效利用Flash的存储空间。
    本Flash文件系统中解决的办法是在系统中创建一个任务recycle_task专门进行垃圾回收,该任务实时地检查空闲队列。若空闲队列中的扇区数小于6时便进行垃圾回收,清除脏数据。在进行垃圾回收时,从待擦写队列中(包括脏块队列和干净块队列)取出一个扇区,将FAT中的该扇区的状态修改为过时的OBSOLETE,并将该扇区的擦除次数加1,然后在空闲块队列中申请一个空闲扇区,将回收扇区中的有效数据写到新申请的扇区中,修改FAT中新申请的扇区的状态,最后擦写回收扇区,并将其链接到空闲块队列中。

4.4 均衡磨损

    均衡磨损的主旨是随机地将“干净”(无需擦写)的块的内容移至另一个空闲块后擦写该扇区,然后将其链接到空闲块队列中,等待写入新的数据。本Flash文件系统借鉴了JFFS2的均衡磨损技术,将Flash扇区分别分配在四个队列中:
    ①干净块队列(clean_list):扇区中的文件都是有效的;
    ②脏块队列(dirty_list):扇区中至少有一个文件被标识为DIRTY;
    ③空闲块队列(free_list):扇区是空闲扇区;
    ④坏块队列(bad_list):扇区中存在坏块。
    以上各个队列是按照扇区擦除次数升序排列的,每次都从队列头取一个扇区,即取擦除次数最少的扇区进行处理,这样保证各个扇区擦除的次数比较均衡。
    每当系统中的空闲扇区数小于6时,垃圾回收任务便在可擦除队列中查找一个可供回收的扇区。前面已经提到,可擦除队列包括干净块队列和脏块队列,那么究竟从哪个队列中取出一个扇区进行回收呢?本Flash文件系统使用了一个非常简单的随机方法来决定选择哪个扇区。如果一个随机量除以100的余数非0,就从dirty_list中选一个扇区;否则,如果取余结果为0,就从clean_list中选择一个扇区。用这种方法,在99%的情况下,会重新利用那些含有脏数据的空间,提高了擦除效率,减少了不必要的擦除;在1%的情况下,擦除存满有效文件的扇区,来保证数据在闪存上循环移动,从而达到磨损均衡。

5  总结

    本文所设计的Flash文件系统已经成功地应用到了笔者所参加的嵌入式系统的产品中,经过反复测试已经证明了本Flash文件系统基本上满足了掉电安全机制、垃圾回收机制、均衡磨损机制。但是由于文件分配表并没有参与均衡磨损,所以还没有达到理想上的整片Flash的均衡磨损,相信在后续的工作会得到进一步的改进和完善。
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值