*/
const char *yaffs_guts_c_version =
- "$Id: yaffs_guts.c,v 1.98 2009-12-07 01:17:33 charles Exp $";
+ "$Id: yaffs_guts.c,v 1.101 2009-12-25 01:53:05 charles Exp $";
#include "yportenv.h"
yaffs_FileStructure *fStruct,
__u32 chunkId);
+static void yaffs_SkipRestOfBlock(yaffs_Device *dev);
+static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
+ int chunkInNAND,
+ const __u8 *data,
+ yaffs_ExtendedTags *tags);
+
/* Function to calculate chunk and offset */
static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
if (!(tags && obj && oh)) {
T(YAFFS_TRACE_VERIFY,
- (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR),
- (__u32)tags, (__u32)obj, (__u32)oh));
+ (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
+ tags, obj, oh));
return;
}
}
+
+static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
+ int chunkInNAND,
+ const __u8 *data,
+ yaffs_ExtendedTags *tags)
+{
+ int retval = YAFFS_OK;
+ yaffs_ExtendedTags tempTags;
+ __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
+ int result;
+
+ result = yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,&tempTags);
+ if(memcmp(buffer,data,dev->nDataBytesPerChunk) ||
+ tempTags.objectId != tags->objectId ||
+ tempTags.chunkId != tags->chunkId ||
+ tempTags.byteCount != tags->byteCount)
+ retval = YAFFS_FAIL;
+
+ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
+
+ return retval;
+}
+
static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
const __u8 *data,
yaffs_ExtendedTags *tags,
* 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.
+ *
+ * Mods to the above
+ * If an erase check fails or the write fails we skip the
+ * rest of the block.
*/
- if (bi->gcPrioritise) {
- yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
- /* try another chunk */
- continue;
- }
/* let's give it a try */
attempts++;
(TSTR("**>> yaffs chunk %d was not erased"
TENDSTR), chunk));
- /* try another chunk */
+ /* If not erased, delete this one,
+ * skip rest of block and
+ * try another chunk */
+ yaffs_DeleteChunk(dev,chunk,1,__LINE__);
+ yaffs_SkipRestOfBlock(dev);
continue;
}
- bi->skipErasedCheck = 1;
}
writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
data, tags);
+
+ if(!bi->skipErasedCheck)
+ writeOk = yaffs_VerifyChunkWritten(dev, chunk, data, tags);
+
if (writeOk != YAFFS_OK) {
+ /* Clean up aborted write, skip to next block and
+ * try another chunk */
yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
- /* try another chunk */
continue;
}
+ bi->skipErasedCheck = 1;
+
/* Copy the data into the robustification buffer */
yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
/* Delete the chunk */
yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
+ yaffs_SkipRestOfBlock(dev);
}
if (tn) {
hasData = 0;
- for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
- if (tn->internal[i] && level > 0) {
- tn->internal[i] =
- yaffs_PruneWorker(dev, tn->internal[i],
- level - 1,
- (i == 0) ? del0 : 1);
- }
+ if(level > 0){
+ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
+ if (tn->internal[i]) {
+ tn->internal[i] =
+ yaffs_PruneWorker(dev, tn->internal[i],
+ level - 1,
+ (i == 0) ? del0 : 1);
+ }
+
+ if (tn->internal[i])
+ hasData++;
+ }
+ } else {
+ int tnodeSize;
+ __u32 *map = (__u32 *)tn;
+ tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
- if (tn->internal[i])
- hasData++;
- }
+ if (tnodeSize < sizeof(yaffs_Tnode))
+ tnodeSize = sizeof(yaffs_Tnode);
+ tnodeSize /= sizeof(__u32);
+
+ for(i = 0; !hasData && i < tnodeSize; i++){
+ if(map[i])
+ hasData++;
+ }
+ }
if (hasData == 0 && del0) {
/* Free and return NULL */
}
+/*
+ * yaffs_SkipRestOfBlock() skips over the rest of the allocation block
+ * if we don't want to write to it.
+ */
+static void yaffs_SkipRestOfBlock(yaffs_Device *dev)
+{
+ if(dev->allocationBlock > 0){
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
+ if(bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING){
+ bi->blockState = YAFFS_BLOCK_STATE_FULL;
+ dev->allocationBlock = -1;
+ }
+ }
+}
+
+
static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
int wholeBlock)
{
cp.structType = sizeof(cp);
T(YAFFS_TRACE_CHECKPOINT, (
- TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
- cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, (unsigned) obj));
+ TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR),
+ cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, obj));
ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
if (cp.structType != sizeof(cp)) {
T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
- cp.structType, sizeof(cp), ok));
+ cp.structType, (int)sizeof(cp), ok));
ok = 0;
}
dev->allocationBlock = blk;
dev->allocationPage = c;
dev->allocationBlockFinder = blk;
- /* Set it to here to encourage the allocator to go forth from here. */
+ /* Set block finder here to encourage the allocator to go forth from here. */
}
break;
}
-/*
- if (parent == dev->deletedDir) {
- yaffs_DestroyObject(in);
- bi->hasShrinkHeader = 1;
- }
-*/
}
}
}
state = YAFFS_BLOCK_STATE_FULL;
}
+ if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
+ /* If the block was partially allocated then treat it as fully allocated.*/
+ state = YAFFS_BLOCK_STATE_FULL;
+ dev->allocationBlock = -1;
+ }
+
bi->blockState = state;
/* Now let's see if it was dirty */
dev->allocationBlockFinder = blk;
} else {
/* This is a partially written block that is not
- * the current allocation block. This block must have
- * had a write failure, so set up for retirement.
+ * the current allocation block.
*/
- /* bi->needsRetiring = 1; ??? TODO */
- bi->gcPrioritise = 1;
-
T(YAFFS_TRACE_ALWAYS,
(TSTR("Partially written block %d detected" TENDSTR),
blk));
oh->
shadowsObject,
1);
+
yaffs_SetObjectName(in, oh->name);
state = YAFFS_BLOCK_STATE_FULL;
}
+
bi->blockState = state;
/* Now let's see if it was dirty */
}
}
+
+ yaffs_SkipRestOfBlock(dev);
if (altBlockIndex)
YFREE_ALT(blockIndex);
do { \
if (sizeof(structure) != syze) { \
T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
- name, syze, sizeof(structure))); \
+ name, syze, (int) sizeof(structure))); \
return YAFFS_FAIL; \
} \
} while (0)
/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */
/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */
#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
- yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode");
+/* yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); */
#endif
#ifndef CONFIG_YAFFS_WINCE
yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader");