X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs%2F.git;a=blobdiff_plain;f=yaffs_guts.c;h=4c7e81af75ef9b1c136ec0a4b464cde7272c3ba5;hp=6bc6136e807285f2b4c692f3bf683bb2a77a24d7;hb=3f107ebf545c27322a15a458198a3cd5dbc876f3;hpb=cefeada5db633fd3c37cde66e2e62c73052c18bd diff --git a/yaffs_guts.c b/yaffs_guts.c index 6bc6136..4c7e81a 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -26,6 +26,10 @@ #define T(x) #endif +// 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); + // 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. @@ -63,7 +67,7 @@ static const char yaffs_countBits[256] = 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 int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND); +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); static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj); @@ -71,15 +75,14 @@ static int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name); static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId); static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj); static int yaffs_CheckStructures(void); -static yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj); loff_t yaffs_GetFileSize(yaffs_Object *obj); static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve); -#if YAFFS_PARANOID -static int yaffs_CheckFileSanity(yaffs_Object *in) +#ifdef YAFFS_PARANOID +static int yaffs_CheckFileSanity(yaffs_Object *in); #else #define yaffs_CheckFileSanity(in) #endif @@ -108,9 +111,63 @@ static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare) { - return dev->readChunkFromNAND(dev,chunkInNAND,data,spare); + int retVal; + __u8 calcEcc[3]; + yaffs_Spare localSpare; + + 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; + } + + retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,spare); + if(data) + { + // Do ECC correction + //Todo handle any errors + nand_calculate_ecc(data,calcEcc); + nand_correct_data (data,spare->ecc1, calcEcc); + nand_calculate_ecc(&data[256],calcEcc); + nand_correct_data (&data[256],spare->ecc2, calcEcc); + } + return retVal; +} + +#ifdef YAFFS_PARANOID + +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]; + + int retVal; + + retVal = YAFFS_OK; + + dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare); + + + + if(!init) + { + memset(cmpbuf,0xff,YAFFS_BYTES_PER_CHUNK); + init = 1; + } + + if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) retVal = YAFFS_FAIL; + if(memcmp(cmpbuf,spare,16)) retVal = YAFFS_FAIL; + + return retVal; + } +#endif + + int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND) { return dev->eraseBlockInNAND(dev,blockInNAND); @@ -127,6 +184,9 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8 int writeOk = 0; + unsigned char rbData[YAFFS_BYTES_PER_CHUNK]; + yaffs_Spare rbSpare; + do{ chunk = yaffs_AllocateChunk(dev,useReserve); @@ -135,8 +195,33 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8 writeOk = yaffs_WriteChunkToNAND(dev,chunk,data,spare); if(writeOk) { - //Todo read-back and verify + // Readback & verify // If verify fails, then delete this chunk and try again + // To verify we compare everything except the block and + // page status bytes. + yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare); + + if(memcmp(data,rbData,YAFFS_BYTES_PER_CHUNK) != 0 || + spare->tagByte0 != rbSpare.tagByte0 || + spare->tagByte1 != rbSpare.tagByte1 || + spare->tagByte2 != rbSpare.tagByte2 || + spare->tagByte3 != rbSpare.tagByte3 || + spare->tagByte4 != rbSpare.tagByte4 || + spare->tagByte5 != rbSpare.tagByte5 || + spare->tagByte6 != rbSpare.tagByte6 || + spare->tagByte7 != rbSpare.tagByte7 || + spare->ecc1[0] != rbSpare.ecc1[0] || + spare->ecc1[1] != rbSpare.ecc1[1] || + spare->ecc1[2] != rbSpare.ecc1[2] || + spare->ecc2[0] != rbSpare.ecc2[0] || + spare->ecc2[1] != rbSpare.ecc2[1] || + spare->ecc2[2] != rbSpare.ecc2[2] ) + { + // Didn't verify + yaffs_DeleteChunk(dev,chunk); + writeOk = 0; + } + } } } while(chunk >= 0 && ! writeOk); @@ -178,20 +263,60 @@ static __u16 yaffs_CalcNameSum(const char *name) } -void yaffs_CalcECC(const __u8 *buffer, yaffs_Spare *spare) +void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) { - - // Todo do nothing now. Need to put in ecc - spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xFF; - spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xFF; + nand_calculate_ecc (data , spare->ecc1); + nand_calculate_ecc (&data[256] , spare->ecc2); } void yaffs_CalcTagsECC(yaffs_Tags *tags) { // Todo don't do anything yet. Need to calculate ecc - tags->ecc = 0xFFFFFFFF; + unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes; + unsigned i,j; + unsigned ecc = 0; + unsigned bit = 0; + + tags->ecc = 0; + + for(i = 0; i < 8; i++) + { + for(j = 1; j &0x7f; j<<=1) + { + bit++; + if(b[i] & j) + { + ecc ^= bit; + } + } + } + + tags->ecc = ecc; + + } +void yaffs_CheckECCOnTags(yaffs_Tags *tags) +{ + unsigned ecc = tags->ecc; + + yaffs_CalcTagsECC(tags); + + ecc ^= tags->ecc; + + if(ecc) + { + // Needs fixing + unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes; + + ecc--; + + b[ecc / 8] ^= (1 << (ecc & 7)); + + // Now recvalc the ecc + yaffs_CalcTagsECC(tags); + } +} ///////////////////////// TNODES /////////////////////// @@ -939,8 +1064,10 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectTyp INIT_LIST_HEAD(&theObject->variant.directoryVariant.children); break; case YAFFS_OBJECT_TYPE_SYMLINK: + // No action required break; case YAFFS_OBJECT_TYPE_HARDLINK: + // No action required break; case YAFFS_OBJECT_TYPE_UNKNOWN: // todo this should not happen @@ -999,6 +1126,12 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type, yaffs_Device *dev = parent->myDev; + // Check if the entry exists. If it does then fail the call since we don't want a dup. + if(yaffs_FindObjectByName(parent,name)) + { + return NULL; + } + in = yaffs_CreateNewObject(dev,-1,type); if(in) @@ -1093,7 +1226,10 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const obj->dirty = 1; yaffs_AddObjectToDirectory(newDir,obj); - return yaffs_UpdateObjectHeader(obj,newName); + if(yaffs_UpdateObjectHeader(obj,newName) >= 0) + { + return YAFFS_OK; + } } return YAFFS_FAIL; @@ -1334,7 +1470,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve) } #ifdef YAFFS_PARANOID - if(yaffs_CheckChunkErased(retVal) == YAFFS_FAIL) + if(yaffs_CheckChunkErased(dev,retVal) == YAFFS_FAIL) { T(("..................Trying to allocate non-erased page %d\n",retVal)); } @@ -1411,7 +1547,7 @@ int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block) else { // It's a data chunk - yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk); + yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0); } @@ -1476,7 +1612,7 @@ static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr) tu->asBytes[6]= sparePtr->tagByte6; tu->asBytes[7]= sparePtr->tagByte7; - // Todo Check ECC on tags + yaffs_CheckECCOnTags(tagsPtr); } static void yaffs_SpareInitialise(yaffs_Spare *spare) @@ -1503,6 +1639,7 @@ static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_ return YAFFS_OK; } +#if 0 static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_Tags *tags) { // NB There must be tags, data is optional @@ -1528,6 +1665,8 @@ static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, con return yaffs_WriteChunkToNAND(dev,chunkInNAND,buffer,&spare); } +#endif + static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_Tags *tags, int useReserve) { @@ -1582,7 +1721,7 @@ int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags) theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits; // Now we need to do the shifting etc and search for it - for(i = 0,found = 0; i < dev->chunkGroupSize && !found; i++) + for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++) { yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags); if(tags->chunkId == chunkInInode && @@ -1624,7 +1763,7 @@ int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits; // Now we need to do the shifting etc and search for it - for(i = 0,found = 0; i < dev->chunkGroupSize && !found; i++) + for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++) { yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags); if(tags->chunkId == chunkInInode && @@ -1685,20 +1824,20 @@ static int yaffs_CheckFileSanity(yaffs_Object *in) for(chunk = 1; chunk <= nChunks; chunk++) { - tn = yaffs_FindLevel0Tnode(&in->variant.fileVariant, chunk); + tn = yaffs_FindLevel0Tnode(in->myDev,&in->variant.fileVariant, chunk); if(tn) { - theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits; + theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << in->myDev->chunkGroupBits; - yaffs_ReadChunkTagsFromNAND(theChunk,tags); + yaffs_ReadChunkTagsFromNAND(in->myDev,theChunk,tags); if(tags->chunkId == chunk && tags->objectId == in->objectId) { // found it; - + } else { @@ -1721,13 +1860,53 @@ static int yaffs_CheckFileSanity(yaffs_Object *in) #endif -static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND) +static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan) { yaffs_Tnode *tn; yaffs_Device *dev = in->myDev; + int existingChunk; + yaffs_Tags existingTags; + yaffs_Tags newTags; + unsigned existingSerial, newSerial; + tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode); + + if(inScan) + { + // If we're scanning then we need to test for duplicates + // NB This does not need to be efficient since it should only ever + // happen when the power fails during a write, then only one + // chunk should ever be affected. + + existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK]; + + if(existingChunk != 0) + { + // We have a duplicate now we need to decide which one to use + // To do this we get both sets of tags and compare serial numbers. + yaffs_ReadChunkTagsFromNAND(dev,chunkInInode, &newTags); + yaffs_ReadChunkTagsFromNAND(dev,existingChunk, &existingTags); + newSerial = newTags.serialNumber; + existingSerial = existingTags.serialNumber; + if(((existingSerial+1) & 3) == newSerial) + { + // Use new + // Delete the old one and drop through to update the tnode + yaffs_DeleteChunk(dev,existingChunk); + } + else + { + // Use existing. + // Delete the new one and return early so that the tnode isn't changed + yaffs_DeleteChunk(dev,chunkInInode); + return YAFFS_OK; + } + } + } + tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = chunkInNAND; + return YAFFS_OK; } @@ -1753,18 +1932,18 @@ static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId) { int block = chunkId / YAFFS_CHUNKS_PER_BLOCK; int page = chunkId % YAFFS_CHUNKS_PER_BLOCK; - yaffs_Tags tags; + yaffs_Spare spare; + + yaffs_SpareInitialise(&spare); - // Mark the deleted NAND page as deleted - tags.chunkId = 0; - tags.objectId = 0; - tags.byteCount = 0; - tags.ecc = 0; + spare.pageStatus = 0; // To mark it as deleted. + - yaffs_WriteChunkWithTagsToNAND(dev,chunkId,NULL,&tags); + yaffs_WriteChunkToNAND(dev,chunkId,NULL,&spare); // Pull out of the management area. + // If the whole block became dirty, this will kick off an erasure. if( dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_ALLOCATING || dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_FULL) { @@ -1782,7 +1961,7 @@ static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId) } else { - T(("Bad news deteing chunk %d\n",chunkId)); + T(("Bad news deleting chunk %d\n",chunkId)); } } @@ -1851,7 +2030,7 @@ int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 * newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve); if(newChunkId >= 0) { - yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId); + yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId,0); if(prevChunkId >= 0) @@ -1927,7 +2106,8 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name) switch(in->variantType) { - case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem + case YAFFS_OBJECT_TYPE_UNKNOWN: + // Should not happen break; case YAFFS_OBJECT_TYPE_FILE: oh->fileSize = in->variant.fileVariant.fileSize; @@ -1935,7 +2115,8 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name) case YAFFS_OBJECT_TYPE_HARDLINK: oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId; break; - case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing + case YAFFS_OBJECT_TYPE_DIRECTORY: + // Do nothing break; case YAFFS_OBJECT_TYPE_SYMLINK: strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH); @@ -2233,6 +2414,7 @@ int yaffs_FlushFile(yaffs_Object *in) int retVal; if(in->dirty) { + T(("flushing object header\n")); retVal = yaffs_UpdateObjectHeader(in,NULL); } else @@ -2402,12 +2584,14 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj) char name[YAFFS_MAX_NAME_LENGTH+1]; hl = list_entry(obj->hardLinks.next,yaffs_Object,hardLinks); + list_del_init(&hl->hardLinks); list_del_init(&hl->siblings); yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1); retVal = yaffs_ChangeObjectName(obj, hl->parent, name); + if(retVal == YAFFS_OK) { retVal = yaffs_DoGenericObjectDeletion(hl); @@ -2465,12 +2649,12 @@ static int yaffs_Scan(yaffs_Device *dev) int chunk; int c; int deleted; - int inuse; yaffs_BlockState state; yaffs_Object *hardList = NULL; yaffs_Object *hl; - __u32 pageBits; +// int inuse; +// __u32 pageBits; yaffs_ObjectHeader *oh; yaffs_Object *in; @@ -2478,18 +2662,24 @@ static int yaffs_Scan(yaffs_Device *dev) __u8 chunkData[YAFFS_BYTES_PER_CHUNK]; + + // Scan all the blocks... + for(blk = dev->startBlock; blk <= dev->endBlock; blk++) { deleted = 0; - pageBits = 0; - inuse = 0; - state = YAFFS_BLOCK_STATE_UNKNOWN; + dev->blockInfo[blk].pageBits = 0; + dev->blockInfo[blk].pagesInUse = 0; + state = YAFFS_BLOCK_STATE_SCANNING; + + // Read each chunk in the block. for(c = 0; c < YAFFS_CHUNKS_PER_BLOCK && - state == YAFFS_BLOCK_STATE_UNKNOWN; c++) + state == YAFFS_BLOCK_STATE_SCANNING; c++) { // Read the spare area and decide what to do chunk = blk * YAFFS_CHUNKS_PER_BLOCK + c; + yaffs_ReadChunkFromNAND(dev,chunk,NULL,&spare); @@ -2499,7 +2689,14 @@ static int yaffs_Scan(yaffs_Device *dev) // This block looks ok, now what's in this chunk? yaffs_GetTagsFromSpare(&spare,&tags); - if(tags.objectId == YAFFS_UNUSED_OBJECT_ID) + if(yaffs_countBits[spare.pageStatus] < 6) + { + // A deleted chunk + deleted++; + dev->nFreeChunks ++; + T((" %d %d deleted\n",blk,c)); + } + else if(tags.objectId == YAFFS_UNUSED_OBJECT_ID) { // An unassigned chunk in the block // This means that either the block is empty or @@ -2522,99 +2719,114 @@ static int yaffs_Scan(yaffs_Device *dev) dev->nFreeChunks += (YAFFS_CHUNKS_PER_BLOCK - c); } - else if(tags.objectId == 0) - { - // A deleted chunk - deleted++; - dev->nFreeChunks ++; - T((" %d %d deleted\n",blk,c)); - } else if(tags.chunkId > 0) { // A data chunk. - inuse++; - pageBits |= ( 1 <blockInfo[blk].pageBits |= (1 << c); + dev->blockInfo[blk].pagesInUse++; + in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE); - // todo check for a clash (two data chunks with + // PutChunkIntoFIle checks for a clash (two data chunks with // the same chunkId). - yaffs_PutChunkIntoFile(in,tags.chunkId,chunk); + yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1); T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); } else { // chunkId == 0, so it is an ObjectHeader. - inuse++; - pageBits |= ( 1 <blockInfo[blk].pageBits |= (1 << c); + dev->blockInfo[blk].pagesInUse++; + yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL); + oh = (yaffs_ObjectHeader *)chunkData; in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type); + if(in->valid) { - // todo we have already filled this one. We have - // a duplicate. Need to fix + // We have already filled this one. We have a duplicate and need to resolve it. + + unsigned existingSerial = in->serial; + unsigned newSerial = tags.serialNumber; + + if(((existingSerial+1) & 3) == newSerial) + { + // Use new one - destroy the exisiting one + yaffs_DeleteChunk(dev,in->chunkId); + in->valid = 0; + } + else + { + // Use existing - destroy this one. + yaffs_DeleteChunk(dev,chunk); + } } - // we don't have a duplicate... + if(!in->valid) + { + // we need to load this info - in->valid = 1; - in->variantType = oh->type; - - in->st_mode = oh->st_mode; - 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->chunkId = chunk; - - in->sum = oh->sum; - in->dirty = 0; + in->valid = 1; + in->variantType = oh->type; + + in->st_mode = oh->st_mode; + 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->chunkId = chunk; + + in->sum = oh->sum; + in->dirty = 0; - // directory stuff... - // hook up to parent - - parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY); - if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN) - { - // Set up as a directory - parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY; - INIT_LIST_HEAD(&parent->variant.directoryVariant.children); - } - else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) - { - // Hoosterman, another problem.... - // We're trying to use a non-directory as a directory - // Todo ... handle - } + // directory stuff... + // hook up to parent + + parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY); + if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN) + { + // Set up as a directory + parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY; + INIT_LIST_HEAD(&parent->variant.directoryVariant.children); + } + else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) + { + // Hoosterman, another problem.... + // We're trying to use a non-directory as a directory + // Todo ... handle + } - yaffs_AddObjectToDirectory(parent,in); + yaffs_AddObjectToDirectory(parent,in); - // Note re hardlinks. - // Since we might scan a hardlink before its equivalent object is scanned - // we put them all in a list. - // After scanning is complete, we should have all the objects, so we run through this - // list and fix up all the chains. - - switch(in->variantType) - { - case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem - break; - case YAFFS_OBJECT_TYPE_FILE: - in->variant.fileVariant.fileSize = oh->fileSize; - break; - case YAFFS_OBJECT_TYPE_HARDLINK: - in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId; - (yaffs_Object *)(in->hardLinks.next) = hardList; - hardList = in; - break; - case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing - break; - case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing - in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias); - break; + // Note re hardlinks. + // Since we might scan a hardlink before its equivalent object is scanned + // we put them all in a list. + // After scanning is complete, we should have all the objects, so we run through this + // list and fix up all the chains. + + switch(in->variantType) + { + case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem + break; + case YAFFS_OBJECT_TYPE_FILE: + in->variant.fileVariant.fileSize = oh->fileSize; + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId; + (yaffs_Object *)(in->hardLinks.next) = hardList; + hardList = in; + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing + break; + case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing + in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias); + break; + } + T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType)); } - T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType)); } } else @@ -2624,21 +2836,26 @@ static int yaffs_Scan(yaffs_Device *dev) } } - if(state == YAFFS_BLOCK_STATE_UNKNOWN) + if(state == YAFFS_BLOCK_STATE_SCANNING) { - // If we got this far, then the block is fully allocated. - // ie. Full or Dirty - state = (inuse) ? YAFFS_BLOCK_STATE_FULL : YAFFS_BLOCK_STATE_DIRTY; - + // If we got this far while scanning, then the block is fully allocated. + state = YAFFS_BLOCK_STATE_FULL; } - dev->blockInfo[blk].pageBits = pageBits; - dev->blockInfo[blk].pagesInUse = inuse; dev->blockInfo[blk].blockState = state; + // Now let's see if it was dirty + if( dev->blockInfo[blk].pagesInUse == 0 && + dev->blockInfo[blk].blockState == YAFFS_BLOCK_STATE_FULL) + { + yaffs_BlockBecameDirty(dev,blk); + } + } - // Todo fix up the hard link chains + // Fix up the hard link chains. + // We should now have scanned all the objects, now it's time to add these + // hardlinks. while(hardList) { hl = hardList; @@ -2648,12 +2865,14 @@ static int yaffs_Scan(yaffs_Device *dev) if(in) { + // Add the hardlink pointers hl->variant.hardLinkVariant.equivalentObject=in; list_add(&hl->hardLinks,&in->hardLinks); } else { - //Todo Need to report this better. + //Todo Need to report/handle this better. + // Got a problem... hardlink to a non-existant object hl->variant.hardLinkVariant.equivalentObject=NULL; INIT_LIST_HEAD(&hl->hardLinks); @@ -2759,7 +2978,7 @@ int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object * // GetEquivalentObject dereferences any hard links to get to the // actual object. -static yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj) +yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj) { if(obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { @@ -2921,8 +3140,8 @@ int yaffs_DumpObject(yaffs_Object *obj) yaffs_GetObjectName(obj,name,256); - YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n", - yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial, + YPRINTF(("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n", + obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial, obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj))); #if 0