X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_guts.c;h=d289c294c2d463d8396663c06205cc309cee0ca3;hp=c24c3fe28310423e5ab205848c32a047673c6f71;hb=db670e4a90555c2809667b3a032e08ca26d23e8c;hpb=1611f6f850584af2a33e790f2e7e652d77ec6526 diff --git a/yaffs_guts.c b/yaffs_guts.c index c24c3fe..d289c29 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -1,4 +1,3 @@ - /* * YAFFS: Yet another FFS. A NAND-flash specific file system. * @@ -14,7 +13,7 @@ */ //yaffs_guts.c -const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.7 2005-07-03 10:32:40 charles Exp $"; +const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.13 2005-08-01 04:53:01 charles Exp $"; #include "yportenv.h" @@ -103,7 +102,7 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type); static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj); -static int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink); +static int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink, int shadows); static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj); static int yaffs_CheckStructures(void); static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit); @@ -141,6 +140,8 @@ loff_t yaffs_GetFileSize(yaffs_Object *obj); static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve); +static void yaffs_VerifyFreeChunks(yaffs_Device *dev); + #ifdef YAFFS_PARANOID static int yaffs_CheckFileSanity(yaffs_Object *in); #else @@ -152,6 +153,8 @@ static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId); static int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *buffer, yaffs_ExtendedTags *tags) { + chunkInNAND -= dev->chunkOffset; + if(dev->readChunkWithTagsFromNAND) return dev->readChunkWithTagsFromNAND(dev,chunkInNAND,buffer,tags); else @@ -160,6 +163,8 @@ static int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __ static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_ExtendedTags *tags) { + chunkInNAND -= dev->chunkOffset; + if(tags) { tags->sequenceNumber = dev->sequenceNumber; @@ -185,6 +190,8 @@ static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkIn static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo) { + blockNo -= dev->blockOffset; + if(dev->markNANDBlockBad) return dev->markNANDBlockBad(dev,blockNo); else @@ -192,15 +199,19 @@ static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo) } static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo, yaffs_BlockState *state, unsigned *sequenceNumber) { + blockNo -= dev->blockOffset; + if(dev->queryNANDBlock) return dev->queryNANDBlock(dev,blockNo,state,sequenceNumber); else return yaffs_TagsCompatabilityQueryNANDBlock(dev,blockNo,state,sequenceNumber); } -int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND) +static int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND) { int result; + + blockInNAND -= dev->blockOffset; dev->nBlockErasures++; result = dev->eraseBlockInNAND(dev,blockInNAND); @@ -279,12 +290,12 @@ static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo) static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk) { - if(blk < dev->startBlock || blk > dev->endBlock) + if(blk < dev->internalStartBlock || blk > dev->internalEndBlock) { T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),blk)); YBUG(); } - return dev->chunkBits + (dev->chunkBitmapStride * (blk - dev->startBlock)); + return dev->chunkBits + (dev->chunkBitmapStride * (blk - dev->internalStartBlock)); } static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev,int blk) @@ -326,19 +337,6 @@ static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev,int blk) return 0; } -#if 0 -// Function to manipulate block info -static Y_INLINE yaffs_BlockInfo* yaffs_GetBlockInfo(yaffs_Device *dev, int blk) -{ - if(blk < dev->startBlock || blk > dev->endBlock) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),blk)); - YBUG(); - } - return &dev->blockInfo[blk - dev->startBlock]; -} -#endif - static Y_INLINE int yaffs_HashFunction(int n) { @@ -356,125 +354,6 @@ yaffs_Object *yaffs_LostNFound(yaffs_Device *dev) return dev->lostNFoundDir; } -#if 0 -static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare) -{ - if(chunkInNAND < dev->startBlock * dev->nChunksPerBlock) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),chunkInNAND)); - return YAFFS_FAIL; - } - - dev->nPageWrites++; - return dev->writeChunkToNAND(dev,chunkInNAND,data,spare); -} - - - -static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, - int chunkInNAND, - __u8 *data, - yaffs_Spare *spare, - int doErrorCorrection) -{ - int retVal; - yaffs_Spare localSpare; - - dev->nPageReads++; - - - - - if(!spare && data) - { - // If we don't have a real spare, then we use a local one. - // Need this for the calculation of the ecc - spare = &localSpare; - } - - - if(!dev->useNANDECC) - { - retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,spare); - if(data && doErrorCorrection) - { - // Do ECC correction - //Todo handle any errors - int eccResult1,eccResult2; - __u8 calcEcc[3]; - - yaffs_ECCCalculate(data,calcEcc); - eccResult1 = yaffs_ECCCorrect (data,spare->ecc1, calcEcc); - yaffs_ECCCalculate(&data[256],calcEcc); - eccResult2 = yaffs_ECCCorrect(&data[256],spare->ecc2, calcEcc); - - if(eccResult1>0) - { - T(YAFFS_TRACE_ERROR, (TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND)); - dev->eccFixed++; - } - else if(eccResult1<0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND)); - dev->eccUnfixed++; - } - - if(eccResult2>0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND)); - dev->eccFixed++; - } - else if(eccResult2<0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND)); - dev->eccUnfixed++; - } - - if(eccResult1 || eccResult2) - { - // Hoosterman, we had a data problem on this page - yaffs_HandleReadDataError(dev,chunkInNAND); - } - } - } - else - { - // Must allocate enough memory for spare+2*sizeof(int) for ecc results from device. - struct yaffs_NANDSpare nspare; - retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare*)&nspare); - memcpy (spare, &nspare, sizeof(yaffs_Spare)); - if(data && doErrorCorrection) - { - if(nspare.eccres1>0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND)); - } - else if(nspare.eccres1<0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND)); - } - - if(nspare.eccres2>0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND)); - } - else if(nspare.eccres2<0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND)); - } - - if(nspare.eccres1 || nspare.eccres2) - { - // Hoosterman, we had a data problem on this page - yaffs_HandleReadDataError(dev,chunkInNAND); - } - - } - } - return retVal; -} - -#endif @@ -709,7 +588,7 @@ static __u16 yaffs_CalcNameSum(const YCHAR *name) return sum; } -void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name) +static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name) { #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM if(name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) @@ -774,13 +653,13 @@ static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes) { newTnodes[i].internal[0] = &newTnodes[i+1]; #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG - newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = 1; + newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; #endif } newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes; #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG - newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = 1; + newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; #endif dev->freeTnodes = newTnodes; dev->nFreeTnodes+= nTnodes; @@ -825,7 +704,7 @@ static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev) { tn = dev->freeTnodes; #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG - if(tn->internal[YAFFS_NTNODES_INTERNAL] != 1) + if(tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) { // Hoosterman, this thing looks like it isn't in the list T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 1" TENDSTR))); @@ -853,7 +732,7 @@ static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn) // Hoosterman, this thing looks like it is already in the list T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 2" TENDSTR))); } - tn->internal[YAFFS_NTNODES_INTERNAL] = 1; + tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1; #endif tn->internal[0] = dev->freeTnodes; dev->freeTnodes = tn; @@ -1089,7 +968,7 @@ static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStru } -int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode) +static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode) { int j; @@ -1212,6 +1091,7 @@ static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk) if(theBlock) { theBlock->softDeletions++; + dev->nFreeChunks++; } } @@ -1508,7 +1388,7 @@ static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u3 obj->unlinkAllowed= 0; // ... or unlink it obj->deleted = 0; obj->unlinked = 0; - obj->st_mode = mode; + obj->yst_mode = mode; obj->myDev = dev; obj->chunkId = 0; // Not a valid chunk. } @@ -1615,7 +1495,7 @@ static void yaffs_InitialiseObjects(yaffs_Device *dev) -int yaffs_FindNiceObjectBucket(yaffs_Device *dev) +static int yaffs_FindNiceObjectBucket(yaffs_Device *dev) { static int x = 0; int i; @@ -1691,7 +1571,7 @@ static int yaffs_CreateNewObjectNumber(yaffs_Device *dev) return n; } -void yaffs_HashObject(yaffs_Object *in) +static void yaffs_HashObject(yaffs_Object *in) { int bucket = yaffs_HashFunction(in->objectId); yaffs_Device *dev = in->myDev; @@ -1764,7 +1644,7 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectTyp #else - theObject->st_atime = theObject->st_mtime = theObject->st_ctime = Y_CURRENT_TIME; + theObject->yst_atime = theObject->yst_mtime = theObject->yst_ctime = Y_CURRENT_TIME; #endif switch(type) { @@ -1796,7 +1676,7 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectTyp return theObject; } -yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type) +static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type) { yaffs_Object *theObject = NULL; @@ -1814,7 +1694,7 @@ yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaf } -YCHAR *yaffs_CloneString(const YCHAR *str) +static YCHAR *yaffs_CloneString(const YCHAR *str) { YCHAR *newStr = NULL; @@ -1833,7 +1713,7 @@ YCHAR *yaffs_CloneString(const YCHAR *str) // equivalentObject only has meaning for a hard link; // aliasString only has meaning for a sumlink. // rdev only has meaning for devices (a subset of special objects) -yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type, +static yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type, yaffs_Object *parent, const YCHAR *name, __u32 mode, @@ -1861,7 +1741,7 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type, in->valid = 1; in->variantType = type; - in->st_mode = mode; + in->yst_mode = mode; #ifdef CONFIG_YAFFS_WINCE yfsd_WinFileTimeNow(in->win_atime); @@ -1869,11 +1749,11 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type, in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1]; #else - in->st_atime = in->st_mtime = in->st_ctime = Y_CURRENT_TIME; + in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME; - in->st_rdev = rdev; - in->st_uid = uid; - in->st_gid = gid; + in->yst_rdev = rdev; + in->yst_uid = uid; + in->yst_gid = gid; #endif in->nDataChunks = 0; @@ -1903,7 +1783,7 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type, } if(/*yaffs_GetNumberOfFreeChunks(dev) <= 0 || */ - yaffs_UpdateObjectHeader(in,name,0,0) < 0) + yaffs_UpdateObjectHeader(in,name,0,0,0) < 0) { // Could not create the object header, fail the creation yaffs_DestroyObject(in); @@ -1953,10 +1833,12 @@ yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, yaffs_Object * } -static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force) +static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force,int shadows) { int unlinkOp; int deleteOp; + + yaffs_Object * existingTarget; if(newDir == NULL) { @@ -1981,13 +1863,16 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const deleteOp = (newDir == obj->myDev->deletedDir); + existingTarget = yaffs_FindObjectByName(newDir,newName); + // If the object is a file going into the unlinked directory, then it is OK to just stuff it in since // duplicate names are allowed. // Otherwise only proceed if the new name does not exist and if we're putting it into a directory. if( (unlinkOp|| deleteOp || force || - !yaffs_FindObjectByName(newDir,newName)) && + (shadows > 0) || + !existingTarget) && newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) { yaffs_SetObjectName(obj,newName); @@ -1998,7 +1883,7 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const if(unlinkOp) obj->unlinked = 1; // If it is a deletion then we mark it as a shrink for gc purposes. - if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp) >= 0) + if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp,shadows) >= 0) { return YAFFS_OK; } @@ -2012,6 +1897,7 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object *newDir, const YCHAR *newName) { yaffs_Object *obj; + yaffs_Object *existingTarget; int force = 0; #ifdef CONFIG_YAFFS_CASE_INSENSITIVE @@ -2025,9 +1911,29 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object #endif obj = yaffs_FindObjectByName(oldDir,oldName); + if(obj && obj->renameAllowed) { - return yaffs_ChangeObjectName(obj,newDir,newName,force); + + // Now do the handling for an existing target, if there is one + + existingTarget = yaffs_FindObjectByName(newDir,newName); + if(existingTarget && + existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && + !list_empty(&existingTarget->variant.directoryVariant.children)) + { + // There is a target that is a non-empty directory, so we have to fail + return YAFFS_FAIL; // EEXIST or ENOTEMPTY + } + else if(existingTarget) + { + // Nuke the target first, using shadowing + yaffs_ChangeObjectName(obj,newDir,newName,force,existingTarget->objectId); + yaffs_Unlink(newDir,newName); + } + + + return yaffs_ChangeObjectName(obj,newDir,newName,force,0); } return YAFFS_FAIL; } @@ -2170,7 +2076,7 @@ static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo * { seq = dev->sequenceNumber; - for(i = dev->startBlock; i <= dev->endBlock; i++) + for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { b = yaffs_GetBlockInfo(dev,i); if(b->blockState == YAFFS_BLOCK_STATE_FULL && @@ -2225,13 +2131,14 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,int aggressive) } pagesInUse = (aggressive)? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1; + if(aggressive) { - iterations = dev->endBlock - dev->startBlock + 1; + iterations = dev->internalEndBlock - dev->internalStartBlock + 1; } else { - iterations = dev->endBlock - dev->startBlock + 1; + iterations = dev->internalEndBlock - dev->internalStartBlock + 1; iterations = iterations / 16; if(iterations > 200) { @@ -2242,12 +2149,12 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,int aggressive) for(i = 0; i <= iterations && pagesInUse > 0 ; i++) { b++; - if ( b < dev->startBlock || b > dev->endBlock) + if ( b < dev->internalStartBlock || b > dev->internalEndBlock) { - b = dev->startBlock; + b = dev->internalStartBlock; } - if(b < dev->startBlock || b > dev->endBlock) + if(b < dev->internalStartBlock || b > dev->internalEndBlock) { T(YAFFS_TRACE_ERROR,(TSTR("**>> Block %d is not valid" TENDSTR),b)); YBUG(); @@ -2328,6 +2235,8 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo) } else { + dev->nFreeChunks -= dev->nChunksPerBlock; // We lost a block of free space + yaffs_RetireBlock(dev,blockNo); T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo)); } @@ -2339,7 +2248,7 @@ static void yaffs_DumpBlockStats(yaffs_Device *dev) int i,j; yaffs_BlockInfo *bi; - for(i= dev->startBlock; i <=dev->endBlock; i++) + for(i= dev->internalStartBlock; i <=dev->internalEndBlock; i++) { bi = yaffs_GetBlockInfo(dev,i); T(YAFFS_TRACE_ALLOCATE,(TSTR("%3d state %d shrink %d inuse %d/%d seq %d pages"),i, @@ -2388,12 +2297,12 @@ static int yaffs_FindBlockForAllocation(yaffs_Device *dev) // Find an empty block. - for(i = dev->startBlock; i <= dev->endBlock; i++) + for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { dev->allocationBlockFinder++; - if(dev->allocationBlockFinder < dev->startBlock || dev->allocationBlockFinder> dev->endBlock) + if(dev->allocationBlockFinder < dev->internalStartBlock || dev->allocationBlockFinder> dev->internalEndBlock) { - dev->allocationBlockFinder = dev->startBlock; + dev->allocationBlockFinder = dev->internalStartBlock; } bi = yaffs_GetBlockInfo(dev,dev->allocationBlockFinder); @@ -2420,6 +2329,15 @@ static int yaffs_FindBlockForAllocation(yaffs_Device *dev) } +// To determine if we have enough space we just look at the +// number of erased blocks. + +static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev) +{ + int reservedChunks = (dev->nReservedBlocks * dev->nChunksPerBlock); + return (dev->nFreeChunks > reservedChunks); +} + static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve) { @@ -2433,7 +2351,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve) dev->allocationPage = 0; } - if(!useReserve && dev->nErasedBlocks nReservedBlocks) + if(!useReserve && !yaffs_CheckSpaceForAllocation(dev)) { // Not enough space to allocate unless we're allowed to use the reserve. return -1; @@ -2476,14 +2394,6 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve) } -// To determine if we have enough space we just look at the -// number of erased blocks. -// The cache is allowed to use reserved blocks. - -static int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev) -{ - return (dev->nErasedBlocks >= dev->nReservedBlocks); -} static int yaffs_GetErasedChunks(yaffs_Device *dev) @@ -2501,7 +2411,7 @@ static int yaffs_GetErasedChunks(yaffs_Device *dev) } -int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) +static int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) { int oldChunk; int newChunk; @@ -2524,9 +2434,15 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR),block,bi->pagesInUse,bi->hasShrinkHeader)); //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits)); + + //yaffs_VerifyFreeChunks(dev); bi->hasShrinkHeader = 0; // clear the flag so that the block can erase + + dev->nFreeChunks -= bi->softDeletions; // Take off the number of soft deleted entries because + // they're going to get really deleted during GC. + dev->isDoingGC = 1; if(!yaffs_StillSomeChunkBits(dev,block)) { @@ -2536,7 +2452,7 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) else { - __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__); + __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__); for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock; chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block); @@ -2567,7 +2483,7 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) if(object && object->deleted && tags.chunkId != 0) { // Data chunk in a deleted file, throw it away - // It's a deleted data chunk, + // It's a soft deleted data chunk, // No need to copy this, just forget about it and fix up the // object. @@ -2634,6 +2550,7 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) yaffs_ReleaseTempBuffer(dev,buffer,__LINE__); + //yaffs_VerifyFreeChunks(dev); // Do any required cleanups for(i = 0; i < cleanups; i++) @@ -2656,6 +2573,11 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) { T(YAFFS_TRACE_GC,(TSTR("gc did not increase free chunks before %d after %d" TENDSTR),chunksBefore,chunksAfter)); } + + + dev->isDoingGC = 0; + + //yaffs_VerifyFreeChunks(dev); return YAFFS_OK; } @@ -2733,21 +2655,27 @@ static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev) // The idea is to help clear out space in a more spread-out manner. // Dunno if it really does anything useful. // -int yaffs_CheckGarbageCollection(yaffs_Device *dev) +static int yaffs_CheckGarbageCollection(yaffs_Device *dev) { int block; int aggressive; int gcOk = YAFFS_OK; int maxTries = 0; - //yaffs_DoUnlinkedFileDeletion(dev); + //yaffs_VerifyFreeChunks(dev); + + if(dev->isDoingGC) + { + // Bail out so we don't get recursive gc + return YAFFS_OK; + } // This loop should pass the first time. // We'll only see looping here if the erase of the collected block fails. do{ maxTries++; - if(dev->nErasedBlocks <= (dev->nReservedBlocks + 2)) + if(dev->nErasedBlocks < dev->nReservedBlocks) { // We need a block soon... aggressive = 1; @@ -2773,11 +2701,11 @@ int yaffs_CheckGarbageCollection(yaffs_Device *dev) gcOk = yaffs_GarbageCollectBlock(dev,block); } - if(dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) + if(dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) { T(YAFFS_TRACE_GC,(TSTR("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" TENDSTR),dev->nErasedBlocks,maxTries,block)); } - } while((dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) && (block > 0) && (maxTries < 5)); + } while((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0) && (maxTries < 2)); return aggressive ? gcOk: YAFFS_OK; } @@ -2935,7 +2863,7 @@ static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chu ///////////////////////////////////////////////////////////////////////////////////////////////////////// -int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags) +static int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags) { //Get the Tnode, then get the level 0 offset chunk offset yaffs_Tnode *tn; @@ -2963,7 +2891,7 @@ int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags * return retVal; } -int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags) +static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags) { //Get the Tnode, then get the level 0 offset chunk offset yaffs_Tnode *tn; @@ -3190,7 +3118,7 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn -int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer) +static int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer) { int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL); @@ -3260,9 +3188,10 @@ void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND,int lyn) bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING || bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) { - dev->nFreeChunks++; + dev->nFreeChunks++; yaffs_ClearChunkBit(dev,block,page); + bi->pagesInUse--; if(bi->pagesInUse == 0 && @@ -3284,7 +3213,7 @@ void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND,int lyn) -int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve) +static int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve) { // Find old chunk Need to do this to get serial number // Write new one and patch into tree. @@ -3340,7 +3269,7 @@ int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 * // UpdateObjectHeader updates the header on NAND for an object. // If name is not NULL, then that new name is used. // -int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink) +int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink,int shadows) { yaffs_BlockInfo *bi; @@ -3383,7 +3312,10 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int i // Header data oh->type = in->variantType; - oh->st_mode = in->st_mode; + oh->yst_mode = in->yst_mode; + + // shadowing + oh->shadowsObject = shadows; #ifdef CONFIG_YAFFS_WINCE oh->win_atime[0] = in->win_atime[0]; @@ -3393,12 +3325,12 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int i oh->win_ctime[1] = in->win_ctime[1]; oh->win_mtime[1] = in->win_mtime[1]; #else - oh->st_uid = in->st_uid; - oh->st_gid = in->st_gid; - oh->st_atime = in->st_atime; - oh->st_mtime = in->st_mtime; - oh->st_ctime = in->st_ctime; - oh->st_rdev = in->st_rdev; + oh->yst_uid = in->yst_uid; + oh->yst_gid = in->yst_gid; + oh->yst_atime = in->yst_atime; + oh->yst_mtime = in->yst_mtime; + oh->yst_ctime = in->yst_ctime; + oh->yst_rdev = in->yst_rdev; #endif if(in->parent) { @@ -3464,6 +3396,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int i newTags.extraFileLength = oh->fileSize; newTags.extraIsShrinkHeader = oh->isShrink; newTags.extraEquivalentObjectId = oh->equivalentObjectId; + newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0; newTags.extraObjectType = in->variantType; // Create new chunk in NAND @@ -3517,7 +3450,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int i static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) { yaffs_Device *dev = obj->myDev; - int lowest; + int lowest = -99; // Stop compiler whining. int i; yaffs_ChunkCache *cache; int chunkWritten = 0; @@ -3978,7 +3911,7 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in yaffs_ChunkCache *cache; // If we can't find the data in the cache, then load it up. cache = yaffs_FindChunkCache(in,chunk); - if(!cache && yaffs_CheckSpaceForChunkCache(in->myDev)) + if(!cache && yaffs_CheckSpaceForAllocation(in->myDev)) { cache = yaffs_GrabChunkCache(in->myDev); cache->object = in; @@ -4117,8 +4050,8 @@ static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize) chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL); if(chunkId > 0) { - if(chunkId < (dev->startBlock * dev->nChunksPerBlock) || - chunkId >= ((dev->endBlock+1) * dev->nChunksPerBlock)) + if(chunkId < (dev->internalStartBlock * dev->nChunksPerBlock) || + chunkId >= ((dev->internalEndBlock+1) * dev->nChunksPerBlock)) { T(YAFFS_TRACE_ALWAYS,(TSTR("Found daft chunkId %d for %d"TENDSTR),chunkId,i)); } @@ -4182,7 +4115,7 @@ int yaffs_ResizeFile(yaffs_Object *in, int newSize) in->parent->objectId != YAFFS_OBJECTID_DELETED ) { - yaffs_UpdateObjectHeader(in,NULL, 0, 1); + yaffs_UpdateObjectHeader(in,NULL, 0, 1,0); } @@ -4230,12 +4163,12 @@ int yaffs_FlushFile(yaffs_Object *in, int updateTime) yfsd_WinFileTimeNow(in->win_mtime); #else - in->st_mtime = Y_CURRENT_TIME; + in->yst_mtime = Y_CURRENT_TIME; #endif } - retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL; + retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL; } else { @@ -4256,7 +4189,7 @@ static int yaffs_DoGenericObjectDeletion(yaffs_Object *in) if(in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) { // Move to the unlinked directory so we have a record that it was deleted. - yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0); + yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0); } @@ -4319,7 +4252,7 @@ static int yaffs_UnlinkFile(yaffs_Object *in) #endif if(immediateDeletion) { - retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0); + retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0); T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId)); in->deleted=1; in->myDev->nDeletedFiles++; @@ -4331,7 +4264,7 @@ static int yaffs_UnlinkFile(yaffs_Object *in) } else { - retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0); + retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0,0); } } @@ -4450,7 +4383,7 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj) yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1); - retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0); + retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0,0); if(retVal == YAFFS_OK) { @@ -4501,6 +4434,11 @@ int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name) //////////////// Initialisation Scanning ///////////////// +void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, int backwardScanning) +{ + //Todo +} + #if 0 // For now we use the SmartMedia check. // We look at the blockStatus byte in the first two chunks @@ -4573,13 +4511,13 @@ static int yaffs_Scan(yaffs_Device *dev) yaffs_ObjectHeader *oh; yaffs_Object *in; yaffs_Object *parent; - int nBlocks = dev->endBlock - dev->startBlock + 1; + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; __u8 *chunkData; yaffs_BlockIndex *blockIndex = NULL; - T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan starts startblk %d endblk %d..." TENDSTR),dev->startBlock,dev->endBlock)); + T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),dev->internalStartBlock,dev->internalEndBlock)); chunkData = yaffs_GetTempBuffer(dev,__LINE__); @@ -4593,7 +4531,7 @@ static int yaffs_Scan(yaffs_Device *dev) // Scan all the blocks to determine their state - for(blk = dev->startBlock; blk <= dev->endBlock; blk++) + for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { bi = yaffs_GetBlockInfo(dev,blk); yaffs_ClearChunkBits(dev,blk); @@ -4673,8 +4611,8 @@ static int yaffs_Scan(yaffs_Device *dev) } else { - startIterator = dev->startBlock; - endIterator = dev->endBlock; + startIterator = dev->internalStartBlock; + endIterator = dev->internalEndBlock; } // For each block.... @@ -4799,6 +4737,11 @@ static int yaffs_Scan(yaffs_Device *dev) in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type); + if(oh->shadowsObject > 0) + { + yaffs_HandleShadowedObject(dev,oh->shadowsObject,0); + } + if(in->valid) { // We have already filled this one. We have a duplicate and need to resolve it. @@ -4828,7 +4771,7 @@ static int yaffs_Scan(yaffs_Device *dev) in->valid = 1; in->variantType = oh->type; - in->st_mode = oh->st_mode; + in->yst_mode = oh->yst_mode; #ifdef CONFIG_YAFFS_WINCE in->win_atime[0] = oh->win_atime[0]; in->win_ctime[0] = oh->win_ctime[0]; @@ -4837,12 +4780,12 @@ static int yaffs_Scan(yaffs_Device *dev) in->win_ctime[1] = oh->win_ctime[1]; in->win_mtime[1] = oh->win_mtime[1]; #else - in->st_uid = oh->st_uid; - in->st_gid = oh->st_gid; - in->st_atime = oh->st_atime; - in->st_mtime = oh->st_mtime; - in->st_ctime = oh->st_ctime; - in->st_rdev = oh->st_rdev; + in->yst_uid = oh->yst_uid; + in->yst_gid = oh->yst_gid; + in->yst_atime = oh->yst_atime; + in->yst_mtime = oh->yst_mtime; + in->yst_ctime = oh->yst_ctime; + in->yst_rdev = oh->yst_rdev; #endif in->chunkId = chunk; @@ -4854,7 +4797,7 @@ static int yaffs_Scan(yaffs_Device *dev) in->valid = 1; in->variantType = oh->type; - in->st_mode = oh->st_mode; + in->yst_mode = oh->yst_mode; #ifdef CONFIG_YAFFS_WINCE in->win_atime[0] = oh->win_atime[0]; in->win_ctime[0] = oh->win_ctime[0]; @@ -4863,12 +4806,12 @@ static int yaffs_Scan(yaffs_Device *dev) in->win_ctime[1] = oh->win_ctime[1]; in->win_mtime[1] = oh->win_mtime[1]; #else - in->st_uid = oh->st_uid; - in->st_gid = oh->st_gid; - in->st_atime = oh->st_atime; - in->st_mtime = oh->st_mtime; - in->st_ctime = oh->st_ctime; - in->st_rdev = oh->st_rdev; + in->yst_uid = oh->yst_uid; + in->yst_gid = oh->yst_gid; + in->yst_atime = oh->yst_atime; + in->yst_mtime = oh->yst_mtime; + in->yst_ctime = oh->yst_ctime; + in->yst_rdev = oh->yst_rdev; #endif in->chunkId = chunk; @@ -5003,6 +4946,8 @@ static int yaffs_Scan(yaffs_Device *dev) } + // Handle the unlinked files. Since they were left in an unlinked state we should + // just delete them. { struct list_head *i; struct list_head *n; @@ -5047,7 +4992,7 @@ static int yaffs_ScanBackwards(yaffs_Device *dev) yaffs_ObjectHeader *oh; yaffs_Object *in; yaffs_Object *parent; - int nBlocks = dev->endBlock - dev->startBlock + 1; + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; __u8 *chunkData; @@ -5060,21 +5005,18 @@ static int yaffs_ScanBackwards(yaffs_Device *dev) return YAFFS_FAIL; } - T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards starts startblk %d endblk %d..." TENDSTR),dev->startBlock,dev->endBlock)); + T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards starts intstartblk %d intendblk %d..." TENDSTR),dev->internalStartBlock,dev->internalEndBlock)); chunkData = yaffs_GetTempBuffer(dev,__LINE__); dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; - if(dev->isYaffs2) - { - blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); - } + blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); // Scan all the blocks to determine their state - for(blk = dev->startBlock; blk <= dev->endBlock; blk++) + for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { bi = yaffs_GetBlockInfo(dev,blk); yaffs_ClearChunkBits(dev,blk); @@ -5128,7 +5070,6 @@ static int yaffs_ScanBackwards(yaffs_Device *dev) // Sort the blocks // Dungy old bubble sort for now... - if(dev->isYaffs2) { yaffs_BlockIndex temp; int i; @@ -5146,12 +5087,9 @@ static int yaffs_ScanBackwards(yaffs_Device *dev) // Now scan the blocks looking at the data. - if(dev->isYaffs2) - { - startIterator = 0; - endIterator = nBlocksToScan-1; - T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan)); - } + startIterator = 0; + endIterator = nBlocksToScan-1; + T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan)); // For each block.... backwards @@ -5364,7 +5302,7 @@ static int yaffs_ScanBackwards(yaffs_Device *dev) in->valid = 1; in->variantType = oh->type; - in->st_mode = oh->st_mode; + in->yst_mode = oh->yst_mode; #ifdef CONFIG_YAFFS_WINCE in->win_atime[0] = oh->win_atime[0]; in->win_ctime[0] = oh->win_ctime[0]; @@ -5373,12 +5311,12 @@ static int yaffs_ScanBackwards(yaffs_Device *dev) in->win_ctime[1] = oh->win_ctime[1]; in->win_mtime[1] = oh->win_mtime[1]; #else - in->st_uid = oh->st_uid; - in->st_gid = oh->st_gid; - in->st_atime = oh->st_atime; - in->st_mtime = oh->st_mtime; - in->st_ctime = oh->st_ctime; - in->st_rdev = oh->st_rdev; + in->yst_uid = oh->yst_uid; + in->yst_gid = oh->yst_gid; + in->yst_atime = oh->yst_atime; + in->yst_mtime = oh->yst_mtime; + in->yst_ctime = oh->yst_ctime; + in->yst_rdev = oh->yst_rdev; #endif in->chunkId = chunk; @@ -5390,7 +5328,7 @@ static int yaffs_ScanBackwards(yaffs_Device *dev) in->valid = 1; in->variantType = oh->type; - in->st_mode = oh->st_mode; + in->yst_mode = oh->yst_mode; #ifdef CONFIG_YAFFS_WINCE in->win_atime[0] = oh->win_atime[0]; in->win_ctime[0] = oh->win_ctime[0]; @@ -5399,14 +5337,20 @@ static int yaffs_ScanBackwards(yaffs_Device *dev) in->win_ctime[1] = oh->win_ctime[1]; in->win_mtime[1] = oh->win_mtime[1]; #else - in->st_uid = oh->st_uid; - in->st_gid = oh->st_gid; - in->st_atime = oh->st_atime; - in->st_mtime = oh->st_mtime; - in->st_ctime = oh->st_ctime; - in->st_rdev = oh->st_rdev; + in->yst_uid = oh->yst_uid; + in->yst_gid = oh->yst_gid; + in->yst_atime = oh->yst_atime; + in->yst_mtime = oh->yst_mtime; + in->yst_ctime = oh->yst_ctime; + in->yst_rdev = oh->yst_rdev; #endif in->chunkId = chunk; + + if(oh->shadowsObject > 0) + { + yaffs_HandleShadowedObject(dev,oh->shadowsObject,0); + } + yaffs_SetObjectName(in,oh->name); in->dirty = 0; @@ -5643,6 +5587,10 @@ yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const YCHAR *name) yaffs_Object *l; + if(!name) + { + return NULL; + } if(!directory) { @@ -5836,10 +5784,10 @@ unsigned yaffs_GetObjectType(yaffs_Object *obj) case YAFFS_OBJECT_TYPE_SYMLINK: return DT_LNK; break; case YAFFS_OBJECT_TYPE_HARDLINK: return DT_REG; break; case YAFFS_OBJECT_TYPE_SPECIAL: - if(S_ISFIFO(obj->st_mode)) return DT_FIFO; - if(S_ISCHR(obj->st_mode)) return DT_CHR; - if(S_ISBLK(obj->st_mode)) return DT_BLK; - if(S_ISSOCK(obj->st_mode)) return DT_SOCK; + if(S_ISFIFO(obj->yst_mode)) return DT_FIFO; + if(S_ISCHR(obj->yst_mode)) return DT_CHR; + if(S_ISBLK(obj->yst_mode)) return DT_BLK; + if(S_ISSOCK(obj->yst_mode)) return DT_SOCK; default: return DT_REG; break; } } @@ -5863,17 +5811,17 @@ int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr) { unsigned int valid = attr->ia_valid; - if(valid & ATTR_MODE) obj->st_mode = attr->ia_mode; - if(valid & ATTR_UID) obj->st_uid = attr->ia_uid; - if(valid & ATTR_GID) obj->st_gid = attr->ia_gid; + if(valid & ATTR_MODE) obj->yst_mode = attr->ia_mode; + if(valid & ATTR_UID) obj->yst_uid = attr->ia_uid; + if(valid & ATTR_GID) obj->yst_gid = attr->ia_gid; - if(valid & ATTR_ATIME) obj->st_atime = Y_TIME_CONVERT(attr->ia_atime); - if(valid & ATTR_CTIME) obj->st_ctime = Y_TIME_CONVERT(attr->ia_ctime); - if(valid & ATTR_MTIME) obj->st_mtime = Y_TIME_CONVERT(attr->ia_mtime); + if(valid & ATTR_ATIME) obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); + if(valid & ATTR_CTIME) obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime); + if(valid & ATTR_MTIME) obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime); if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size); - yaffs_UpdateObjectHeader(obj,NULL,1,0); + yaffs_UpdateObjectHeader(obj,NULL,1,0,0); return YAFFS_OK; @@ -5882,13 +5830,13 @@ int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr) { unsigned int valid = 0; - attr->ia_mode = obj->st_mode; valid |= ATTR_MODE; - attr->ia_uid = obj->st_uid; valid |= ATTR_UID; - attr->ia_gid = obj->st_gid; valid |= ATTR_GID; + attr->ia_mode = obj->yst_mode; valid |= ATTR_MODE; + attr->ia_uid = obj->yst_uid; valid |= ATTR_UID; + attr->ia_gid = obj->yst_gid; valid |= ATTR_GID; - Y_TIME_CONVERT(attr->ia_atime)= obj->st_atime; valid |= ATTR_ATIME; - Y_TIME_CONVERT(attr->ia_ctime) = obj->st_ctime; valid |= ATTR_CTIME; - Y_TIME_CONVERT(attr->ia_mtime) = obj->st_mtime; valid |= ATTR_MTIME; + Y_TIME_CONVERT(attr->ia_atime)= obj->yst_atime; valid |= ATTR_ATIME; + Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; valid |= ATTR_CTIME; + Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; valid |= ATTR_MTIME; attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE; @@ -5945,7 +5893,7 @@ int yaffs_DumpObject(yaffs_Object *obj) ///////////////////////// Initialisation code /////////////////////////// -int yaffs_CheckDevFunctions(const yaffs_Device *dev) +static int yaffs_CheckDevFunctions(const yaffs_Device *dev) { // Common functions, gotta have @@ -5991,6 +5939,20 @@ int yaffs_GutsInitialise(yaffs_Device *dev) T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Need a device" TENDSTR))); return YAFFS_FAIL; } + + dev->internalStartBlock = dev->startBlock; + dev->internalEndBlock = dev->endBlock; + dev->blockOffset = 0; + dev->chunkOffset = 0; + dev->nFreeChunks = 0; + + if(dev->startBlock == 0) + { + dev->internalStartBlock = dev->startBlock + 1; + dev->internalEndBlock = dev->endBlock + 1; + dev->blockOffset = 1; + dev->chunkOffset = dev->nChunksPerBlock; + } // Check geometry parameters. @@ -5998,9 +5960,9 @@ int yaffs_GutsInitialise(yaffs_Device *dev) (!dev->isYaffs2 && dev->nBytesPerChunk !=512) || dev->nChunksPerBlock < 2 || dev->nReservedBlocks < 2 || - dev->startBlock <= 0 || - dev->endBlock <= 0 || - dev->endBlock <= (dev->startBlock + dev->nReservedBlocks + 2) // otherwise it is too small + dev->internalStartBlock <= 0 || + dev->internalEndBlock <= 0 || + dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2) // otherwise it is too small ) { T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s " TENDSTR), @@ -6045,15 +6007,15 @@ int yaffs_GutsInitialise(yaffs_Device *dev) dev->isMounted = 1; - nBlocks = dev->endBlock - dev->startBlock + 1; + nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; // OK now calculate a few things for the device // Calculate chunkGroupBits. - // We need to find the next power of 2 > than endBlock + // We need to find the next power of 2 > than internalEndBlock - x = dev->nChunksPerBlock * (dev->endBlock+1); + x = dev->nChunksPerBlock * (dev->internalEndBlock+1); for(bits = extraBits = 0; x > 1; bits++) { @@ -6106,6 +6068,7 @@ int yaffs_GutsInitialise(yaffs_Device *dev) dev->tagsEccUnfixed=0; dev->nErasureFailures = 0; dev->nErasedBlocks = 0; + dev->isDoingGC = 0; //dev->localBuffer = YMALLOC(dev->nBytesPerChunk); // Initialise temporary buffers @@ -6176,12 +6139,14 @@ int yaffs_GutsInitialise(yaffs_Device *dev) // Zero out stats dev->nPageReads = 0; - dev->nPageWrites = 0; + dev->nPageWrites = 0; dev->nBlockErasures = 0; dev->nGCCopies = 0; dev->nRetriedWrites = 0; dev->nRetiredBlocks = 0; + + yaffs_VerifyFreeChunks(dev); T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); return YAFFS_OK; @@ -6252,19 +6217,15 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) #endif -int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) +static int yaffs_CountFreeChunks(yaffs_Device *dev) { int nFree; - int pending; int b; - int nDirtyCacheChunks=0; - - yaffs_BlockInfo *blk; - - struct list_head *i; - yaffs_Object *l; + + yaffs_BlockInfo *blk; + - for(nFree = 0, b = dev->startBlock; b <= dev->endBlock; b++) + for(nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; b++) { blk = yaffs_GetBlockInfo(dev,b); @@ -6272,44 +6233,36 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) { case YAFFS_BLOCK_STATE_EMPTY: case YAFFS_BLOCK_STATE_ALLOCATING: - case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse); break; + case YAFFS_BLOCK_STATE_COLLECTING: + case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse + blk->softDeletions); break; default: break; } + } + return nFree; +} - pending = 0; - - // To the free chunks add the chunks that are in the deleted unlinked files. - list_for_each(i,&dev->deletedDir->variant.directoryVariant.children) - { - if(i) - { - l = list_entry(i, yaffs_Object,siblings); - if(l->deleted) - { - pending++; - pending += l->nDataChunks; - } - } - } - - - - //printf("___________ really free is %d, pending %d, nFree is %d\n",nFree,pending, nFree+pending); - - if(nFree != dev->nFreeChunks) - { - // printf("___________Different! really free is %d, nFreeChunks %d\n",nFree dev->nFreeChunks); - } - nFree += pending; + +int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) +{ + // This is what we report to the outside world + + int nFree; + int nDirtyCacheChunks; + +#if 1 + nFree = dev->nFreeChunks; +#else + nFree = yaffs_CountFreeChunks(dev); +#endif // Now count the number of dirty chunks in the cache and subtract those { int i; - for(i = 0; i < dev->nShortOpCaches; i++) + for( nDirtyCacheChunks = 0,i = 0; i < dev->nShortOpCaches; i++) { if(dev->srCache[i].dirty) nDirtyCacheChunks++; } @@ -6325,7 +6278,20 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) } +static int yaffs_freeVerificationFailures; +static void yaffs_VerifyFreeChunks(yaffs_Device *dev) +{ + int counted = yaffs_CountFreeChunks(dev); + + int difference = dev->nFreeChunks - counted; + + if(difference) + { + T(YAFFS_TRACE_ALWAYS,(TSTR("Freechunks verification failure %d %d %d" TENDSTR),dev->nFreeChunks,counted,difference)); + yaffs_freeVerificationFailures++; + } +} /////////////////// YAFFS test code //////////////////////////////////