changeset 404:792f3d959342

yaffs: More background gc tweaks. 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>
author Charles Manning <cdhmanning@gmail.com>
date Tue, 20 Apr 2010 14:36:01 +1200
parents 205fa93db422
children 00750a6b5ad8
files yaffs_fs.c yaffs_guts.c yaffs_guts.h
diffstat 3 files changed, 66 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/yaffs_fs.c
+++ b/yaffs_fs.c
@@ -1944,9 +1944,15 @@ static unsigned yaffs_bg_gc_urgency(yaff
 {
 	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
 
 	yaffs_Device *dev = yaffs_SuperToDevice(sb);
 	unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
-
-	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",
+	unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
+	int do_checkpoint;
+
+	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 *
 
 		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 supe
 {
 	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 += 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 *p
 		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);
--- a/yaffs_guts.c
+++ b/yaffs_guts.c
@@ -3465,11 +3465,18 @@ static unsigned yaffs_FindBlockForGarbag
 			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_FindBlockForGarbag
 		  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(
 		}
 
 		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(
  * 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 *d
 	/* 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;
--- a/yaffs_guts.h
+++ b/yaffs_guts.h
@@ -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_Objec
 
 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);