i2c: add quirk checks to core
[cascardo/linux.git] / fs / inode.c
index 86bfaca..f00b16f 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
  *
@@ -403,7 +404,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);
 }
@@ -634,7 +636,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;
@@ -1268,6 +1270,56 @@ struct inode *ilookup(struct super_block *sb, unsigned long ino)
 }
 EXPORT_SYMBOL(ilookup);
 
+/**
+ * find_inode_nowait - find an inode in the inode cache
+ * @sb:                super block of file system to search
+ * @hashval:   hash value (usually inode number) to search for
+ * @match:     callback used for comparisons between inodes
+ * @data:      opaque data pointer to pass to @match
+ *
+ * Search for the inode specified by @hashval and @data in the inode
+ * cache, where the helper function @match will return 0 if the inode
+ * does not match, 1 if the inode does match, and -1 if the search
+ * should be stopped.  The @match function must be responsible for
+ * taking the i_lock spin_lock and checking i_state for an inode being
+ * freed or being initialized, and incrementing the reference count
+ * before returning 1.  It also must not sleep, since it is called with
+ * the inode_hash_lock spinlock held.
+ *
+ * This is a even more generalized version of ilookup5() when the
+ * function must never block --- find_inode() can block in
+ * __wait_on_freeing_inode() --- or when the caller can not increment
+ * the reference count because the resulting iput() might cause an
+ * inode eviction.  The tradeoff is that the @match funtion must be
+ * very carefully implemented.
+ */
+struct inode *find_inode_nowait(struct super_block *sb,
+                               unsigned long hashval,
+                               int (*match)(struct inode *, unsigned long,
+                                            void *),
+                               void *data)
+{
+       struct hlist_head *head = inode_hashtable + hash(sb, hashval);
+       struct inode *inode, *ret_inode = NULL;
+       int mval;
+
+       spin_lock(&inode_hash_lock);
+       hlist_for_each_entry(inode, head, i_hash) {
+               if (inode->i_sb != sb)
+                       continue;
+               mval = match(inode, hashval, data);
+               if (mval == 0)
+                       continue;
+               if (mval == 1)
+                       ret_inode = inode;
+               goto out;
+       }
+out:
+       spin_unlock(&inode_hash_lock);
+       return ret_inode;
+}
+EXPORT_SYMBOL(find_inode_nowait);
+
 int insert_inode_locked(struct inode *inode)
 {
        struct super_block *sb = inode->i_sb;
@@ -1418,11 +1470,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);
@@ -1481,14 +1542,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;
@@ -1498,9 +1554,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