From 36dc48ebac4140345b3f5955d5013f6c22ad827a Mon Sep 17 00:00:00 2001 From: Charles Manning Date: Fri, 16 Apr 2010 15:39:16 +1200 Subject: [PATCH] yaffs New background garbage collector and related tweaks This commit - introduces the yaffs background garbage collection feature - tweaks the foregound garbage collection to do less work - changes the way auto-checkpointing works - tweaks the block refreshing logic. The aim of the background garbage collector is to do at least some of the garbage collection in the background so that writing operations will not have to do as much garbage collection which should make writes faster. The amount of background garbage collection is controlled by the ratio between the amount of erased space vs the amount of free space: * If less than quarter of free space is erased, then background gc is frequent. * Else if less than a half of the free space is erased, then background gc is still done reasonably frequently. * else (at least half of the free space is erased) the background gc is done infrequently. Background gc is not attempted if the partition is checkpointed since that would invalidate the checkpoint. The auto-checkpointing feature has changed slightly. If the yaffs_auto_checkpoint value is set to 1 or 2 then the auto checkpointing will be blocked if the erased space is less than half the free space (ie. the auto-checkpointing is blocked to allow background gc to progress). Oring in 4 into the yaffs_auto_checkpoint will do a one-shot override, forcing a checkpoint and suspending background gc until the partition is dirtied by a write, erase etc. The block refreshing control has been changed. The dev->param.refreshPeriod now controls how many blocks are garbage collected before another refresh is performed. Values around 1000 probably make the best sense. Signed-off-by: Charles Manning --- direct/yaffscfg2k.c | 2 +- yaffs_fs.c | 52 +++++++++++++++++++++++++++++++++++---------- yaffs_guts.c | 6 ++++-- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/direct/yaffscfg2k.c b/direct/yaffscfg2k.c index 3c0341c..92785e1 100644 --- a/direct/yaffscfg2k.c +++ b/direct/yaffscfg2k.c @@ -182,7 +182,7 @@ int yaffs_StartUp(void) flashDev.param.isYaffs2 = 1; flashDev.param.useNANDECC=1; flashDev.param.wideTnodesDisabled=0; - flashDev.param.refreshPeriod = 10000; + flashDev.param.refreshPeriod = 1000; flashDev.param.nShortOpCaches = 10; // Use caches flashDev.context = (void *) 2; // Used to identify the device in fstat. flashDev.param.writeChunkWithTagsToNAND = yflash2_WriteChunkWithTagsToNAND; diff --git a/yaffs_fs.c b/yaffs_fs.c index 5c0157a..ca02d46 100644 --- a/yaffs_fs.c +++ b/yaffs_fs.c @@ -1939,21 +1939,42 @@ static void yaffs_FlushSuperBlock(struct super_block *sb, int do_checkpoint) yaffs_CheckpointSave(dev); } -static int yaffs_do_sync_fs(struct super_block *sb, int do_checkpoint) + +static unsigned yaffs_bg_gc_urgency(yaffs_Device *dev) +{ + unsigned erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock; + struct yaffs_LinuxContext *context = yaffs_DeviceToContext(dev); + + if(!context->bgRunning) + return 0; + else if(erasedChunks > dev->nFreeChunks/2) + return 0; + else if(erasedChunks > dev->nFreeChunks/4) + return 1; + else + return 2; +} + +static int yaffs_do_sync_fs(struct super_block *sb, + int request_checkpoint) { 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", sb->s_dirt ? "dirty" : "clean", - do_checkpoint ? "with checkpoint" : "no checkpoint", + request_checkpoint ? "checkpoint requested" : "no checkpoint", oneshot_checkpoint ? " one-shot" : "" )); if (sb->s_dirt || oneshot_checkpoint) { yaffs_GrossLock(dev); - yaffs_FlushSuperBlock(sb,do_checkpoint); + yaffs_FlushSuperBlock(sb, request_checkpoint || oneshot_checkpoint); yaffs_GrossUnlock(dev); sb->s_dirt = 0; @@ -1961,6 +1982,7 @@ static int yaffs_do_sync_fs(struct super_block *sb, int do_checkpoint) if(oneshot_checkpoint) yaffs_auto_checkpoint &= ~4; } + return 0; } @@ -1991,9 +2013,9 @@ static int yaffs_BackgroundThread(void *data) unsigned long next_dir_update = now; unsigned long next_gc = now; unsigned long expires; + unsigned int urgency; int gcResult; - unsigned int erasedChunks; struct timer_list timer; T(YAFFS_TRACE_BACKGROUND, @@ -2025,10 +2047,10 @@ static int yaffs_BackgroundThread(void *data) if(time_after(now,next_gc) && ! dev->isCheckpointed){ gcResult = yaffs_BackgroundGarbageCollect(dev); - erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock; - if(erasedChunks < dev->nFreeChunks/4) + urgency = yaffs_bg_gc_urgency(dev); + if(urgency > 1) next_gc = now + HZ/50+1; - else if(erasedChunks < dev->nFreeChunks/2) + else if(urgency > 0) next_gc = now + HZ/20+1; else next_gc = now + HZ * 2; @@ -2110,9 +2132,13 @@ static void yaffs_write_super(struct super_block *sb) static int yaffs_write_super(struct super_block *sb) #endif { + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2); + + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, + ("yaffs_write_super%s\n", + request_checkpoint ? " checkpt" : "")); - T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, ("yaffs_write_super\n")); - yaffs_do_sync_fs(sb, yaffs_auto_checkpoint >= 2); + yaffs_do_sync_fs(sb, request_checkpoint); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) return 0; @@ -2126,9 +2152,13 @@ static int yaffs_sync_fs(struct super_block *sb, int wait) static int yaffs_sync_fs(struct super_block *sb) #endif { - T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, ("yaffs_sync_fs\n")); + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1); + + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, + ("yaffs_sync_fs%s\n", + request_checkpoint ? " checkpt" : "")); - yaffs_do_sync_fs(sb,yaffs_auto_checkpoint >= 1); + yaffs_do_sync_fs(sb, request_checkpoint); return 0; } diff --git a/yaffs_guts.c b/yaffs_guts.c index 65e33a6..42e234a 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -3428,8 +3428,10 @@ static unsigned yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, int maxThreshold = dev->param.nChunksPerBlock/2; threshold = background ? (dev->gcNotDone + 2) * 2 : 0; - threshold = max(threshold, YAFFS_GC_PASSIVE_THRESHOLD); - threshold = min(threshold, maxThreshold); + if(threshold maxThreshold) + threshold = maxThreshold; iterations = nBlocks / 16 + 1; if (iterations > 100) -- 2.30.2