📄 yaffs_guts.cpp
字号:
// Clean it up... bi->blockState = YAFFS_BLOCK_STATE_EMPTY; dev->nErasedBlocks++; bi->pagesInUse = 0; bi->softDeletions = 0; yaffs_ClearChunkBits(dev,blockNo); T(YAFFS_TRACE_ERASE,(TSTR("Erased block %d" TENDSTR),blockNo)); } /*else //BY CEN 不产生坏块 { yaffs_RetireBlock(dev,blockNo); T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo)); }*/}//描述:返回一个空block(blockState == YAFFS_BLOCK_STATE_EMPTY)的号码,如果没有则返回-1static int yaffs_FindBlockForAllocation(yaffs_Device *dev){ int i; yaffs_BlockInfo *bi; if(dev->nErasedBlocks < 1) { // Hoosterman we've got a problem. // Can't get space to gc T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no space during gc" TENDSTR))); return -1; } // Find an empty block. for(i = dev->startBlock; i <= dev->endBlock; i++) { dev->allocationBlockFinder++; if(dev->allocationBlockFinder <dev->startBlock || dev->allocationBlockFinder> dev->endBlock) { dev->allocationBlockFinder = dev->startBlock; } bi = yaffs_GetBlockInfo(dev,dev->allocationBlockFinder); if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY) { bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING; dev->nErasedBlocks--; return dev->allocationBlockFinder; } } return -1; }//描述:分配一个chunk,返回chunkInNAMD,全部都是根据内存中的yaffs_BlockInfo查找,并不用搜索FLASHstatic int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve){ int retVal; yaffs_BlockInfo *bi; if(dev->allocationBlock < 0) //原来的block的chunk已经用完 { // Get next block to allocate off dev->allocationBlock = yaffs_FindBlockForAllocation(dev); //返回一个空block(blockState == YAFFS_BLOCK_STATE_EMPTY)的号码,如果没有则返回-1 dev->allocationPage = 0; } if(!useReserve && dev->nErasedBlocks <= dev->nReservedBlocks) //剩下的擦除块属于保留, { //并且规定不得使用保留块 // Not enough space to allocate unless we're allowed to use the reserve. return -1; } // Next page please.... if(dev->allocationBlock >= 0) { bi = yaffs_GetBlockInfo(dev,dev->allocationBlock); retVal = (dev->allocationBlock * dev->nChunksPerBlock) + dev->allocationPage; //$$$$:返回chunkInNAMD bi->pagesInUse++; yaffs_SetChunkBit(dev,dev->allocationBlock,dev->allocationPage); dev->allocationPage++; dev->nFreeChunks--; // If the block is full set the state to full if(dev->allocationPage >= dev->nChunksPerBlock) { bi->blockState = YAFFS_BLOCK_STATE_FULL; dev->allocationBlock = -1; } return retVal; } T(YAFFS_TRACE_ERROR,(TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR))); return -1; }// To determine if we have enough space we just look at the // number of erased blocks.// The cache is allowed to use reserved blocks.static int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev){ return (dev->nErasedBlocks >= dev->nReservedBlocks);}//描述:回收一个block内有用的chunk,把它们写到一个新blockstatic int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block){ int oldChunk; int newChunk; int chunkInBlock; int markNAND; yaffs_Spare spare; yaffs_Tags tags; __u8 buffer[YAFFS_BYTES_PER_CHUNK]; // yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block); yaffs_Object *object; //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits)); for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock; chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block); chunkInBlock++, oldChunk++ ) { if(yaffs_CheckChunkBit(dev,block,chunkInBlock)) //本次的chunk(chunkInBlock)的bit为1,即数据有效 { // This page is in use and might need to be copied off markNAND = 1; //T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk)); yaffs_ReadChunkFromNAND(dev,oldChunk,buffer, &spare,1); yaffs_GetTagsFromSpare(dev,&spare,&tags); object = yaffs_FindObjectByNumber(dev,tags.objectId); if(object && object->deleted && tags.chunkId != 0) { // Data chunk in a deleted file, throw it away // It's a deleted data chunk, // No need to copy this, just forget about it and fix up the // object. //yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0); //文件被删除了,但它的数据chunk还是有效的,ChunkBit还是为1,在删除文件的时候只是使 //object->deleted为1,并没有对数据chunk进行操作, //在垃圾回收时遇到这样的数据chunk,不用回收,让它在块擦除时被擦掉 object->nDataChunks--; if(object->nDataChunks <= 0) { // Time to delete the file too yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top); object->variant.fileVariant.top = NULL; T(YAFFS_TRACE_TRACING,(TSTR("yaffs: About to finally delete object %d" TENDSTR),object->objectId)); yaffs_DoGenericObjectDeletion(object); } markNAND = 0; } else if( 0 /* Todo object && object->deleted && object->nDataChunks == 0 */) { // Deleted object header with no data chunks. // Can be discarded and the file deleted. object->chunkId = 0; yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top); object->variant.fileVariant.top = NULL; yaffs_DoGenericObjectDeletion(object); } else if(object) { // It's either a data chunk in a live file or // an ObjectHeader, so we're interested in it. // NB Need to keep the ObjectHeaders of deleted files // until the whole file has been deleted off tags.serialNumber++; yaffs_LoadTagsIntoSpare(&spare, &tags); dev->nGCCopies++; newChunk = yaffs_WriteNewChunkToNAND(dev, buffer, &spare,1); //在调用yaffs_WriteNewChunkToNAND()的地方都先yaffs_LoadTagsIntoSpare()初始化好spare if(newChunk < 0) { return YAFFS_FAIL; } // Ok, now fix up the Tnodes etc. if(tags.chunkId == 0) { // It's a header object->chunkId = newChunk; object->serial = tags.serialNumber; } else { // It's a data chunk yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0); //把新的chunkInNAND(newChunk)填到文件的树结构的叶子 } } yaffs_DeleteChunk(dev,oldChunk,markNAND); //清空该chunkInNAND(chunkId)的ChunkBit和该block的信息,markNAND为1,则把spare标为删除并写会FLASH } } return YAFFS_OK;}static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev){ // find a file to delete struct list_head *i; yaffs_Object *l; //Scan the unlinked files looking for one to delete list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children) { if(i) { l = list_entry(i, yaffs_Object,siblings); if(l->deleted) { return l; } } } return NULL;}static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev){ // This does background deletion on unlinked files.. only deleted ones. // If we don't have a file we're working on then find one if(!dev->unlinkedDeletion && dev->nDeletedFiles > 0) { dev->unlinkedDeletion = yaffs_FindDeletedUnlinkedFile(dev); } // OK, we're working on a file... if(dev->unlinkedDeletion) { yaffs_Object *obj = dev->unlinkedDeletion; int delresult; int limit; // Number of chunks to delete in a file. // NB this can be exceeded, but not by much. limit = -1; delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit); if(obj->nDataChunks == 0) { // Done all the deleting of data chunks. // Now dump the header and clean up yaffs_FreeTnode(dev,obj->variant.fileVariant.top); obj->variant.fileVariant.top = NULL; yaffs_DoGenericObjectDeletion(obj); dev->nDeletedFiles--; dev->nUnlinkedFiles--; dev->nBackgroundDeletions++; dev->unlinkedDeletion = NULL; } }}#if 0#define YAFFS_GARBAGE_COLLECT_LOW_WATER 2static int yaffs_CheckGarbageCollection(yaffs_Device *dev){ int block; int aggressive=0; //yaffs_DoUnlinkedFileDeletion(dev); if(dev->nErasedBlocks <= (dev->nReservedBlocks + YAFFS_GARBAGE_COLLECT_LOW_WATER)) { aggressive = 1; } if(aggressive) { block = yaffs_FindDirtiestBlock(dev,aggressive); if(block >= 0) { dev->garbageCollections++; return yaffs_GarbageCollectBlock(dev,block); } else { return YAFFS_FAIL; } } return YAFFS_OK;}#endif// New garbage collector// If we're very low on erased blocks then we do aggressive garbage collection// otherwise we do "passive" garbage collection.// Aggressive gc looks further (whole array) and will accept dirtier blocks.// Passive gc only inspects smaller areas and will only accept cleaner blocks.//// The idea is to help clear out space in a more spread-out manner.// Dunno if it really does anything useful.////描述:找出已经写满并且有用页面最少的块,并回收该block内有用的chunk,把它们写到一个新blockstatic int yaffs_CheckGarbageCollection(yaffs_Device *dev){ int block; int aggressive=0; //yaffs_DoUnlinkedFileDeletion(dev); if(dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) //已擦除干净的块小于保留水准 { aggressive = 1; } block = yaffs_FindDirtiestBlock(dev,aggressive); //找出已经写满并且有用页面最少的块,并返回块号 if(block >= 0) { dev->garbageCollections++; if(!aggressive) { dev->passiveGarbageCollections++; } T(YAFFS_TRACE_GC,(TSTR("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),dev->nErasedBlocks,aggressive)); return yaffs_GarbageCollectBlock(dev,block); //回收一个block内有用的chunk,把它们写到一个新block } return aggressive ? YAFFS_FAIL : YAFFS_OK;}//////////////////////////// TAGS /////////////////////////////////////////描述:计算好tags->ecc,并把tags的相应字段装入到sparestatic void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr){ yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr; yaffs_CalcTagsECC(tagsPtr); sparePtr->tagByte0 = tu->asBytes[0]; sparePtr->tagByte1 = tu->asBytes[1]; sparePtr->tagByte2 = tu->asBytes[2]; sparePtr->tagByte3 = tu->asBytes[3]; sparePtr->tagByte4 = tu->asBytes[4]; sparePtr->tagByte5 = tu->asBytes[5]; sparePtr->tagByte6 = tu->asBytes[6]; sparePtr->tagByte7 = tu->asBytes[7];}static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr){ yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr; int result; tu->asBytes[0]= sparePtr->tagByte0; tu->asBytes[1]= sparePtr->tagByte1; tu->asBytes[2]= sparePtr->tagByte2; tu->asBytes[3]= sparePtr->tagByte3; tu->asBytes[4]= sparePtr->tagByte4; tu->asBytes[5]= sparePtr->tagByte5; tu->asBytes[6]= sparePtr->tagByte6; tu->asBytes[7]= sparePtr->tagByte7; result = yaffs_CheckECCOnTags(tagsPtr); //????:为什么没有错误处理? if(result> 0) { dev->tagsEccFixed++; } else if(result <0) { dev->tagsEccUnfixed++; }}static void yaffs_SpareInitialise(yaffs_Spare *spare){ memset(spare,0xFF,sizeof(yaffs_Spare));}static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags, int *chunkDeleted){ if(tags) { yaffs_Spare spare; if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,NULL,&spare,1) == YAFFS_OK) { *chunkDeleted = (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0; yaffs_GetTagsFromSpare(dev,&spare,tags); return YAFFS_OK; } else { return YAFFS_FAIL; } } return YAFFS_OK;}#if 0static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_Tags *tags){ // NB There must be tags, data is optional // If there is data, then an ECC is calculated on it. yaffs_Spare spare; if(!tags) { return YAFFS_FAIL; } yaffs_SpareInitialise(&spare); //全部设成0xff if(!dev->useNANDECC && buffer) { yaffs_CalcECC(buffer,&spare); } yaffs_LoadTagsIntoSpare(&spare,tags); return yaffs_WriteChunkToNAND(dev,chunkInNAND,buffer,&spare); }#endif//描述:根据tags生成spare,buffer作为数据,分配chunk,并写到FLASH中去,返回写到的chunkInNAMDstatic int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_Tags *tags, int useReserve){ // NB There must be tags, data is optional // If there is data, then an ECC is calculated on it. yaffs_Spare spare; //内存中的yaffs_Tags与FLASH中的yaffs_Spare相对应 if(!tags) { return YAFFS_FAIL; } yaffs_SpareInitialise(&spare); //全部设成0xff yaffs_CalcECC(buffer, &spare); //计算出数据(buffer)的ecc,并放入spare的ecc中 /*if(!dev->useNANDECC && buffer) { yaffs_CalcECC(buffer,&spare); }*/ yaffs_LoadTagsIntoSpare(&spare, tags); //计算好tags->ecc,并把tags的相应字段装入到spare return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve); //在调用yaffs_WriteNewChunkToNAND()的地方都先yaffs_LoadTagsIntoSpare()初始化好spare //把buffer和spare写到FLASH,经过以下各个过程:分配一个chunk,(校验是否擦除OK),写,(读出来校验), //不成功则重写}//描述:如果tags的chunkId和objectId且chunkDeleted为假,则返回真static int yaffs_TagsMatch(const yaffs_Tags *tags, int objectId, int chunkInObject, int chunkDeleted){ return ( tags->chunkId == chunkInObject && tags->objectId == objectId && !chunkDeleted) ? 1 : 0; }//描述:从该文件的树结构中查找该文件(in)的chunkInInode对应的chunkInNAND,从FLASH中一一读取同组所有Chunk,// 找出objectId和chunkInInode符合的Chunk,返回chunkInNAND和从FLASH
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -