APP下载

基于SD 卡的FAT32 文件系统可靠性设计

2021-03-24卢俊辉史丽娟

关键词:格式化扇区空闲

卢俊辉,刘 旗,史丽娟

(江汉大学 智能制造学院,湖北 武汉 430056)

0 引言

SD 卡体积小、容量大、存取方便,适于嵌入式系统存储海量数据,便于在Windows 操作系统中拷贝和查看,文件存储格式采用FAT32 文件系统,其存储量可达2 TB。FAT32 文件系统主要包括引导记录区(DBR)、文件分配表(FAT)、文件目录表(FDT)和数据区(DATA)。DBR 占用逻辑0 扇区和逻辑1 扇区,保存文件系统的重要参数,如扇区数量、簇大小、文件分配表大小、根目录簇号等;FAT 记录簇号和簇分配状态,是FAT32 文件系统链式存储的关键,记录文件数据间的链表存储关系;FDT 存储文件和子目录信息,如文件的名称、大小、创建时间以及起始簇号等;DATA 存储文件数据。DBR、FAT、FDT 和DATA 之间存在链表存储关系,簇是文件系统记录数据的最小存储单位,其中DBR 指向空闲簇号,FAT 指向FDT 所占簇号,FDT 指向DATA 所占簇号。FAT32 文件系统写文件实质是更新DBR、更新FAT、写FDT 和写DATA,空闲簇号是写FDT 和DATA 的目标簇号,因此DBR 保存的空闲簇号尤为重要。

1 FAT32 文件系统用于嵌入式系统的问题和现状

SD 卡按照FAT32 文件系统格式化以后,DBR、FAT 按照逻辑扇区存储,以下逻辑扇区简称为扇区。为DBR 预留了0 ~2 449 扇区,预留扇区足够DBR 使用。为FAT 预留了2 450 ~32 767扇区,预留扇区足够FAT 使用。FDT 和DATA 按照逻辑簇存储,每个簇通常占用8 个扇区,以下逻辑簇简称为簇。向SD 卡写文件时,FDT 首先占用空闲簇,即FDT0 占用2 簇存储文件目录,DATA 占 用 其 后 的 簇,即DATA0 占 用3 簇、DATA1 占 用4 簇,依 次DATA127 占 用130 簇。当FDT0 写 完128 个 文 件 目 录,即2 簇 空 间 被 用 完,FDT1 开 始 占 用131 簇,DATA128 开 始 占 用132簇,以此类推,FAT32 文件系统链式结构见表1。

表1 FAT32 文件系统FDT 与DATA 穿插存储Tab.1 FDT and DATA interleaved storage in the FAT32 file system

通过分析FAT32 文件系统可知,FDT 和DATA 总是占用空闲簇,导致FDT 与DATA 互相穿插。当SD 卡存储海量文件时,FDT 和DATA 位置混乱,嵌入式系统读写文件需要通过链表关系花费大量时间查询,链表式存储降低了嵌入式系统的实时性。其次,空闲簇号保存在DBR 的第二扇区内,每写一次FDT 或DATA,需要读取DBR 空闲簇号作为写FDT 或DATA 目标簇号,然后DBR 空闲簇号需要增加1 并更新DBR,FAT32 文件系统缺少空闲簇号冗余备份,一旦空闲簇号读写出错,则会造成FDT 和DATA 相互覆盖,导致文件系统出错;再次,DBR 更新一次则DBR 存储空闲簇号的扇区被擦写一次,SD 卡扇区擦写寿命约十余万次,减少DBR 扇区擦写次数很有必要;最后,嵌入式系统稳定性较差,导致SD 卡读写难免出现差错,而FAT32 文件系统缺少检错功能,不及时检错并纠错将对数据恢复过程带来困难。

为防止FDT 和DATA 互相穿插,杨书凯等[1]提出建立空数据文件填满存储介质,然后将后期采集的数据写到空数据文件中,但是FDT 的一个簇只能保存128 个目录,因此该方法只能建立128 个空文件,根本不能满足数据采集系统应用;为了避免FDT 和DATA 复杂的查询编程,石长华等[2]和吴增等[3]移植znFAT 文件系统到嵌入式系统,李敏等[4]移植FATS 文件系统到嵌入式系统,但是znFAT 和FATS 文件系统依然按照FAT32 文件系统进行底层处理,没有从根本上改变文件操作方法。对于DBR 进行冗余备份鲜见文献报道。对于DBR、FAT、FDT 的纠错,陈培 德 等[5]对FAT 进 行 恢 复,陈 潮 等[6]对DBR 进 行 恢 复,蒋 笑[7]对FAT 和DBR 进 行 恢 复,迟 扬等[8]和顾广宇等[9]对DATA 进行恢复,但是均为后期离线恢复,后期数据量大,恢复难度较大。

为了解决上述问题,本文从顺序存储、冗余备份和实时纠错3 个方面提高FAT32 文件系统的实时性和可靠性。针对数据采集系统,对FAT32 文件系统进行简化,简化后文件管理系统只能写文件和读文件,另外增加如下规定:所有文件格式相同、文件容量相同,文件名采用短格式,文件系统无子目录;簇是文件最小单位,一个簇存储一个文件,一个簇包含8 个扇区,即一个文件占用4k 字节。

2 FAT32 文件系统的改进

2.1 FAT32 文件系统顺序存储

为防止FDT 和DATA 之间互相穿插,在DATA 前预留足够的空间给FDT,DBR、FAT、FDT 和DATA 按照顺序存储,它们之间的链式结构变为类似索引结构,提高查询效率。

以SD 卡存储50 万个文件为例,50 万个文件需要占用50 万个文件目录,1 个文件目录占用32字节,每簇可以存储128 个文件目录,50 万个文件目录需要占用3 907 个簇,为符合二进制计算,FDF 预留4 096 个簇。FDT 占用第2 到4 097 簇,从4 098 簇开始存储DATA 文件,其文件系统顺序存储见表2。

表2 改进FAT32 文件系统FDT 与DATA 顺序存储Tab.2 FDT and DATA sequentially storage in the improved FAT32 file system

FAT32 文件系统按照顺序存储,对DBR 更新、FAT 更新、写FDT 和写DATA 过程做相应改变。DBR 更新过程如下:读取DBR 空闲簇号,如果空闲簇号小于4 096,说明未预留4 096 个FDT 簇,SD 卡按照改进后的方式进行格式化,否则DBR 空闲簇号递增保存;FAT 更新过程如下:如果DBR 空闲簇号小于4 096,FAT 第一个单元填充FF FF FF F8,从第2 个单元连续填充4 095 个FF FF FF F0 标志,填满FAT 前32 个簇空间,然后按照FAT32 文件系统规则在FAT适当位置写入FDT 占用簇号。FDT 写过程如下:在FDT 当前簇内空位写入文件目录,1 个FDT簇存储128 个文件目录,写满128 个目录后进入下一个FDT 预留簇;DATA 写过程没有变化,按照FAT32 文件系统规则将数据写入FDT 所指的空闲簇。

FAT32 文件系统改进为顺序存储,从第2 簇到4 097 簇存储FDT,从4 098 簇开始存储DATA,顺序存储仍然兼容FAT32 文件系统规则。

2.2 FAT32 文件系统冗余循环备份

FAT32 文件系统最重要的是空闲簇号,空闲簇号就是写FDT 或写DATA 的下一个簇号,空闲簇号存储在DBR 的4 个固定字节,每次写文件需要先读取空闲簇号,然后对空闲簇号加1 并更新DBR。因为空闲簇号极其重要,FAT32 文件系统对DBR 进行了备份,DBR 备份是简单的重复备份,备份仅用于FAT32 文件系统后期数据恢复。简单的重复备份可能会出现以下3 种错误:一是原始数据出现错误;二是原始数据和备份出现相同的错误;三是原始数据和备份出现不同的错误,简单的重复备份无法解决上述错误。因为FAT32 文件系统对DBR 原始数据的备份只是简单的重复备份,原始数据和备份数据之间本身没有规律,FAT32 文件系统无法确定原始数据错误还是备份数据错误。空闲簇号作为更新FAT、FDT 和DATA 的重要依据,一旦DBR 空闲簇号出现上述错误,轻则部分文件被覆盖,重则整个文件系统混乱,导致数据无法恢复。

为了防止空闲簇号出现错误,本文对空闲簇号进行16 次循环冗余递增存储,分别存储在DBR 后16 个相邻扇区固定位置。循环冗余存储不是进行重复备份,而是对空闲簇号进行16 次循环递增加1 存储,最大空闲簇号作为有效空闲簇号,其余15 个空闲簇号作为冗余备份。每次读取DBR 空闲簇号都是按顺序读16 个空闲簇号,为防止最大空闲簇号出现问题,规定最大空闲簇号必须等于次大空闲簇号加1,否则以次大空闲簇号作为有效空闲簇号。

16 次循环冗余递增存储带来两个好处:其一,如果最大空闲簇号存储错误,则以次大空闲簇号作为有效空闲簇号,最多影响一个文件的存储;其二,FAT32 文件系统每写一次FDT 或DATA,DBR 存储空闲簇号扇区必须擦写一次,SD 卡存储单元寿命也就10 万次,因此文件数量不能超过10 万个。如果采用16 个连续扇区循环冗余递增存储空闲簇号,保存50 万个文件,每个扇区擦写31 250 次,有效地延长了SD 卡寿命。

2.3 FAT32 文件系统检错和纠错

在写文件的过程中,SD 卡可能因外界因素导致存储错误,单片机虽然不能处理数据本身的错误,但是可以发现违反FAT32 文件系统规则的错误,对DBR、FAT 和FDT 进行检错和纠错,可以避免给后期数据存储带来无法恢复的问题。

DBR 按照16 次循环冗余递增存储空闲簇号,正常情况下最大空闲簇号作为有效空闲簇号,其余15 个簇号存储的空闲簇号备份。写文件前,依次读取DBR 内16 个簇号,选取最大空闲簇号作为有效空闲簇号,如果最大空闲簇号比次大空闲簇号大于1 以上,则最大空闲簇号错误,那么以次大空闲簇号作为有效空闲簇号,递增加1 后更新最大空闲簇号。

经过顺序存储改进后,FAT 按顺序存储FDT 簇号,每次修改FAT 时,检查当前扇区FAT 所指的FDT 簇号是否按顺序存储,如果未按序存储,则按顺序修改FDT 簇号。如果FAT 恰好进入下一扇区,则需要检查上一个扇区FDT 簇号是否按顺序存储。

FDT 所存储的文件目录首字节不能为0x00,因为FAT32 系统规定当FDT 文件目录首字节为0x00 时,代表FDT 文件目录结束。每次在写FDT 文件目录时,检查当前扇区存储的FDT 文件目录首字节是否为0x00。如果检测到FDT 文件目录首字节为0x00,简单的处理方法是首字节填充0xE5,较好的处理方法是按照前期FDT 规律进行填充。如果写FDT 为下一个空扇区,则检查前一个扇区存储的文件目录首字节是否为0x00。为防止当前FDT 文件目录后存在无效目录,必须确保当前FDT 文件目录后的首字节为0x00。

3 FAT32 文件系统可靠性改进实例

3.1 SD 卡SPI 接 口

以8 G 存储容量SD 卡为例,采用C8051F340 单片机采集到的数据存储到SD 卡,C8051F340单片机本身具有SPI 协议,因此直接采用SPI 指令读写SD 卡字节,SPI 时钟频率设定为200 kHz,SD 卡与单片机SPI 协议引脚接线见图1。

3.2 SD 卡初始化

SD 卡上电复位后,需要使SD 卡进入SPI 通信模式,通过SPI 总线发送指令CMD0 使卡复位,接着发送指令CMD1 激活卡进入内部初始化处理,最后使卡退出空闲状态。当SD 卡退出空闲状态后,就可以发送其他命令来操作卡。接着发送指令CMD58 读取SD 卡的电压、容量、卡的大小等信息,最后发送指令CMD16 设定扇区大小为512 字节[10]。SD 卡的初始化流程见图2。?

图2 SD 卡初始化流程Fig.2 The initialization process of the SD card

3.3 SD 卡自检

SD 卡初始化完成后需要自检,SD 卡自检流程见图3。首先读取DBR 起始物理扇区,根据DBR 内的信息,确定FAT 起始物理扇区,再根据FDT 预留空间确定FDT 起始物理扇区。为了防止FDT 和DATA 之间穿插,需要提前给FDT 预留足够的空间,因此空闲簇号要大于FDT 预留空间,可以通过比较DBR 内中最大的空闲簇号和FDT 预留空间来判断是否预留了足够的FDT 空间,若空闲簇号大于FDT 预留空间,则说明预留了足够的FDT 空间,否则SD 卡需要进行格式化。

3.4 SD 卡格式化

与标准的FAT32 文件系统格式化不同之处在于,此处SD 卡格式化增加了DBR 冗余存储预留空间、FDT 与DATA 的顺序存储预留空间,SD 卡格式化流程见图4。首先,为实现DBR 的16次冗余存储,在DBR 后面预留16 个扇区,其实质是将DBR 所占扇区数增加到16 个扇区,当然也可以增加更多扇区保存其他参数,比如采集系统的其他信息。其次,为了保证FDT 与DATA 的顺序存储,在FDT 后预留4 096 个簇,预留的空间足够FDT 使用,并将FDT 的起始位置写入DBR 内。再次,FAT 首字节填充F8 FF FF FF,其后填充4 095 个FF FF FF F0,提示文件系统FDT 预留的4 096 个簇不能存储DATA。最后,如上所述,FDT 预留了4 096 个簇,SD 卡格式化理论上4 096 个簇应完全清零,为了节省时间,只需要将FDT 的首扇区清零即可。

3.5 SD 卡写文件

SD 卡写文件包含DBR 更新、FAT 更新、FDT 更新和写DATA,为提高SD 文件存储可靠性,加入必要的检错和纠错,SD 卡写文件流程见图5。首先,读取并比较DBR 内16 个循环冗余递增的空闲簇号,以最大的空闲簇号作为有效空闲簇号,有效空闲簇号所在扇区的下一个循环扇区保存有效空闲簇号递增加1 并更新DBR,为了防止有效空闲簇号出现错误,要求有效空闲簇号小于其余空闲簇号增加16。其次,根据FDT 所在簇号计算出FDT 在FAT 内的索引位置,将FDT 簇号填入FAT 索引,并对当前FAT 进行更新;为防止FAT 存储的FDT 出错,每次更新FAT 时检查FDT 索引是否按顺序排列,若FDT 索引混乱则重新按序排列FDT。再次,检测前期存储的FDT 文件目录首字节是否为0x00,若是则填充0xE5,防止FDT 目录中断;检查文件目录后面字节是否为0x00,否则后面字节清零,防止FDT 增加无效文件目录;当检查前期存储的FDT 检错和纠错后,再添加最新FDT 文件目录。最后,在有效空闲簇号所指向的簇内写DATA,完成文件的写入。

图3 SD 卡自检流程Fig.3 The self-check process of the SD card

图4 SD 卡格式化流程Fig.4 The format process of the SD card

图5 SD 卡写文件流程Fig.5 The file writing process of the SD card

4 结语

分析了FAT32 文件系统在嵌入式系统应用中存在的问题,通过预留FDT 空间来防止FDT和DATA 互相穿插,对DBR 空闲簇号进行循环冗余递增存储,对FAT32 文件系统格式的检查和纠错,通过上述方法对FAT32 文件系统的改进。以C8051F340 单片机为例,实现SD 卡存储10万个文件,提高了嵌入式系统利用SD 卡存储文件的可靠性,同时完全兼容FAT32 文件系统。为防止FAT、FDT 和DATA 混乱,按照上述改进后,不允许进行删除操作,这个问题不影响SD 卡应用于嵌入式系统数据存储。

猜你喜欢

格式化扇区空闲
MBR磁盘转换为GPT磁盘的研究与实现
分阶段调整增加扇区通行能力策略
现代人守则:昏死之前请把手机格式化
重建GPT分区与NTFS_DBR的研究
“鸟”字谜
西湾村采风
U盘故障排除经验谈
彪悍的“宠”生,不需要解释
格式化