Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[sfrench/cifs-2.6.git] / fs / inode.c
index 0013ac1af8e75d6178dbcf67a311ea3e4d326ff7..643ac43e5a5c7d6f43fe938fd4c0df6c91e2e0ce 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/hash.h>
 #include <linux/swap.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 #include <linux/pagemap.h>
 #include <linux/cdev.h>
 #include <linux/bootmem.h>
@@ -147,13 +148,13 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode)
        inode->i_cdev = NULL;
        inode->i_rdev = 0;
        inode->dirtied_when = 0;
-       if (security_inode_alloc(inode)) {
-               if (inode->i_sb->s_op->destroy_inode)
-                       inode->i_sb->s_op->destroy_inode(inode);
-               else
-                       kmem_cache_free(inode_cachep, (inode));
-               return NULL;
-       }
+
+       if (security_inode_alloc(inode))
+               goto out_free_inode;
+
+       /* allocate and initialize an i_integrity */
+       if (ima_inode_alloc(inode))
+               goto out_free_security;
 
        spin_lock_init(&inode->i_lock);
        lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
@@ -189,6 +190,15 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode)
        inode->i_mapping = mapping;
 
        return inode;
+
+out_free_security:
+       security_inode_free(inode);
+out_free_inode:
+       if (inode->i_sb->s_op->destroy_inode)
+               inode->i_sb->s_op->destroy_inode(inode);
+       else
+               kmem_cache_free(inode_cachep, (inode));
+       return NULL;
 }
 EXPORT_SYMBOL(inode_init_always);
 
@@ -359,6 +369,7 @@ static int invalidate_list(struct list_head *head, struct list_head *dispose)
                invalidate_inode_buffers(inode);
                if (!atomic_read(&inode->i_count)) {
                        list_move(&inode->i_list, dispose);
+                       WARN_ON(inode->i_state & I_NEW);
                        inode->i_state |= I_FREEING;
                        count++;
                        continue;
@@ -460,6 +471,7 @@ static void prune_icache(int nr_to_scan)
                                continue;
                }
                list_move(&inode->i_list, &freeable);
+               WARN_ON(inode->i_state & I_NEW);
                inode->i_state |= I_FREEING;
                nr_pruned++;
        }
@@ -656,6 +668,7 @@ void unlock_new_inode(struct inode *inode)
         * just created it (so there can be no old holders
         * that haven't tested I_LOCK).
         */
+       WARN_ON((inode->i_state & (I_LOCK|I_NEW)) != (I_LOCK|I_NEW));
        inode->i_state &= ~(I_LOCK|I_NEW);
        wake_up_inode(inode);
 }
@@ -1139,11 +1152,17 @@ EXPORT_SYMBOL(remove_inode_hash);
  * I_FREEING is set so that no-one will take a new reference to the inode while
  * it is being deleted.
  */
-static void generic_delete_inode_async(void *data, async_cookie_t cookie)
+void generic_delete_inode(struct inode *inode)
 {
-       struct inode *inode = data;
        const struct super_operations *op = inode->i_sb->s_op;
 
+       list_del_init(&inode->i_list);
+       list_del_init(&inode->i_sb_list);
+       WARN_ON(inode->i_state & I_NEW);
+       inode->i_state |= I_FREEING;
+       inodes_stat.nr_inodes--;
+       spin_unlock(&inode_lock);
+
        security_inode_delete(inode);
 
        if (op->delete_inode) {
@@ -1167,16 +1186,6 @@ static void generic_delete_inode_async(void *data, async_cookie_t cookie)
        destroy_inode(inode);
 }
 
-void generic_delete_inode(struct inode *inode)
-{
-       list_del_init(&inode->i_list);
-       list_del_init(&inode->i_sb_list);
-       inode->i_state |= I_FREEING;
-       inodes_stat.nr_inodes--;
-       spin_unlock(&inode_lock);
-       async_schedule_special(generic_delete_inode_async, inode, &inode->i_sb->s_async_list);
-}
-
 EXPORT_SYMBOL(generic_delete_inode);
 
 static void generic_forget_inode(struct inode *inode)
@@ -1191,16 +1200,19 @@ static void generic_forget_inode(struct inode *inode)
                        spin_unlock(&inode_lock);
                        return;
                }
+               WARN_ON(inode->i_state & I_NEW);
                inode->i_state |= I_WILL_FREE;
                spin_unlock(&inode_lock);
                write_inode_now(inode, 1);
                spin_lock(&inode_lock);
+               WARN_ON(inode->i_state & I_NEW);
                inode->i_state &= ~I_WILL_FREE;
                inodes_stat.nr_unused--;
                hlist_del_init(&inode->i_hash);
        }
        list_del_init(&inode->i_list);
        list_del_init(&inode->i_sb_list);
+       WARN_ON(inode->i_state & I_NEW);
        inode->i_state |= I_FREEING;
        inodes_stat.nr_inodes--;
        spin_unlock(&inode_lock);
@@ -1288,6 +1300,40 @@ sector_t bmap(struct inode * inode, sector_t block)
 }
 EXPORT_SYMBOL(bmap);
 
+/*
+ * With relative atime, only update atime if the previous atime is
+ * earlier than either the ctime or mtime or if at least a day has
+ * passed since the last atime update.
+ */
+static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
+                            struct timespec now)
+{
+
+       if (!(mnt->mnt_flags & MNT_RELATIME))
+               return 1;
+       /*
+        * Is mtime younger than atime? If yes, update atime:
+        */
+       if (timespec_compare(&inode->i_mtime, &inode->i_atime) >= 0)
+               return 1;
+       /*
+        * Is ctime younger than atime? If yes, update atime:
+        */
+       if (timespec_compare(&inode->i_ctime, &inode->i_atime) >= 0)
+               return 1;
+
+       /*
+        * Is the previous atime value older than a day? If yes,
+        * update atime:
+        */
+       if ((long)(now.tv_sec - inode->i_atime.tv_sec) >= 24*60*60)
+               return 1;
+       /*
+        * Good, we can skip the atime update:
+        */
+       return 0;
+}
+
 /**
  *     touch_atime     -       update the access time
  *     @mnt: mount the inode is accessed on
@@ -1315,17 +1361,12 @@ void touch_atime(struct vfsmount *mnt, struct dentry *dentry)
                goto out;
        if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
                goto out;
-       if (mnt->mnt_flags & MNT_RELATIME) {
-               /*
-                * With relative atime, only update atime if the previous
-                * atime is earlier than either the ctime or mtime.
-                */
-               if (timespec_compare(&inode->i_mtime, &inode->i_atime) < 0 &&
-                   timespec_compare(&inode->i_ctime, &inode->i_atime) < 0)
-                       goto out;
-       }
 
        now = current_fs_time(inode->i_sb);
+
+       if (!relatime_need_update(mnt, inode, now))
+               goto out;
+
        if (timespec_equal(&inode->i_atime, &now))
                goto out;