yaffs: Cache object xattrib state.
[yaffs2.git] / yaffs_guts.c
index 6efa94f57d268a8b4d2beddbcdb996eb20907024..6ea5698b5052dd375e15bceba736a183209587cc 100644 (file)
@@ -25,6 +25,7 @@
 #include "yaffs_yaffs1.h"
 #include "yaffs_yaffs2.h"
 #include "yaffs_bitmap.h"
+#include "yaffs_verify.h"
 
 #include "yaffs_nand.h"
 #include "yaffs_packedtags2.h"
@@ -65,7 +66,7 @@ static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
                                        yaffs_ObjectType type);
 
 
-static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod);
+static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod);
 
 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
 static int yaffs_CheckStructures(void);
@@ -87,30 +88,22 @@ static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
 
 static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
 
-static void yaffs_VerifyDirectory(yaffs_Object *directory);
-#ifdef YAFFS_PARANOID
-static int yaffs_CheckFileSanity(yaffs_Object *in);
-#else
-#define yaffs_CheckFileSanity(in)
-#endif
-
 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
 
 static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
                                yaffs_ExtendedTags *tags);
 
-static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
-               unsigned pos);
-static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
-                                       yaffs_FileStructure *fStruct,
-                                       __u32 chunkId);
-
 static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
                                        int chunkInNAND,
                                        const __u8 *data,
                                        yaffs_ExtendedTags *tags);
 
+
+static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize);
+static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev,YCHAR *ohName, const YCHAR *name);
+
+
 /* Function to calculate chunk and offset */
 
 static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
@@ -301,460 +294,7 @@ int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer)
  * Verification code
  */
 
-static int yaffs_SkipVerification(yaffs_Device *dev)
-{
-       dev=dev;
-       return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
-}
-
-static int yaffs_SkipFullVerification(yaffs_Device *dev)
-{
-       dev=dev;
-       return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
-}
-
-static int yaffs_SkipNANDVerification(yaffs_Device *dev)
-{
-       dev=dev;
-       return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
-}
-
-static const char *blockStateName[] = {
-"Unknown",
-"Needs scanning",
-"Scanning",
-"Empty",
-"Allocating",
-"Full",
-"Dirty",
-"Checkpoint",
-"Collecting",
-"Dead"
-};
-
-
-static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
-{
-       int actuallyUsed;
-       int inUse;
-
-       if (yaffs_SkipVerification(dev))
-               return;
-
-       /* Report illegal runtime states */
-       if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
-               T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
-
-       switch (bi->blockState) {
-       case YAFFS_BLOCK_STATE_UNKNOWN:
-       case YAFFS_BLOCK_STATE_SCANNING:
-       case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
-               T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
-               n, blockStateName[bi->blockState]));
-       }
-
-       /* Check pages in use and soft deletions are legal */
-
-       actuallyUsed = bi->pagesInUse - bi->softDeletions;
-
-       if (bi->pagesInUse < 0 || bi->pagesInUse > dev->param.nChunksPerBlock ||
-          bi->softDeletions < 0 || bi->softDeletions > dev->param.nChunksPerBlock ||
-          actuallyUsed < 0 || actuallyUsed > dev->param.nChunksPerBlock)
-               T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
-               n, bi->pagesInUse, bi->softDeletions));
-
-
-       /* Check chunk bitmap legal */
-       inUse = yaffs_CountChunkBits(dev, n);
-       if (inUse != bi->pagesInUse)
-               T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
-                       n, bi->pagesInUse, inUse));
-
-       /* Check that the sequence number is valid.
-        * Ten million is legal, but is very unlikely
-        */
-
-        yaffs2_VerifyBlock(dev,bi,n);
-}
-
-
-
-static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,
-               int n)
-{
-       yaffs_VerifyBlock(dev, bi, n);
 
-       /* After collection the block should be in the erased state */
-       /* This will need to change if we do partial gc */
-
-       if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
-                       bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
-               T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
-                       n, bi->blockState));
-       }
-}
-
-void yaffs_VerifyBlocks(yaffs_Device *dev)
-{
-       int i;
-       int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
-       int nIllegalBlockStates = 0;
-
-       if (yaffs_SkipVerification(dev))
-               return;
-
-       memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
-
-       for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
-               yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
-               yaffs_VerifyBlock(dev, bi, i);
-
-               if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
-                       nBlocksPerState[bi->blockState]++;
-               else
-                       nIllegalBlockStates++;
-       }
-
-       T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
-       T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
-
-       T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
-       if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
-               T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
-
-       for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
-               T(YAFFS_TRACE_VERIFY,
-                 (TSTR("%s %d blocks"TENDSTR),
-                 blockStateName[i], nBlocksPerState[i]));
-
-       if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
-               T(YAFFS_TRACE_VERIFY,
-                (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
-                dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
-
-       if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
-               T(YAFFS_TRACE_VERIFY,
-                (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
-                dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
-
-       if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
-               T(YAFFS_TRACE_VERIFY,
-                (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
-                nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
-
-       T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
-
-}
-
-/*
- * Verify the object header. oh must be valid, but obj and tags may be NULL in which
- * case those tests will not be performed.
- */
-static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
-{
-       if (obj && yaffs_SkipVerification(obj->myDev))
-               return;
-
-       if (!(tags && obj && oh)) {
-               T(YAFFS_TRACE_VERIFY,
-                               (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
-                               tags, obj, oh));
-               return;
-       }
-
-       if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
-                       oh->type > YAFFS_OBJECT_TYPE_MAX)
-               T(YAFFS_TRACE_VERIFY,
-                       (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
-                       tags->objectId, oh->type));
-
-       if (tags->objectId != obj->objectId)
-               T(YAFFS_TRACE_VERIFY,
-                       (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
-                       tags->objectId, obj->objectId));
-
-
-       /*
-        * Check that the object's parent ids match if parentCheck requested.
-        *
-        * Tests do not apply to the root object.
-        */
-
-       if (parentCheck && tags->objectId > 1 && !obj->parent)
-               T(YAFFS_TRACE_VERIFY,
-                       (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
-                       tags->objectId, oh->parentObjectId));
-
-       if (parentCheck && obj->parent &&
-                       oh->parentObjectId != obj->parent->objectId &&
-                       (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
-                       obj->parent->objectId != YAFFS_OBJECTID_DELETED))
-               T(YAFFS_TRACE_VERIFY,
-                       (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
-                       tags->objectId, oh->parentObjectId, obj->parent->objectId));
-
-       if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
-               T(YAFFS_TRACE_VERIFY,
-                       (TSTR("Obj %d header name is NULL"TENDSTR),
-                       obj->objectId));
-
-       if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
-               T(YAFFS_TRACE_VERIFY,
-                       (TSTR("Obj %d header name is 0xFF"TENDSTR),
-                       obj->objectId));
-}
-
-
-#if 0
-/* Not being used, but don't want to throw away yet */
-static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
-                                       __u32 level, int chunkOffset)
-{
-       int i;
-       yaffs_Device *dev = obj->myDev;
-       int ok = 1;
-
-       if (tn) {
-               if (level > 0) {
-
-                       for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
-                               if (tn->internal[i]) {
-                                       ok = yaffs_VerifyTnodeWorker(obj,
-                                                       tn->internal[i],
-                                                       level - 1,
-                                                       (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
-                               }
-                       }
-               } else if (level == 0) {
-                       yaffs_ExtendedTags tags;
-                       __u32 objectId = obj->objectId;
-
-                       chunkOffset <<=  YAFFS_TNODES_LEVEL0_BITS;
-
-                       for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
-                               __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
-
-                               if (theChunk > 0) {
-                                       /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
-                                       yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
-                                       if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
-                                               T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
-                                                       objectId, chunkOffset, theChunk,
-                                                       tags.objectId, tags.chunkId));
-                                       }
-                               }
-                               chunkOffset++;
-                       }
-               }
-       }
-
-       return ok;
-
-}
-
-#endif
-
-static void yaffs_VerifyFile(yaffs_Object *obj)
-{
-       int requiredTallness;
-       int actualTallness;
-       __u32 lastChunk;
-       __u32 x;
-       __u32 i;
-       yaffs_Device *dev;
-       yaffs_ExtendedTags tags;
-       yaffs_Tnode *tn;
-       __u32 objectId;
-
-       if (!obj)
-               return;
-
-       if (yaffs_SkipVerification(obj->myDev))
-               return;
-
-       dev = obj->myDev;
-       objectId = obj->objectId;
-
-       /* Check file size is consistent with tnode depth */
-       lastChunk =  obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
-       x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
-       requiredTallness = 0;
-       while (x > 0) {
-               x >>= YAFFS_TNODES_INTERNAL_BITS;
-               requiredTallness++;
-       }
-
-       actualTallness = obj->variant.fileVariant.topLevel;
-
-       /* Check that the chunks in the tnode tree are all correct.
-        * We do this by scanning through the tnode tree and
-        * checking the tags for every chunk match.
-        */
-
-       if (yaffs_SkipNANDVerification(dev))
-               return;
-
-       for (i = 1; i <= lastChunk; i++) {
-               tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
-
-               if (tn) {
-                       __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
-                       if (theChunk > 0) {
-                               /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
-                               yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
-                               if (tags.objectId != objectId || tags.chunkId != i) {
-                                       T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
-                                               objectId, i, theChunk,
-                                               tags.objectId, tags.chunkId));
-                               }
-                       }
-               }
-       }
-}
-
-
-static void yaffs_VerifyHardLink(yaffs_Object *obj)
-{
-       if (obj && yaffs_SkipVerification(obj->myDev))
-               return;
-
-       /* Verify sane equivalent object */
-}
-
-static void yaffs_VerifySymlink(yaffs_Object *obj)
-{
-       if (obj && yaffs_SkipVerification(obj->myDev))
-               return;
-
-       /* Verify symlink string */
-}
-
-static void yaffs_VerifySpecial(yaffs_Object *obj)
-{
-       if (obj && yaffs_SkipVerification(obj->myDev))
-               return;
-}
-
-static void yaffs_VerifyObject(yaffs_Object *obj)
-{
-       yaffs_Device *dev;
-
-       __u32 chunkMin;
-       __u32 chunkMax;
-
-       __u32 chunkIdOk;
-       __u32 chunkInRange;
-       __u32 chunkShouldNotBeDeleted;
-       __u32 chunkValid;
-
-       if (!obj)
-               return;
-
-       if (obj->beingCreated)
-               return;
-
-       dev = obj->myDev;
-
-       if (yaffs_SkipVerification(dev))
-               return;
-
-       /* Check sane object header chunk */
-
-       chunkMin = dev->internalStartBlock * dev->param.nChunksPerBlock;
-       chunkMax = (dev->internalEndBlock+1) * dev->param.nChunksPerBlock - 1;
-
-       chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
-       chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
-       chunkValid = chunkInRange &&
-                       yaffs_CheckChunkBit(dev,
-                                       obj->hdrChunk / dev->param.nChunksPerBlock,
-                                       obj->hdrChunk % dev->param.nChunksPerBlock);
-       chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
-
-       if (!obj->fake &&
-                       (!chunkIdOk || chunkShouldNotBeDeleted)) {
-               T(YAFFS_TRACE_VERIFY,
-                       (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
-                       obj->objectId, obj->hdrChunk,
-                       chunkIdOk ? "" : ",out of range",
-                       chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
-       }
-
-       if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
-               yaffs_ExtendedTags tags;
-               yaffs_ObjectHeader *oh;
-               __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
-
-               oh = (yaffs_ObjectHeader *)buffer;
-
-               yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
-                               &tags);
-
-               yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
-
-               yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
-       }
-
-       /* Verify it has a parent */
-       if (obj && !obj->fake &&
-                       (!obj->parent || obj->parent->myDev != dev)) {
-               T(YAFFS_TRACE_VERIFY,
-                       (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
-                       obj->objectId, obj->parent));
-       }
-
-       /* Verify parent is a directory */
-       if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
-               T(YAFFS_TRACE_VERIFY,
-                       (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
-                       obj->objectId, obj->parent->variantType));
-       }
-
-       switch (obj->variantType) {
-       case YAFFS_OBJECT_TYPE_FILE:
-               yaffs_VerifyFile(obj);
-               break;
-       case YAFFS_OBJECT_TYPE_SYMLINK:
-               yaffs_VerifySymlink(obj);
-               break;
-       case YAFFS_OBJECT_TYPE_DIRECTORY:
-               yaffs_VerifyDirectory(obj);
-               break;
-       case YAFFS_OBJECT_TYPE_HARDLINK:
-               yaffs_VerifyHardLink(obj);
-               break;
-       case YAFFS_OBJECT_TYPE_SPECIAL:
-               yaffs_VerifySpecial(obj);
-               break;
-       case YAFFS_OBJECT_TYPE_UNKNOWN:
-       default:
-               T(YAFFS_TRACE_VERIFY,
-               (TSTR("Obj %d has illegaltype %d"TENDSTR),
-               obj->objectId, obj->variantType));
-               break;
-       }
-}
-
-void yaffs_VerifyObjects(yaffs_Device *dev)
-{
-       yaffs_Object *obj;
-       int i;
-       struct ylist_head *lh;
-
-       if (yaffs_SkipVerification(dev))
-               return;
-
-       /* Iterate through the objects in each hash entry */
-
-       for (i = 0; i <  YAFFS_NOBJECT_BUCKETS; i++) {
-               ylist_for_each(lh, &dev->objectBucket[i].list) {
-                       if (lh) {
-                               obj = ylist_entry(lh, yaffs_Object, hashLink);
-                               yaffs_VerifyObject(obj);
-                       }
-               }
-       }
-}
 
 
 /*
@@ -1087,6 +627,18 @@ void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
        obj->sum = yaffs_CalcNameSum(name);
 }
 
+void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+       YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1];
+       memset(tmpName,0,sizeof(tmpName));
+       yaffs_LoadNameFromObjectHeader(obj->myDev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1);
+       yaffs_SetObjectName(obj,tmpName);
+#else
+       yaffs_SetObjectName(obj,oh->name);
+#endif
+}
+
 /*-------------------- TNODES -------------------
 
  * List of spare tnodes
@@ -1154,7 +706,7 @@ void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
        }
 }
 
-static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
+__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
                unsigned pos)
 {
        __u32 *map = (__u32 *)tn;
@@ -1191,7 +743,7 @@ static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
  */
 
 /* FindLevel0Tnode finds the level 0 tnode, if one exists. */
-static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
+yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
                                        yaffs_FileStructure *fStruct,
                                        __u32 chunkId)
 {
@@ -2554,7 +2106,6 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
        int newChunk;
        int markNAND;
        int retVal = YAFFS_OK;
-       int cleanups = 0;
        int i;
        int isCheckpointBlock;
        int matchingChunk;
@@ -2672,14 +2223,15 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
                                         * We have to decrement free chunks so this works out properly.
                                         */
                                        dev->nFreeChunks--;
+                                       bi->softDeletions--;
 
                                        object->nDataChunks--;
 
                                        if (object->nDataChunks <= 0) {
                                                /* remeber to clean up the object */
-                                               dev->gcCleanupList[cleanups] =
+                                               dev->gcCleanupList[dev->nCleanups] =
                                                    tags.objectId;
-                                               cleanups++;
+                                               dev->nCleanups++;
                                        }
                                        markNAND = 0;
                                } else if (0) {
@@ -2765,8 +2317,23 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
                yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
 
 
+
+       }
+
+       yaffs_VerifyCollectedBlock(dev, bi, block);
+
+
+
+       if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
+               /*
+                * The gc did not complete. Set block state back to FULL
+                * because checkpointing does not restore gc.
+                */
+               bi->blockState = YAFFS_BLOCK_STATE_FULL;
+       } else {
+               /* The gc completed. */
                /* Do any required cleanups */
-               for (i = 0; i < cleanups; i++) {
+               for (i = 0; i < dev->nCleanups; i++) {
                        /* Time to delete the file too */
                        object =
                            yaffs_FindObjectByNumber(dev,
@@ -2786,20 +2353,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
 
                }
 
-       }
-
-       yaffs_VerifyCollectedBlock(dev, bi, block);
-
 
-
-       if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
-               /*
-                * The gc did not complete. Set block state back to FULL
-                * because checkpointing does not restore gc.
-                */
-               bi->blockState = YAFFS_BLOCK_STATE_FULL;
-       } else {
-               /* The gc completed. */
                chunksAfter = yaffs_GetErasedChunks(dev);
                if (chunksBefore >= chunksAfter) {
                        T(YAFFS_TRACE_GC,
@@ -2809,6 +2363,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
                }
                dev->gcBlock = 0;
                dev->gcChunk = 0;
+               dev->nCleanups = 0;
        }
 
        dev->gcDisable = 0;
@@ -2880,7 +2435,16 @@ static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
                        threshold = dev->param.nChunksPerBlock;
                        iterations = nBlocks;
                } else {
-                       int maxThreshold = dev->param.nChunksPerBlock/2;
+                       int maxThreshold;
+
+                       if(background)
+                               maxThreshold = dev->param.nChunksPerBlock/2;
+                       else
+                               maxThreshold = dev->param.nChunksPerBlock/8;
+
+                       if(maxThreshold <  YAFFS_GC_PASSIVE_THRESHOLD)
+                               maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD;
+
                        threshold = background ?
                                (dev->gcNotDone + 2) * 2 : 0;
                        if(threshold <YAFFS_GC_PASSIVE_THRESHOLD)
@@ -2945,8 +2509,10 @@ static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
                  dev->param.nChunksPerBlock - dev->gcPagesInUse,
                  prioritised));
 
+               dev->nGCBlocks++;
                if(background)
                        dev->backgroundGCs++;
+
                dev->gcDirtiest = 0;
                dev->gcPagesInUse = 0;
                dev->gcNotDone = 0;
@@ -2980,10 +2546,8 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background)
        int aggressive = 0;
        int gcOk = YAFFS_OK;
        int maxTries = 0;
-
        int minErased;
        int erasedChunks;
-
        int checkpointBlockAdjust;
 
        if(dev->param.gcControl &&
@@ -3011,6 +2575,9 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background)
                if (dev->nErasedBlocks < minErased)
                        aggressive = 1;
                else {
+                       if(!background && erasedChunks > (dev->nFreeChunks / 4))
+                               break;
+
                        if(dev->gcSkip > 20)
                                dev->gcSkip = 20;
                        if(erasedChunks < dev->nFreeChunks/2 ||
@@ -3030,10 +2597,12 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background)
                if (dev->gcBlock < 1 && !aggressive) {
                        dev->gcBlock = yaffs2_FindRefreshBlock(dev);
                        dev->gcChunk = 0;
+                       dev->nCleanups=0;
                }
                if (dev->gcBlock < 1) {
                        dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive, background);
                        dev->gcChunk = 0;
+                       dev->nCleanups=0;
                }
 
                if (dev->gcBlock > 0) {
@@ -3152,63 +2721,6 @@ static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
        return retVal;
 }
 
-#ifdef YAFFS_PARANOID
-
-static int yaffs_CheckFileSanity(yaffs_Object *in)
-{
-       int chunk;
-       int nChunks;
-       int fSize;
-       int failed = 0;
-       int objId;
-       yaffs_Tnode *tn;
-       yaffs_Tags localTags;
-       yaffs_Tags *tags = &localTags;
-       int theChunk;
-       int chunkDeleted;
-
-       if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
-               return YAFFS_FAIL;
-
-       objId = in->objectId;
-       fSize = in->variant.fileVariant.fileSize;
-       nChunks =
-           (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
-
-       for (chunk = 1; chunk <= nChunks; chunk++) {
-               tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
-                                          chunk);
-
-               if (tn) {
-
-                       theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
-
-                       if (yaffs_CheckChunkBits
-                           (dev, theChunk / dev->param.nChunksPerBlock,
-                            theChunk % dev->param.nChunksPerBlock)) {
-
-                               yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
-                                                           tags,
-                                                           &chunkDeleted);
-                               if (yaffs_TagsMatch
-                                   (tags, in->objectId, chunk, chunkDeleted)) {
-                                       /* found it; */
-
-                               }
-                       } else {
-
-                               failed = 1;
-                       }
-
-               } else {
-                       /* T(("No level 0 found for %d\n", chunk)); */
-               }
-       }
-
-       return failed ? YAFFS_FAIL : YAFFS_OK;
-}
-
-#endif
 
 int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
                                int chunkInNAND, int inScan)
@@ -3475,7 +2987,7 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
                if (prevChunkId > 0)
                        yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
 
-               yaffs_CheckFileSanity(in);
+               yaffs_VerifyFileSanity(in);
        }
        return newChunkId;
 
@@ -3558,7 +3070,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
 
                if (name && *name) {
                        memset(oh->name, 0, sizeof(oh->name));
-                       yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
+                       yaffs_LoadObjectHeaderFromName(dev,oh->name,name);
                } else if (prevChunkId > 0)
                        memcpy(oh->name, oldName, sizeof(oh->name));
                else
@@ -3600,7 +3112,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
 
                /* process any xattrib modifications */
                if(xmod)
-                       yaffs_ApplyXMod(dev, (char *)buffer, xmod);
+                       yaffs_ApplyXMod(in, (char *)buffer, xmod);
 
 
                /* Tags */
@@ -4690,6 +4202,9 @@ static void yaffs_StripDeletedObjects(yaffs_Device *dev)
        struct ylist_head *n;
        yaffs_Object *l;
 
+       if (dev->readOnly)
+               return;
+
        /* Soft delete all the unlinked files */
        ylist_for_each_safe(i, n,
                &dev->unlinkedDir->variant.directoryVariant.children) {
@@ -4743,6 +4258,8 @@ static void yaffs_FixHangingObjects(yaffs_Device *dev)
        int depthLimit;
        int hanging;
 
+       if (dev->readOnly)
+               return;
 
        /* Iterate through the objects in each hash entry,
         * looking at each object.
@@ -4872,7 +4389,7 @@ static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
                in->yst_rdev = oh->yst_rdev;
 
 #endif
-               yaffs_SetObjectName(in, oh->name);
+               yaffs_SetObjectNameFromOH(in, oh);
 
                if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
                        in->variant.symLinkVariant.alias =
@@ -4887,82 +4404,6 @@ static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
 
 /*------------------------------  Directory Functions ----------------------------- */
 
-static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
-{
-       struct ylist_head *lh;
-       yaffs_Object *listObj;
-
-       int count = 0;
-
-       if (!obj) {
-               T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
-               YBUG();
-               return;
-       }
-
-       if (yaffs_SkipVerification(obj->myDev))
-               return;
-
-       if (!obj->parent) {
-               T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
-               YBUG();
-               return;
-       }
-
-       if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
-               T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
-               YBUG();
-       }
-
-       /* Iterate through the objects in each hash entry */
-
-       ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
-               if (lh) {
-                       listObj = ylist_entry(lh, yaffs_Object, siblings);
-                       yaffs_VerifyObject(listObj);
-                       if (obj == listObj)
-                               count++;
-               }
-        }
-
-       if (count != 1) {
-               T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
-               YBUG();
-       }
-}
-
-static void yaffs_VerifyDirectory(yaffs_Object *directory)
-{
-       struct ylist_head *lh;
-       yaffs_Object *listObj;
-
-       if (!directory) {
-               YBUG();
-               return;
-       }
-
-       if (yaffs_SkipFullVerification(directory->myDev))
-               return;
-
-       if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
-               T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
-               YBUG();
-       }
-
-       /* Iterate through the objects in each hash entry */
-
-       ylist_for_each(lh, &directory->variant.directoryVariant.children) {
-               if (lh) {
-                       listObj = ylist_entry(lh, yaffs_Object, siblings);
-                       if (listObj->parent != directory) {
-                               T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
-                               YBUG();
-                       }
-                       yaffs_VerifyObjectInDirectory(listObj);
-               }
-       }
-}
-
 /*
  *yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new
  * link (ie. name) is created or deleted in the directory.
@@ -4984,6 +4425,7 @@ static void yaffs_UpdateParent(yaffs_Object *obj)
        yaffs_Device *dev;
        if(!obj)
                return;
+#ifndef CONFIG_YAFFS_WINCE
 
        dev = obj->myDev;
        obj->dirty = 1;
@@ -4998,6 +4440,7 @@ static void yaffs_UpdateParent(yaffs_Object *obj)
 
        } else
                yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
+#endif
 }
 
 void yaffs_UpdateDirtyDirectories(yaffs_Device *dev)
@@ -5198,36 +4641,124 @@ yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
        return obj;
 }
 
-int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize)
-{
-       memset(name, 0, buffSize * sizeof(YCHAR));
-
-       yaffs_CheckObjectDetailsLoaded(obj);
+/*
+ *  A note or two on object names.
+ *  * If the object name is missing, we then make one up in the form objnnn
+ *
+ *  * ASCII names are stored in the object header's name field from byte zero
+ *  * Unicode names are historically stored starting from byte zero.
+ *
+ * Then there are automatic Unicode names...
+ * The purpose of these is to save names in a way that can be read as
+ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
+ * system to share files.
+ *
+ * These automatic unicode are stored slightly differently...
+ *  - If the name can fit in the ASCII character space then they are saved as 
+ *    ascii names as per above.
+ *  - If the name needs Unicode then the name is saved in Unicode
+ *    starting at oh->name[1].
 
-       if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
-               yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
-       } else if (obj->hdrChunk <= 0) {
+ */
+static void yaffs_FixNullName(yaffs_Object * obj,YCHAR * name, int buffSize)
+{
+       /* Create an object name if we could not find one. */
+       if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 0){
                YCHAR locName[20];
                YCHAR numString[20];
                YCHAR *x = &numString[19];
                unsigned v = obj->objectId;
                numString[19] = 0;
-               while (v > 0) {
+               while(v>0){
                        x--;
                        *x = '0' + (v % 10);
                        v /= 10;
                }
                /* make up a name */
                yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
-               yaffs_strcat(locName, x);
+               yaffs_strcat(locName,x);
                yaffs_strncpy(name, locName, buffSize - 1);
+       }
+}
+
+static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+       if(dev->param.autoUnicode){
+               if(*ohName){
+                       /* It is an ASCII name, so do an ASCII to unicode conversion */
+                       const char *asciiOhName = (const char *)ohName;
+                       int n = bufferSize - 1;
+                       while(n > 0 && *asciiOhName){
+                               *name = *asciiOhName;
+                               name++;
+                               asciiOhName++;
+                               n--;
+                       }
+               } else 
+                       yaffs_strncpy(name,ohName+1, bufferSize -1);
+       } else
+#endif
+               yaffs_strncpy(name, ohName, bufferSize - 1);
+}
 
+
+static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev, YCHAR *ohName, const YCHAR *name)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+
+       int isAscii;
+       YCHAR *w;
+
+       if(dev->param.autoUnicode){
+
+               isAscii = 1;
+               w = name;
+       
+               /* Figure out if the name will fit in ascii character set */
+               while(isAscii && *w){
+                       if((*w) & 0xff00)
+                               isAscii = 0;
+                       w++;
+               }
+
+               if(isAscii){
+                       /* It is an ASCII name, so do a unicode to ascii conversion */
+                       char *asciiOhName = (char *)ohName;
+                       int n = YAFFS_MAX_NAME_LENGTH  - 1;
+                       while(n > 0 && *name){
+                               *asciiOhName= *name;
+                               name++;
+                               asciiOhName++;
+                               n--;
+                       }
+               } else{
+                       /* It is a unicode name, so save starting at the second YCHAR */
+                       *ohName = 0;
+                       yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2);
+               }
        }
+       else 
+#endif
+               yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1);
+
+}
+
+int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize)
+{
+       memset(name, 0, buffSize * sizeof(YCHAR));
+       
+       yaffs_CheckObjectDetailsLoaded(obj);
+
+       if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
+               yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
+       } 
 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
-       else if (obj->shortName[0])
-               yaffs_strncpy(name, obj->shortName,YAFFS_SHORT_NAME_LENGTH+1);
+       else if (obj->shortName[0]) {
+               yaffs_strcpy(name, obj->shortName);
+       }
 #endif
-       else {
+       else if(obj->hdrChunk > 0) {
                int result;
                __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
 
@@ -5240,15 +4771,17 @@ int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize)
                                                        obj->hdrChunk, buffer,
                                                        NULL);
                }
-               yaffs_strncpy(name, oh->name, buffSize - 1);
-               name[buffSize-1]=0;
+               yaffs_LoadNameFromObjectHeader(obj->myDev,name,oh->name,buffSize);
 
                yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
        }
 
-       return yaffs_strnlen(name,buffSize-1);
+       yaffs_FixNullName(obj,name,buffSize);
+
+       return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH);
 }
 
+
 int yaffs_GetObjectFileLength(yaffs_Object *obj)
 {
        /* Dereference any hard linking */
@@ -5385,7 +4918,7 @@ int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
 #endif
 
 
-static int yaffs_DoXMod(yaffs_Object *obj, int set, const char *name, const void *value, int size, int flags)
+static int yaffs_DoXMod(yaffs_Object *obj, int set, const YCHAR *name, const void *value, int size, int flags)
 {
        yaffs_XAttrMod xmod;
 
@@ -5406,10 +4939,11 @@ static int yaffs_DoXMod(yaffs_Object *obj, int set, const char *name, const void
                return -ENOSPC;
 }
 
-static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod)
+static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod)
 {
        int retval = 0;
        int x_offs = sizeof(yaffs_ObjectHeader);
+       yaffs_Device *dev = obj->myDev;
        int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader);
 
        char * x_buffer = buffer + x_offs;
@@ -5419,12 +4953,15 @@ static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod
        else
                retval = nval_del(x_buffer, x_size, xmod->name);
 
+       obj->hasXattr = nval_hasvalues(x_buffer, x_size);
+       obj->xattrKnown = 1;
+
        xmod->result = retval;
 
        return retval;
 }
 
-static int yaffs_DoXFetch(yaffs_Object *obj, const char *name, void *value, int size)
+static int yaffs_DoXFetch(yaffs_Object *obj, const YCHAR *name, void *value, int size)
 {
        char *buffer = NULL;
        int result;
@@ -5440,6 +4977,16 @@ static int yaffs_DoXFetch(yaffs_Object *obj, const char *name, void *value, int
        if(obj->hdrChunk < 1)
                return -ENODATA;
 
+       /* If we know that the object has no xattribs then don't do all the
+        * reading and parsing.
+        */
+       if(obj->xattrKnown && !obj->hasXattr){
+               if(name)
+                       return -ENODATA;
+               else
+                       return 0;
+       }
+
        buffer = yaffs_GetTempBuffer(dev, __LINE__);
        if(!buffer)
                return -ENOMEM;
@@ -5451,6 +4998,11 @@ static int yaffs_DoXFetch(yaffs_Object *obj, const char *name, void *value, int
        else{
                x_buffer =  buffer + x_offs;
 
+               if (!obj->xattrKnown){
+                       obj->hasXattr = nval_hasvalues(x_buffer, x_size);
+                       obj->xattrKnown = 1;
+               }
+
                if(name)
                        retval = nval_get(x_buffer, x_size, name, value, size);
                else
@@ -5460,17 +5012,17 @@ static int yaffs_DoXFetch(yaffs_Object *obj, const char *name, void *value, int
        return retval;
 }
 
-int yaffs_SetXAttribute(yaffs_Object *obj, const char *name, const void * value, int size, int flags)
+int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags)
 {
        return yaffs_DoXMod(obj, 1, name, value, size, flags);
 }
 
-int yaffs_RemoveXAttribute(yaffs_Object *obj, const char *name)
+int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name)
 {
        return yaffs_DoXMod(obj, 0, name, NULL, 0, 0);
 }
 
-int yaffs_GetXAttribute(yaffs_Object *obj, const char *name, void *value, int size)
+int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size)
 {
        return yaffs_DoXFetch(obj, name, value, size);
 }
@@ -5902,7 +5454,7 @@ void yaffs_Deinitialise(yaffs_Device *dev)
        }
 }
 
-static int yaffs_CountFreeChunks(yaffs_Device *dev)
+int yaffs_CountFreeChunks(yaffs_Device *dev)
 {
        int nFree=0;
        int b;
@@ -5969,27 +5521,6 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
 
 }
 
-static int yaffs_freeVerificationFailures;
-
-void yaffs_VerifyFreeChunks(yaffs_Device *dev)
-{
-       int counted;
-       int difference;
-
-       if (yaffs_SkipVerification(dev))
-               return;
-
-       counted = yaffs_CountFreeChunks(dev);
-
-       difference = dev->nFreeChunks - counted;
-
-       if (difference) {
-               T(YAFFS_TRACE_ALWAYS,
-                 (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
-                  dev->nFreeChunks, counted, difference));
-               yaffs_freeVerificationFailures++;
-       }
-}
 
 /*---------------------------------------- YAFFS test code ----------------------*/