📄 yaffs_guts.c
字号:
int i; for (i = 0; i < dev->nChunksPerBlock; i++) { if (!yaffs_CheckChunkErased (dev, blockNo * dev->nChunksPerBlock + i)) { T(YAFFS_TRACE_ERROR, (TSTR (">>Block %d erasure supposedly OK, but chunk %d not erased" TENDSTR), blockNo, i)); } } } if (erasedOk) { /* Clean it up... */ bi->blockState = YAFFS_BLOCK_STATE_EMPTY; dev->nErasedBlocks++; bi->pagesInUse = 0; bi->softDeletions = 0; bi->hasShrinkHeader = 0; bi->skipErasedCheck = 1; /* This is clean, so no need to check */ bi->gcPrioritise = 0; yaffs_ClearChunkBits(dev, blockNo); T(YAFFS_TRACE_ERASE, (TSTR("Erased block %d" TENDSTR), blockNo)); } else { dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */ yaffs_RetireBlock(dev, blockNo); T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, (TSTR("**>> Block %d retired" TENDSTR), blockNo)); }}static 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 more eraased blocks" TENDSTR))); return -1; } /* Find an empty block. */ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { dev->allocationBlockFinder++; if (dev->allocationBlockFinder < dev->internalStartBlock || dev->allocationBlockFinder > dev->internalEndBlock) { dev->allocationBlockFinder = dev->internalStartBlock; } bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder); if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) { bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING; dev->sequenceNumber++; bi->sequenceNumber = dev->sequenceNumber; dev->nErasedBlocks--; T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocated block %d, seq %d, %d left" TENDSTR), dev->allocationBlockFinder, dev->sequenceNumber, dev->nErasedBlocks)); return dev->allocationBlockFinder; } } T(YAFFS_TRACE_ALWAYS, (TSTR ("yaffs tragedy: no more eraased blocks, but there should have been %d" TENDSTR), dev->nErasedBlocks)); return -1;}// Check if there's space to allocate...// Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?static int yaffs_CheckSpaceForAllocation(yaffs_Device * dev){ int reservedChunks; int reservedBlocks = dev->nReservedBlocks; int checkpointBlocks; checkpointBlocks = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; if(checkpointBlocks < 0) checkpointBlocks = 0; reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock); return (dev->nFreeChunks > reservedChunks);}static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr){ int retVal; yaffs_BlockInfo *bi; if (dev->allocationBlock < 0) { /* Get next block to allocate off */ dev->allocationBlock = yaffs_FindBlockForAllocation(dev); dev->allocationPage = 0; } if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) { /* Not enough space to allocate unless we're allowed to use the reserve. */ return -1; } if (dev->nErasedBlocks < dev->nReservedBlocks && dev->allocationPage == 0) { T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR))); } /* Next page please.... */ if (dev->allocationBlock >= 0) { bi = yaffs_GetBlockInfo(dev, dev->allocationBlock); retVal = (dev->allocationBlock * dev->nChunksPerBlock) + dev->allocationPage; 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; } if(blockUsedPtr) *blockUsedPtr = bi; return retVal; } T(YAFFS_TRACE_ERROR, (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR))); return -1;}static int yaffs_GetErasedChunks(yaffs_Device * dev){ int n; n = dev->nErasedBlocks * dev->nChunksPerBlock; if (dev->allocationBlock > 0) { n += (dev->nChunksPerBlock - dev->allocationPage); } return n;}static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block){ int oldChunk; int newChunk; int chunkInBlock; int markNAND; int retVal = YAFFS_OK; int cleanups = 0; int i; int isCheckpointBlock; int chunksBefore = yaffs_GetErasedChunks(dev); int chunksAfter; yaffs_ExtendedTags tags; yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block); yaffs_Object *object; isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT); bi->blockState = YAFFS_BLOCK_STATE_COLLECTING; T(YAFFS_TRACE_TRACING, (TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR), block, bi->pagesInUse, bi->hasShrinkHeader)); /*yaffs_VerifyFreeChunks(dev); */ bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */ /* Take off the number of soft deleted entries because * they're going to get really deleted during GC. */ dev->nFreeChunks -= bi->softDeletions; dev->isDoingGC = 1; if (isCheckpointBlock || !yaffs_StillSomeChunkBits(dev, block)) { T(YAFFS_TRACE_TRACING, (TSTR ("Collecting block %d that has no chunks in use" TENDSTR), block)); yaffs_BlockBecameDirty(dev, block); } else { __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); for (chunkInBlock = 0, oldChunk = block * dev->nChunksPerBlock; chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev, block); chunkInBlock++, oldChunk++) { if (yaffs_CheckChunkBit(dev, block, chunkInBlock)) { /* This page is in use and might need to be copied off */ markNAND = 1; yaffs_InitialiseTags(&tags); yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk, buffer, &tags); object = yaffs_FindObjectByNumber(dev, tags.objectId); T(YAFFS_TRACE_GC_DETAIL, (TSTR ("Collecting page %d, %d %d %d " TENDSTR), chunkInBlock, tags.objectId, tags.chunkId, tags.byteCount)); if (!object) { T(YAFFS_TRACE_ERROR, (TSTR ("page %d in gc has no object " TENDSTR), oldChunk)); } if (object && object->deleted && tags.chunkId != 0) { /* Data chunk in a deleted file, throw it away * It's a soft deleted data chunk, * No need to copy this, just forget about it and * fix up the object. */ object->nDataChunks--; if (object->nDataChunks <= 0) { /* remeber to clean up the object */ dev->gcCleanupList[cleanups] = tags.objectId; cleanups++; } 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++; dev->nGCCopies++; if (tags.chunkId == 0) { /* It is an object Id, * We need to nuke the shrinkheader flags first * We no longer want the shrinkHeader flag since its work is done * and if it is left in place it will mess up scanning. * Also, clear out any shadowing stuff */ yaffs_ObjectHeader *oh; oh = (yaffs_ObjectHeader *)buffer; oh->isShrink = 0; oh->shadowsObject = -1; tags.extraShadows = 0; tags.extraIsShrinkHeader = 0; } newChunk = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1); if (newChunk < 0) { retVal = YAFFS_FAIL; } else { /* 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, __LINE__); } } yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); /* Do any required cleanups */ for (i = 0; i < cleanups; i++) { /* Time to delete the file too */ object = yaffs_FindObjectByNumber(dev, dev->gcCleanupList[i]); if (object) { yaffs_FreeTnode(dev, object->variant.fileVariant. top); object->variant.fileVariant.top = NULL; T(YAFFS_TRACE_GC, (TSTR ("yaffs: About to finally delete object %d" TENDSTR), object->objectId)); yaffs_DoGenericObjectDeletion(object); object->myDev->nDeletedFiles--; } } } if (chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev))) { T(YAFFS_TRACE_GC, (TSTR ("gc did not increase free chunks before %d after %d" TENDSTR), chunksBefore, chunksAfter)); } dev->isDoingGC = 0; return YAFFS_OK;}/* New garbage collector * If we're very low on erased blocks then we do aggressive garbage collection * otherwise we do "leasurely" garbage collection. * Aggressive gc looks further (whole array) and will accept less dirty blocks. * Passive gc only inspects smaller areas and will only accept more dirty 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; int gcOk = YAFFS_OK; int maxTries = 0; int checkpointBlockAdjust; if (dev->isDoingGC) { /* Bail out so we don't get recursive gc */ return YAFFS_OK; } /* This loop should pass the first time. * We'll only see looping here if the erase of the collected block fails. */ do { maxTries++; checkpointBlockAdjust = (dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint); if(checkpointBlockAdjust < 0) checkpointBlockAdjust = 0; if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust)) { /* We need a block soon...*/ aggressive = 1; } else { /* We're in no hurry */ aggressive = 0; } block = yaffs_FindBlockForGarbageCollection(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)); gcOk = yaffs_GarbageCollectBlock(dev, block); } if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) { T(YAFFS_TRACE_GC, (TSTR ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" TENDSTR), dev->nErasedBlocks, maxTries, block)); } } while ((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0) && (maxTries < 2)); return aggressive ? gcOk : YAFFS_OK;}/*------------------------- TAGS --------------------------------*/static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId, int chunkInObject){ return (tags->chunkId == chunkInObject && tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;}/*-------------------- Data file manipulation -----------------*/static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode, yaffs_ExtendedTags * tags){ /*Get the Tnode, then get the level 0 offset chunk offset */ yaffs_Tnode *tn; int theChunk = -1; yaffs_ExtendedTags localTags; int retVal = -1; 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 = yaffs_GetChunkGroupBase(dev,tn,chunkInInode); retVal = yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, chunkInInode); } return retVal;}static int yaffs_FindAndDeleteChunkInFile(yaffs_Object * in, int chunkInInode, yaffs_ExtendedTags * tags){ /* Get the Tnode, then get the level 0 offset chunk offset */ yaffs_Tnode *tn; int theChunk = -1; yaffs_ExtendedTags localTags; yaffs_Device *dev = in->myDev; int retVal = -1; if (!tags) { /* Passed a NULL, so use our own tags space */ tags = &localTags; } tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode); if (tn) { theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode); retVal = yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, chunkInInode); /* Delete the entry in the filestructure (if found) */ if (retVal != -1) { yaffs_PutLevel0Tnode(dev,tn,chunkInInode,0); } } else { /*T(("No level 0 found for %d\n", chunkInInode)); */ } if (retVal == -1) { /* T(("Could not find %d to delete\n",chunkInInode)); */ } return retVal;}#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(("Objec
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -