yaffs Add stats tracking and control for background gc instrumentation
[yaffs2.git] / yaffs_guts.c
index a8b850a71711dda636dc3dd330f5576f0d9c6f2b..389a57ca79f25efb475ef3e1311f3e6e4ab3c8b5 100644 (file)
@@ -99,6 +99,11 @@ static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
                                        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,
@@ -622,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
@@ -2089,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;
@@ -2207,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) {
@@ -2300,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,
@@ -2321,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,
@@ -2344,6 +2363,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
                }
                dev->gcBlock = 0;
                dev->gcChunk = 0;
+               dev->nCleanups = 0;
        }
 
        dev->gcDisable = 0;
@@ -2480,8 +2500,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;
@@ -2565,10 +2587,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) {
@@ -3036,7 +3060,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
@@ -4168,6 +4192,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) {
@@ -4221,6 +4248,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.
@@ -4350,7 +4379,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 =
@@ -4386,6 +4415,7 @@ static void yaffs_UpdateParent(yaffs_Object *obj)
        yaffs_Device *dev;
        if(!obj)
                return;
+#ifndef CONFIG_YAFFS_WINCE
 
        dev = obj->myDev;
        obj->dirty = 1;
@@ -4400,6 +4430,7 @@ static void yaffs_UpdateParent(yaffs_Object *obj)
 
        } else
                yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
+#endif
 }
 
 void yaffs_UpdateDirtyDirectories(yaffs_Device *dev)
@@ -4600,36 +4631,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__);
 
@@ -4642,15 +4761,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 */
@@ -4787,7 +4908,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;
 
@@ -4826,7 +4947,7 @@ static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod
        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;
@@ -4862,17 +4983,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);
 }