*** empty log message ***
[yaffs/.git] / yaffs_guts.c
index 66014bb3f449d95b5a94aec02ff026c17c622c0c..4c7e81af75ef9b1c136ec0a4b464cde7272c3ba5 100644 (file)
@@ -75,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
@@ -136,6 +135,39 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8
        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);
@@ -1094,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)
@@ -1188,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;
@@ -1429,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));
                }
@@ -1598,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
@@ -1623,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)
 {
@@ -1677,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 &&
@@ -1719,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 &&
@@ -1780,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
                                {
@@ -1888,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)
        {
@@ -2370,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
@@ -2539,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);
@@ -2602,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;
@@ -2615,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);
 
                        
@@ -2636,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 
@@ -2659,20 +2719,14 @@ 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);
-                                       // PutChuunkIntoFIle checks 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,1);
                                        T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));    
@@ -2680,78 +2734,99 @@ static int yaffs_Scan(yaffs_Device *dev)
                                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
@@ -2761,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;
@@ -2785,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);
                        
@@ -2896,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)
        {
@@ -3058,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