*** empty log message ***
[yaffs/.git] / yaffs_guts.c
index 6bc6136e807285f2b4c692f3bf683bb2a77a24d7..4c7e81af75ef9b1c136ec0a4b464cde7272c3ba5 100644 (file)
 #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 <<c);                           
+                                       dev->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 <<c);                           
+                                       // Thus, we read in the object header and make the object
+                                       dev->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