Input: elantech - reset touchpad before configuring it
[pandora-kernel.git] / fs / inode.c
index ee4e66b..d3ebdbe 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/ima.h>
 #include <linux/cred.h>
 #include <linux/buffer_head.h> /* for inode_has_buffers */
+#include <linux/ratelimit.h>
 #include "internal.h"
 
 /*
@@ -191,6 +192,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
        }
        inode->i_private = NULL;
        inode->i_mapping = mapping;
+       INIT_LIST_HEAD(&inode->i_dentry);       /* buggered by rcu freeing */
 #ifdef CONFIG_FS_POSIX_ACL
        inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED;
 #endif
@@ -241,6 +243,11 @@ void __destroy_inode(struct inode *inode)
        BUG_ON(inode_has_buffers(inode));
        security_inode_free(inode);
        fsnotify_inode_delete(inode);
+       if (!inode->i_nlink) {
+               WARN_ON(atomic_long_read(&inode->i_sb->s_remove_count) == 0);
+               atomic_long_dec(&inode->i_sb->s_remove_count);
+       }
+
 #ifdef CONFIG_FS_POSIX_ACL
        if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED)
                posix_acl_release(inode->i_acl);
@@ -254,7 +261,6 @@ EXPORT_SYMBOL(__destroy_inode);
 static void i_callback(struct rcu_head *head)
 {
        struct inode *inode = container_of(head, struct inode, i_rcu);
-       INIT_LIST_HEAD(&inode->i_dentry);
        kmem_cache_free(inode_cachep, inode);
 }
 
@@ -268,6 +274,82 @@ static void destroy_inode(struct inode *inode)
                call_rcu(&inode->i_rcu, i_callback);
 }
 
+/**
+ * drop_nlink - directly drop an inode's link count
+ * @inode: inode
+ *
+ * This is a low-level filesystem helper to replace any
+ * direct filesystem manipulation of i_nlink.  In cases
+ * where we are attempting to track writes to the
+ * filesystem, a decrement to zero means an imminent
+ * write when the file is truncated and actually unlinked
+ * on the filesystem.
+ */
+void drop_nlink(struct inode *inode)
+{
+       WARN_ON(inode->i_nlink == 0);
+       inode->__i_nlink--;
+       if (!inode->i_nlink)
+               atomic_long_inc(&inode->i_sb->s_remove_count);
+}
+EXPORT_SYMBOL(drop_nlink);
+
+/**
+ * clear_nlink - directly zero an inode's link count
+ * @inode: inode
+ *
+ * This is a low-level filesystem helper to replace any
+ * direct filesystem manipulation of i_nlink.  See
+ * drop_nlink() for why we care about i_nlink hitting zero.
+ */
+void clear_nlink(struct inode *inode)
+{
+       if (inode->i_nlink) {
+               inode->__i_nlink = 0;
+               atomic_long_inc(&inode->i_sb->s_remove_count);
+       }
+}
+EXPORT_SYMBOL(clear_nlink);
+
+/**
+ * set_nlink - directly set an inode's link count
+ * @inode: inode
+ * @nlink: new nlink (should be non-zero)
+ *
+ * This is a low-level filesystem helper to replace any
+ * direct filesystem manipulation of i_nlink.
+ */
+void set_nlink(struct inode *inode, unsigned int nlink)
+{
+       if (!nlink) {
+               clear_nlink(inode);
+       } else {
+               /* Yes, some filesystems do change nlink from zero to one */
+               if (inode->i_nlink == 0)
+                       atomic_long_dec(&inode->i_sb->s_remove_count);
+
+               inode->__i_nlink = nlink;
+       }
+}
+EXPORT_SYMBOL(set_nlink);
+
+/**
+ * inc_nlink - directly increment an inode's link count
+ * @inode: inode
+ *
+ * This is a low-level filesystem helper to replace any
+ * direct filesystem manipulation of i_nlink.  Currently,
+ * it is only here for parity with dec_nlink().
+ */
+void inc_nlink(struct inode *inode)
+{
+       if (WARN_ON(inode->i_nlink == 0))
+               atomic_long_dec(&inode->i_sb->s_remove_count);
+
+       inode->__i_nlink++;
+}
+EXPORT_SYMBOL(inc_nlink);
+
 void address_space_init_once(struct address_space *mapping)
 {
        memset(mapping, 0, sizeof(*mapping));
@@ -290,7 +372,6 @@ void inode_init_once(struct inode *inode)
 {
        memset(inode, 0, sizeof(*inode));
        INIT_HLIST_NODE(&inode->i_hash);
-       INIT_LIST_HEAD(&inode->i_dentry);
        INIT_LIST_HEAD(&inode->i_devices);
        INIT_LIST_HEAD(&inode->i_wb_list);
        INIT_LIST_HEAD(&inode->i_lru);
@@ -692,6 +773,8 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan)
        else
                __count_vm_events(PGINODESTEAL, reap);
        spin_unlock(&sb->s_inode_lru_lock);
+       if (current->reclaim_state)
+               current->reclaim_state->reclaimed_slab += reap;
 
        dispose_list(&freeable);
 }
@@ -1508,7 +1591,7 @@ void file_update_time(struct file *file)
        if (sync_it & S_MTIME)
                inode->i_mtime = now;
        mark_inode_dirty_sync(inode);
-       mnt_drop_write(file->f_path.mnt);
+       mnt_drop_write_file(file);
 }
 EXPORT_SYMBOL(file_update_time);
 
@@ -1568,7 +1651,7 @@ __setup("ihash_entries=", set_ihash_entries);
  */
 void __init inode_init_early(void)
 {
-       int loop;
+       unsigned int loop;
 
        /* If hashes are distributed across NUMA nodes, defer
         * hash allocation until vmalloc space is available.
@@ -1586,13 +1669,13 @@ void __init inode_init_early(void)
                                        &i_hash_mask,
                                        0);
 
-       for (loop = 0; loop < (1 << i_hash_shift); loop++)
+       for (loop = 0; loop < (1U << i_hash_shift); loop++)
                INIT_HLIST_HEAD(&inode_hashtable[loop]);
 }
 
 void __init inode_init(void)
 {
-       int loop;
+       unsigned int loop;
 
        /* inode slab cache */
        inode_cachep = kmem_cache_create("inode_cache",
@@ -1616,7 +1699,7 @@ void __init inode_init(void)
                                        &i_hash_mask,
                                        0);
 
-       for (loop = 0; loop < (1 << i_hash_shift); loop++)
+       for (loop = 0; loop < (1U << i_hash_shift); loop++)
                INIT_HLIST_HEAD(&inode_hashtable[loop]);
 }
 
@@ -1647,7 +1730,7 @@ EXPORT_SYMBOL(init_special_inode);
  * @mode: mode of the new inode
  */
 void inode_init_owner(struct inode *inode, const struct inode *dir,
-                       mode_t mode)
+                       umode_t mode)
 {
        inode->i_uid = current_fsuid();
        if (dir && dir->i_mode & S_ISGID) {