X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_fs.c;h=caade8ae1f06931d9290a9286536e30e4abde38a;hp=0ee40e7c36bfbd69dbda58e8c8281c22b746fc92;hb=80bad6d7cb530b6ddac3c51716400b401dfa86db;hpb=710ded16f463700dde2753ce4a352097051f88f7 diff --git a/yaffs_fs.c b/yaffs_fs.c index 0ee40e7..caade8a 100644 --- a/yaffs_fs.c +++ b/yaffs_fs.c @@ -69,6 +69,7 @@ extern const char *yaffs_guts_c_version; #ifdef YAFFS_COMPILE_BACKGROUND #include #include +#include #endif @@ -1063,9 +1064,8 @@ static int yaffs_write_end(struct file *filp, struct address_space *mapping, addr = kva + offset_into_page; T(YAFFS_TRACE_OS, - ("yaffs_write_end addr %x pos %x nBytes %d\n", - (unsigned) addr, - (int)pos, copied)); + ("yaffs_write_end addr %p pos %x nBytes %d\n", + addr,(unsigned)pos, copied)); ret = yaffs_file_write(filp, addr, copied, &pos); @@ -1938,28 +1938,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; } @@ -1976,38 +2005,100 @@ static int yaffs_do_sync_fs(struct super_block *sb, int do_checkpoint) */ #ifdef YAFFS_COMPILE_BACKGROUND + +void yaffs_background_waker(unsigned long data) +{ + wake_up_process((struct task_struct *)data); +} + static int yaffs_BackgroundThread(void *data) { yaffs_Device *dev = (yaffs_Device *)data; struct yaffs_LinuxContext *context = yaffs_DeviceToContext(dev); + unsigned long now = jiffies; + unsigned long next_dir_update = now; + unsigned long next_gc = now; + unsigned long expires; + unsigned int urgency; + + int gcResult; + struct timer_list timer; T(YAFFS_TRACE_BACKGROUND, ("yaffs_background starting for dev %p\n", (void *)dev)); - + + set_freezable(); + while(context->bgRunning){ T(YAFFS_TRACE_BACKGROUND, ("yaffs_background\n")); if(kthread_should_stop()) break; + + if(try_to_freeze()) + continue; + yaffs_GrossLock(dev); - yaffs_UpdateDirtyDirectories(dev); + + now = jiffies; + + if(time_after(now, next_dir_update)){ + yaffs_UpdateDirtyDirectories(dev); + next_dir_update = now + HZ; + } + + 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); - msleep(500); +#if 1 + expires = next_dir_update; + if (time_before(next_gc,expires)) + expires = next_gc; + if(time_before(expires,now)) + expires = now + HZ; + + init_timer(&timer); + timer.expires = expires+1; + timer.data = (unsigned long) current; + timer.function = yaffs_background_waker; + + set_current_state(TASK_INTERRUPTIBLE); + add_timer(&timer); + schedule(); + del_timer_sync(&timer); +#else + msleep(10); +#endif } + return 0; } static int yaffs_BackgroundStart(yaffs_Device *dev) { int retval = 0; - struct yaffs_LinuxContext *context = yaffs_DeviceToContext(dev); context->bgRunning = 1; - context->bgThread = kthread_run(yaffs_BackgroundThread,(void *)dev,"yaffs_%x",(unsigned)dev); + context->bgThread = kthread_run(yaffs_BackgroundThread, + (void *)dev,"yaffs-bg"); if(IS_ERR(context->bgThread)){ retval = PTR_ERR(context->bgThread); @@ -2051,9 +2142,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; @@ -2067,9 +2162,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; } @@ -2173,6 +2272,10 @@ static void yaffs_put_super(struct super_block *sb) T(YAFFS_TRACE_OS, ("yaffs_put_super\n")); + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, ("Shutting down yaffs background thread\n")); + yaffs_BackgroundStop(dev); + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, ("yaffs background thread shut down\n")); + yaffs_GrossLock(dev); yaffs_FlushSuperBlock(sb,1); @@ -2180,7 +2283,6 @@ static void yaffs_put_super(struct super_block *sb) if (yaffs_DeviceToContext(dev)->putSuperFunc) yaffs_DeviceToContext(dev)->putSuperFunc(sb); - yaffs_BackgroundStop(dev); yaffs_Deinitialise(dev); @@ -2545,7 +2647,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, #ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING param->refreshPeriod = 0; #else - param->refreshPeriod = 10000; + param->refreshPeriod = 100; #endif if(options.empty_lost_and_found_overridden) @@ -2806,8 +2908,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); @@ -2900,8 +3004,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); @@ -3133,6 +3238,7 @@ static void __exit exit_yaffs_fs(void) " removing. \n")); remove_proc_entry("yaffs", YPROC_ROOT); + remove_proc_entry("yaffs_debug", YPROC_ROOT); fsinst = fs_to_install;