* published by the Free Software Foundation.
*/
-
const char *yaffs_guts_c_version =
- "$Id: yaffs_guts.c,v 1.72 2009-01-16 00:44:45 charles Exp $";
+ "$Id: yaffs_guts.c,v 1.78 2009-01-27 02:52:45 charles Exp $";
#include "yportenv.h"
#include "yaffs_packedtags2.h"
-#ifdef CONFIG_YAFFS_WINCE
-void yfsd_LockYAFFS(BOOL fsLockOnly);
-void yfsd_UnlockYAFFS(BOOL fsLockOnly);
-#endif
-
#define YAFFS_PASSIVE_GC_CHUNKS 2
#include "yaffs_ecc.h"
__u32 chunkMax;
__u32 chunkIdOk;
- __u32 chunkIsLive;
+ __u32 chunkInRange;
+ __u32 chunkShouldNotBeDeleted;
+ __u32 chunkValid;
if(!obj)
return;
+
+ if(obj->beingCreated)
+ return;
dev = obj->myDev;
chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
- chunkIdOk = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
- chunkIsLive = chunkIdOk &&
+ chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
+ chunkIdOk = chunkInRange || obj->hdrChunk == 0;
+ chunkValid = chunkInRange &&
yaffs_CheckChunkBit(dev,
obj->hdrChunk / dev->nChunksPerBlock,
obj->hdrChunk % dev->nChunksPerBlock);
+ chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
+
if(!obj->fake &&
- (!chunkIdOk || !chunkIsLive)) {
+ (!chunkIdOk || chunkShouldNotBeDeleted)) {
T(YAFFS_TRACE_VERIFY,
(TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
obj->objectId,obj->hdrChunk,
chunkIdOk ? "" : ",out of range",
- chunkIsLive || !chunkIdOk ? "" : ",marked as deleted"));
+ chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
}
- if(chunkIdOk && chunkIsLive &&!yaffs_SkipNANDVerification(dev)) {
+ if(chunkValid &&!yaffs_SkipNANDVerification(dev)) {
yaffs_ExtendedTags tags;
yaffs_ObjectHeader *oh;
__u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
yaffs_InvalidateCheckpoint(dev);
- yaffs_MarkBlockBad(dev, blockInNAND);
+ if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
+ if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
+ T(YAFFS_TRACE_ALWAYS, (TSTR(
+ "yaffs: Failed to mark bad and erase block %d"
+ TENDSTR), blockInNAND));
+ }
+ else {
+ yaffs_ExtendedTags tags;
+ int chunkId = blockInNAND * dev->nChunksPerBlock;
+
+ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
+
+ memset(buffer, 0xff, dev->nDataBytesPerChunk);
+ yaffs_InitialiseTags(&tags);
+ tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
+ if (dev->writeChunkWithTagsToNAND(dev, chunkId -
+ dev->chunkOffset, buffer, &tags) != YAFFS_OK)
+ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
+ TCONT("write bad block marker to block %d")
+ TENDSTR), blockInNAND));
+
+ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
+ }
+ }
bi->blockState = YAFFS_BLOCK_STATE_DEAD;
bi->gcPrioritise = 0;
bname++;
}
}
-
return sum;
}
/* Now sweeten it up... */
memset(tn, 0, sizeof(yaffs_Object));
+ tn->beingCreated = 1;
+
tn->myDev = dev;
tn->hdrChunk = 0;
tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
if (dev->lostNFoundDir) {
yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
}
+
+ tn->beingCreated = 0;
}
dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
theObject->yst_atime = theObject->yst_mtime =
theObject->yst_ctime = Y_CURRENT_TIME;
#endif
-
-#if 0
- theObject->sum_prev = 12345;
- theObject->sum_trailer = 6789;
-#endif
-
switch (type) {
case YAFFS_OBJECT_TYPE_FILE:
theObject->variant.fileVariant.fileSize = 0;
* 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;
- tags.extraShadows = 0;
tags.extraIsShrinkHeader = 0;
yaffs_VerifyObjectHeader(object,oh,&tags,1);
}
yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
-
/* Do any required cleanups */
if(nBytes < 1 || nBytes > dev->totalBytesPerChunk){
T(YAFFS_TRACE_ERROR,
(TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
- while(1){}
- }
+ YBUG();
+ }
cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
}
-static void yaffs_CheckpointObjectToObject( yaffs_Object *obj,yaffs_CheckpointObject *cp)
+static int yaffs_CheckpointObjectToObject( yaffs_Object *obj,yaffs_CheckpointObject *cp)
{
yaffs_Object *parent;
+
+ if (obj->variantType != cp->variantType) {
+ T(YAFFS_TRACE_ERROR,(TSTR("Checkpoint read object %d type %d "
+ TCONT("chunk %d does not match existing object type %d")
+ TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
+ obj->variantType));
+ return 0;
+ }
obj->objectId = cp->objectId;
else
parent = NULL;
- if(parent)
+ if(parent) {
+ if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ T(YAFFS_TRACE_ALWAYS,(TSTR("Checkpoint read object %d parent %d type %d"
+ TCONT(" chunk %d Parent type, %d, not directory")
+ TENDSTR),
+ cp->objectId,cp->parentId,cp->variantType,cp->hdrChunk,parent->variantType));
+ return 0;
+ }
yaffs_AddObjectToDirectory(parent, obj);
+ }
obj->hdrChunk = cp->hdrChunk;
obj->variantType = cp->variantType;
if(obj->hdrChunk > 0)
obj->lazyLoaded = 1;
+ return 1;
}
else if(ok){
obj = yaffs_FindOrCreateObjectByNumber(dev,cp.objectId, cp.variantType);
if(obj) {
- yaffs_CheckpointObjectToObject(obj,&cp);
+ ok = yaffs_CheckpointObjectToObject(obj,&cp);
+ if (!ok)
+ break;
if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
ok = yaffs_ReadCheckpointTnodes(obj);
} else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
}
}
+ else
+ ok = 0;
}
}
cache->locked = 1;
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
+
memcpy(buffer, &cache->data[start], nToCopy);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
cache->locked = 0;
} else {
/* Read into the local buffer then copy..*/
yaffs_GetTempBuffer(dev, __LINE__);
yaffs_ReadChunkDataFromObject(in, chunk,
localBuffer);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
+
memcpy(buffer, &localBuffer[start], nToCopy);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
+
yaffs_ReleaseTempBuffer(dev, localBuffer,
__LINE__);
}
} else {
-#ifdef CONFIG_YAFFS_WINCE
- __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
-
- /* Under WinCE can't do direct transfer. Need to use a local buffer.
- * This is because we otherwise screw up WinCE's memory mapper
- */
- yaffs_ReadChunkDataFromObject(in, chunk, localBuffer);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
- memcpy(buffer, localBuffer, dev->nDataBytesPerChunk);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
- yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
-#endif
-
-#else
/* A full chunk. Read directly into the supplied buffer. */
yaffs_ReadChunkDataFromObject(in, chunk, buffer);
-#endif
+
}
n -= nToCopy;
if(chunk * dev->nDataBytesPerChunk + start != offset ||
start >= dev->nDataBytesPerChunk){
- T(YAFFS_TRACE_ERROR,(TSTR("AddrToChunk of offset %d gives chunk %d start %d"TENDSTR),
- (int)offset, chunk,start));
+ T(YAFFS_TRACE_ERROR,(
+ TSTR("AddrToChunk of offset %d gives chunk %d start %d"
+ TENDSTR),
+ (int)offset, chunk,start));
}
chunk++;
if (cache) {
yaffs_UseChunkCache(dev, cache, 1);
cache->locked = 1;
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
+
memcpy(&cache->data[start], buffer,
nToCopy);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
+
cache->locked = 0;
cache->nBytes = nToWriteBack;
yaffs_ReadChunkDataFromObject(in, chunk,
localBuffer);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
+
memcpy(&localBuffer[start], buffer, nToCopy);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
chunkWritten =
yaffs_WriteChunkDataToObject(in, chunk,
localBuffer,
} else {
/* A full chunk. Write directly from the supplied buffer. */
-#ifdef CONFIG_YAFFS_WINCE
- /* Under WinCE can't do direct transfer. Need to use a local buffer.
- * This is because we otherwise screw up WinCE's memory mapper
- */
- __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
- memcpy(localBuffer, buffer, dev->nDataBytesPerChunk);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
- chunkWritten =
- yaffs_WriteChunkDataToObject(in, chunk, localBuffer,
- dev->nDataBytesPerChunk,
- 0);
- yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
-#else
+
chunkWritten =
yaffs_WriteChunkDataToObject(in, chunk, buffer,
dev->nDataBytesPerChunk,
0);
-#endif
+
/* Since we've overwritten the cached data, we better invalidate it. */
yaffs_InvalidateChunkCache(in, chunk);
}
* and the inode associated with the file.
* It does not delete the links associated with the file.
*/
-
static int yaffs_UnlinkFile(yaffs_Object * in)
{
obj =
yaffs_FindOrCreateObjectByNumber(dev, objId,
YAFFS_OBJECT_TYPE_FILE);
+ if (!obj)
+ return;
yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
obj->variant.fileVariant.shrinkSize = 0;
obj->valid = 1; /* So that we don't read any other info for this file */
bi->blockState = state;
bi->sequenceNumber = sequenceNumber;
+ if(bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
+ bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
+
T(YAFFS_TRACE_SCAN_DEBUG,
(TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
state, sequenceNumber));
yaffs_FindOrCreateObjectByNumber
(dev, oh->parentObjectId,
YAFFS_OBJECT_TYPE_DIRECTORY);
- if (parent->variantType ==
+ if(!parent)
+ alloc_failed = 1;
+ if (parent && parent->variantType ==
YAFFS_OBJECT_TYPE_UNKNOWN) {
/* Set up as a directory */
parent->variantType =
YINIT_LIST_HEAD(&parent->variant.
directoryVariant.
children);
- } else if (parent->variantType !=
+ } else if (!parent || parent->variantType !=
YAFFS_OBJECT_TYPE_DIRECTORY)
{
/* Hoosterman, another problem....
if(bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
+ if(bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
+ bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
T(YAFFS_TRACE_SCAN_DEBUG,
(TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
dev->nFreeChunks++;
} else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED){
- printf("Error in ECC\n");
- /* Don't actually delete because the chunk is not yet set up as being in use */
- /* yaffs_DeleteChunk(dev, chunk, 1, __LINE__); */
+ T(YAFFS_TRACE_SCAN,
+ (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
+ blk, c));
+
+ dev->nFreeChunks++;
+
}else if (tags.chunkId > 0) {
/* chunkId > 0 so it is a data chunk... */
unsigned int endpos;
in = yaffs_FindOrCreateObjectByNumber
(dev, tags.objectId,
tags.extraObjectType);
+ if (!in)
+ alloc_failed = 1;
}
if (!in ||
oh->isShrink = oh->inbandIsShrink;
}
- if (!in)
+ if (!in) {
in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
+ if (!in)
+ alloc_failed = 1;
+ }
}
(TSTR
("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
TENDSTR), tags.objectId, chunk));
-
+ continue;
}
if (in->valid) {
}
+ if (!in->valid && in->variantType !=
+ (oh ? oh->type : tags.extraObjectType))
+ T(YAFFS_TRACE_ERROR, (
+ TSTR("yaffs tragedy: Bad object type, "
+ TCONT("%d != %d, for object %d at chunk ")
+ TCONT("%d during scan")
+ TENDSTR), oh ?
+ oh->type : tags.extraObjectType,
+ in->variantType, tags.objectId,
+ chunk));
+
if (!in->valid &&
(tags.objectId == YAFFS_OBJECTID_ROOT ||
tags.objectId ==
}
in->dirty = 0;
+ if (!parent)
+ alloc_failed = 1;
+
/* directory stuff...
* hook up to parent
*/
- if (parent->variantType ==
+ if (parent && parent->variantType ==
YAFFS_OBJECT_TYPE_UNKNOWN) {
/* Set up as a directory */
parent->variantType =
YINIT_LIST_HEAD(&parent->variant.
directoryVariant.
children);
- } else if (parent->variantType !=
+ } else if (!parent || parent->variantType !=
YAFFS_OBJECT_TYPE_DIRECTORY)
{
/* Hoosterman, another problem....