X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_guts.c;h=44eaed692cedb05ac60af308d4d4a3e999fee577;hp=d4ecda3c035e74375bf4db24e147ed495b4fa882;hb=7211ad39b355b558a4f8a97bc4821ee859888bd6;hpb=92ee023b9d7144e178a050eff898aaae4415096b diff --git a/yaffs_guts.c b/yaffs_guts.c index d4ecda3..44eaed6 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.58 2008-07-03 20:06:05 charles Exp $"; + "$Id: yaffs_guts.c,v 1.78 2009-01-27 02:52:45 charles Exp $"; #include "yportenv.h" @@ -33,11 +33,6 @@ const char *yaffs_guts_c_version = #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" @@ -97,6 +92,7 @@ static void yaffs_VerifyFreeChunks(yaffs_Device * dev); static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in); +static void yaffs_VerifyDirectory(yaffs_Object *directory); #ifdef YAFFS_PARANOID static int yaffs_CheckFileSanity(yaffs_Object * in); #else @@ -405,14 +401,11 @@ static int yaffs_SkipVerification(yaffs_Device *dev) return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); } -#if 0 static int yaffs_SkipFullVerification(yaffs_Device *dev) { return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); } -#endif - static int yaffs_SkipNANDVerification(yaffs_Device *dev) { return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); @@ -440,7 +433,7 @@ static void yaffs_VerifyBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n) return; /* Report illegal runtime states */ - if(bi->blockState <0 || bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) + if(bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has undefined state %d"TENDSTR),n,bi->blockState)); switch(bi->blockState){ @@ -484,9 +477,10 @@ static void yaffs_VerifyCollectedBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int yaffs_VerifyBlock(dev,bi,n); /* After collection the block should be in the erased state */ - /* TODO: This will need to change if we do partial gc */ + /* This will need to change if we do partial gc */ - if(bi->blockState != YAFFS_BLOCK_STATE_EMPTY){ + if(bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && + bi->blockState != YAFFS_BLOCK_STATE_EMPTY){ T(YAFFS_TRACE_ERROR,(TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), n,bi->blockState)); } @@ -509,7 +503,7 @@ static void yaffs_VerifyBlocks(yaffs_Device *dev) yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); yaffs_VerifyBlock(dev,bi,i); - if(bi->blockState >=0 && bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) + if(bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) nBlocksPerState[bi->blockState]++; else nIllegalBlockStates++; @@ -553,7 +547,7 @@ static void yaffs_VerifyBlocks(yaffs_Device *dev) */ static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) { - if(yaffs_SkipVerification(obj->myDev)) + if(obj && yaffs_SkipVerification(obj->myDev)) return; if(!(tags && obj && oh)){ @@ -628,7 +622,6 @@ static int yaffs_VerifyTnodeWorker(yaffs_Object * obj, yaffs_Tnode * tn, } } } else if (level == 0) { - int i; yaffs_ExtendedTags tags; __u32 objectId = obj->objectId; @@ -668,7 +661,10 @@ static void yaffs_VerifyFile(yaffs_Object *obj) yaffs_Tnode *tn; __u32 objectId; - if(obj && yaffs_SkipVerification(obj->myDev)) + if(!obj) + return; + + if(yaffs_SkipVerification(obj->myDev)) return; dev = obj->myDev; @@ -719,12 +715,6 @@ static void yaffs_VerifyFile(yaffs_Object *obj) } -static void yaffs_VerifyDirectory(yaffs_Object *obj) -{ - if(obj && yaffs_SkipVerification(obj->myDev)) - return; - -} static void yaffs_VerifyHardLink(yaffs_Object *obj) { @@ -756,10 +746,15 @@ static void yaffs_VerifyObject(yaffs_Object *obj) __u32 chunkMax; __u32 chunkIdOk; - __u32 chunkIsLive; + __u32 chunkInRange; + __u32 chunkShouldNotBeDeleted; + __u32 chunkValid; if(!obj) return; + + if(obj->beingCreated) + return; dev = obj->myDev; @@ -771,21 +766,24 @@ static void yaffs_VerifyObject(yaffs_Object *obj) 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__); @@ -1035,7 +1033,30 @@ static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND) 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; @@ -1106,7 +1127,7 @@ static __u16 yaffs_CalcNameSum(const YCHAR * name) __u16 sum = 0; __u16 i = 1; - YUCHAR *bname = (YUCHAR *) name; + const YUCHAR *bname = (const YUCHAR *) name; if (bname) { while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) { @@ -1125,6 +1146,7 @@ static __u16 yaffs_CalcNameSum(const YCHAR * name) static void yaffs_SetObjectName(yaffs_Object * obj, const YCHAR * name) { #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM + memset(obj->shortName,0,sizeof (YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1)); if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) { yaffs_strcpy(obj->shortName, name); } else { @@ -1909,6 +1931,9 @@ static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device * dev) { yaffs_Object *tn = NULL; +#ifdef VALGRIND_TEST + tn = YMALLOC(sizeof(yaffs_Object)); +#else /* If there are none left make more */ if (!dev->freeObjects) { yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS); @@ -1919,16 +1944,27 @@ static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device * dev) dev->freeObjects = (yaffs_Object *) (dev->freeObjects->siblings.next); dev->nFreeObjects--; - + } +#endif + if(tn){ /* 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; YINIT_LIST_HEAD(&(tn->hardLinks)); YINIT_LIST_HEAD(&(tn->hashLink)); YINIT_LIST_HEAD(&tn->siblings); + + + /* Now make the directory sane */ + if(dev->rootDir){ + tn->parent = dev->rootDir; + ylist_add(&(tn->siblings),&dev->rootDir->variant.directoryVariant.children); + } /* Add it to the lost and found directory. * NB Can't put root or lostNFound in lostNFound so @@ -1937,6 +1973,8 @@ static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device * dev) if (dev->lostNFoundDir) { yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn); } + + tn->beingCreated = 0; } dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ @@ -1985,6 +2023,13 @@ static void yaffs_FreeObject(yaffs_Object * tn) yaffs_Device *dev = tn->myDev; + + if(tn->parent) + YBUG(); + if(!ylist_empty(&tn->siblings)) + YBUG(); + + #ifdef __KERNEL__ if (tn->myInode) { /* We're still hooked up to a cached inode. @@ -1997,11 +2042,14 @@ static void yaffs_FreeObject(yaffs_Object * tn) yaffs_UnhashObject(tn); +#ifdef VALGRIND_TEST + YFREE(tn); +#else /* Link into the free list. */ tn->siblings.next = (struct ylist_head *)(dev->freeObjects); dev->freeObjects = tn; dev->nFreeObjects++; - +#endif dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ } @@ -2285,6 +2333,9 @@ static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, } in = yaffs_CreateNewObject(dev, -1, type); + + if(!in) + return YAFFS_FAIL; if(type == YAFFS_OBJECT_TYPE_SYMLINK){ str = yaffs_CloneString(aliasString); @@ -2415,7 +2466,7 @@ static int yaffs_ChangeObjectName(yaffs_Object * obj, yaffs_Object * newDir, if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { T(YAFFS_TRACE_ALWAYS, (TSTR - ("tragendy: yaffs_ChangeObjectName: newDir is not a directory" + ("tragedy: yaffs_ChangeObjectName: newDir is not a directory" TENDSTR))); YBUG(); } @@ -2462,9 +2513,15 @@ static int yaffs_ChangeObjectName(yaffs_Object * obj, yaffs_Object * newDir, int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName, yaffs_Object * newDir, const YCHAR * newName) { - yaffs_Object *obj; - yaffs_Object *existingTarget; + yaffs_Object *obj=NULL; + yaffs_Object *existingTarget=NULL; int force = 0; + + + if(!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) + YBUG(); + if(!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) + YBUG(); #ifdef CONFIG_YAFFS_CASE_INSENSITIVE /* Special case for case insemsitive systems (eg. WinCE). @@ -2476,17 +2533,12 @@ int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName, } #endif - obj = yaffs_FindObjectByName(oldDir, oldName); - /* Check new name to long. */ - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK && - yaffs_strlen(newName) > YAFFS_MAX_ALIAS_LENGTH) - /* ENAMETOOLONG */ - return YAFFS_FAIL; - else if (obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK && - yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) + else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) /* ENAMETOOLONG */ return YAFFS_FAIL; + obj = yaffs_FindObjectByName(oldDir, oldName); + if (obj && obj->renameAllowed) { /* Now do the handling for an existing target, if there is one */ @@ -2800,7 +2852,7 @@ static int yaffs_FindBlockForAllocation(yaffs_Device * dev) * Can't get space to gc */ T(YAFFS_TRACE_ERROR, - (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR))); + (TSTR("yaffs tragedy: no more erased blocks" TENDSTR))); return -1; } @@ -2831,7 +2883,7 @@ static int yaffs_FindBlockForAllocation(yaffs_Device * dev) T(YAFFS_TRACE_ALWAYS, (TSTR - ("yaffs tragedy: no more eraased blocks, but there should have been %d" + ("yaffs tragedy: no more erased blocks, but there should have been %d" TENDSTR), dev->nErasedBlocks)); return -1; @@ -2841,7 +2893,8 @@ static int yaffs_FindBlockForAllocation(yaffs_Device * dev) static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev) { - if(!dev->nCheckpointBlocksRequired){ + if(!dev->nCheckpointBlocksRequired && + dev->isYaffs2){ /* Not a valid value so recalculate */ int nBytes = 0; int nBlocks; @@ -2880,9 +2933,14 @@ static int yaffs_CheckSpaceForAllocation(yaffs_Device * dev) int reservedBlocks = dev->nReservedBlocks; int checkpointBlocks; - checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; - if(checkpointBlocks < 0) - checkpointBlocks = 0; + if(dev->isYaffs2){ + checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) - + dev->blocksInCheckpoint; + if(checkpointBlocks < 0) + checkpointBlocks = 0; + } else { + checkpointBlocks =0; + } reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock); @@ -2956,17 +3014,17 @@ static int yaffs_GetErasedChunks(yaffs_Device * dev) } -static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) +static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block, int wholeBlock) { int oldChunk; int newChunk; - int chunkInBlock; int markNAND; int retVal = YAFFS_OK; int cleanups = 0; int i; int isCheckpointBlock; int matchingChunk; + int maxCopies; int chunksBefore = yaffs_GetErasedChunks(dev); int chunksAfter; @@ -2982,8 +3040,11 @@ static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) 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)); + (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR), + block, + bi->pagesInUse, + bi->hasShrinkHeader, + wholeBlock)); /*yaffs_VerifyFreeChunks(dev); */ @@ -3009,13 +3070,20 @@ static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) yaffs_VerifyBlock(dev,bi,block); - for (chunkInBlock = 0, oldChunk = block * dev->nChunksPerBlock; - chunkInBlock < dev->nChunksPerBlock - && yaffs_StillSomeChunkBits(dev, block); - chunkInBlock++, oldChunk++) { - if (yaffs_CheckChunkBit(dev, block, chunkInBlock)) { + maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10; + oldChunk = block * dev->nChunksPerBlock + dev->gcChunk; + + for ( /* init already done */; + retVal == YAFFS_OK && + dev->gcChunk < dev->nChunksPerBlock && + (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING)&& + maxCopies > 0; + dev->gcChunk++, oldChunk++) { + if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) { /* This page is in use and might need to be copied off */ + + maxCopies--; markNAND = 1; @@ -3030,8 +3098,8 @@ static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) T(YAFFS_TRACE_GC_DETAIL, (TSTR - ("Collecting page %d, %d %d %d " TENDSTR), - chunkInBlock, tags.objectId, tags.chunkId, + ("Collecting chunk in block %d, %d %d %d " TENDSTR), + dev->gcChunk, tags.objectId, tags.chunkId, tags.byteCount)); if(object && !yaffs_SkipVerification(dev)){ @@ -3057,9 +3125,11 @@ static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) tags.objectId, tags.chunkId, tags.byteCount)); } - if (object && object->deleted - && tags.chunkId != 0) { - /* Data chunk in a deleted file, throw it away + if (object && + object->deleted && + object->softDeleted && + tags.chunkId != 0) { + /* Data chunk in a soft 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. @@ -3102,14 +3172,11 @@ static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) * 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 = oh->inbandShadowsObject = -1; - tags.extraShadows = 0; tags.extraIsShrinkHeader = 0; yaffs_VerifyObjectHeader(object,oh,&tags,1); @@ -3138,7 +3205,8 @@ static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) } } - yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__); + if(retVal == YAFFS_OK) + yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__); } } @@ -3178,9 +3246,15 @@ static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) TENDSTR), chunksBefore, chunksAfter)); } + /* If the gc completed then clear the current gcBlock so that we find another. */ + if(bi->blockState != YAFFS_BLOCK_STATE_COLLECTING){ + dev->gcBlock = -1; + dev->gcChunk = 0; + } + dev->isDoingGC = 0; - return YAFFS_OK; + return retVal; } /* New garbage collector @@ -3225,7 +3299,12 @@ static int yaffs_CheckGarbageCollection(yaffs_Device * dev) aggressive = 0; } - block = yaffs_FindBlockForGarbageCollection(dev, aggressive); + if(dev->gcBlock <= 0){ + dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive); + dev->gcChunk = 0; + } + + block = dev->gcBlock; if (block > 0) { dev->garbageCollections++; @@ -3238,7 +3317,7 @@ static int yaffs_CheckGarbageCollection(yaffs_Device * dev) ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR), dev->nErasedBlocks, aggressive)); - gcOk = yaffs_GarbageCollectBlock(dev, block); + gcOk = yaffs_GarbageCollectBlock(dev,block,aggressive); } if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) { @@ -3247,8 +3326,9 @@ static int yaffs_CheckGarbageCollection(yaffs_Device * dev) ("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)); + } while ((dev->nErasedBlocks < dev->nReservedBlocks) && + (block > 0) && + (maxTries < 2)); return aggressive ? gcOk : YAFFS_OK; } @@ -3482,8 +3562,10 @@ static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode, * not be loaded during a scan */ - newSerial = newTags.serialNumber; - existingSerial = existingTags.serialNumber; + if(inScan > 0) { + newSerial = newTags.serialNumber; + existingSerial = existingTags.serialNumber; + } if ((inScan > 0) && (in->myDev->isYaffs2 || @@ -3631,6 +3713,14 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object * in, int chunkInInode, newTags.serialNumber = (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1; newTags.byteCount = nBytes; + + if(nBytes < 1 || nBytes > dev->totalBytesPerChunk){ + T(YAFFS_TRACE_ERROR, + (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes)); + YBUG(); + } + + newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, @@ -3940,35 +4030,15 @@ void yaffs_FlushEntireDeviceCache(yaffs_Device *dev) static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device * dev) { int i; - int usage; - int theOne; if (dev->nShortOpCaches > 0) { for (i = 0; i < dev->nShortOpCaches; i++) { if (!dev->srCache[i].object) return &dev->srCache[i]; } - - return NULL; - - theOne = -1; - usage = 0; /* just to stop the compiler grizzling */ - - for (i = 0; i < dev->nShortOpCaches; i++) { - if (!dev->srCache[i].dirty && - ((dev->srCache[i].lastUse < usage && theOne >= 0) || - theOne < 0)) { - usage = dev->srCache[i].lastUse; - theOne = i; - } - } - - - return theOne >= 0 ? &dev->srCache[theOne] : NULL; - } else { - return NULL; } + return NULL; } static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device * dev) @@ -4248,10 +4318,18 @@ static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp, 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; @@ -4263,8 +4341,16 @@ static void yaffs_CheckpointObjectToObject( yaffs_Object *obj,yaffs_CheckpointOb 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; @@ -4284,6 +4370,7 @@ static void yaffs_CheckpointObjectToObject( yaffs_Object *obj,yaffs_CheckpointOb if(obj->hdrChunk > 0) obj->lazyLoaded = 1; + return 1; } @@ -4313,7 +4400,6 @@ static int yaffs_CheckpointTnodeWorker(yaffs_Object * in, yaffs_Tnode * tn, } } else if (level == 0) { __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS; - /* printf("write tnode at %d\n",baseOffset); */ ok = (yaffs_CheckpointWrite(dev,&baseOffset,sizeof(baseOffset)) == sizeof(baseOffset)); if(ok) ok = (yaffs_CheckpointWrite(dev,tn,tnodeSize) == tnodeSize); @@ -4362,7 +4448,6 @@ static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj) /* Read level 0 tnode */ - /* printf("read tnode at %d\n",baseChunk); */ tn = yaffs_GetTnodeRaw(dev); if(tn) ok = (yaffs_CheckpointRead(dev,tn,tnodeSize) == tnodeSize); @@ -4459,7 +4544,9 @@ static int yaffs_ReadCheckpointObjects(yaffs_Device *dev) 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) { @@ -4470,6 +4557,8 @@ static int yaffs_ReadCheckpointObjects(yaffs_Device *dev) } } + else + ok = 0; } } @@ -4722,14 +4811,9 @@ int yaffs_ReadDataFromFile(yaffs_Object * in, __u8 * buffer, loff_t offset, 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..*/ @@ -4738,41 +4822,19 @@ int yaffs_ReadDataFromFile(yaffs_Object * in, __u8 * buffer, loff_t offset, 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; @@ -4797,7 +4859,8 @@ int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset, int nToWriteBack; int startOfWrite = offset; int chunkWritten = 0; - int nBytesRead; + __u32 nBytesRead; + __u32 chunkStart; yaffs_Device *dev; @@ -4807,6 +4870,14 @@ int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset, //chunk = offset / dev->nDataBytesPerChunk + 1; //start = offset % dev->nDataBytesPerChunk; yaffs_AddrToChunk(dev,offset,&chunk,&start); + + 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)); + } chunk++; /* OK now check for the curveball where the start and end are in @@ -4821,9 +4892,12 @@ int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset, * we need to write back as much as was there before. */ - nBytesRead = - in->variant.fileVariant.fileSize - - ((chunk - 1) * dev->nDataBytesPerChunk); + chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk); + + if(chunkStart > in->variant.fileVariant.fileSize) + nBytesRead = 0; /* Past end of file */ + else + nBytesRead = in->variant.fileVariant.fileSize - chunkStart; if (nBytesRead > dev->nDataBytesPerChunk) { nBytesRead = dev->nDataBytesPerChunk; @@ -4832,6 +4906,9 @@ int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset, nToWriteBack = (nBytesRead > (start + n)) ? nBytesRead : (start + n); + + if(nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk) + YBUG(); } else { nToCopy = dev->nDataBytesPerChunk - start; @@ -4871,16 +4948,12 @@ int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset, 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; @@ -4908,15 +4981,10 @@ int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset, 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, @@ -4931,30 +4999,13 @@ int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset, } 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); } @@ -5083,7 +5134,8 @@ int yaffs_ResizeFile(yaffs_Object * in, loff_t newSize) * show we've shrunk the file, if need be * Do this only if the file is not in the deleted directories. */ - if (in->parent->objectId != YAFFS_OBJECTID_UNLINKED && + if (in->parent && + in->parent->objectId != YAFFS_OBJECTID_UNLINKED && in->parent->objectId != YAFFS_OBJECTID_DELETED) { yaffs_UpdateObjectHeader(in, NULL, 0, (newSize < oldFileSize) ? 1 : 0, 0); @@ -5165,56 +5217,59 @@ static int yaffs_UnlinkFile(yaffs_Object * in) int retVal; int immediateDeletion = 0; - if (1) { #ifdef __KERNEL__ - if (!in->myInode) { - immediateDeletion = 1; - - } + if (!in->myInode) { + immediateDeletion = 1; + } #else - if (in->inUse <= 0) { - immediateDeletion = 1; - - } + if (in->inUse <= 0) { + immediateDeletion = 1; + } #endif - if (immediateDeletion) { - retVal = - yaffs_ChangeObjectName(in, in->myDev->deletedDir, - _Y("deleted"), 0, 0); - T(YAFFS_TRACE_TRACING, - (TSTR("yaffs: immediate deletion of file %d" TENDSTR), - in->objectId)); - in->deleted = 1; - in->myDev->nDeletedFiles++; - if (0 && in->myDev->isYaffs2) { - yaffs_ResizeFile(in, 0); - } - yaffs_SoftDeleteFile(in); - } else { - retVal = - yaffs_ChangeObjectName(in, in->myDev->unlinkedDir, - _Y("unlinked"), 0, 0); - } + if (immediateDeletion) { + retVal = + yaffs_ChangeObjectName(in, in->myDev->deletedDir, + _Y("deleted"), 0, 0); + T(YAFFS_TRACE_TRACING, + (TSTR("yaffs: immediate deletion of file %d" TENDSTR), + in->objectId)); + in->deleted = 1; + in->myDev->nDeletedFiles++; + if (1 || in->myDev->isYaffs2) { + yaffs_ResizeFile(in, 0); + } + yaffs_SoftDeleteFile(in); + } else { + retVal = + yaffs_ChangeObjectName(in, in->myDev->unlinkedDir, + _Y("unlinked"), 0, 0); } + + return retVal; } int yaffs_DeleteFile(yaffs_Object * in) { int retVal = YAFFS_OK; + int deleted = in->deleted; + + yaffs_ResizeFile(in,0); if (in->nDataChunks > 0) { - /* Use soft deletion if there is data in the file */ + /* Use soft deletion if there is data in the file. + * That won't be the case if it has been resized to zero. + */ if (!in->unlinked) { retVal = yaffs_UnlinkFile(in); } if (retVal == YAFFS_OK && in->unlinked && !in->deleted) { - in->deleted = 1; + in->deleted = deleted = 1; in->myDev->nDeletedFiles++; yaffs_SoftDeleteFile(in); } - return in->deleted ? YAFFS_OK : YAFFS_FAIL; + return deleted ? YAFFS_OK : YAFFS_FAIL; } else { /* The file has no data chunks so we toss it immediately */ yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top); @@ -5248,7 +5303,7 @@ static int yaffs_DeleteHardLink(yaffs_Object * in) /* remove this hardlink from the list assocaited with the equivalent * object */ - ylist_del(&in->hardLinks); + ylist_del_init(&in->hardLinks); return yaffs_DoGenericObjectDeletion(in); } @@ -5381,6 +5436,8 @@ static void yaffs_HandleShadowedObject(yaffs_Device * dev, int objId, 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 */ @@ -5446,6 +5503,35 @@ struct yaffs_ShadowFixerStruct { struct yaffs_ShadowFixerStruct *next; }; + +static void yaffs_StripDeletedObjects(yaffs_Device *dev) +{ + /* + * Sort out state of unlinked and deleted objects after scanning. + */ + struct ylist_head *i; + struct ylist_head *n; + yaffs_Object *l; + + /* Soft delete all the unlinked files */ + ylist_for_each_safe(i, n, + &dev->unlinkedDir->variant.directoryVariant.children) { + if (i) { + l = ylist_entry(i, yaffs_Object, siblings); + yaffs_DestroyObject(l); + } + } + + ylist_for_each_safe(i, n, + &dev->deletedDir->variant.directoryVariant.children) { + if (i) { + l = ylist_entry(i, yaffs_Object, siblings); + yaffs_DestroyObject(l); + } + } + +} + static int yaffs_Scan(yaffs_Device * dev) { yaffs_ExtendedTags tags; @@ -5474,7 +5560,6 @@ static int yaffs_Scan(yaffs_Device * dev) __u8 *chunkData; - //TODO Throw all the yaffs2 stuuf out of yaffs_Scan since it is only for yaffs1 format. T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR), @@ -5496,6 +5581,9 @@ static int yaffs_Scan(yaffs_Device * dev) 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)); @@ -5540,7 +5628,7 @@ static int yaffs_Scan(yaffs_Device * dev) /* Let's have a good look at this chunk... */ - if (!dev->isYaffs2 && tags.chunkDeleted) { + if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) { /* YAFFS1 only... * A deleted chunk */ @@ -5569,17 +5657,6 @@ static int yaffs_Scan(yaffs_Device * dev) dev->allocationBlockFinder = blk; /* Set it to here to encourage the allocator to go forth from here. */ - /* Yaffs2 sanity check: - * This should be the one with the highest sequence number - */ - if (dev->isYaffs2 - && (dev->sequenceNumber != - bi->sequenceNumber)) { - T(YAFFS_TRACE_ALWAYS, - (TSTR - ("yaffs: Allocation block %d was not highest sequence id: block seq = %d, dev seq = %d" - TENDSTR), blk,bi->sequenceNumber,dev->sequenceNumber)); - } } dev->nFreeChunks += (dev->nChunksPerBlock - c); @@ -5677,9 +5754,7 @@ static int yaffs_Scan(yaffs_Device * dev) unsigned existingSerial = in->serial; unsigned newSerial = tags.serialNumber; - if (dev->isYaffs2 || - ((existingSerial + 1) & 3) == - newSerial) { + if (((existingSerial + 1) & 3) == newSerial) { /* Use new one - destroy the exisiting one */ yaffs_DeleteChunk(dev, in->hdrChunk, @@ -5716,6 +5791,7 @@ static int yaffs_Scan(yaffs_Device * dev) in->yst_rdev = oh->yst_rdev; #endif in->hdrChunk = chunk; + in->serial = tags.serialNumber; } else if (in && !in->valid) { /* we need to load this info */ @@ -5740,6 +5816,7 @@ static int yaffs_Scan(yaffs_Device * dev) in->yst_rdev = oh->yst_rdev; #endif in->hdrChunk = chunk; + in->serial = tags.serialNumber; yaffs_SetObjectName(in, oh->name); in->dirty = 0; @@ -5752,7 +5829,9 @@ static int yaffs_Scan(yaffs_Device * dev) 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 = @@ -5760,7 +5839,7 @@ static int yaffs_Scan(yaffs_Device * dev) YINIT_LIST_HEAD(&parent->variant. directoryVariant. children); - } else if (parent->variantType != + } else if (!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { /* Hoosterman, another problem.... @@ -5793,15 +5872,6 @@ static int yaffs_Scan(yaffs_Device * dev) /* Todo got a problem */ break; case YAFFS_OBJECT_TYPE_FILE: - if (dev->isYaffs2 - && oh->isShrink) { - /* Prune back the shrunken chunks */ - yaffs_PruneResizedChunks - (in, oh->fileSize); - /* Mark the block as having a shrinkHeader */ - bi->hasShrinkHeader = 1; - } - if (dev->useHeaderFileSize) in->variant.fileVariant. @@ -5832,10 +5902,12 @@ static int yaffs_Scan(yaffs_Device * dev) break; } - if (parent == dev->deletedDir) { +/* + if (parent == dev->deletedDir) { yaffs_DestroyObject(in); bi->hasShrinkHeader = 1; } +*/ } } } @@ -5865,25 +5937,6 @@ static int yaffs_Scan(yaffs_Device * dev) yaffs_HardlinkFixup(dev,hardList); - /* Handle the unlinked files. Since they were left in an unlinked state we should - * just delete them. - */ - { - struct ylist_head *i; - struct ylist_head *n; - - yaffs_Object *l; - /* Soft delete all the unlinked files */ - ylist_for_each_safe(i, n, - &dev->unlinkedDir->variant.directoryVariant. - children) { - if (i) { - l = ylist_entry(i, yaffs_Object, siblings); - yaffs_DestroyObject(l); - } - } - } - /* Fix up any shadowed objects */ { struct yaffs_ShadowFixerStruct *fixer; @@ -5924,7 +5977,7 @@ static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) { __u8 *chunkData; yaffs_ObjectHeader *oh; - yaffs_Device *dev = in->myDev; + yaffs_Device *dev; yaffs_ExtendedTags tags; int result; int alloc_failed = 0; @@ -5932,6 +5985,8 @@ static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) if(!in) return; + dev = in->myDev; + #if 0 T(YAFFS_TRACE_SCAN,(TSTR("details for object %d %s loaded" TENDSTR), in->objectId, @@ -6054,6 +6109,8 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) 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, @@ -6074,8 +6131,7 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { /* Determine the highest sequence number */ - if (dev->isYaffs2 && - sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && + if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) { blockIndex[nBlocksToScan].seq = sequenceNumber; @@ -6086,7 +6142,7 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) if (sequenceNumber >= dev->sequenceNumber) { dev->sequenceNumber = sequenceNumber; } - } else if (dev->isYaffs2) { + } else { /* TODO: Nasty sequence number! */ T(YAFFS_TRACE_SCAN, (TSTR @@ -6212,11 +6268,11 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) * had a write failure, so set up for retirement. */ - bi->needsRetiring = 1; + /* bi->needsRetiring = 1; ??? TODO */ bi->gcPrioritise = 1; T(YAFFS_TRACE_ALWAYS, - (TSTR("Partially written block %d being set for retirement" TENDSTR), + (TSTR("Partially written block %d detected" TENDSTR), blk)); } @@ -6226,7 +6282,14 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) dev->nFreeChunks++; - } else if (tags.chunkId > 0) { + } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED){ + 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; __u32 chunkBase = @@ -6297,6 +6360,8 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) in = yaffs_FindOrCreateObjectByNumber (dev, tags.objectId, tags.extraObjectType); + if (!in) + alloc_failed = 1; } if (!in || @@ -6327,8 +6392,11 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) oh->isShrink = oh->inbandIsShrink; } - if (!in) + if (!in) { in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type); + if (!in) + alloc_failed = 1; + } } @@ -6338,7 +6406,7 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) (TSTR ("yaffs tragedy: Could not make object for object %d at chunk %d during scan" TENDSTR), tags.objectId, chunk)); - + continue; } if (in->valid) { @@ -6360,7 +6428,9 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) (oh) ? oh-> parentObjectId : tags. extraParentObjectId; - unsigned isShrink = + + + isShrink = (oh) ? oh->isShrink : tags. extraIsShrinkHeader; @@ -6393,6 +6463,17 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) } + 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 == @@ -6485,11 +6566,14 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) } 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 = @@ -6497,7 +6581,7 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) YINIT_LIST_HEAD(&parent->variant. directoryVariant. children); - } else if (parent->variantType != + } else if (!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { /* Hoosterman, another problem.... @@ -6612,37 +6696,6 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) */ yaffs_HardlinkFixup(dev,hardList); - - /* - * Sort out state of unlinked and deleted objects. - */ - { - struct ylist_head *i; - struct ylist_head *n; - - yaffs_Object *l; - - /* Soft delete all the unlinked files */ - ylist_for_each_safe(i, n, - &dev->unlinkedDir->variant.directoryVariant. - children) { - if (i) { - l = ylist_entry(i, yaffs_Object, siblings); - yaffs_DestroyObject(l); - } - } - - /* Soft delete all the deletedDir files */ - ylist_for_each_safe(i, n, - &dev->deletedDir->variant.directoryVariant. - children) { - if (i) { - l = ylist_entry(i, yaffs_Object, siblings); - yaffs_DestroyObject(l); - - } - } - } yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); @@ -6657,15 +6710,102 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) /*------------------------------ Directory Functions ----------------------------- */ +static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj) +{ + struct ylist_head *lh; + yaffs_Object *listObj; + + int count = 0; + + if(!obj){ + T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR))); + YBUG(); + } + + if(yaffs_SkipVerification(obj->myDev)) + return; + + if(!obj->parent){ + T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR))); + YBUG(); + } + + if(obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY){ + T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR))); + YBUG(); + } + + /* Iterate through the objects in each hash entry */ + + ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) { + if (lh) { + listObj = ylist_entry(lh, yaffs_Object, siblings); + yaffs_VerifyObject(listObj); + if(obj == listObj) + count ++; + } + } + + if(count != 1){ + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR),count)); + YBUG(); + } + +} + +static void yaffs_VerifyDirectory(yaffs_Object *directory) +{ + + struct ylist_head *lh; + yaffs_Object *listObj; + + if(!directory) + YBUG(); + + if(yaffs_SkipFullVerification(directory->myDev)) + return; + + + if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY){ + T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR),directory->variantType)); + YBUG(); + } + + /* Iterate through the objects in each hash entry */ + + ylist_for_each(lh, &directory->variant.directoryVariant.children) { + if (lh) { + listObj = ylist_entry(lh, yaffs_Object, siblings); + if(listObj->parent != directory){ + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR),listObj->parent)); + YBUG(); + } + yaffs_VerifyObjectInDirectory(listObj); + } + } + +} + + static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj) { yaffs_Device *dev = obj->myDev; + yaffs_Object *parent; + + yaffs_VerifyObjectInDirectory(obj); + parent = obj->parent; + yaffs_VerifyDirectory(parent); + if(dev && dev->removeObjectCallback) dev->removeObjectCallback(obj); + ylist_del_init(&obj->siblings); obj->parent = NULL; + + yaffs_VerifyDirectory(parent); + } @@ -6690,12 +6830,18 @@ static void yaffs_AddObjectToDirectory(yaffs_Object * directory, if (obj->siblings.prev == NULL) { /* Not initialised */ - YINIT_LIST_HEAD(&obj->siblings); + YBUG(); - } else if (!ylist_empty(&obj->siblings)) { - /* If it is holed up somewhere else, un hook it */ - yaffs_RemoveObjectFromDirectory(obj); - } + } else if (ylist_empty(&obj->siblings)) { + YBUG(); + } + + + yaffs_VerifyDirectory(directory); + + yaffs_RemoveObjectFromDirectory(obj); + + /* Now add it */ ylist_add(&obj->siblings, &directory->variant.directoryVariant.children); obj->parent = directory; @@ -6706,6 +6852,11 @@ static void yaffs_AddObjectToDirectory(yaffs_Object * directory, obj->myDev->nUnlinkedFiles++; obj->renameAllowed = 0; } + + yaffs_VerifyDirectory(directory); + yaffs_VerifyObjectInDirectory(obj); + + } yaffs_Object *yaffs_FindObjectByName(yaffs_Object * directory, @@ -6742,6 +6893,9 @@ yaffs_Object *yaffs_FindObjectByName(yaffs_Object * directory, if (i) { l = ylist_entry(i, yaffs_Object, siblings); + if(l->parent != directory) + YBUG(); + yaffs_CheckObjectDetailsLoaded(l); /* Special case for lost-n-found */ @@ -6827,9 +6981,18 @@ int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize) yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1); } else if (obj->hdrChunk <= 0) { YCHAR locName[20]; + YCHAR numString[20]; + YCHAR *x = &numString[19]; + unsigned v = obj->objectId; + numString[19] = 0; + while(v>0){ + x--; + *x = '0' + (v % 10); + v /= 10; + } /* make up a name */ - yaffs_sprintf(locName, _Y("%s%d"), YAFFS_LOSTNFOUND_PREFIX, - obj->objectId); + yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX); + yaffs_strcat(locName,x); yaffs_strncpy(name, locName, buffSize - 1); } @@ -7097,6 +7260,8 @@ int yaffs_GutsInitialise(yaffs_Device * dev) dev->blockOffset = 0; dev->chunkOffset = 0; dev->nFreeChunks = 0; + + dev->gcBlock = -1; if (dev->startBlock == 0) { dev->internalStartBlock = dev->startBlock + 1; @@ -7108,7 +7273,7 @@ int yaffs_GutsInitialise(yaffs_Device * dev) /* Check geometry parameters. */ if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) || - (!dev->isYaffs2 && dev->totalBytesPerChunk != 512) || + (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) || (dev->inbandTags && !dev->isYaffs2 ) || dev->nChunksPerBlock < 2 || dev->nReservedBlocks < 2 || @@ -7162,24 +7327,19 @@ int yaffs_GutsInitialise(yaffs_Device * dev) dev->isMounted = 1; - - /* OK now calculate a few things for the device */ /* * Calculate all the chunk size manipulation numbers: */ - { - __u32 x = dev->nDataBytesPerChunk; - /* We always use dev->chunkShift and dev->chunkDiv */ - dev->chunkShift = Shifts(x); - x >>= dev->chunkShift; - dev->chunkDiv = x; - /* We only use chunk mask if chunkDiv is 1 */ - dev->chunkMask = (1<chunkShift) - 1; - } + x = dev->nDataBytesPerChunk; + /* We always use dev->chunkShift and dev->chunkDiv */ + dev->chunkShift = Shifts(x); + x >>= dev->chunkShift; + dev->chunkDiv = x; + /* We only use chunk mask if chunkDiv is 1 */ + dev->chunkMask = (1<chunkShift) - 1; - /* * Calculate chunkGroupBits. * We need to find the next power of 2 > than internalEndBlock @@ -7267,7 +7427,9 @@ int yaffs_GutsInitialise(yaffs_Device * dev) dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; } - buf = dev->srCache = YMALLOC(srCacheBytes); + dev->srCache = YMALLOC(srCacheBytes); + + buf = (__u8 *) dev->srCache; if(dev->srCache) memset(dev->srCache,0,srCacheBytes); @@ -7346,6 +7508,8 @@ int yaffs_GutsInitialise(yaffs_Device * dev) }else if(!yaffs_Scan(dev)) init_failed = 1; + + yaffs_StripDeletedObjects(dev); } if(init_failed){ @@ -7405,6 +7569,9 @@ void yaffs_Deinitialise(yaffs_Device * dev) dev->isMounted = 0; + + if(dev->deinitialiseNAND) + dev->deinitialiseNAND(dev); } }