Fix race yaffs_flush_inodes against iput
[yaffs2.git] / yaffs_vfs_multi.c
index 707fcb39911417b3fe3d67301110a647135e7c59..a36d9bfaa9d2ba8c21bcf5af02095ab947b07002 100644 (file)
@@ -35,6 +35,9 @@
  * for any version of Linux.
  */
 #include <linux/version.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0))
+#include <linux/iversion.h>
+#endif
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
 #define YAFFS_COMPILE_BACKGROUND
 #include <linux/statfs.h>
 
 #define UnlockPage(p) unlock_page(p)
-#define Page_Uptodate(page)    test_bit(PG_uptodate, &(page)->flags)
+#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
 
 /* FIXME: use sb->s_id instead ? */
-#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
+#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
 
 #else
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
 #define YPROC_ROOT  (&proc_root)
 #else
-#define YPROC_ROOT  NULL
+#define YPROC_ROOT NULL
 #endif
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
 #define Y_INIT_TIMER(a)        init_timer(a)
-#else
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
 #define Y_INIT_TIMER(a)        init_timer_on_stack(a)
+#else
+#define Y_INIT_TIMER(a,cb) timer_setup_on_stack(a,cb,0)
 #endif
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
@@ -172,18 +177,12 @@ static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
 #include "yaffs_trace.h"
 #include "yaffs_guts.h"
 #include "yaffs_attribs.h"
-
 #include "yaffs_linux.h"
-
 #include "yaffs_mtdif.h"
 #include "yaffs_packedtags2.h"
 #include "yaffs_getblockinfo.h"
 
-unsigned int yaffs_trace_mask =
-               YAFFS_TRACE_BAD_BLOCKS |
-               YAFFS_TRACE_ALWAYS |
-               0;
-
+unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS | 0;
 unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
 unsigned int yaffs_auto_checkpoint = 1;
 unsigned int yaffs_gc_control = 1;
@@ -249,11 +248,10 @@ MODULE_PARM(yaffs_gc_control, "i");
 #include <linux/seq_file.h>
 #endif
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
 #define PAGE_CACHE_SIZE PAGE_SIZE
 #define PAGE_CACHE_SHIFT PAGE_SHIFT
 #define Y_GET_DENTRY(f) ((f)->f_path.dentry)
-#define page_cache_release put_page
 #define YAFFS_NEW_XATTR 1
 #define YAFFS_NEW_GET_LINK 1
 #else
@@ -262,9 +260,23 @@ MODULE_PARM(yaffs_gc_control, "i");
 #define YAFFS_NEW_GET_LINK 0
 #endif
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
+#define page_cache_release put_page
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0))
+#define update_dir_time(dir) do {\
+               (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
+       } while (0)
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0))
+#define update_dir_time(dir) do {\
+               (dir)->i_ctime = (dir)->i_mtime = current_kernel_time(); \
+       } while (0)
+#else
 #define update_dir_time(dir) do {\
-                       (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
-               } while (0)
+               (dir)->i_ctime = (dir)->i_mtime = current_kernel_time64(); \
+       } while (0)
+#endif
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0))
 static inline int setattr_prepare(struct dentry *dentry, struct iattr *attr)
@@ -800,7 +812,7 @@ static int yaffs_sync_object(struct file *file, struct dentry *dentry,
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
 static const struct file_operations yaffs_file_operations = {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
        .read = new_sync_read,
        .write = new_sync_write,
 #endif
@@ -973,7 +985,7 @@ static int yaffs_setxattr(struct dentry *dentry, const char *name,
        return error;
 }
 
-#ifdef YAFFS_NEW_XATTR
+#if (YAFFS_NEW_XATTR > 0)
 static ssize_t yaffs_getxattr(struct dentry * dentry, struct inode *inode,
        const char *name, void *buff, size_t size)
 {
@@ -1646,7 +1658,11 @@ static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
 
        if (ret_val == YAFFS_OK) {
                inode_dec_link_count(dentry->d_inode);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0))
+               inode_inc_iversion(dir);
+#else
                dir->i_version++;
+#endif
                yaffs_gross_unlock(dev);
                update_dir_time(dir);
                return 0;
@@ -1816,8 +1832,10 @@ static int yaffs_iterate(struct file *f, struct dir_context *dc)
                goto out;
        }
 
-       if (!dir_emit_dots(f, dc))
+       if (!dir_emit_dots(f, dc)) {
+               yaffs_gross_unlock(dev);
                return 0;
+       }
 
        curoffs = 1;
 
@@ -2127,10 +2145,26 @@ static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev)
 
 #ifdef YAFFS_COMPILE_BACKGROUND
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+struct timer_struct {
+       struct task_struct *task;
+       struct timer_list timer;
+};
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+static void yaffs_background_waker(struct timer_list *t)
+{
+       struct timer_struct *ts = from_timer(ts, t, timer);
+
+       wake_up_process(ts->task);
+}
+#else
 void yaffs_background_waker(unsigned long data)
 {
        wake_up_process((struct task_struct *)data);
 }
+#endif
 
 static int yaffs_bg_thread_fn(void *data)
 {
@@ -2143,7 +2177,11 @@ static int yaffs_bg_thread_fn(void *data)
        unsigned int urgency;
 
        int gc_result;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+       struct timer_struct timer;
+#else
        struct timer_list timer;
+#endif
 
        yaffs_trace(YAFFS_TRACE_BACKGROUND,
                "yaffs_background starting for dev %p", (void *)dev);
@@ -2189,24 +2227,32 @@ static int yaffs_bg_thread_fn(void *data)
                         }
                }
                yaffs_gross_unlock(dev);
-#if 1
                expires = next_dir_update;
                if (time_before(next_gc, expires))
                        expires = next_gc;
                if (time_before(expires, now))
                        expires = now + HZ;
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+               Y_INIT_TIMER(&timer.timer, yaffs_background_waker);
+               timer.timer.expires = expires + 1;
+               timer.task = current;
+#else
                Y_INIT_TIMER(&timer);
                timer.expires = expires + 1;
                timer.data = (unsigned long)current;
                timer.function = yaffs_background_waker;
+#endif
 
                set_current_state(TASK_INTERRUPTIBLE);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+               add_timer(&timer.timer);
+               schedule();
+               del_timer_sync(&timer.timer);
+#else
                add_timer(&timer);
                schedule();
                del_timer_sync(&timer);
-#else
-               msleep(10);
 #endif
        }
 
@@ -3743,8 +3789,8 @@ static void __exit exit_yaffs_fs(void)
 }
 
 module_init(init_yaffs_fs)
-    module_exit(exit_yaffs_fs)
+module_exit(exit_yaffs_fs)
 
-    MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
+MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
 MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2011");
 MODULE_LICENSE("GPL");