X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_fs.c;h=25d3d2260fa4b36d1409b8f302ebebb303d5a09e;hp=5c0157a90bdaab4ecb674370f26e09bdf6c6d232;hb=6e5a71caad2176450f764d3e359fb972b86d83e2;hpb=c565b5da13774bc9d5f661d93a127ba86a8769e7 diff --git a/yaffs_fs.c b/yaffs_fs.c index 5c0157a..25d3d22 100644 --- a/yaffs_fs.c +++ b/yaffs_fs.c @@ -1939,28 +1939,57 @@ 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); + 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) + 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); + unsigned gc_urgent = yaffs_bg_gc_urgency(dev); + int do_checkpoint; - 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", - 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_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; } @@ -1991,9 +2020,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, @@ -2016,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); - erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock; - if(erasedChunks < dev->nFreeChunks/4) - next_gc = now + HZ/50+1; - else if(erasedChunks < dev->nFreeChunks/2) - 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 @@ -2110,9 +2143,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\n")); - yaffs_do_sync_fs(sb, yaffs_auto_checkpoint >= 2); + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, + ("yaffs_write_super%s\n", + request_checkpoint ? " checkpt" : "")); + + yaffs_do_sync_fs(sb, request_checkpoint); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) return 0; @@ -2126,9 +2163,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; } @@ -2868,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); @@ -2962,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);