yaffs: More background gc tweaks.
authorCharles Manning <cdhmanning@gmail.com>
Tue, 20 Apr 2010 02:36:01 +0000 (14:36 +1200)
committerCharles Manning <cdhmanning@gmail.com>
Tue, 20 Apr 2010 02:36:01 +0000 (14:36 +1200)
Slight changes to urgency thresholds

Fix problem where background gc was interfering with sync resulting in
checkpoints being lost.

Add more tracing for background gc.

Signed-off-by: Charles Manning <cdhmanning@gmail.com>
yaffs_fs.c
yaffs_guts.c
yaffs_guts.h

index ca02d468266b7ebbd1d76a7bce82e3ec4abb9033..25d3d2260fa4b36d1409b8f302ebebb303d5a09e 100644 (file)
@@ -1944,9 +1944,15 @@ static unsigned yaffs_bg_gc_urgency(yaffs_Device *dev)
 {
        unsigned erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
        struct yaffs_LinuxContext *context = yaffs_DeviceToContext(dev);
+       unsigned scatteredFree = 0; /* Free chunks not in an erased block */
+
+       if(erasedChunks < dev->nFreeChunks)
+               scatteredFree = (dev->nFreeChunks - erasedChunks);
 
        if(!context->bgRunning)
                return 0;
+       else if(scatteredFree < (dev->param.nChunksPerBlock * 2))
+               return 0;
        else if(erasedChunks > dev->nFreeChunks/2)
                return 0;
        else if(erasedChunks > dev->nFreeChunks/4)
@@ -1961,27 +1967,28 @@ static int yaffs_do_sync_fs(struct super_block *sb,
 
        yaffs_Device *dev = yaffs_SuperToDevice(sb);
        unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
+       unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
+       int do_checkpoint;
 
-       if(!oneshot_checkpoint &&
-               yaffs_bg_gc_urgency(dev) > 0)
-               request_checkpoint = 0;
-
-       T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, 
-               ("yaffs_do_sync_fs: %s %s%s\n",
+       T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
+               ("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n",
+               gc_urgent,
                sb->s_dirt ? "dirty" : "clean",
                request_checkpoint ? "checkpoint requested" : "no checkpoint",
                oneshot_checkpoint ? " one-shot" : "" ));
 
-       if (sb->s_dirt || oneshot_checkpoint) {
-               yaffs_GrossLock(dev);
-               yaffs_FlushSuperBlock(sb, request_checkpoint || oneshot_checkpoint);
-               yaffs_GrossUnlock(dev);
+       yaffs_GrossLock(dev);
+       do_checkpoint = ((request_checkpoint && !gc_urgent) ||
+                       oneshot_checkpoint) &&
+                       !dev->isCheckpointed;
 
+       if (sb->s_dirt || do_checkpoint) {
+               yaffs_FlushSuperBlock(sb, !dev->isCheckpointed && do_checkpoint);
                sb->s_dirt = 0;
-
                if(oneshot_checkpoint)
                        yaffs_auto_checkpoint &= ~4;
        }
+       yaffs_GrossUnlock(dev);
 
        return 0;
 }
@@ -2038,22 +2045,26 @@ static int yaffs_BackgroundThread(void *data)
 
                now = jiffies;
 
-               if(time_after(now, next_dir_update) &&
-                       !dev->isCheckpointed){
+               if(time_after(now, next_dir_update)){
                        yaffs_UpdateDirtyDirectories(dev);
                        next_dir_update = now + HZ;
                }
 
-               if(time_after(now,next_gc) &&
-                       ! dev->isCheckpointed){
-                       gcResult = yaffs_BackgroundGarbageCollect(dev);
-                       urgency = yaffs_bg_gc_urgency(dev);
-                       if(urgency > 1)
-                               next_gc = now + HZ/50+1;
-                       else if(urgency > 0)
-                               next_gc = now + HZ/20+1;
-                       else
-                               next_gc = now + HZ * 2;
+               if(time_after(now,next_gc)){
+                       if(!dev->isCheckpointed){
+                               urgency = yaffs_bg_gc_urgency(dev);
+                               gcResult = yaffs_BackgroundGarbageCollect(dev, urgency);
+                               if(urgency > 1)
+                                       next_gc = now + HZ/20+1;
+                               else if(urgency > 0)
+                                       next_gc = now + HZ/10+1;
+                               else
+                                       next_gc = now + HZ * 2;
+                       } else /*
+                               * gc not running so set to next_dir_update
+                               * to cut down on wake ups
+                               */
+                               next_gc = next_dir_update;
                }
                yaffs_GrossUnlock(dev);
 #if 1
@@ -2134,7 +2145,7 @@ static int yaffs_write_super(struct super_block *sb)
 {
        unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
 
-       T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
+       T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
                ("yaffs_write_super%s\n",
                request_checkpoint ? " checkpt" : ""));
 
@@ -2898,8 +2909,10 @@ static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev)
        buf += sprintf(buf, "nPageReads......... %u\n", dev->nPageReads);
        buf += sprintf(buf, "nBlockErasures..... %u\n", dev->nBlockErasures);
        buf += sprintf(buf, "nGCCopies.......... %u\n", dev->nGCCopies);
-       buf += sprintf(buf, "garbageCollections. %u\n", dev->garbageCollections);
-       buf += sprintf(buf, "passiveGCs......... %u\n", dev->passiveGarbageCollections);
+       buf += sprintf(buf, "allGCs............. %u\n", dev->allGCs);
+       buf += sprintf(buf, "passiveGCs......... %u\n", dev->passiveGCs);
+       buf += sprintf(buf, "oldestDirtyGCs..... %u\n", dev->oldestDirtyGCs);
+       buf += sprintf(buf, "backgroundGCs...... %u\n", dev->backgroundGCs);
        buf += sprintf(buf, "nRetriedWrites..... %u\n", dev->nRetriedWrites);
        buf += sprintf(buf, "nRetireBlocks...... %u\n", dev->nRetiredBlocks);
        buf += sprintf(buf, "eccFixed........... %u\n", dev->eccFixed);
@@ -2992,8 +3005,9 @@ static int yaffs_debug_proc_read(char *page,
                nTnodes = dev->nTnodesCreated - dev->nFreeTnodes;
                
                
-               buf += sprintf(buf,"%d, %d, %d, %d, %d\n", 
+               buf += sprintf(buf,"%d, %d, %d, %u, %u, %d, %d\n",
                                n, dev->nFreeChunks, erasedChunks,
+                               dev->backgroundGCs, dev->oldestDirtyGCs,
                                nObjects, nTnodes);
        }
        up(&yaffs_context_lock);
index 42e234a73f56852b4d5760733c3f9ec59e3ae076..2ab6edfd197b1ea3d5285032ad00848924a25226 100644 (file)
@@ -3465,11 +3465,18 @@ static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
                        selected = dev->gcDirtiest;
        }
 
-       if(!selected && dev->param.isYaffs2 && dev->gcNotDone >= ( background ? 10 : 20)){
+       /*
+        * If nothing has been selected for a while, try selecting the oldest dirty
+        * because that's gumming up the works.
+        */
+
+       if(!selected && dev->param.isYaffs2 &&
+               dev->gcNotDone >= ( background ? 10 : 20)){
                yaffs_FindOldestDirtySequence(dev);
                if(dev->oldestDirtyBlock > 0) {
                        selected = dev->oldestDirtyBlock;
                        dev->gcDirtiest = selected;
+                       dev->oldestDirtyGCs++;
                        bi = yaffs_GetBlockInfo(dev, selected);
                        dev->gcPagesInUse =  bi->pagesInUse - bi->softDeletions;
                } else
@@ -3483,6 +3490,8 @@ static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
                  dev->param.nChunksPerBlock - dev->gcPagesInUse,
                  prioritised));
 
+               if(background)
+                       dev->backgroundGCs++;
                dev->gcDirtiest = 0;
                dev->gcPagesInUse = 0;
                dev->gcNotDone = 0;
@@ -3575,9 +3584,9 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background)
                }
 
                if (dev->gcBlock > 0) {
-                       dev->garbageCollections++;
+                       dev->allGCs++;
                        if (!aggressive)
-                               dev->passiveGarbageCollections++;
+                               dev->passiveGCs++;
 
                        T(YAFFS_TRACE_GC,
                          (TSTR
@@ -3605,11 +3614,11 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background)
  * Garbage collects. Intended to be called from a background thread.
  * Returns non-zero if at least half the free chunks are erased.
  */
-int yaffs_BackgroundGarbageCollect(yaffs_Device *dev)
+int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency)
 {
        int erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
 
-       T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc" TENDSTR)));
+       T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR),urgency));
 
        yaffs_CheckGarbageCollection(dev, 1);
        return erasedChunks > dev->nFreeChunks/2;
@@ -7907,8 +7916,10 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        /* OK, we've finished verifying the device, lets continue with initialisation */
 
        /* More device initialisation */
-       dev->garbageCollections = 0;
-       dev->passiveGarbageCollections = 0;
+       dev->allGCs = 0;
+       dev->passiveGCs = 0;
+       dev->oldestDirtyGCs = 0;
+       dev->backgroundGCs = 0;
        dev->gcBlockFinder = 0;
        dev->bufferedBlock = -1;
        dev->doingBufferedBlockRewrite = 0;
index 8c0b782492af595dcaf7afe7f0c7284293e7459c..da41904bdf3d55355eeb57ba3345052c4a7873f8 100644 (file)
@@ -763,8 +763,10 @@ struct yaffs_DeviceStruct {
        __u32 nBlockErasures;
        __u32 nErasureFailures;
        __u32 nGCCopies;
-       __u32 garbageCollections;
-       __u32 passiveGarbageCollections;
+       __u32 allGCs;
+       __u32 passiveGCs;
+       __u32 oldestDirtyGCs;
+       __u32 backgroundGCs;
        __u32 nRetriedWrites;
        __u32 nRetiredBlocks;
        __u32 eccFixed;
@@ -897,7 +899,7 @@ void yaffs_HandleDeferedFree(yaffs_Object *obj);
 
 void yaffs_UpdateDirtyDirectories(yaffs_Device *dev);
 
-int yaffs_BackgroundGarbageCollect(yaffs_Device *dev);
+int yaffs_BackgroundGarbageCollect(yaffs_Device *dev, unsigned urgency);
 
 /* Debug dump  */
 int yaffs_DumpObject(yaffs_Object *obj);