打了一晚的麻将,渐渐啊有手感了。午夜 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 时候,需要补齐 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.