From: Charles Manning Date: Tue, 20 Apr 2010 02:36:01 +0000 (+1200) Subject: yaffs: More background gc tweaks. X-Git-Tag: pre-name-change~84 X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=commitdiff_plain;h=6e5a71caad2176450f764d3e359fb972b86d83e2 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 --- diff --git a/yaffs_fs.c b/yaffs_fs.c index ca02d46..25d3d22 100644 --- a/yaffs_fs.c +++ b/yaffs_fs.c @@ -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); diff --git a/yaffs_guts.c b/yaffs_guts.c index 42e234a..2ab6edf 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -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; diff --git a/yaffs_guts.h b/yaffs_guts.h index 8c0b782..da41904 100644 --- 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_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);