📄 yaffs_guts.c
字号:
tags.serialNumber++; yaffs_LoadTagsIntoSpare(&spare,&tags); dev->nGCCopies++; newChunk = yaffs_WriteNewChunkToNAND(dev, buffer, &spare,1); 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); } } yaffs_DeleteChunk(dev,oldChunk,markNAND); } } 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.//static 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); } return aggressive ? YAFFS_FAIL : YAFFS_OK;}//////////////////////////// TAGS ///////////////////////////////////////static 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); if(!dev->useNANDECC && buffer) { yaffs_CalcECC(buffer,&spare); } yaffs_LoadTagsIntoSpare(&spare,tags); return yaffs_WriteChunkToNAND(dev,chunkInNAND,buffer,&spare); }#endifstatic 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; if(!tags) { return YAFFS_FAIL; } yaffs_SpareInitialise(&spare); if(!dev->useNANDECC && buffer) { yaffs_CalcECC(buffer,&spare); } yaffs_LoadTagsIntoSpare(&spare,tags); return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve); }static int yaffs_TagsMatch(const yaffs_Tags *tags, int objectId, int chunkInObject, int chunkDeleted){ return ( tags->chunkId == chunkInObject && tags->objectId == objectId && !chunkDeleted) ? 1 : 0; }int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags){ //Get the Tnode, then get the level 0 offset chunk offset yaffs_Tnode *tn; int theChunk = -1; yaffs_Tags localTags; int i; int found = 0; int chunkDeleted; yaffs_Device *dev = in->myDev; if(!tags) { // Passed a NULL, so use our own tags space tags = &localTags; } tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode); if(tn) { theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits; // Now we need to do the shifting etc and search for it for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++) { yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags,&chunkDeleted); if(yaffs_TagsMatch(tags,in->objectId,chunkInInode,chunkDeleted)) { // found it; found = 1; } else { theChunk++; } } } return found ? theChunk : -1;}int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags){ //Get the Tnode, then get the level 0 offset chunk offset yaffs_Tnode *tn; int theChunk = -1; yaffs_Tags localTags; int i; int found = 0; yaffs_Device *dev = in->myDev; int chunkDeleted; if(!tags) { // Passed a NULL, so use our own tags space tags = &localTags; } tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode); if(tn) { theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits; // Now we need to do the shifting etc and search for it for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++) { yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags,&chunkDeleted); if(yaffs_TagsMatch(tags,in->objectId,chunkInInode,chunkDeleted)) { // found it; found = 1; } else { theChunk++; } } // Delete the entry in the filestructure if(found) { tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = 0; } } else { //T(("No level 0 found for %d\n", chunkInInode)); } if(!found) { //T(("Could not find %d to delete\n",chunkInInode)); } return found ? theChunk : -1;}#ifdef YAFFS_PARANOIDstatic int yaffs_CheckFileSanity(yaffs_Object *in){ int chunk; int nChunks; int fSize; int failed = 0; int objId; yaffs_Tnode *tn; yaffs_Tags localTags; yaffs_Tags *tags = &localTags; int theChunk; int chunkDeleted; if(in->variantType != YAFFS_OBJECT_TYPE_FILE) { //T(("Object not a file\n")); return YAFFS_FAIL; } objId = in->objectId; fSize = in->variant.fileVariant.fileSize; nChunks = (fSize + in->myDev->nBytesPerChunk -1)/in->myDev->nBytesPerChunk; for(chunk = 1; chunk <= nChunks; chunk++) { tn = yaffs_FindLevel0Tnode(in->myDev,&in->variant.fileVariant, chunk); if(tn) { theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << in->myDev->chunkGroupBits; yaffs_ReadChunkTagsFromNAND(in->myDev,theChunk,tags,&chunkDeleted); if(yaffs_TagsMatch(tags,in->objectId,chunk,chunkDeleted)) { // found it; } else { //T(("File problem file [%d,%d] NAND %d tags[%d,%d]\n", // objId,chunk,theChunk,tags->chunkId,tags->objectId); failed = 1; } } else { //T(("No level 0 found for %d\n", chunk)); } } return failed ? YAFFS_FAIL : YAFFS_OK;}#endifstatic int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan){ yaffs_Tnode *tn; yaffs_Device *dev = in->myDev; int existingChunk; yaffs_Tags existingTags; yaffs_Tags newTags; unsigned existingSerial, newSerial; int newChunkDeleted; tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode); if(!tn) { return YAFFS_FAIL; } existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK]; if(inScan) { // If we're scanning then we need to test for duplicates // NB This does not need to be efficient since it should only ever // happen when the power fails during a write, then only one // chunk should ever be affected. if(existingChunk != 0) { // NB Right now existing chunk will not be real chunkId if the device >= 32MB // thus we have to do a FindChunkInFile to get the real chunk id. // // We have a duplicate now we need to decide which one to use // To do this we get both sets of tags and compare serial numbers. yaffs_ReadChunkTagsFromNAND(dev,chunkInNAND, &newTags,&newChunkDeleted); // Do a proper find existingChunk = yaffs_FindChunkInFile(in,chunkInInode, &existingTags); if(existingChunk <=0) { //Hoosterman - how did this happen? T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: existing chunk < 0 in scan" TENDSTR))); } // NB The deleted flags should be false, otherwise the chunks will // not be loaded during a scan newSerial = newTags.serialNumber; existingSerial = existingTags.serialNumber; if( existingChunk <= 0 || ((existingSerial+1) & 3) == newSerial) { // Use new // Delete the old one and drop through to update the tnode yaffs_DeleteChunk(dev,existingChunk,1); } else { // Use existing. // Delete the new one and return early so that the tnode isn't changed yaffs_DeleteChunk(dev,chunkInNAND,1); return YAFFS_OK; } } } if(existingChunk == 0) { in->nDataChunks++; } tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = (chunkInNAND >> dev->chunkGroupBits); return YAFFS_OK;}int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer){ int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL); if(chunkInNAND >= 0) { return yaffs_ReadChunkFromNAND(in->myDev,chunkInNAND,buffer,NULL,1); } else { memset(buffer,0,YAFFS_BYTES_PER_CHUNK); return 0; }}static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND){ int block; int page; yaffs_Spare spare; yaffs_BlockInfo *bi; if(chunkId <=
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -