📄 yaffs_guts.c
字号:
int chunksBefore = yaffs_GetErasedChunks(dev); int chunksAfter; yaffs_ExtendedTags tags; yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block); yaffs_Object *object; 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 (!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); } } } 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; 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++; if (dev->nErasedBlocks < dev->nReservedBlocks) { /* 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(("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 = yaffs_GetChunkGroupBase(dev,tn,chunk); if (yaffs_CheckChunkBits (dev, theChunk / dev->nChunksPerBlock, theChunk % dev->nChunksPerBlock)) { yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk, tags, &chunkDeleted); if (yaffs_TagsMatch (tags, in->objectId, chunk, chunkDeleted)) { /* found it; */ } } else { 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){ /* NB inScan is zero unless scanning. * For forward scanning, inScan is > 0; * for backward scanning inScan is < 0 */ yaffs_Tnode *tn; yaffs_Device *dev = in->myDev; int existingChunk; yaffs_ExtendedTags existingTags; yaffs_ExtendedTags newTags; unsigned existingSerial, newSerial; if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { /* Just ignore an attempt at putting a chunk into a non-file during scanning * If it is not during Scanning then something went wrong! */ if (!inScan) { T(YAFFS_TRACE_ERROR, (TSTR ("yaffs tragedy:attempt to put data chunk into a non-file" TENDSTR))); YBUG(); } yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); return YAFFS_OK; } tn = yaffs_AddOrFindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode); if (!tn) { return YAFFS_FAIL; } existingChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode); if (inScan != 0) { /* 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. * * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO * Update: For backward scanning we don't need to re-read tags so this is quite cheap. */ 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: * * Backwards scanning YAFFS2: The old one is what we use, dump the new one. * Forward scanning YAFFS2: The new one is what we use, dump the old one. * YAFFS1: Get both sets of tags and compare serial numbers. */ if (inScan > 0) { /* Only do this for forward scanning */ yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, NULL, &newTags); /* 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 ((inScan > 0) && (in->myDev->isYaffs2 || existingChunk <= 0 || ((existingSerial + 1) & 3) == newSerial)) { /* Forward scanning. * Use new * Delete the old one and drop through to update the tnode */ yaffs_DeleteChunk(dev, existingChunk, 1, __LINE__); } else { /* Backward scanning or we want to use the existing one * Use existing. * Delete the new one and return early so that the tnode isn't changed */ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); return YAFFS_OK; } } } if (existingChunk == 0) { in->nDataChunks++; } yaffs_PutLevel0Tnode(dev,tn,chunkInInode,chunkInNAND); return YAFFS_OK;}static int yaffs_ReadChunkDataFromObject(yaffs_Object * in, int chunkInInode, __u8 * buffer){ int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL); if (chunkInNAND >= 0) { return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND, buffer, NULL); } else { T(YAFFS_TRACE_NANDACCESS, (TSTR("Chunk %d not found zero instead" TENDSTR), chunkInNAND)); /* get sane (zero) data if you read a hole */ memset(buffer, 0, in->myDev->nBytesPerChunk); return 0; }}void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn){ int block; int page; yaffs_ExtendedTags tags; yaffs_BlockInfo *bi; if
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -