X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_fs.c;h=25d3d2260fa4b36d1409b8f302ebebb303d5a09e;hp=95538ab4ea2210ee6278847b5260a7a50a3cc115;hb=6e5a71caad2176450f764d3e359fb972b86d83e2;hpb=f9cb4ba6cdd270bf21d76dcb8e8381a9c143f670 diff --git a/yaffs_fs.c b/yaffs_fs.c index 95538ab..25d3d22 100644 --- a/yaffs_fs.c +++ b/yaffs_fs.c @@ -41,6 +41,11 @@ extern const char *yaffs_guts_c_version; #define YAFFS_COMPILE_BACKGROUND #endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) +#define YAFFS_COMPILE_EXPORTFS +#endif + + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) #include #endif @@ -56,11 +61,15 @@ extern const char *yaffs_guts_c_version; #include #include #include + +#ifdef YAFFS_COMPILE_EXPORTFS #include +#endif #ifdef YAFFS_COMPILE_BACKGROUND #include #include +#include #endif @@ -417,12 +426,12 @@ static void yaffs_GrossUnlock(yaffs_Device *dev) up(&(yaffs_DeviceToContext(dev)->grossLock)); } - +#ifdef YAFFS_COMPILE_EXPORTFS static struct inode * yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, uint32_t generation) { - return yaffs_iget(sb, ino); + return Y_IGET(sb, ino); } static struct dentry * @@ -453,7 +462,7 @@ struct dentry *yaffs2_get_parent(struct dentry *dentry) parent_obj = d_obj->parent; if (parent_obj) { parent_ino = yaffs_GetObjectInode(parent_obj); - inode = yaffs_iget(sb, parent_ino); + inode = Y_IGET(sb, parent_ino); if (IS_ERR(inode)) { parent = ERR_CAST(inode); @@ -470,7 +479,6 @@ struct dentry *yaffs2_get_parent(struct dentry *dentry) return parent; } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,9)) /* Just declare a zero structure as a NULL value implies * using the default functions of expfs. */ @@ -1442,13 +1450,11 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) /* If the directory has changed since the open or last call to readdir, rewind to after the 2 canned entries. */ -#if 0 /* For exportfs patch */ if (f->f_version != inode->i_version) { offset = 2; f->f_pos = offset; f->f_version = inode->i_version; } -#endif while(sc->nextReturn){ curoffs++; @@ -1933,22 +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); - T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, - ("yaffs_do_sync_fs: %s %s\n", + 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_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) { - 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; } @@ -1965,26 +2006,88 @@ 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; } @@ -2040,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; @@ -2056,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; } @@ -2162,6 +2273,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); @@ -2169,7 +2284,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); @@ -2305,7 +2419,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, sb->s_op = &yaffs_super_ops; sb->s_flags |= MS_NOATIME; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,9)) +#ifdef YAFFS_COMPILE_EXPORTFS sb->s_export_op = &yaffs_export_ops; #endif @@ -2534,7 +2648,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) @@ -2795,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); @@ -2889,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); @@ -3122,6 +3239,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;