*/
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"
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);
}
* 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);
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;
}
dev->freeTnodes = tn;
dev->nFreeTnodes++;
}
+ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
+
}
static void yaffs_DeinitialiseTnodes(yaffs_Device * dev)
yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
}
}
+
+ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
return tn;
}
tn->siblings.next = (struct list_head *)(dev->freeObjects);
dev->freeObjects = tn;
dev->nFreeObjects++;
+
+ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
+
}
#ifdef __KERNEL__
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 */
* block has only a few pages in use.
*/
- nonAggressiveSkip--;
+ dev->nonAggressiveSkip--;
- if (!aggressive && (nonAggressiveSkip > 0)) {
+ if (!aggressive && (dev->nonAggressiveSkip > 0)) {
return -1;
}
dev->oldestDirtySequence = 0;
if (dirtiest > 0) {
- nonAggressiveSkip = 4;
+ dev->nonAggressiveSkip = 4;
}
return dirtiest;
}
+
+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)
int reservedBlocks = dev->nReservedBlocks;
int checkpointBlocks;
- checkpointBlocks = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint;
+ checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
if(checkpointBlocks < 0)
checkpointBlocks = 0;
do {
maxTries++;
- checkpointBlockAdjust = (dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint);
+ checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
if(checkpointBlockAdjust < 0)
checkpointBlockAdjust = 0;
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) {
/* 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);
}
}
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)){
/* 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;
(newSize < oldFileSize) ? 1 : 0, 0);
}
- return newSize;
+ return YAFFS_OK;
}
loff_t yaffs_GetFileSize(yaffs_Object * obj)
#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
{
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;