大致几百次重启后出现的崩溃,估计和擦写时重启有关,需要重新格式化。很难复现该故障。但总是偶尔的出现这种故障,挺烦人的,大家有无解决思路?
woodhead版本曾经总结过:
3、TFFS在操作过程中掉电会引起TFFS系统崩溃,是否有办法避免
答:可以修改sysTffs.c里面的函数sysTffsFormat的第4个参数vmAddressingLimit为0来避免绝大多数安全问题。
这个的原理是什么,woodhead能否解释一下?是否可行我待会试一试。谢谢!
阐述该问题前,需要说明TFFS的几个过程:
1、映射的过程
由于flash是读写不对称的介质,写的时候必须解锁(需要特殊的驱动完成),并且只能把1写成0,不能把0直接写成1,只能通过擦除来解决。TFFS就是为了在Flash上满足dosFs最简单的需求产生的。为了延长flash的寿命,必须尽量少的使用擦除,这就要求dosFS给出的虚拟扇区号不能跟物理地址直接对应。TFFS在内部对物理地址按照可用扇区的顺序编排了一个逻辑扇区号。TFFS必须解决好一个映射关系是从虚拟扇区号到物理扇区号的映射。在每次启动的时候需要把前面的映射关系恢复起来,而TFFS能够通过物理地址看到的只是逻辑扇区号,所以还要维护一个从逻辑扇区号到虚拟扇区号的映射。
从虚拟扇区号到物理扇区号的映射,TFFS有两种方式,一种是直接映射,举个例子,要映射128个虚拟扇区,映射的方法是在内存中建立一张表(pageTable),表的顺序是从0到127(实际上还要加一些其他页表,我们先简单化),每个表项4个字节,记录逻辑扇区号,当dosfs做读写操作传入虚拟扇区号的时候,直接把虚拟扇区号作为索引查pageTable得到逻辑扇区号,再通过逻辑扇区号找到它所在的逻辑Unit(这一步可以直接做移位操作),再通过逻辑Unit和物理Unit的对应关系找到物理的block,最后通过逻辑扇区在逻辑Unit内的偏移找到物理地址。所谓的直接索引实际上是把虚拟扇区直接映射到了逻辑扇区,后面的过程无论哪种索引方式都是一样的。
另一种方法是间接索引,这种索引方法是现把虚拟扇区按照顺序划成页,比如0~127为第一页,128~256为第二页,以次类推,有多少扇区都映射到页里面,同样也建立一张页表(pageTable),其内容是一个逻辑扇区号,这个逻辑扇区内记录的是本页内所有虚拟扇区的索引,页表的内容依然是逻辑扇区号,每项4字节,每页128项,共512字节,刚好填满一个扇区,页内索引的顺序按物理地址进行,第一个4字节对应本页的第一个虚拟扇区,第二个4字节对应本页的第二个虚拟扇区,类推到127。当dosfs传给TFFS一个虚拟扇区号的时候,TFFS先除以128得到页号,根据内存中页表的逻辑扇区号找到索引表,然后根据虚拟扇区在本页的偏移找到索引表中的位置,读出里面的逻辑扇区号,再通过这个逻辑扇区号去找实际的物理地址。
直接索引和间接索引可以同时使用,界限就是格式化参数中的第4个参数设置的大小,例如设置缺省的64K,那么直接索引的虚拟扇区个数就是64K/512=128个,虚拟扇区号大于等于128的全部使用间接索引。
2、内容替换的过程
一个虚拟扇区创建后,会有修改的现象。例如dosfs修改文件中的内容;或者重新打开文件填内容时,fat表对应的扇区需要修改此文件对应的大小和位置等内容。修改的过程对于间接索引扇区有替换扇区(replaceSector)来解决,每一步都有一个状态与之对应,即使掉电也能够恢复。对于直接索引扇区过程如下:
a)、分配一个空闲扇区;
b)、把新内容写入空闲扇区;
c)、把新扇区在BAM区记录的虚拟扇区号由未分配改为需要替换的虚拟扇区号;
d)、把被替换掉的扇区在BAM区记录的虚拟扇区号和状态改成0(垃圾)。
3、mount的过程
mount的目的是通过读flash里面每个block头部的BAM区(本block内每个扇区按物理顺序对应4字节,4字节内容由该扇区的虚拟扇区号和扇区状态组成)取得虚拟扇区号,通过虚拟扇区号的大小决定它
处于直接索引页还是间接索引页,把页表恢复起来。mount的时候如果某个虚拟扇区号存在两份(正常情况不应该出现两份),会以第一份为准。
现在问题出现了,如果在替换过程的c)步骤完成以后,d)步骤开始之前,系统复位了,系统中将出现两个一样的虚拟扇区,mount的时候以物理上的第一份为准,本此启动mount了一份,运行了一段时间后,这个虚拟扇区的内容可能又做了修改,如果运行过程中进行过垃圾回收可能会导致这两个虚拟扇区的物理位置发生变化。系统下次重启动的时候,再找到物理上的第一个有可能不是复位前的那个,这样就导致了dosfs读到的内容不正常,如果此扇区内记录的fat(fat肯定记录在前面几个扇区,并且修改频繁,所以这种可能性非常大),就会引起dosfs故障。
所以建议,不用直接索引!!!!!
谢谢版主解释的这么详细
我曾经复现过一次故障,然后单步跟踪,发现是在ftllite.c的mountFTL函数如下语句中,检测到某一个vol.pageTable[iPage]值为 UNASSIGNED_SECTOR(好像是第0页,iPage为0),从而返回flBadFormat退出,加载失败。
for (iPage = 0; iPage < vol.noOfPages; iPage++)
if (vol.pageTable[iPage] == UNASSIGNED_SECTOR)
{
DEBUG_PRINT((("#:Corrupted pageTable page%d found to be currupted, mount aborted\r\n"),iPage));
vol.badFormat = TRUE;
}
我格式化参数是直接映射范围默认为64K的,第0页的应该是采用直接映射的吧,而且恰好是FAT表的对应扇区?
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
【换取逻辑分析仪】自制底板并驱动ArduinoNanoRP2040ConnectLCD扩展板被打赏47分 | |
【分享评测,赢取加热台】RISC-V GCC 内嵌汇编使用被打赏38分 | |
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 | |
【分享评测,赢取加热台】使用8051单片机驱动WS2812被打赏40分 |