X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs%2F.git;a=blobdiff_plain;f=yaffs_guts.c;h=2fddbc2d66ea2c3ecf055cde57e397070e37f51c;hp=eaa18fda50db7701b6235d0621ff51cb7141d41f;hb=fda65c091dee0b79326a319fea302015e5f19683;hpb=f40b8435a109889e57bc37743ac7eb6badf1dd95 diff --git a/yaffs_guts.c b/yaffs_guts.c index eaa18fd..2fddbc2 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -14,6 +14,8 @@ */ //yaffs_guts.c +const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.14 2002-12-04 19:12:43 charles Exp $"; + #include "yportenv.h" #include "yaffsinterface.h" @@ -23,6 +25,7 @@ #define YAFFS_GARBAGE_COLLECT_LOW_WATER 2 + // 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); @@ -63,7 +66,7 @@ static int yaffs_CountBits(__u8 x) // Local prototypes static int yaffs_CheckObjectHashSanity(yaffs_Device *dev); static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr); -static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr); +static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr); static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan); static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type); @@ -107,18 +110,15 @@ static int yaffs_CheckFileSanity(yaffs_Object *in); #define yaffs_CheckFileSanity(in) #endif -#ifdef CONFIG_YAFFS_SHORT_OP_CACHE -static void yaffs_InvalidateChunkCache(yaffs_Object *in); -#define yaffs_INVALIDATECHUNKCACHE(in) yaffs_InvalidateChunkCache(in) -#else -#define yaffs_INVALIDATECHUNKCACHE(in) -#endif +static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in); +static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId); static __inline__ yaffs_BlockInfo* yaffs_GetBlockInfo(yaffs_Device *dev, int blk) { if(blk < dev->startBlock || blk > dev->endBlock) { + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: block %d is not valid" TENDSTR),blk)); YBUG(); } return &dev->blockInfo[blk - dev->startBlock]; @@ -144,20 +144,43 @@ 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) + { + 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); } +struct nandspare { + yaffs_Spare spare; + int eccres1; + int eccres2; +}; -int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare,int doErrorCorrection) +int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, + int chunkInNAND, + __u8 *data, + yaffs_Spare *spare, + int doErrorCorrection) { int retVal; - __u8 calcEcc[3]; yaffs_Spare localSpare; - int eccResult1,eccResult2; - + +#ifndef CONFIG_YAFFS_USE_NANDECC + __u8 calcEcc[3]; + int eccResult1,eccResult2; +#else + struct nandspare nspare; +#endif + dev->nPageReads++; + + + if(!spare && data) { // If we don't have a real spare, then we use a local one. @@ -165,40 +188,45 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 spare = &localSpare; } - retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,spare); + +#ifndef CONFIG_YAFFS_USE_NANDECC + retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,spare); + if(data && doErrorCorrection) + { + // Hoosterman, we had a data problem on this page + yaffs_HandleReadDataError(dev,chunkInNAND); + } +#else + retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare*)&nspare); + memcpy (spare, &nspare, sizeof(yaffs_Spare)); if(data && doErrorCorrection) { - // 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); - - if(eccResult1>0) + if(nspare.eccres1>0) { - T((TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND)); + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND)); } - else if(eccResult1<0) + else if(nspare.eccres1<0) { - T((TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND)); + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND)); } - - if(eccResult2>0) + + if(nspare.eccres2>0) { - T((TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND)); + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND)); } - else if(eccResult2<0) + else if(nspare.eccres2<0) { - T((TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND)); + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND)); } - - if(eccResult1 || eccResult2) + + if(nspare.eccres2 || nspare.eccres2) { // Hoosterman, we had a data problem on this page yaffs_HandleReadDataError(dev,chunkInNAND); } + } +#endif return retVal; } @@ -265,7 +293,7 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8 #endif if(!writeOk) { - T((TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk)); + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk)); } else { @@ -283,9 +311,9 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8 #ifndef CONFIG_YAFFS_DISABLE_WRITE_VERIFY if(!yaffs_VerifyCompare(data,rbData,spare,&rbSpare)) - { + { // Didn't verify - T((TSTR("**>> yaffs write verify failed on chunk %d" TENDSTR), chunk)); + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write verify failed on chunk %d" TENDSTR), chunk)); writeOk = 0; } @@ -309,7 +337,7 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8 if(attempts > 1) { - T((TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts)); + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts)); dev->nRetriedWrites+= (attempts - 1); } @@ -360,7 +388,7 @@ static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND) // Mark the block for retirement yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1; - T((TSTR("**>>Block %d marked for retirement" TENDSTR),blockInNAND)); + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>>Block %d marked for retirement" TENDSTR),blockInNAND)); //TODO @@ -443,9 +471,13 @@ static __u16 yaffs_CalcNameSum(const char *name) __u8 *bname = (__u8 *)name; if(bname) { - while (*bname) + while ((*bname) && (i <=YAFFS_MAX_NAME_LENGTH)) { +#ifdef CONFIG_YAFFS_WINCE + sum += toupper(*bname) * i; +#else sum += (*bname) * i; +#endif i++; bname++; } @@ -453,6 +485,20 @@ static __u16 yaffs_CalcNameSum(const char *name) return sum; } +void yaffs_SetObjectName(yaffs_Object *obj, const char *name) +{ +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM + if(name && strlen(name) <= YAFFS_SHORT_NAME_LENGTH) + { + strcpy(obj->shortName,name); + } + else + { + obj->shortName[0]='\0'; + } +#endif + obj->sum = yaffs_CalcNameSum(name); +} void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) { @@ -488,7 +534,7 @@ void yaffs_CalcTagsECC(yaffs_Tags *tags) } -void yaffs_CheckECCOnTags(yaffs_Tags *tags) +int yaffs_CheckECCOnTags(yaffs_Tags *tags) { unsigned ecc = tags->ecc; @@ -496,9 +542,9 @@ void yaffs_CheckECCOnTags(yaffs_Tags *tags) ecc ^= tags->ecc; - if(ecc) + if(ecc && ecc <= 64) { - // Needs fixing + // TODO: Handle the failure better. Retire? unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes; ecc--; @@ -507,7 +553,17 @@ void yaffs_CheckECCOnTags(yaffs_Tags *tags) // Now recvalc the ecc yaffs_CalcTagsECC(tags); + + return 1; // recovered error } + else if(ecc) + { + // Wierd ecc failure value + // TODO Need to do somethiong here + return -1; //unrecovered error + } + + return 0; } @@ -543,7 +599,7 @@ static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes) if (!newTnodes) { - YALERT("Could not malloc tnodes"); + T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not allocate Tnodes"TENDSTR))); return YAFFS_FAIL; } @@ -559,11 +615,13 @@ static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes) dev->nTnodesCreated += nTnodes; // Now add this bunch of tnodes to a list for freeing up. - + // NB If we can't add this to the management list it isn't fatal + // but it just means we can't free this bunch of tnodes later. tnl = YMALLOC(sizeof(yaffs_TnodeList)); if(!tnl) { - YALERT("Could not add tnodes to management list"); + T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not add tnodes to management list" TENDSTR))); + } else { @@ -573,7 +631,7 @@ static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes) } - YINFO("Tnodes created"); + T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Tnodes added" TENDSTR))); return YAFFS_OK; @@ -637,6 +695,7 @@ static void yaffs_InitialiseTnodes(yaffs_Device*dev) } +#if 0 void yaffs_TnodeTest(yaffs_Device *dev) { @@ -664,6 +723,8 @@ void yaffs_TnodeTest(yaffs_Device *dev) } } +#endif + ////////////////// END OF TNODE MANIPULATION /////////////////////////// @@ -685,17 +746,17 @@ static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,yaffs_FileStructure // Check sane level and chunk Id if(level < 0 || level > YAFFS_TNODES_MAX_LEVEL) { - char str[50]; - sprintf(str,"Bad level %d",level); - YALERT(str); +// char str[50]; +// sprintf(str,"Bad level %d",level); +// YALERT(str); return NULL; } if(chunkId > YAFFS_MAX_CHUNK_ID) { - char str[50]; - sprintf(str,"Bad chunkId %d",chunkId); - YALERT(str); +// char str[50]; +// sprintf(str,"Bad chunkId %d",chunkId); +// YALERT(str); return NULL; } @@ -742,37 +803,38 @@ static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStru yaffs_Tnode *tn; int requiredTallness; + int i; + int l; - __u32 i; - __u32 l; - + __u32 x; + //T((TSTR("AddOrFind topLevel=%d, chunk=%d"),fStruct->topLevel,chunkId)); // Check sane level and page Id if(fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL) { - char str[50]; - sprintf(str,"Bad level %d",fStruct->topLevel); - YALERT(str); +// char str[50]; +// sprintf(str,"Bad level %d",fStruct->topLevel); +// YALERT(str); return NULL; } if(chunkId > YAFFS_MAX_CHUNK_ID) { - char str[50]; - sprintf(str,"Bad chunkId %d",chunkId); - YALERT(str); +// char str[50]; +// sprintf(str,"Bad chunkId %d",chunkId); +// YALERT(str); return NULL; } // First check we're tall enough (ie enough topLevel) - i = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS); + x = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS); requiredTallness = 0; - while(i) + while(x) { - i >>= YAFFS_TNODES_INTERNAL_BITS; + x >>= YAFFS_TNODES_INTERNAL_BITS; requiredTallness++; } @@ -795,7 +857,7 @@ static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStru } else { - YALERT("No more tnodes"); + T(YAFFS_TRACE_ERROR,(TSTR("yaffs: no more tnodes" TENDSTR))); } } @@ -809,19 +871,19 @@ static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStru tn = fStruct->top; while (l > 0 && tn) { - i = (chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) & + x = (chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) & YAFFS_TNODES_INTERNAL_MASK; //T((TSTR(" [%d:%d]"),l,i)); - if(!tn->internal[i]) + if(!tn->internal[x]) { //T((TSTR(" added"))); - tn->internal[i] = yaffs_GetTnode(dev); + tn->internal[x] = yaffs_GetTnode(dev); } - tn = tn->internal[i]; + tn = tn->internal[x]; l--; } @@ -1028,6 +1090,7 @@ static int yaffs_PruneFileStructure(yaffs_Device *dev, yaffs_FileStructure *fStr + /////////////////////// End of File Structure functions. ///////////////// // yaffs_CreateFreeObjects creates a bunch more objects and @@ -1046,7 +1109,7 @@ static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects) if (!newObjects) { - YALERT("Could not allocate more objects"); + T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Could not allocate more objects" TENDSTR))); return YAFFS_FAIL; } @@ -1066,7 +1129,7 @@ static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects) list = YMALLOC(sizeof(yaffs_ObjectList)); if(!list) { - YALERT("Could not add Objects to management list"); + T(YAFFS_TRACE_ALLOCATE,(TSTR("Could not add objects to management list" TENDSTR))); } else { @@ -1076,8 +1139,6 @@ static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects) } - YINFO("Objects created"); - return YAFFS_OK; } @@ -1263,7 +1324,7 @@ static int yaffs_CreateNewObjectNumber(yaffs_Device *dev) int found = 0; struct list_head *i; - int n = bucket; + __u32 n = (__u32)bucket; //yaffs_CheckObjectHashSanity(); @@ -1296,16 +1357,16 @@ void yaffs_HashObject(yaffs_Object *in) if(!list_empty(&in->hashLink)) { - YINFO("!!!"); + //YINFO("!!!"); } - + list_add(&in->hashLink,&dev->objectBucket[bucket].list); dev->objectBucket[bucket].count++; } -yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,int number) +yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,__u32 number) { int bucket = yaffs_HashFunction(number); struct list_head *i; @@ -1346,8 +1407,14 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectTyp theObject->objectId = number; yaffs_HashObject(theObject); theObject->variantType = type; - theObject->st_atime = theObject->st_mtime = theObject->st_ctime = CURRENT_TIME; +#ifdef CONFIG_YAFFS_WINCE + yfsd_WinFileTimeNow(theObject->win_atime); + theObject->win_ctime[0] = theObject->win_mtime[0] = theObject->win_atime[0]; + theObject->win_ctime[1] = theObject->win_mtime[1] = theObject->win_atime[1]; +#else + theObject->st_atime = theObject->st_mtime = theObject->st_ctime = CURRENT_TIME; +#endif switch(type) { case YAFFS_OBJECT_TYPE_FILE: @@ -1443,14 +1510,21 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type, in->variantType = type; in->st_mode = mode; + +#ifdef CONFIG_YAFFS_WINCE + yfsd_WinFileTimeNow(in->win_atime); + in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0]; + in->win_ctime[1] = in->win_mtime[1] = in->win_atime[0]; + +#else + in->st_atime = in->st_mtime = in->st_ctime = CURRENT_TIME; in->st_rdev = rdev; in->st_uid = uid; in->st_gid = gid; - in->st_atime = in->st_mtime = in->st_ctime = CURRENT_TIME; - +#endif in->nDataChunks = 0; - in->sum = yaffs_CalcNameSum(name); + yaffs_SetObjectName(in,name); in->dirty = 1; yaffs_AddObjectToDirectory(parent,in); @@ -1526,7 +1600,7 @@ yaffs_Object *yaffs_Link(yaffs_Object *parent, const char *name, yaffs_Object *e } -static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const char *newName) +static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const char *newName,int force) { int unlinkOp; @@ -1540,11 +1614,12 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const // 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|| - (!yaffs_FindObjectByName(newDir,newName) && - newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)) + if( (unlinkOp|| + force || + !yaffs_FindObjectByName(newDir,newName)) && + newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) { - obj->sum = yaffs_CalcNameSum(newName); + yaffs_SetObjectName(obj,newName); obj->dirty = 1; yaffs_AddObjectToDirectory(newDir,obj); @@ -1561,14 +1636,27 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const return YAFFS_FAIL; } + + int yaffs_RenameObject(yaffs_Object *oldDir, const char *oldName, yaffs_Object *newDir, const char *newName) { yaffs_Object *obj; + int force = 0; + +#ifdef CONFIG_YAFFS_WINCE + // 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 + if(oldDir == newDir && _stricmp(oldName,newName) == 0) + { + force = 1; + } +#endif obj = yaffs_FindObjectByName(oldDir,oldName); if(obj && obj->renameAllowed) { - return yaffs_ChangeObjectName(obj,newDir,newName); + return yaffs_ChangeObjectName(obj,newDir,newName,force); } return YAFFS_FAIL; } @@ -1595,7 +1683,7 @@ static int yaffs_CheckObjectHashSanity(yaffs_Device *dev) if(countEm != dev->objectBucket[bucket].count) { - YALERT("Inode hash inconsistency"); + T(YAFFS_TRACE_ERROR,(TSTR("Inode hash inconsistency" TENDSTR))); ok = YAFFS_FAIL; } } @@ -1603,6 +1691,7 @@ static int yaffs_CheckObjectHashSanity(yaffs_Device *dev) return ok; } +#if 0 void yaffs_ObjectTest(yaffs_Device *dev) { yaffs_Object *in[1000]; @@ -1659,7 +1748,7 @@ void yaffs_ObjectTest(yaffs_Device *dev) } - +#endif /////////////////////////// Block Management and Page Allocation /////////////////// @@ -1699,10 +1788,16 @@ static int yaffs_FindDirtiestBlock(yaffs_Device *dev) for(i = dev->startBlock; i <= dev->endBlock && pagesInUse > 2 ; i++) { b++; - if (b > dev->endBlock) + if ( b < dev->startBlock || b > dev->endBlock) { b = dev->startBlock; } + + if(b < dev->startBlock || b > dev->endBlock) + { + T(YAFFS_TRACE_ERROR,(TSTR("**>> Block %d is not valid" TENDSTR),b)); + YBUG(); + } bi = yaffs_GetBlockInfo(dev,b); @@ -1735,7 +1830,7 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo) erasedOk = yaffs_EraseBlockInNAND(dev,blockNo); if(!erasedOk) { - T((TSTR("**>> Erasure failed %d" TENDSTR),blockNo)); + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Erasure failed %d" TENDSTR),blockNo)); } } @@ -1746,12 +1841,12 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo) bi->pagesInUse = 0; bi->pageBits = 0; - T((TSTR("Erased block %d" TENDSTR),blockNo)); + T(YAFFS_TRACE_ERASE,(TSTR("Erased block %d" TENDSTR),blockNo)); } else { yaffs_RetireBlock(dev,blockNo); - T((TSTR("**>> Block %d retired" TENDSTR),blockNo)); + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo)); } } @@ -1765,6 +1860,8 @@ static int yaffs_FindBlockForAllocation(yaffs_Device *dev) { // Hoosterman we've got a problem. // Can't get space to gc + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: no space during gc" TENDSTR))); + return -1; } @@ -1829,11 +1926,20 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve) return retVal; } - T((TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR))); + T(YAFFS_TRACE_ERROR,(TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR))); return -1; } +// To determine if we have enough space we just look at the +// number of erased blocks. +// The cache is allowed to use reserved blocks. + +int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev) +{ + return (dev->nErasedBlocks >= YAFFS_RESERVED_BLOCKS); +} + int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) { @@ -1867,41 +1973,57 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) yaffs_ReadChunkFromNAND(dev,oldChunk,buffer, &spare,1); - yaffs_GetTagsFromSpare(&spare,&tags); - tags.serialNumber++; - yaffs_LoadTagsIntoSpare(&spare,&tags); + yaffs_GetTagsFromSpare(dev,&spare,&tags); -#if 0 - newChunk = yaffs_AllocatePage(dev,1); - if(newChunk < 0) + object = yaffs_FindObjectByNumber(dev,tags.objectId); + + if(object && object->deleted && tags.chunkId != 0) { - return YAFFS_FAIL; + // Data chunk in a deleted file, throw it away + // It's a deleted data chunk, + // No need to copy this, just forget about it and fix up the + // object. + + yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0); + object->nDataChunks--; } - - yaffs_WriteChunkToNAND(dev,newChunk, buffer, &spare); - -#else - newChunk = yaffs_WriteNewChunkToNAND(dev, buffer, &spare,1); -#endif - if(newChunk < 0) + else if( 0 /* Todo object && object->deleted && object->nDataChunks == 0 */) { - return YAFFS_FAIL; + // Deleted object header with no data chunks. + // Can be discarded + object->chunkId = 0; + //Todo some clean up + } + else if(object) + { + // It's either a data chunk in a live file or + // an ObjectHeader, so we're interested in it. + // NB Need to keep the ObjectHeaders of deleted files + // until the whole file has been deleted off + tags.serialNumber++; + yaffs_LoadTagsIntoSpare(&spare,&tags); - object = yaffs_FindObjectByNumber(dev,tags.objectId); + + newChunk = yaffs_WriteNewChunkToNAND(dev, buffer, &spare,1); - // Ok, now fix up the Tnodes etc. + if(newChunk < 0) + { + return YAFFS_FAIL; + } - if(tags.chunkId == 0) - { - // It's a header - object->chunkId = newChunk; - } - else - { - // It's a data chunk - yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0); - + // Ok, now fix up the Tnodes etc. + + if(tags.chunkId == 0) + { + // It's a header + object->chunkId = newChunk; + } + else + { + // It's a data chunk + yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0); + } } yaffs_DeleteChunk(dev,oldChunk); @@ -1945,9 +2067,22 @@ static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev) if(dev->unlinkedDeletion) { yaffs_Object *obj = dev->unlinkedDeletion; - int limit; int delresult; - limit = 50; // Max number of chunks to delete in a file. NB this can be exceeded, but not by much. + int limit; // Number of chunks to delete in a file. + // NB this can be exceeded, but not by much. + + limit = 5; +#if 0 + if(dev->nErasedBlocks <= (YAFFS_RESERVED_BLOCKS + YAFFS_GARBAGE_COLLECT_LOW_WATER)) + { + limit = 50; // Doing GC soon, so dig deeper + } + else + { + limit = 5; + } +#endif + delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit); if(obj->nDataChunks == 0) @@ -1964,6 +2099,8 @@ static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev) } } + + static int yaffs_CheckGarbageCollection(yaffs_Device *dev) { int block; @@ -2020,9 +2157,10 @@ static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr) sparePtr->tagByte7 = tu->asBytes[7]; } -static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr) +static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr) { yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr; + int result; tu->asBytes[0]= sparePtr->tagByte0; tu->asBytes[1]= sparePtr->tagByte1; @@ -2033,7 +2171,15 @@ static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr) tu->asBytes[6]= sparePtr->tagByte6; tu->asBytes[7]= sparePtr->tagByte7; - yaffs_CheckECCOnTags(tagsPtr); + result = yaffs_CheckECCOnTags(tagsPtr); + if(result> 0) + { + dev->tagsEccFixed++; + } + else if(result <0) + { + dev->tagsEccUnfixed++; + } } static void yaffs_SpareInitialise(yaffs_Spare *spare) @@ -2049,7 +2195,7 @@ static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_ if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,NULL,&spare,1) == YAFFS_OK) { *chunkDeleted = (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0; - yaffs_GetTagsFromSpare(&spare,tags); + yaffs_GetTagsFromSpare(dev,&spare,tags); return YAFFS_OK; } else @@ -2076,11 +2222,12 @@ static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, con yaffs_SpareInitialise(&spare); - +#ifndef CONFIG_YAFFS_USE_NANDECC if(buffer) { yaffs_CalcECC(buffer,&spare); } +#endif yaffs_LoadTagsIntoSpare(&spare,tags); @@ -2104,11 +2251,13 @@ static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buff yaffs_SpareInitialise(&spare); +#ifndef CONFIG_YAFFS_USE_NANDECC if(buffer) { yaffs_CalcECC(buffer,&spare); } +#endif yaffs_LoadTagsIntoSpare(&spare,tags); @@ -2227,7 +2376,7 @@ int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags } -#if YAFFS_PARANOID +#ifdef YAFFS_PARANOID static int yaffs_CheckFileSanity(yaffs_Object *in) { @@ -2334,7 +2483,9 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn if(existingChunk <=0) { //Hoosterman - how did this happen? - // todo + + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: existing chunk < 0 in scan" TENDSTR))); + } @@ -2466,36 +2617,6 @@ int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 * yaffs_CalcTagsECC(&newTags); - - #if 0 - // Create new chunk in NAND - newChunkId = yaffs_AllocatePage(dev,useReserve); - - - if(newChunkId >= 0) - { - - - yaffs_WriteChunkWithTagsToNAND(dev,newChunkId,buffer,&newTags); - - yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId); - - - if(prevChunkId >= 0) - { - yaffs_DeleteChunk(dev,prevChunkId); - - } - - yaffs_CheckFileSanity(in); - - return newChunkId; - } - - - return -1; -#else - newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve); if(newChunkId >= 0) { @@ -2512,7 +2633,7 @@ int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 * } return newChunkId; -#endif + @@ -2537,7 +2658,6 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force) yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bufferNew; yaffs_ObjectHeader *ohOld = (yaffs_ObjectHeader *)bufferOld; - yaffs_INVALIDATECHUNKCACHE(in); if(!in->fake || force) { @@ -2555,15 +2675,24 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force) // Header data oh->type = in->variantType; - + oh->st_mode = in->st_mode; + +#ifdef CONFIG_YAFFS_WINCE + oh->win_atime[0] = in->win_atime[0]; + oh->win_ctime[0] = in->win_ctime[0]; + oh->win_mtime[0] = in->win_mtime[0]; + oh->win_atime[1] = in->win_atime[1]; + 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; - +#endif if(in->parent) { oh->parentObjectId = in->parent->objectId; @@ -2573,7 +2702,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force) oh->parentObjectId = 0; } - oh->sum = in->sum; + //oh->sum = in->sum; if(name && *name) { memset(oh->name,0,YAFFS_MAX_NAME_LENGTH + 1); @@ -2621,30 +2750,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force) yaffs_CalcTagsECC(&newTags); - - -#if 0 - // Create new chunk in NAND - newChunkId = yaffs_AllocatePage(dev,1); - - if(newChunkId >= 0) - { - yaffs_WriteChunkWithTagsToNAND(dev,newChunkId,bufferNew,&newTags); - - in->chunkId = newChunkId; - - if(prevChunkId >= 0) - { - yaffs_DeleteChunk(dev,prevChunkId); - } - - in->dirty = 0; - return newChunkId; - } - - return -1; -#else // Create new chunk in NAND newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,bufferNew,&newTags,1); @@ -2663,44 +2769,86 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force) return newChunkId; -#endif } return 0; } -/////////////////////// Short Read Cache //////////////////////////////// -// In many siturations where there is no high level buffering a lot of -// reads might be short sequential reads. eg. scanning a jpeg file. -// In these cases, a shoprt read cache can provide a huge perfomance benefit +/////////////////////// Short Operations Cache //////////////////////////////// +// In many siturations where there is no high level buffering (eg WinCE) a lot of +// reads might be short sequential reads, and a lot of writes may be short +// sequential writes. eg. scanning/writing a jpeg file. +// In these cases, a short read/write cache can provide a huge perfomance benefit // with dumb-as-a-rock code. -// There are a limited number (~10) of cache chunks per device +// There are a limited number (~10) of cache chunks per device so that we don't +// need a very intelligent search. #ifdef CONFIG_YAFFS_SHORT_OP_CACHE -// Invalidate all the cache pages associated with this object -// Do this whenever ther file is modified... dumb as a rock remember! -static void yaffs_InvalidateChunkCache(yaffs_Object *in) + +static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) { + yaffs_Device *dev = obj->myDev; + int lowest; int i; - yaffs_Device *dev = in->myDev; - int id = in->objectId; + yaffs_ChunkCache *cache; + int chunkWritten; + int nBytes; - for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++) - { - if(dev->srCache[i].objectId == id) + do{ + cache = NULL; + + // Find the dirty cache for this object with the lowest chunk id. + for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++) { - dev->srCache[i].objectId = 0; + if(dev->srCache[i].object == obj && + dev->srCache[i].dirty) + { + if(!cache || dev->srCache[i].chunkId < lowest) + { + cache = &dev->srCache[i]; + lowest = cache->chunkId; + } + } } - } + + if(cache) + { + //Write it out + + nBytes = cache->object->variant.fileVariant.fileSize - ((cache->chunkId -1) * YAFFS_BYTES_PER_CHUNK); + + if(nBytes > YAFFS_BYTES_PER_CHUNK) + { + nBytes= YAFFS_BYTES_PER_CHUNK; + } + + chunkWritten = yaffs_WriteChunkDataToObject(cache->object, + cache->chunkId, + cache->data, + nBytes,1); + + cache->dirty = 0; + } + + } while(cache && chunkWritten > 0); + + if(cache) + { + //Hoosterman, disk full while writing cache out. + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: no space during caceh write" TENDSTR))); + + } + } // Grab us a chunk for use. // First look for an empty one. -// Then look for the least recently used one. -static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) +// Then look for the least recently used non-dirty one. +// Then look for the least recently used dirty one...., flush and look again. +static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev) { int i; int usage; @@ -2708,7 +2856,7 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++) { - if(dev->srCache[i].objectId == 0) + if(!dev->srCache[i].object) { //T(("Grabbing empty %d\n",i)); @@ -2716,13 +2864,14 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) } } + theOne = -1; + usage = 0; // just to stop the compiler grizzling - usage = dev->srCache[i].lastUse; - theOne = 0; - - for(i = 1; i < YAFFS_N_CACHE_CHUNKS; i++) + for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++) { - if(dev->srCache[i].lastUse < usage) + if(!dev->srCache[i].dirty && + ((dev->srCache[i].lastUse < usage && theOne >= 0)|| + theOne < 0)) { usage = dev->srCache[i].lastUse; theOne = i; @@ -2730,20 +2879,62 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) } //T(("Grabbing non-empty %d\n",theOne)); - return &dev->srCache[theOne]; + return theOne >= 0 ? &dev->srCache[theOne] : NULL; } +static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) +{ + yaffs_ChunkCache *cache; + yaffs_Object *theObj; + int usage; + int i; + + // Try find a non-dirty one... + + cache = yaffs_GrabChunkCacheWorker(dev); + + if(!cache) + { + // They were all dirty, find the last recently used object and flush + // its cache, then find again. + // NB what's here is not very accurate, we actually flush the object + // the last recently used page. + + theObj = dev->srCache[0].object; + usage = dev->srCache[0].lastUse; + + for(i = 1; i < YAFFS_N_CACHE_CHUNKS; i++) + { + if( dev->srCache[i].object && + dev->srCache[i].lastUse < usage) + { + usage = dev->srCache[i].lastUse; + theObj = dev->srCache[i].object; + } + } + + yaffs_FlushFilesChunkCache(theObj); + + // Try again + cache = yaffs_GrabChunkCacheWorker(dev); + } + + return cache; + +} + + // Find a cached chunk -static yaffs_ChunkCache *yaffs_FindChunkCache(yaffs_Device *dev, int objectId, int chunkId) +static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, int chunkId) { + yaffs_Device *dev = obj->myDev; int i; -; for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++) { - if(dev->srCache[i].objectId == objectId && + if(dev->srCache[i].object == obj && dev->srCache[i].chunkId == chunkId) { dev->cacheHits++; @@ -2756,10 +2947,10 @@ static yaffs_ChunkCache *yaffs_FindChunkCache(yaffs_Device *dev, int objectId, i } // Mark the chunk for the least recently used algorithym -static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache) +static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int isAWrite) { if( dev->srLastUse < 0 || - dev->srLastUse > 1000000) + dev->srLastUse > 100000000) { // Reset the cache usages int i; @@ -2774,6 +2965,71 @@ static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache) cache->lastUse = dev->srLastUse; + if(isAWrite) + { + cache->dirty = 1; + } +} + +// Invalidate a single cache page. +// Do this when a whole page gets written, +// ie the short cache for this page is no longer valid. +static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId) +{ + yaffs_ChunkCache *cache = yaffs_FindChunkCache(object,chunkId); + + if(cache) + { + cache->object = NULL; + } +} + + +// Invalidate all the cache pages associated with this object +// Do this whenever ther file is deleted or resized. +static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in) +{ + int i; + yaffs_Device *dev = in->myDev; + + // Now invalidate it. + for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++) + { + if(dev->srCache[i].object == in) + { + dev->srCache[i].object = NULL; + } + } +} + + +#else +// Stubs for disabling short op caching + +static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) +{} + +static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) +{ + return NULL; +} + + +static yaffs_ChunkCache *yaffs_FindChunkCache(yaffs_Device *dev, int objectId, int chunkId) +{ + return NULL; +} + +static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache) +{ +} + +static void yaffs_InvalidateChunkCache(yaffs_Object *obj, int chunkId) +{ +} + +static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in) +{ } @@ -2794,13 +3050,6 @@ static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache) int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nBytes) { -// yaffs_Device *dev = in->myDev; - -#ifdef CONFIG_YAFFS_SHORT_OP_CACHE - yaffs_ChunkCache *cache; -#else - __u8 localBuffer[YAFFS_BYTES_PER_CHUNK]; -#endif int chunk; int start; @@ -2808,6 +3057,10 @@ int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nB int n = nBytes; int nDone = 0; + yaffs_Device *dev; + + dev = in->myDev; + while(n > 0) { chunk = offset / YAFFS_BYTES_PER_CHUNK + 1; // The first chunk is 1 @@ -2828,29 +3081,39 @@ int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nB { // An incomplete start or end chunk (or maybe both start and end chunk) #ifdef CONFIG_YAFFS_SHORT_OP_CACHE + yaffs_ChunkCache *cache; // If we can't find the data in the cache, then load it up. - cache = yaffs_FindChunkCache(in->myDev,in->objectId,chunk); + cache = yaffs_FindChunkCache(in,chunk); if(!cache) { cache = yaffs_GrabChunkCache(in->myDev); - cache->objectId = in->objectId; + cache->object = in; cache->chunkId = chunk; + cache->dirty = 0; yaffs_ReadChunkDataFromObject(in,chunk,cache->data); } - yaffs_UseChunkCache(in->myDev,cache); + yaffs_UseChunkCache(dev,cache,0); memcpy(buffer,&cache->data[start],nToCopy); #else // Read into the local buffer then copy... - yaffs_ReadChunkDataFromObject(in,chunk,localBuffer); - memcpy(buffer,&localBuffer[start],nToCopy); + yaffs_ReadChunkDataFromObject(in,chunk,dev->localBuffer); + memcpy(buffer,&dev->localBuffer[start],nToCopy); #endif } else { +#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 + yaffs_ReadChunkDataFromObject(in,chunk,dev->localBuffer); + memcpy(buffer,dev->localBuffer,YAFFS_BYTES_PER_CHUNK); +#else // A full chunk. Read directly into the supplied buffer. yaffs_ReadChunkDataFromObject(in,chunk,buffer); +#endif } n -= nToCopy; @@ -2864,9 +3127,9 @@ int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nB } + int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes) { - __u8 localBuffer[YAFFS_BYTES_PER_CHUNK]; int chunk; int start; @@ -2874,10 +3137,14 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in int n = nBytes; int nDone = 0; int nToWriteBack; - int endOfWrite = offset+nBytes; + int startOfWrite = offset; int chunkWritten = 0; + int nBytesRead; + + yaffs_Device *dev; + + dev = in->myDev; - yaffs_INVALIDATECHUNKCACHE(in); while(n > 0 && chunkWritten >= 0) { @@ -2887,10 +3154,24 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in // OK now check for the curveball where the start and end are in // the same chunk. + if( (start + n) < YAFFS_BYTES_PER_CHUNK) { nToCopy = n; - nToWriteBack = (start + n); + + // Now folks, to calculate how many bytes to write back.... + // If we're overwriting and not writing to then end of file then + // we need to write back as much as was there before. + + nBytesRead = in->variant.fileVariant.fileSize - ((chunk -1) * YAFFS_BYTES_PER_CHUNK); + + if(nBytesRead > YAFFS_BYTES_PER_CHUNK) + { + nBytesRead = YAFFS_BYTES_PER_CHUNK; + } + + nToWriteBack = (nBytesRead > (start + n)) ? nBytesRead : (start +n); + } else { @@ -2900,22 +3181,59 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in if(nToCopy != YAFFS_BYTES_PER_CHUNK) { + // An incomplete start or end chunk (or maybe both start and end chunk) +#ifdef CONFIG_YAFFS_SHORT_OP_CACHE + 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)) + { + cache = yaffs_GrabChunkCache(in->myDev); + cache->object = in; + cache->chunkId = chunk; + cache->dirty = 0; + yaffs_ReadChunkDataFromObject(in,chunk,cache->data); + } + + if(cache) + { + yaffs_UseChunkCache(dev,cache,1); + memcpy(&cache->data[start],buffer,nToCopy); + } + else + { + chunkWritten = -1; // fail the write + } +#else + + // An incomplete start or end chunk (or maybe both start and end chunk) // Read into the local buffer then copy, then copy over and write back. - yaffs_ReadChunkDataFromObject(in,chunk,localBuffer); + yaffs_ReadChunkDataFromObject(in,chunk,dev->localBuffer); - memcpy(&localBuffer[start],buffer,nToCopy); + memcpy(&dev->localBuffer[start],buffer,nToCopy); - chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,nToWriteBack,0); + chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,dev->localBuffer,nToWriteBack,0); - //T(("Write with readback to chunk %d %d\n",chunk,chunkWritten)); + //T(("Write with readback to chunk %d %d start %d copied %d wrote back %d\n",chunk,chunkWritten,start, nToCopy, nToWriteBack)); +#endif } else { + +#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 + memcpy(dev->localBuffer,buffer,YAFFS_BYTES_PER_CHUNK); + chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,dev->localBuffer,YAFFS_BYTES_PER_CHUNK,0); +#else // A full chunk. Write directly from the supplied buffer. chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,buffer,YAFFS_BYTES_PER_CHUNK,0); +#endif + // Since we've overwritten the cached data, we better invalidate it. + yaffs_InvalidateChunkCache(in,chunk); //T(("Write to chunk %d %d\n",chunk,chunkWritten)); } @@ -2931,13 +3249,12 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in // Update file object - if(endOfWrite > in->variant.fileVariant.fileSize) + if((startOfWrite + nDone) > in->variant.fileVariant.fileSize) { - in->variant.fileVariant.fileSize = endOfWrite; + in->variant.fileVariant.fileSize = (startOfWrite + nDone); } in->dirty = 1; - /*in->st_mtime = CURRENT_TIME; only update in flush*/ return nDone; } @@ -2952,9 +3269,9 @@ int yaffs_ResizeFile(yaffs_Object *in, int newSize) yaffs_Device *dev = in->myDev; - __u8 localBuffer[YAFFS_BYTES_PER_CHUNK]; - yaffs_INVALIDATECHUNKCACHE(in); + yaffs_FlushFilesChunkCache(in); + yaffs_InvalidateWholeChunkCache(in); if(in->variantType != YAFFS_OBJECT_TYPE_FILE) { @@ -2995,9 +3312,9 @@ int yaffs_ResizeFile(yaffs_Object *in, int newSize) int lastChunk = 1+ newSize/YAFFS_BYTES_PER_CHUNK; // Got to read and rewrite the last chunk with its new size. - yaffs_ReadChunkDataFromObject(in,lastChunk,localBuffer); + yaffs_ReadChunkDataFromObject(in,lastChunk,dev->localBuffer); - yaffs_WriteChunkDataToObject(in,lastChunk,localBuffer,sizeOfPartialChunk,1); + yaffs_WriteChunkDataToObject(in,lastChunk,dev->localBuffer,sizeOfPartialChunk,1); } @@ -3041,8 +3358,14 @@ int yaffs_FlushFile(yaffs_Object *in) if(in->dirty) { //T(("flushing object header\n")); + + yaffs_FlushFilesChunkCache(in); +#ifdef CONFIG_YAFFS_WINCE + yfsd_WinFileTimeNow(in->win_mtime); +#else in->st_mtime = CURRENT_TIME; +#endif retVal = yaffs_UpdateObjectHeader(in,NULL,0); } @@ -3058,10 +3381,13 @@ int yaffs_FlushFile(yaffs_Object *in) static int yaffs_DoGenericObjectDeletion(yaffs_Object *in) { - yaffs_INVALIDATECHUNKCACHE(in); + + // First off, invalidate the file's data in the cache, without flushing. + yaffs_InvalidateWholeChunkCache(in); + yaffs_RemoveObjectFromDirectory(in); yaffs_DeleteChunk(in->myDev,in->chunkId); -#if __KERNEL__ +#ifdef __KERNEL__ if(in->myInode) { in->myInode->u.generic_ip = NULL; @@ -3081,12 +3407,9 @@ static int yaffs_UnlinkFile(yaffs_Object *in) #ifdef CONFIG_YAFFS_DISABLE_BACKGROUND_DELETION // Delete the file data & tnodes -#if 0 - yaffs_ResizeFile(in,0); -#else - yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0,NULL); -#endif + yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0,NULL); + yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top); @@ -3094,20 +3417,20 @@ static int yaffs_UnlinkFile(yaffs_Object *in) #else int retVal; int immediateDeletion=0; - retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL); + retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0); if(retVal == YAFFS_OK) { //in->unlinked = 1; //in->myDev->nUnlinkedFiles++; //in->renameAllowed = 0; #ifdef __KERNEL__ - if(in->myInode) + if(!in->myInode) { immediateDeletion = 1; } #endif -#if WIN32 +#ifdef CONFIG_YAFFS_WINCE if(in->inUse <= 0) { immediateDeletion = 1; @@ -3117,7 +3440,7 @@ static int yaffs_UnlinkFile(yaffs_Object *in) if(immediateDeletion) { - T((TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId)); + T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId)); in->deleted=1; in->myDev->nDeletedFiles++; } @@ -3184,87 +3507,6 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj) } else if(!list_empty(&obj->hardLinks)) { -#if 0 - // Curve ball: We're unlinking an object that has a hardlink. - // Therefore we can't really delete the object. - // Instead, we do the following: - // - Select a hardlink. - // - Re-type a hardlink as the equivalent object and populate the fields, including the - // objectId. Updating the object id is important so that all the hardlinks do not need - // to be rewritten. - // - Update the equivalet object pointers. - // - Delete all object. - - yaffs_Object *hl; - struct list_head *i; - - - yaffs_RemoveObjectFromDirectory(obj); - - - - hl = list_entry(obj->hardLinks.next, yaffs_Object,hardLinks); - - hl->dirty = 1; - hl->st_mode = obj->st_mode; - hl->st_uid = obj->st_uid; - hl->st_gid = obj->st_gid; - hl->st_atime = obj->st_atime; - hl->st_mtime = obj->st_mtime; - hl->st_ctime = obj->st_ctime; - hl->st_rdev = obj->st_rdev; - - hl->variantType = obj->variantType; - - switch(hl->variantType) - { - case YAFFS_OBJECT_TYPE_FILE: - case YAFFS_OBJECT_TYPE_SYMLINK: - case YAFFS_OBJECT_TYPE_SPECIAL: - // These types are OK to just copy across. - hl->variant = obj->variant; - break; - case YAFFS_OBJECT_TYPE_DIRECTORY: - // Fix the list up - list_add(&hl->variant.directoryVariant.children, - &obj->variant.directoryVariant.children); - list_del(&obj->variant.directoryVariant.children); - - // Now change all the directory children to point to the new parent. - list_for_each(i,&hl->variant.directoryVariant.children) - { - list_entry(i,yaffs_Object,siblings)->parent = hl; - } - break; - - case YAFFS_OBJECT_TYPE_HARDLINK: - case YAFFS_OBJECT_TYPE_UNKNOWN: - // Should not be either of these types. - } - - // Now fix up the hardlink chain - list_del(&obj->hardLinks); - - list_for_each(i,&hl->hardLinks) - { - list_entry(i,yaffs_Object,hardLinks)->variant.hardLinkVariant.equivalentObject = hl; - list_entry(i,yaffs_Object,hardLinks)->variant.hardLinkVariant.equivalentObjectId = hl->objectId; - } - - // Now fix up the hash links. - yaffs_UnhashObject(hl); - hl->objectId = obj->objectId; - yaffs_HashObject(hl); - - // Update the hardlink which has become an object - yaffs_UpdateObjectHeader(hl,NULL,0); - - // Finally throw away the deleted object - yaffs_DeleteChunk(obj->myDev,obj->chunkId); - yaffs_FreeObject(obj); - - return YAFFS_OK; -#else // Curve ball: We're unlinking an object that has a hardlink. // // This problem arises because we are not strictly following @@ -3290,16 +3532,13 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj) yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1); - retVal = yaffs_ChangeObjectName(obj, hl->parent, name); + retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0); if(retVal == YAFFS_OK) { retVal = yaffs_DoGenericObjectDeletion(hl); } return retVal; - -#endif - } else @@ -3417,7 +3656,7 @@ static int yaffs_Scan(yaffs_Device *dev) if(yaffs_IsBlockBad(dev,blk)) { state = YAFFS_BLOCK_STATE_DEAD; - T((TSTR("block %d is bad" TENDSTR),blk)); + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("block %d is bad" TENDSTR),blk)); } // Read each chunk in the block. @@ -3432,7 +3671,7 @@ static int yaffs_Scan(yaffs_Device *dev) // This block looks ok, now what's in this chunk? - yaffs_GetTagsFromSpare(&spare,&tags); + yaffs_GetTagsFromSpare(dev,&spare,&tags); if(yaffs_CountBits(spare.pageStatus) < 6) { @@ -3456,7 +3695,7 @@ static int yaffs_Scan(yaffs_Device *dev) else { // this is the block being allocated from - T((TSTR(" Allocating from %d %d" TENDSTR),blk,c)); + T(YAFFS_TRACE_SCAN,(TSTR(" Allocating from %d %d" TENDSTR),blk,c)); state = YAFFS_BLOCK_STATE_ALLOCATING; dev->allocationBlock = blk; dev->allocationPage = c; @@ -3529,12 +3768,21 @@ static int yaffs_Scan(yaffs_Device *dev) in->variantType = oh->type; in->st_mode = oh->st_mode; +#ifdef CONFIG_YAFFS_WINCE + in->win_atime[0] = oh->win_atime[0]; + in->win_ctime[0] = oh->win_ctime[0]; + in->win_mtime[0] = oh->win_mtime[0]; + in->win_atime[1] = oh->win_atime[1]; + 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; +#endif in->chunkId = chunk; } @@ -3546,15 +3794,24 @@ static int yaffs_Scan(yaffs_Device *dev) in->variantType = oh->type; in->st_mode = oh->st_mode; +#ifdef CONFIG_YAFFS_WINCE + in->win_atime[0] = oh->win_atime[0]; + in->win_ctime[0] = oh->win_ctime[0]; + in->win_mtime[0] = oh->win_mtime[0]; + in->win_atime[1] = oh->win_atime[1]; + 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; +#endif in->chunkId = chunk; - in->sum = oh->sum; + yaffs_SetObjectName(in,oh->name); in->dirty = 0; // directory stuff... @@ -3572,6 +3829,8 @@ static int yaffs_Scan(yaffs_Device *dev) // Hoosterman, another problem.... // We're trying to use a non-directory as a directory // Todo ... handle + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: attempting to use non-directory as a directory in scan" TENDSTR))); + } yaffs_AddObjectToDirectory(parent,in); @@ -3789,6 +4048,12 @@ int yaffs_GetObjectName(yaffs_Object *obj,char *name,int buffSize) strncpy(name,locName,buffSize - 1); } +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM + else if(obj->shortName[0]) + { + strcpy(name,obj->shortName); + } +#endif else { __u8 buffer[YAFFS_BYTES_PER_CHUNK]; @@ -3884,6 +4149,7 @@ char *yaffs_GetSymlinkAlias(yaffs_Object *obj) } } +#ifndef CONFIG_YAFFS_WINCE int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr) { @@ -3924,7 +4190,7 @@ int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr) } - +#endif int yaffs_DumpObject(yaffs_Object *obj) { @@ -3941,7 +4207,7 @@ int yaffs_DumpObject(yaffs_Object *obj) yaffs_GetObjectName(obj,name,256); - YPRINTF(("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n", + T(YAFFS_TRACE_ALWAYS,(TSTR("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n" TENDSTR), obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial, obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj))); @@ -3983,14 +4249,14 @@ int yaffs_GutsInitialise(yaffs_Device *dev) if(!yaffs_CheckStructures()) { - YPRINTF(("yaffs_CheckStructures failed\n")); + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs_CheckStructures failed\n" TENDSTR))); return YAFFS_FAIL; } if(dev->startBlock <= 0 || (dev->endBlock - dev->startBlock) < 10) { - YPRINTF(("startBlock %d or endBlock %d invalid\n", + T(YAFFS_TRACE_ALWAYS,(TSTR("startBlock %d or endBlock %d invalid\n" TENDSTR), dev->startBlock, dev->endBlock)); return YAFFS_FAIL; } @@ -4038,6 +4304,12 @@ int yaffs_GutsInitialise(yaffs_Device *dev) dev->nDeletedFiles = 0; dev->nBackgroundDeletions=0; dev->nUnlinkedFiles = 0; + dev->eccFixed=0; + dev->eccUnfixed=0; + dev->tagsEccFixed=0; + dev->tagsEccUnfixed=0; + + dev->localBuffer = YMALLOC(YAFFS_BYTES_PER_CHUNK); yaffs_InitialiseBlocks(dev,nBlocks); @@ -4050,8 +4322,9 @@ int yaffs_GutsInitialise(yaffs_Device *dev) int i; for(i=0; i < YAFFS_N_CACHE_CHUNKS; i++) { - dev->srCache[i].objectId = 0; + dev->srCache[i].object = NULL; dev->srCache[i].lastUse = 0; + dev->srCache[i].dirty = 0; } dev->srLastUse = 0; } @@ -4123,7 +4396,8 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) #define yaffs_CheckStruct(structure,syze, name) \ if(sizeof(structure) != syze) \ - { YPRINTF(("%s should be %d but is %d\n",name,syze,sizeof(structure))); \ + { \ + T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),name,syze,sizeof(structure))); \ return YAFFS_FAIL; \ } @@ -4140,21 +4414,20 @@ static int yaffs_CheckStructures(void) return YAFFS_OK; } +#if 0 void yaffs_GutsTest(yaffs_Device *dev) { if(yaffs_CheckStructures() != YAFFS_OK) { - YPRINTF(("One or more structures malformed-- aborting\n")); + T(YAFFS_TRACE_ALWAYS,(TSTR("One or more structures malformed-- aborting\n" TENDSTR))); return; } - else - { - YPRINTF(("Structures OK\n")); - } yaffs_TnodeTest(dev); yaffs_ObjectTest(dev); } +#endif +