转自:http://blog.mcuol.com/User/johnyshark/Article/9477_1.htm
打了一晚的麻将,渐渐啊有手感了。午夜2点回宿舍睡觉了,7月1日,一早8点起床,北京今天难得的出太阳了,看了会杂志,继续研究代码吧。昨天bootlstst.c 就算看完了,相当失望啊!居然无用啊!感叹一下先辈们做研究也不容易啊,我接下来看dtest.c。
Dtest就是调用BeatsTest函数。
进入这个函数,先是yaffs_startup(),初始化几个DEV的一些参数。然后yaffs_mount(“/ram”)。yaffs_mount函数目前在我的代码中不能正确调用,所以,下面研究这个函数。
yaffs_mount函数写得比较简洁,主要就是找到DEV,然后yaffs_GutsInitialise(dev);
再进入这个函数yaffs_GutsInitialise(),在yaffs_guts.c中。
字面上理解,gut是内脏的意思,所以该函数差不多就是初始化yaffs的各个基本函数吧。
yaffs_GutsInitialise()初始化完yaffs_Device结构的各项参数后,就进行yaffs_scan()了,这真是个恼人的函数啊。
下面是关于yaffs_scan函数的理解。
进入yaffs_scan函数,首先是一个大循环A,对每一个block,标出bad block,对正常block,又是个循环B,对其中的每一个chunk进行处理。
在循环B内部,读该chunk的spare,把spare结构转化为Tags结构。
然后对这个chunk作各种判断,以实行不同的操作:
1. 若spare结构中(char)pageStatus中“1”的位数<6,则该chunk是一个删除了的chunk;
2. 若tags结构中的ObjectID==yaffs_unused_object_id;
则1)若是第0个chunk,则该Block未被使用
2)否则,该Block为当前正在分配的Block.
3. 若tags结构中chunkID>0,表明是一个datachunk(相对ObjectHeader而言),则setChunkBits()(作用后面说),然后yaffs_FindOrCreateObjectByNumber(),该函数根据ObjectID找到(或创建并找到)一个yaffs_Object_Type_File类型的yaffs_Object。然后通过yaffs_putChunkIntoFile,将当前的chunk加入到某个File(其实是Object的TreeNode中)。
yaffs_putChunkIntoFile()函数后面会具体解释。
4. 若tags结构中chunkID==0,表明是一个ObjectHeader,也就是说该chunk的data区域可以转化为一个yaffs_ObjectHeader结构。然后setChunkBits(),再将该chunk的data读出后转化为一个yaffs_ObjectHeader结构,用yaffs_FindOrCreateObjectByNumber()函数根据ObjectID找到(或创建并找到)一个yaffs_ObjectHeader->ObjectTyep类型的yaffs_Object。
关于yaffs_scan函数的解析还没有完呢,等过阵子吧。
上面提到的clearChunkBits(dev,blk);
setChunkBits(dev,blk);
有什么用呢?
系统在yaffs_Struct结构中维护着一张位图bitmap,该位图每一位都代表着flash上一个chunk的状态,yaffs_SetChunkBits()讲刚分配得到的chunk在位图中对于位置置1,表明该chunk已经使用。
yaffs_PutChunkIntoFile()函数的代码理解,字面意思就是将一个chunk归到一个file中去。
static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan),这里有个非常值得注意的地方,单从函数的字面意思是没法了解到的。
yaffs_PutChunkIntoFile()函数有这样一个注释:
// PutChunkIntoFIle checks for a clash (two data chunks with
// the same chunkId).
注释中提到的情况发生在突然掉电时候,新的chunk已经写好了,但是旧的没有删除,所以在scan的时候把旧的删除了。
首先调用了tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
那么先进入这个函数yaffs_AddOrFindLevel0Tnode()吧
首先是根据chunkInTnode计算出Tnode Tree的高度x.
3bits 3bits 3bits ~~~~~~~~~ 4bits
|--------|--------|--------|~~~~~~~~~~~|------------| (这一行表示chunkInTnode)
x x-1 x-2 0
注意,每个3bits的值都是非零的。此时的x称为requiredTallness.
而fStruct中有个(int)topLevel,所以当topLevel<REQUIREDTALLNESS< span="">时候,需要补齐Tallness
补齐Tallness后,进入一个while循环:
从fStruct->top(是一个Tnode)开始,根据chunkInTnode从高到低位每次用3bits做index依次往下搜索,tn->interna[i](其中tn是一个Tnode,i是每3bits的值)就是下一级的Tnode,若不存在该Tnode,创建后继续往下遍历。找到最后一个Tnode后,返回,由此,已经找到(或创建并找到)了该chunkInInode号对应的chunk在Tnode Tree中的位置。返回该Chunk对应的Tnode.
从yaffs_AddOrFindLevel0Tnode()函数返回。
然后,existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];
此处得到了chunkIdInNAND。
(这里有个注意点,Tnode->level0[]是 U16型的,因此只能表示2^16个chunk,每个Chunk是512Byte,一共是2^6×1K×512Byte = 32MByte),当flash的容量(确切的说是Partiation的容量)大于32M时,existingChunk表示的值不是真正的chunkIdInNAND.)
下面的一段程序只在scan过程执行。
1. 若existingChunk!=0,读取当前chunkIdInNAND的Tags结构,放在NewTags里边。
然后通过函数yaffs_FindChunkInFile()函数找出真正的existingChunk号,并且读出 existingChunk的Tags到existingTags。
如果existingChunk <=0,那么就是说没找到真正的existingChunk号。
出错信息: “yaffs tragedy: existing chunk < 0 in scan”
newSerial = newTags.serialNumber;
existingSerial = existingTags.serialNumber;
然后
如果( existingChunk <= 0 || ((existingSerial+1) & 3) == newSerial),那么就用新的 chunk,删除旧的,yaffs_DeleteChunk(dev,existingChunk,1)。
否则,用旧的,删除新的,yaffs_DeleteChunk(dev,chunkInNAND,1);因为用的旧的chunk,
所以Tnode Tree也不用改了,提前返回。
2. 若existingChunk==0;说明没有冲突啊,则in->nDataChunks++;
(上边讲到的yaffs_FindChunkInFile()函数是怎么工作的呢?
int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags)
首先根据in和chunkInInode找到对应的level0的Tnode(令为tn)
然后,
从tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits这个chunkId开始,搜索chunkGroupSize次,读每个chunk的Tags,看Tags结构中ObjectId,以及chunkInInode号是否符合,找到后将tags给参数。若找到,返回chunkIdInNAND,否则,返回-1.)
最后,把新的chunk放到Tnode里边去。
现在的问题是,总是报错:“yaffs tragedy: existing chunk < 0 in scan”。
我的猜测是这样的,NAND的每个chunk中,spare部分的信息在原始状态下就不正确,使得不能正常mount.