X-Git-Url: https://yaffs.net/gitweb/?a=blobdiff_plain;f=yaffs_guts.c;h=cad48e69c5295409442d5b2f9869f59a18f7bc32;hb=e721e0888655c325e5d5477ae121ff325f2847c0;hp=c81b1e7e35ba5aeb671da38397a10965606f0183;hpb=b0b91352fff81d01d34fd562629ce199c255cdd6;p=yaffs2.git diff --git a/yaffs_guts.c b/yaffs_guts.c index c81b1e7..cad48e6 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -12,7 +12,7 @@ */ const char *yaffs_guts_c_version = - "$Id: yaffs_guts.c,v 1.49 2007-05-15 20:07:40 charles Exp $"; + "$Id: yaffs_guts.c,v 1.53 2007-12-03 03:21:48 charles Exp $"; #include "yportenv.h" @@ -920,86 +920,88 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, yaffs_ExtendedTags * tags, int useReserve) { + int attempts = 0; + int writeOk = 0; int chunk; - int writeOk = 0; - int erasedOk = 1; - int attempts = 0; - yaffs_BlockInfo *bi; - yaffs_InvalidateCheckpoint(dev); do { - chunk = yaffs_AllocateChunk(dev, useReserve,&bi); - - if (chunk >= 0) { - /* First check this chunk is erased, if it needs checking. - * The checking policy (unless forced always on) is as follows: - * Check the first page we try to write in a block. - * - If the check passes then we don't need to check any more. - * - If the check fails, we check again... - * If the block has been erased, we don't need to check. - * - * However, if the block has been prioritised for gc, then - * we think there might be something odd about this block - * and stop using it. - * - * Rationale: - * We should only ever see chunks that have not been erased - * if there was a partially written chunk due to power loss - * This checking policy should catch that case with very - * few checks and thus save a lot of checks that are most likely not - * needed. - */ - - if(bi->gcPrioritise){ - yaffs_DeleteChunk(dev, chunk, 1, __LINE__); - } else { -#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED + yaffs_BlockInfo *bi = 0; + int erasedOk = 0; - bi->skipErasedCheck = 0; + chunk = yaffs_AllocateChunk(dev, useReserve, &bi); + if (chunk < 0) { + /* no space */ + break; + } -#endif - if(!bi->skipErasedCheck){ - erasedOk = yaffs_CheckChunkErased(dev, chunk); - if(erasedOk && !bi->gcPrioritise) - bi->skipErasedCheck = 1; - } + /* First check this chunk is erased, if it needs + * checking. The checking policy (unless forced + * always on) is as follows: + * + * Check the first page we try to write in a block. + * If the check passes then we don't need to check any + * more. If the check fails, we check again... + * If the block has been erased, we don't need to check. + * + * However, if the block has been prioritised for gc, + * then we think there might be something odd about + * this block and stop using it. + * + * Rationale: We should only ever see chunks that have + * not been erased if there was a partially written + * chunk due to power loss. This checking policy should + * catch that case with very few checks and thus save a + * lot of checks that are most likely not needed. + */ + if (bi->gcPrioritise) { + yaffs_DeleteChunk(dev, chunk, 1, __LINE__); + /* try another chunk */ + continue; + } - if (!erasedOk) { - T(YAFFS_TRACE_ERROR, - (TSTR - ("**>> yaffs chunk %d was not erased" - TENDSTR), chunk)); - } else { - writeOk = - yaffs_WriteChunkWithTagsToNAND(dev, chunk, - data, tags); - } - - attempts++; + /* let's give it a try */ + attempts++; - if (writeOk) { - /* - * Copy the data into the robustification buffer. - * NB We do this at the end to prevent duplicates in the case of a write error. - * Todo - */ - yaffs_HandleWriteChunkOk(dev, chunk, data, tags); - - } else { - /* The erased check or write failed */ - yaffs_HandleWriteChunkError(dev, chunk, erasedOk); - } +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED + bi->skipErasedCheck = 0; +#endif + if (!bi->skipErasedCheck) { + erasedOk = yaffs_CheckChunkErased(dev, chunk); + if (erasedOk != YAFFS_OK) { + T(YAFFS_TRACE_ERROR, + (TSTR ("**>> yaffs chunk %d was not erased" + TENDSTR), chunk)); + + /* try another chunk */ + continue; } + bi->skipErasedCheck = 1; } - } while (chunk >= 0 && !writeOk); + writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk, + data, tags); + if (writeOk != YAFFS_OK) { + yaffs_HandleWriteChunkError(dev, chunk, erasedOk); + /* try another chunk */ + continue; + } + + /* Copy the data into the robustification buffer */ + yaffs_HandleWriteChunkOk(dev, chunk, data, tags); + + } while (writeOk != YAFFS_OK && + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); + + if(!writeOk) + chunk = -1; if (attempts > 1) { T(YAFFS_TRACE_ERROR, - (TSTR("**>> yaffs write required %d attempts" TENDSTR), - attempts)); + (TSTR("**>> yaffs write required %d attempts" TENDSTR), + attempts)); + dev->nRetriedWrites += (attempts - 1); } @@ -1144,6 +1146,10 @@ static int yaffs_CreateTnodes(yaffs_Device * dev, int nTnodes) * Must be a multiple of 32-bits */ tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + if(tnodeSize < sizeof(yaffs_Tnode)) + tnodeSize = sizeof(yaffs_Tnode); + + /* make these things */ newTnodes = YMALLOC(nTnodes * tnodeSize); @@ -1234,15 +1240,21 @@ static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device * dev) dev->nFreeTnodes--; } + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ + return tn; } static yaffs_Tnode *yaffs_GetTnode(yaffs_Device * dev) { yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev); + int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + + if(tnodeSize < sizeof(yaffs_Tnode)) + tnodeSize = sizeof(yaffs_Tnode); if(tn) - memset(tn, 0, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); + memset(tn, 0, tnodeSize); return tn; } @@ -1263,6 +1275,8 @@ static void yaffs_FreeTnode(yaffs_Device * dev, yaffs_Tnode * tn) dev->freeTnodes = tn; dev->nFreeTnodes++; } + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ + } static void yaffs_DeinitialiseTnodes(yaffs_Device * dev) @@ -1907,6 +1921,8 @@ static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device * dev) yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn); } } + + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ return tn; } @@ -1968,6 +1984,9 @@ static void yaffs_FreeObject(yaffs_Object * tn) tn->siblings.next = (struct list_head *)(dev->freeObjects); dev->freeObjects = tn; dev->nFreeObjects++; + + dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ + } #ifdef __KERNEL__ @@ -2591,7 +2610,6 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev, int pagesInUse = 0; int prioritised=0; yaffs_BlockInfo *bi; - static int nonAggressiveSkip = 0; int pendingPrioritisedExist = 0; /* First let's see if we need to grab a prioritised block */ @@ -2623,9 +2641,9 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev, * block has only a few pages in use. */ - nonAggressiveSkip--; + dev->nonAggressiveSkip--; - if (!aggressive && (nonAggressiveSkip > 0)) { + if (!aggressive && (dev->nonAggressiveSkip > 0)) { return -1; } @@ -2686,7 +2704,7 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev, dev->oldestDirtySequence = 0; if (dirtiest > 0) { - nonAggressiveSkip = 4; + dev->nonAggressiveSkip = 4; } return dirtiest; @@ -2803,6 +2821,40 @@ static int yaffs_FindBlockForAllocation(yaffs_Device * dev) } + +static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev) +{ + if(!dev->nCheckpointBlocksRequired){ + /* Not a valid value so recalculate */ + int nBytes = 0; + int nBlocks; + int devBlocks = (dev->endBlock - dev->startBlock + 1); + int tnodeSize; + + tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + + if(tnodeSize < sizeof(yaffs_Tnode)) + tnodeSize = sizeof(yaffs_Tnode); + + nBytes += sizeof(yaffs_CheckpointValidity); + nBytes += sizeof(yaffs_CheckpointDevice); + nBytes += devBlocks * sizeof(yaffs_BlockInfo); + nBytes += devBlocks * dev->chunkBitmapStride; + nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects); + nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes); + nBytes += sizeof(yaffs_CheckpointValidity); + nBytes += sizeof(__u32); /* checksum*/ + + /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */ + + nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3; + + dev->nCheckpointBlocksRequired = nBlocks; + } + + return dev->nCheckpointBlocksRequired; +} + // 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) @@ -2811,7 +2863,7 @@ static int yaffs_CheckSpaceForAllocation(yaffs_Device * dev) int reservedBlocks = dev->nReservedBlocks; int checkpointBlocks; - checkpointBlocks = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; + checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; if(checkpointBlocks < 0) checkpointBlocks = 0; @@ -3144,7 +3196,7 @@ static int yaffs_CheckGarbageCollection(yaffs_Device * dev) do { maxTries++; - checkpointBlockAdjust = (dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint); + checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; if(checkpointBlockAdjust < 0) checkpointBlockAdjust = 0; @@ -4222,7 +4274,11 @@ static int yaffs_CheckpointTnodeWorker(yaffs_Object * in, yaffs_Tnode * tn, int i; yaffs_Device *dev = in->myDev; int ok = 1; - int nTnodeBytes = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + + if(tnodeSize < sizeof(yaffs_Tnode)) + tnodeSize = sizeof(yaffs_Tnode); + if (tn) { if (level > 0) { @@ -4240,7 +4296,7 @@ static int yaffs_CheckpointTnodeWorker(yaffs_Object * in, yaffs_Tnode * tn, /* printf("write tnode at %d\n",baseOffset); */ ok = (yaffs_CheckpointWrite(dev,&baseOffset,sizeof(baseOffset)) == sizeof(baseOffset)); if(ok) - ok = (yaffs_CheckpointWrite(dev,tn,nTnodeBytes) == nTnodeBytes); + ok = (yaffs_CheckpointWrite(dev,tn,tnodeSize) == tnodeSize); } } @@ -4274,7 +4330,11 @@ static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj) yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant; yaffs_Tnode *tn; int nread = 0; - + int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; + + if(tnodeSize < sizeof(yaffs_Tnode)) + tnodeSize = sizeof(yaffs_Tnode); + ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk)); while(ok && (~baseChunk)){ @@ -4285,8 +4345,7 @@ static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj) /* printf("read tnode at %d\n",baseChunk); */ tn = yaffs_GetTnodeRaw(dev); if(tn) - ok = (yaffs_CheckpointRead(dev,tn,(dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8) == - (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); + ok = (yaffs_CheckpointRead(dev,tn,tnodeSize) == tnodeSize); else ok = 0; @@ -5007,7 +5066,7 @@ int yaffs_ResizeFile(yaffs_Object * in, loff_t newSize) (newSize < oldFileSize) ? 1 : 0, 0); } - return newSize; + return YAFFS_OK; } loff_t yaffs_GetFileSize(yaffs_Object * obj) @@ -6057,7 +6116,7 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) #ifndef CONFIG_YAFFS_USE_OWN_SORT { /* Use qsort now. */ - qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); + yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); } #else { @@ -7414,7 +7473,7 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev) nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); /* Now we figure out how much to reserve for the checkpoint and report that... */ - blocksForCheckpoint = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; + blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; if(blocksForCheckpoint < 0) blocksForCheckpoint = 0;