work in progress
[yaffs2.git] / yaffs_fs.c
index 95538ab4ea2210ee6278847b5260a7a50a3cc115..5c0157a90bdaab4ecb674370f26e09bdf6c6d232 100644 (file)
@@ -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 <linux/config.h>
 #endif
@@ -56,11 +61,15 @@ extern const char *yaffs_guts_c_version;
 #include <linux/interrupt.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
+
+#ifdef YAFFS_COMPILE_EXPORTFS
 #include <linux/exportfs.h>
+#endif
 
 #ifdef YAFFS_COMPILE_BACKGROUND
 #include <linux/kthread.h>
 #include <linux/delay.h>
+#include <linux/freezer.h>
 #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++;
@@ -1937,17 +1943,23 @@ static int yaffs_do_sync_fs(struct super_block *sb, int do_checkpoint)
 {
 
        yaffs_Device *dev = yaffs_SuperToDevice(sb);
+       unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
+
        T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, 
-               ("yaffs_do_sync_fs: %s %s\n", 
+               ("yaffs_do_sync_fs: %s %s%s\n",
                sb->s_dirt ? "dirty" : "clean",
-               do_checkpoint ? "with checkpoint" : "no checkpoint"));
+               do_checkpoint ? "with checkpoint" : "no checkpoint",
+               oneshot_checkpoint ? " one-shot" : "" ));
 
-       if (sb->s_dirt) {
+       if (sb->s_dirt || oneshot_checkpoint) {
                yaffs_GrossLock(dev);
                yaffs_FlushSuperBlock(sb,do_checkpoint);
                yaffs_GrossUnlock(dev);
 
                sb->s_dirt = 0;
+
+               if(oneshot_checkpoint)
+                       yaffs_auto_checkpoint &= ~4;
        }
        return 0;
 }
@@ -1965,26 +1977,84 @@ 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;
+
+       int gcResult;
+       unsigned int erasedChunks;
+       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) &&
+                       !dev->isCheckpointed){
+                       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;
+               }
                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;
 }
 
@@ -2162,6 +2232,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 +2243,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 +2378,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 +2607,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)
@@ -3122,6 +3195,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;