X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs%2F.git;a=blobdiff_plain;f=yaffs_guts.c;h=5784d7956cc63d008c4df3045968e0839c90f70a;hp=bb714e01bcc79b6bc5df98f490545b8556a7fbcb;hb=64a12f248950e23dd994ff29fd090480e0921930;hpb=d3a46536d1812c81e1c494235ce8f7e25ebb0e1b diff --git a/yaffs_guts.c b/yaffs_guts.c index bb714e0..5784d79 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -14,22 +14,25 @@ */ //yaffs_guts.c -const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.16 2003-01-14 23:15:29 charles Exp $"; +const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.25 2003-05-20 22:30:35 charles Exp $"; #include "yportenv.h" #include "yaffsinterface.h" #include "yaffs_guts.h" +#define YAFFS_PASSIVE_GC_CHUNKS 2 -#define YAFFS_GARBAGE_COLLECT_LOW_WATER 2 - - - +#if 0 +// Use Steven Hill's ECC struff instead // External functions for ECC on data void nand_calculate_ecc (const u_char *dat, u_char *ecc_code); int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc); - +#define yaffs_ECCCalculate(data,ecc) nand_calculate_ecc(data,ecc) +#define yaffs_ECCCorrect(data,read_ecc,calc_ecc) nand_correct_ecc(data,read_ecc,calc_ecc) +#else +#include "yaffs_ecc.h" +#endif // countBits is a quick way of counting the number of bits in a byte. // ie. countBits[n] holds the number of 1 bits in a byte with the value n. @@ -195,7 +198,7 @@ yaffs_Object *yaffs_LostNFound(yaffs_Device *dev) static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare) { - if(chunkInNAND < dev->startBlock * YAFFS_CHUNKS_PER_BLOCK) + if(chunkInNAND < dev->startBlock * dev->nChunksPerBlock) { T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),chunkInNAND)); return YAFFS_FAIL; @@ -216,10 +219,6 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, int retVal; yaffs_Spare localSpare; - __u8 calcEcc[3]; - int eccResult1,eccResult2; - struct yaffs_NANDSpare nspare; - dev->nPageReads++; @@ -240,10 +239,13 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, { // Do ECC correction //Todo handle any errors - nand_calculate_ecc(data,calcEcc); - eccResult1 = nand_correct_data (data,spare->ecc1, calcEcc); - nand_calculate_ecc(&data[256],calcEcc); - eccResult2 = nand_correct_data (&data[256],spare->ecc2, calcEcc); + 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) { @@ -276,6 +278,8 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, } 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) @@ -298,7 +302,7 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND)); } - if(nspare.eccres2 || nspare.eccres2) + if(nspare.eccres1 || nspare.eccres2) { // Hoosterman, we had a data problem on this page yaffs_HandleReadDataError(dev,chunkInNAND); @@ -316,12 +320,10 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND static int init = 0; static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK]; static __u8 data[YAFFS_BYTES_PER_CHUNK]; - static __u8 spare[16]; - - - dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare); - - + // Might as well always allocate the larger size for dev->useNANDECC == true; + static __u8 spare[sizeof(struct yaffs_NANDSpare)]; + + dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare); if(!init) { @@ -438,8 +440,9 @@ static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND) spare.blockStatus = 0; - yaffs_WriteChunkToNAND(dev, blockInNAND * YAFFS_CHUNKS_PER_BLOCK, NULL , &spare); - yaffs_WriteChunkToNAND(dev, blockInNAND * YAFFS_CHUNKS_PER_BLOCK + 1, NULL , &spare); + // TODO change this retirement marking for other NAND types + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL , &spare); + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, NULL , &spare); yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD; dev->nRetiredBlocks++; @@ -463,7 +466,7 @@ static int yaffs_RewriteBufferedBlock(yaffs_Device *dev) static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND) { - int blockInNAND = chunkInNAND/YAFFS_CHUNKS_PER_BLOCK; + int blockInNAND = chunkInNAND/dev->nChunksPerBlock; // Mark the block for retirement yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1; @@ -490,7 +493,7 @@ static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaf static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND) { - int blockInNAND = chunkInNAND/YAFFS_CHUNKS_PER_BLOCK; + int blockInNAND = chunkInNAND/dev->nChunksPerBlock; // Mark the block for retirement yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1; @@ -582,8 +585,8 @@ void yaffs_SetObjectName(yaffs_Object *obj, const char *name) void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) { - nand_calculate_ecc (data , spare->ecc1); - nand_calculate_ecc (&data[256] , spare->ecc2); + yaffs_ECCCalculate(data , spare->ecc1); + yaffs_ECCCalculate(&data[256] , spare->ecc2); } void yaffs_CalcTagsECC(yaffs_Tags *tags) @@ -1148,9 +1151,11 @@ static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level { if(tn->level0[i]) { - theChunk = (tn->level0[i] << in->myDev->chunkGroupBits); - theBlock = yaffs_GetBlockInfo(in->myDev, theChunk/ YAFFS_CHUNKS_PER_BLOCK); + T(YAFFS_TRACE_SCAN,(TSTR("soft delete tch %d cgb %d chunk %d" TENDSTR), + tn->level0[i],in->myDev->chunkGroupBits,theChunk)); + + theBlock = yaffs_GetBlockInfo(in->myDev, theChunk/in->myDev->nChunksPerBlock); if(theBlock) { theBlock->softDeletions++; @@ -1541,7 +1546,7 @@ static int yaffs_CreateNewObjectNumber(yaffs_Device *dev) list_for_each(i,&dev->objectBucket[bucket].list) { // If there is already one in the list - if(list_entry(i, yaffs_Object,hashLink)->objectId == n) + if(i && list_entry(i, yaffs_Object,hashLink)->objectId == n) { found = 0; } @@ -1579,10 +1584,13 @@ yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,__u32 number) list_for_each(i,&dev->objectBucket[bucket].list) { // Look if it is in the list - in = list_entry(i, yaffs_Object,hashLink); - if(in->objectId == number) + if(i) { - return in; + in = list_entry(i, yaffs_Object,hashLink); + if(in->objectId == number) + { + return in; + } } } @@ -1847,7 +1855,7 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const char *oldName, yaffs_Object * yaffs_Object *obj; int force = 0; -#ifdef YAFFS_CASE_INSENSITIVE +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE // Special case for WinCE. // While look-up is case insensitive, the name isn't. // THerefore we might want to change x.txt to X.txt @@ -1987,17 +1995,36 @@ static void yaffs_DeinitialiseBlocks(yaffs_Device *dev) // FindDiretiestBlock is used to select the dirtiest block (or close enough) // for garbage collection. -static int yaffs_FindDirtiestBlock(yaffs_Device *dev) +static int yaffs_FindDirtiestBlock(yaffs_Device *dev,int aggressive) { int b = dev->currentDirtyChecker; int i; + int iterations; int dirtiest = -1; - int pagesInUse = dev->nChunksPerBlock; + int pagesInUse; yaffs_BlockInfo *bi; + + // If we're doing aggressive GC then we are happy to take a less-dirty block, and + // search further. + + pagesInUse = (aggressive)? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1; + if(aggressive) + { + iterations = dev->endBlock - dev->startBlock + 1; + } + else + { + iterations = dev->endBlock - dev->startBlock + 1; + iterations = iterations / 16; + if(iterations > 200) + { + iterations = 200; + } + } - for(i = dev->startBlock; i <= dev->endBlock && pagesInUse > 2 ; i++) + for(i = 0; i <= iterations && pagesInUse > 0 ; i++) { b++; if ( b < dev->startBlock || b > dev->endBlock) @@ -2117,7 +2144,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve) dev->allocationPage = 0; } - if(!useReserve && dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS) + if(!useReserve && dev->nErasedBlocks <= dev->nReservedBlocks) { // Not enough space to allocate unless we're allowed to use the reserve. return -1; @@ -2128,7 +2155,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve) { bi = yaffs_GetBlockInfo(dev,dev->allocationBlock); - retVal = (dev->allocationBlock * YAFFS_CHUNKS_PER_BLOCK) + + retVal = (dev->allocationBlock * dev->nChunksPerBlock) + dev->allocationPage; bi->pagesInUse++; yaffs_SetChunkBit(dev,dev->allocationBlock,dev->allocationPage); @@ -2138,7 +2165,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve) dev->nFreeChunks--; // If the block is full set the state to full - if(dev->allocationPage >= YAFFS_CHUNKS_PER_BLOCK) + if(dev->allocationPage >= dev->nChunksPerBlock) { bi->blockState = YAFFS_BLOCK_STATE_FULL; dev->allocationBlock = -1; @@ -2157,13 +2184,13 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve) // number of erased blocks. // The cache is allowed to use reserved blocks. -int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev) +static int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev) { - return (dev->nErasedBlocks >= YAFFS_RESERVED_BLOCKS); + return (dev->nErasedBlocks >= dev->nReservedBlocks); } -int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) +static int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) { int oldChunk; int newChunk; @@ -2173,7 +2200,7 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) yaffs_Spare spare; yaffs_Tags tags; - __u8 buffer[YAFFS_BYTES_PER_CHUNK]; + __u8 buffer[YAFFS_BYTES_PER_CHUNK]; // yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block); @@ -2181,7 +2208,7 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits)); - for(chunkInBlock = 0,oldChunk = block * YAFFS_CHUNKS_PER_BLOCK; + for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock; chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block); chunkInBlock++, oldChunk++ ) { @@ -2281,10 +2308,13 @@ static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev) //Scan the unlinked files looking for one to delete list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children) { - l = list_entry(i, yaffs_Object,siblings); - if(l->deleted) + if(i) { - return l; + l = list_entry(i, yaffs_Object,siblings); + if(l->deleted) + { + return l; + } } } return NULL; @@ -2328,33 +2358,27 @@ static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev) } - +#if 0 +#define YAFFS_GARBAGE_COLLECT_LOW_WATER 2 static int yaffs_CheckGarbageCollection(yaffs_Device *dev) { int block; + int aggressive=0; //yaffs_DoUnlinkedFileDeletion(dev); - if(dev->nErasedBlocks <= (YAFFS_RESERVED_BLOCKS + YAFFS_GARBAGE_COLLECT_LOW_WATER)) + if(dev->nErasedBlocks <= (dev->nReservedBlocks + YAFFS_GARBAGE_COLLECT_LOW_WATER)) { - dev->garbageCollectionRequired = 1; - } + aggressive = 1; + } - if(dev->garbageCollectionRequired) + if(aggressive) { - dev->garbageCollections++; - dev->garbageCollectionRequired = 0; - if(dev->blockSelectedForGC >= 0) - { - block = dev->blockSelectedForGC; - } - else - { - block = yaffs_FindDirtiestBlock(dev); - } + block = yaffs_FindDirtiestBlock(dev,aggressive); if(block >= 0) { + dev->garbageCollections++; return yaffs_GarbageCollectBlock(dev,block); } else @@ -2365,6 +2389,46 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev) return YAFFS_OK; } +#endif + +// New garbage collector +// If we're very low on erased blocks then we do aggressive garbage collection +// otherwise we do "passive" garbage collection. +// Aggressive gc looks further (whole array) and will accept dirtier blocks. +// Passive gc only inspects smaller areas and will only accept cleaner blocks. +// +// The idea is to help clear out space in a more spread-out manner. +// Dunno if it really does anything useful. +// +static int yaffs_CheckGarbageCollection(yaffs_Device *dev) +{ + int block; + int aggressive=0; + + //yaffs_DoUnlinkedFileDeletion(dev); + + if(dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) + { + aggressive = 1; + } + + block = yaffs_FindDirtiestBlock(dev,aggressive); + + if(block >= 0) + { + dev->garbageCollections++; + if(!aggressive) + { + dev->passiveGarbageCollections++; + } + + T(YAFFS_TRACE_GC,(TSTR("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),dev->nErasedBlocks,aggressive)); + + return yaffs_GarbageCollectBlock(dev,block); + } + + return aggressive ? YAFFS_FAIL : YAFFS_OK; +} //////////////////////////// TAGS /////////////////////////////////////// @@ -2623,7 +2687,7 @@ static int yaffs_CheckFileSanity(yaffs_Object *in) objId = in->objectId; fSize = in->variant.fileVariant.fileSize; - nChunks = (fSize + YAFFS_BYTES_PER_CHUNK -1)/YAFFS_BYTES_PER_CHUNK; + nChunks = (fSize + in->myDev->nBytesPerChunk -1)/in->myDev->nBytesPerChunk; for(chunk = 1; chunk <= nChunks; chunk++) { @@ -2774,8 +2838,8 @@ static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND) if(chunkId <= 0) return; dev->nDeletions++; - block = chunkId / YAFFS_CHUNKS_PER_BLOCK; - page = chunkId % YAFFS_CHUNKS_PER_BLOCK; + block = chunkId / dev->nChunksPerBlock; + page = chunkId % dev->nChunksPerBlock; if(markNAND) { @@ -3067,6 +3131,7 @@ static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) cache->nBytes,1); cache->dirty = 0; + cache->object = NULL; } } while(cache && chunkWritten > 0); @@ -3099,10 +3164,14 @@ static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev) if(!dev->srCache[i].object) { //T(("Grabbing empty %d\n",i)); + + //printf("Grabbing empty %d\n",i); return &dev->srCache[i]; } } + + return NULL; theOne = -1; usage = 0; // just to stop the compiler grizzling @@ -3119,6 +3188,9 @@ static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev) } //T(("Grabbing non-empty %d\n",theOne)); + + //if(theOne >= 0) printf("Grabbed non-empty cache %d\n",theOne); + return theOne >= 0 ? &dev->srCache[theOne] : NULL; } else @@ -3135,6 +3207,7 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) yaffs_Object *theObj; int usage; int i; + int pushout; if(dev->nShortOpCaches > 0) { @@ -3151,6 +3224,8 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) theObj = dev->srCache[0].object; usage = dev->srCache[0].lastUse; + cache = &dev->srCache[0]; + pushout = 0; for(i = 1; i < dev->nShortOpCaches; i++) { @@ -3159,15 +3234,27 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) { usage = dev->srCache[i].lastUse; theObj = dev->srCache[i].object; + cache = &dev->srCache[i]; + pushout = i; } } - yaffs_FlushFilesChunkCache(theObj); + if(!cache || cache->dirty) + { + + //printf("Dirty "); + yaffs_FlushFilesChunkCache(theObj); - // Try again - cache = yaffs_GrabChunkCacheWorker(dev); + // Try again + cache = yaffs_GrabChunkCacheWorker(dev); + } + else + { + //printf(" pushout %d\n",pushout); + } + } - + return cache; } else @@ -3285,6 +3372,7 @@ int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nB int nToCopy; int n = nBytes; int nDone = 0; + yaffs_ChunkCache *cache; yaffs_Device *dev; @@ -3306,14 +3394,18 @@ int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nB nToCopy = YAFFS_BYTES_PER_CHUNK - start; } - if(nToCopy != YAFFS_BYTES_PER_CHUNK) + cache = yaffs_FindChunkCache(in,chunk); + + // If the chunk is already in the cache or it is less than a whole chunk + // then use the cache (if there is caching) + // else bypass the cache. + if( cache || nToCopy != YAFFS_BYTES_PER_CHUNK) { - // An incomplete start or end chunk (or maybe both start and end chunk) if(dev->nShortOpCaches > 0) { - yaffs_ChunkCache *cache; + // If we can't find the data in the cache, then load it up. - cache = yaffs_FindChunkCache(in,chunk); + if(!cache) { cache = yaffs_GrabChunkCache(in->myDev); @@ -3531,7 +3623,7 @@ int yaffs_ResizeFile(yaffs_Object *in, int newSize) // using yaffs_DeleteChunk chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL); - if(chunkId <= 0 || chunkId >= (dev->endBlock * 32)) + if(chunkId < (dev->startBlock * 32) || chunkId >= ((dev->endBlock+1) * 32)) { //T(("Found daft chunkId %d for %d\n",chunkId,i)); } @@ -3605,7 +3697,7 @@ int yaffs_FlushFile(yaffs_Object *in, int updateTime) #endif } - retVal = yaffs_UpdateObjectHeader(in,NULL,0); + retVal = (yaffs_UpdateObjectHeader(in,NULL,0) >= 0)? YAFFS_OK : YAFFS_FAIL; } else { @@ -3862,7 +3954,7 @@ static int yaffs_IsBlockBad(yaffs_Device *dev, int blk) { yaffs_Spare spare; - yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK,NULL,&spare,1); + yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock,NULL,&spare,1); #if 1 if(yaffs_CountBits(spare.blockStatus) < 7) { @@ -3874,7 +3966,7 @@ static int yaffs_IsBlockBad(yaffs_Device *dev, int blk) return 1; } #endif - yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK + 1,NULL,&spare,1); + yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock + 1,NULL,&spare,1); #if 1 if(yaffs_CountBits(spare.blockStatus) < 7) @@ -3933,11 +4025,11 @@ static int yaffs_Scan(yaffs_Device *dev) // Read each chunk in the block. - for(c = 0; c < YAFFS_CHUNKS_PER_BLOCK && + for(c = 0; c < dev->nChunksPerBlock && state == YAFFS_BLOCK_STATE_SCANNING; c++) { // Read the spare area and decide what to do - chunk = blk * YAFFS_CHUNKS_PER_BLOCK + c; + chunk = blk * dev->nChunksPerBlock + c; yaffs_ReadChunkFromNAND(dev,chunk,NULL,&spare,1); @@ -3973,7 +4065,7 @@ static int yaffs_Scan(yaffs_Device *dev) dev->allocationPage = c; } - dev->nFreeChunks += (YAFFS_CHUNKS_PER_BLOCK - c); + dev->nFreeChunks += (dev->nChunksPerBlock - c); } else if(tags.chunkId > 0) { @@ -4191,14 +4283,19 @@ static int yaffs_Scan(yaffs_Device *dev) { struct list_head *i; + struct list_head *n; + yaffs_Object *l; // Soft delete all the unlinked files - list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children) + list_for_each_safe(i,n,&dev->unlinkedDir->variant.directoryVariant.children) { - l = list_entry(i, yaffs_Object,siblings); - if(l->deleted) + if(i) { - yaffs_SoftDeleteFile(l); + l = list_entry(i, yaffs_Object,siblings); + if(l->deleted) + { + yaffs_SoftDeleteFile(l); + } } } } @@ -4256,26 +4353,28 @@ yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const char *name) list_for_each(i,&directory->variant.directoryVariant.children) { - l = list_entry(i, yaffs_Object,siblings); - - // Special case for lost-n-found - if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND) + if(i) { - if(yaffs_strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0) + l = list_entry(i, yaffs_Object,siblings); + + // Special case for lost-n-found + if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND) { - return l; + if(yaffs_strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0) + { + return l; + } } - } - else if(yaffs_SumCompare(l->sum, sum)) - { - // Do a real check - yaffs_GetObjectName(l,buffer,YAFFS_MAX_NAME_LENGTH); - if(yaffs_strcmp(name,buffer) == 0) + else if(yaffs_SumCompare(l->sum, sum)) { - return l; - } - + // Do a real check + yaffs_GetObjectName(l,buffer,YAFFS_MAX_NAME_LENGTH); + if(yaffs_strcmp(name,buffer) == 0) + { + return l; + } + } } } @@ -4291,10 +4390,13 @@ int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object * list_for_each(i,&theDir->variant.directoryVariant.children) { - l = list_entry(i, yaffs_Object,siblings); - if(!fn(l)) + if(i) { - return YAFFS_FAIL; + l = list_entry(i, yaffs_Object,siblings); + if(l && !fn(l)) + { + return YAFFS_FAIL; + } } } @@ -4530,6 +4632,20 @@ int yaffs_GutsInitialise(yaffs_Device *dev) int extraBits; int nBlocks; + if( dev->nBytesPerChunk != YAFFS_BYTES_PER_CHUNK || + + dev->nChunksPerBlock < 2 || + dev->nReservedBlocks < 2 || + dev->startBlock <= 0 || + dev->endBlock <= 0 || + dev->endBlock <= (dev->startBlock + dev->nReservedBlocks) + ) + { + //these parameters must be set before stating yaffs + // Other parameters startBlock, + return YAFFS_FAIL; + } + if(!yaffs_CheckStructures()) @@ -4562,7 +4678,7 @@ int yaffs_GutsInitialise(yaffs_Device *dev) // Calculate chunkGroupBits. // We need to find the next power of 2 > than endBlock - x = YAFFS_CHUNKS_PER_BLOCK * (dev->endBlock+1); + x = dev->nChunksPerBlock * (dev->endBlock+1); for(bits = extraBits = 0; x > 1; bits++) { @@ -4586,18 +4702,14 @@ int yaffs_GutsInitialise(yaffs_Device *dev) } dev->chunkGroupSize = 1 << dev->chunkGroupBits; - // Stuff to be taken out later - dev->nBytesPerChunk = YAFFS_BYTES_PER_CHUNK; - dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; // More device initialisation - dev->garbageCollectionRequired = 0; dev->garbageCollections = 0; + dev->passiveGarbageCollections = 0; dev->currentDirtyChecker = 0; dev->bufferedBlock = -1; dev->doingBufferedBlockRewrite = 0; - dev->blockSelectedForGC = -1; dev->nDeletedFiles = 0; dev->nBackgroundDeletions=0; dev->nUnlinkedFiles = 0; @@ -4674,6 +4786,7 @@ void yaffs_Deinitialise(yaffs_Device *dev) yaffs_DeinitialiseBlocks(dev); yaffs_DeinitialiseTnodes(dev); yaffs_DeinitialiseObjects(dev); + YFREE(dev->localBuffer); } } @@ -4682,7 +4795,7 @@ void yaffs_Deinitialise(yaffs_Device *dev) int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) { - int nFree = dev->nFreeChunks - (YAFFS_CHUNKS_PER_BLOCK * YAFFS_RESERVED_BLOCKS); + int nFree = dev->nFreeChunks - (dev->nChunksPerBlock * YAFFS_RESERVED_BLOCKS); struct list_head *i; yaffs_Object *l; @@ -4700,7 +4813,7 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) } - printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree); + // printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree); if(nFree < 0) nFree = 0; @@ -4715,6 +4828,7 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) int nFree; int pending; int b; + int nDirtyCacheChunks=0; yaffs_BlockInfo *blk; @@ -4740,11 +4854,14 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) // To the free chunks add the chunks that are in the deleted unlinked files. list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children) { - l = list_entry(i, yaffs_Object,siblings); - if(l->deleted) + if(i) { - pending++; - pending += l->nDataChunks; + l = list_entry(i, yaffs_Object,siblings); + if(l->deleted) + { + pending++; + pending += l->nDataChunks; + } } } @@ -4759,6 +4876,20 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) nFree += pending; + // Now count the number of dirty chunks in the cache and subtract those + + { + int i; + for(i = 0; i < dev->nShortOpCaches; i++) + { + if(dev->srCache[i].dirty) nDirtyCacheChunks++; + } + } + + nFree -= nDirtyCacheChunks; + + nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); + if(nFree < 0) nFree = 0; return nFree;