]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - fs/inode.c
vfs: add support for a lazytime mount option
[mirror_ubuntu-bionic-kernel.git] / fs / inode.c
index aa149e7262acffff13db5707eeb0c0144add985c..4feb85cc125f2c345120e8f8ef7eb952f28d1684 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/buffer_head.h> /* for inode_has_buffers */
 #include <linux/ratelimit.h>
 #include <linux/list_lru.h>
+#include <trace/events/writeback.h>
 #include "internal.h"
 
 /*
@@ -30,7 +31,7 @@
  * inode_sb_list_lock protects:
  *   sb->s_inodes, inode->i_sb_list
  * bdi->wb.list_lock protects:
- *   bdi->wb.b_{dirty,io,more_io}, inode->i_wb_list
+ *   bdi->wb.b_{dirty,io,more_io,dirty_time}, inode->i_wb_list
  * inode_hash_lock protects:
  *   inode_hashtable, inode->i_hash
  *
@@ -416,7 +417,8 @@ static void inode_lru_list_add(struct inode *inode)
  */
 void inode_add_lru(struct inode *inode)
 {
-       if (!(inode->i_state & (I_DIRTY | I_SYNC | I_FREEING | I_WILL_FREE)) &&
+       if (!(inode->i_state & (I_DIRTY_ALL | I_SYNC |
+                               I_FREEING | I_WILL_FREE)) &&
            !atomic_read(&inode->i_count) && inode->i_sb->s_flags & MS_ACTIVE)
                inode_lru_list_add(inode);
 }
@@ -647,7 +649,7 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty)
                        spin_unlock(&inode->i_lock);
                        continue;
                }
-               if (inode->i_state & I_DIRTY && !kill_dirty) {
+               if (inode->i_state & I_DIRTY_ALL && !kill_dirty) {
                        spin_unlock(&inode->i_lock);
                        busy = 1;
                        continue;
@@ -1432,11 +1434,20 @@ static void iput_final(struct inode *inode)
  */
 void iput(struct inode *inode)
 {
-       if (inode) {
-               BUG_ON(inode->i_state & I_CLEAR);
-
-               if (atomic_dec_and_lock(&inode->i_count, &inode->i_lock))
-                       iput_final(inode);
+       if (!inode)
+               return;
+       BUG_ON(inode->i_state & I_CLEAR);
+retry:
+       if (atomic_dec_and_lock(&inode->i_count, &inode->i_lock)) {
+               if (inode->i_nlink && (inode->i_state & I_DIRTY_TIME)) {
+                       atomic_inc(&inode->i_count);
+                       inode->i_state &= ~I_DIRTY_TIME;
+                       spin_unlock(&inode->i_lock);
+                       trace_writeback_lazytime_iput(inode);
+                       mark_inode_dirty_sync(inode);
+                       goto retry;
+               }
+               iput_final(inode);
        }
 }
 EXPORT_SYMBOL(iput);
@@ -1495,14 +1506,9 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
        return 0;
 }
 
-/*
- * This does the actual work of updating an inodes time or version.  Must have
- * had called mnt_want_write() before calling this.
- */
-static int update_time(struct inode *inode, struct timespec *time, int flags)
+int generic_update_time(struct inode *inode, struct timespec *time, int flags)
 {
-       if (inode->i_op->update_time)
-               return inode->i_op->update_time(inode, time, flags);
+       int iflags = I_DIRTY_TIME;
 
        if (flags & S_ATIME)
                inode->i_atime = *time;
@@ -1512,9 +1518,27 @@ static int update_time(struct inode *inode, struct timespec *time, int flags)
                inode->i_ctime = *time;
        if (flags & S_MTIME)
                inode->i_mtime = *time;
-       mark_inode_dirty_sync(inode);
+
+       if (!(inode->i_sb->s_flags & MS_LAZYTIME) || (flags & S_VERSION))
+               iflags |= I_DIRTY_SYNC;
+       __mark_inode_dirty(inode, iflags);
        return 0;
 }
+EXPORT_SYMBOL(generic_update_time);
+
+/*
+ * This does the actual work of updating an inodes time or version.  Must have
+ * had called mnt_want_write() before calling this.
+ */
+static int update_time(struct inode *inode, struct timespec *time, int flags)
+{
+       int (*update_time)(struct inode *, struct timespec *, int);
+
+       update_time = inode->i_op->update_time ? inode->i_op->update_time :
+               generic_update_time;
+
+       return update_time(inode, time, flags);
+}
 
 /**
  *     touch_atime     -       update the access time