smb311: Add support for lookup with posix extensions query info
[linux-2.6-microblaze.git] / fs / inode.c
index 37226a9..72c4c34 100644 (file)
@@ -108,7 +108,7 @@ long get_nr_dirty_inodes(void)
  */
 #ifdef CONFIG_SYSCTL
 int proc_nr_inodes(struct ctl_table *table, int write,
-                  void __user *buffer, size_t *lenp, loff_t *ppos)
+                  void *buffer, size_t *lenp, loff_t *ppos)
 {
        inodes_stat.nr_inodes = get_nr_inodes();
        inodes_stat.nr_unused = get_nr_inodes_unused();
@@ -497,7 +497,7 @@ void __insert_inode_hash(struct inode *inode, unsigned long hashval)
 
        spin_lock(&inode_hash_lock);
        spin_lock(&inode->i_lock);
-       hlist_add_head(&inode->i_hash, b);
+       hlist_add_head_rcu(&inode->i_hash, b);
        spin_unlock(&inode->i_lock);
        spin_unlock(&inode_hash_lock);
 }
@@ -513,7 +513,7 @@ void __remove_inode_hash(struct inode *inode)
 {
        spin_lock(&inode_hash_lock);
        spin_lock(&inode->i_lock);
-       hlist_del_init(&inode->i_hash);
+       hlist_del_init_rcu(&inode->i_hash);
        spin_unlock(&inode->i_lock);
        spin_unlock(&inode_hash_lock);
 }
@@ -1107,7 +1107,7 @@ again:
         */
        spin_lock(&inode->i_lock);
        inode->i_state |= I_NEW;
-       hlist_add_head(&inode->i_hash, head);
+       hlist_add_head_rcu(&inode->i_hash, head);
        spin_unlock(&inode->i_lock);
        if (!creating)
                inode_sb_list_add(inode);
@@ -1201,7 +1201,7 @@ again:
                        inode->i_ino = ino;
                        spin_lock(&inode->i_lock);
                        inode->i_state = I_NEW;
-                       hlist_add_head(&inode->i_hash, head);
+                       hlist_add_head_rcu(&inode->i_hash, head);
                        spin_unlock(&inode->i_lock);
                        inode_sb_list_add(inode);
                        spin_unlock(&inode_hash_lock);
@@ -1244,15 +1244,10 @@ static int test_inode_iunique(struct super_block *sb, unsigned long ino)
        struct hlist_head *b = inode_hashtable + hash(sb, ino);
        struct inode *inode;
 
-       spin_lock(&inode_hash_lock);
-       hlist_for_each_entry(inode, b, i_hash) {
-               if (inode->i_ino == ino && inode->i_sb == sb) {
-                       spin_unlock(&inode_hash_lock);
+       hlist_for_each_entry_rcu(inode, b, i_hash) {
+               if (inode->i_ino == ino && inode->i_sb == sb)
                        return 0;
-               }
        }
-       spin_unlock(&inode_hash_lock);
-
        return 1;
 }
 
@@ -1281,6 +1276,7 @@ ino_t iunique(struct super_block *sb, ino_t max_reserved)
        static unsigned int counter;
        ino_t res;
 
+       rcu_read_lock();
        spin_lock(&iunique_lock);
        do {
                if (counter <= max_reserved)
@@ -1288,6 +1284,7 @@ ino_t iunique(struct super_block *sb, ino_t max_reserved)
                res = counter++;
        } while (!test_inode_iunique(sb, res));
        spin_unlock(&iunique_lock);
+       rcu_read_unlock();
 
        return res;
 }
@@ -1456,6 +1453,84 @@ out:
 }
 EXPORT_SYMBOL(find_inode_nowait);
 
+/**
+ * find_inode_rcu - find an inode in the inode cache
+ * @sb:                Super block of file system to search
+ * @hashval:   Key to hash
+ * @test:      Function to test match on an inode
+ * @data:      Data for test function
+ *
+ * Search for the inode specified by @hashval and @data in the inode cache,
+ * where the helper function @test will return 0 if the inode does not match
+ * and 1 if it does.  The @test function must be responsible for taking the
+ * i_lock spin_lock and checking i_state for an inode being freed or being
+ * initialized.
+ *
+ * If successful, this will return the inode for which the @test function
+ * returned 1 and NULL otherwise.
+ *
+ * The @test function is not permitted to take a ref on any inode presented.
+ * It is also not permitted to sleep.
+ *
+ * The caller must hold the RCU read lock.
+ */
+struct inode *find_inode_rcu(struct super_block *sb, unsigned long hashval,
+                            int (*test)(struct inode *, void *), void *data)
+{
+       struct hlist_head *head = inode_hashtable + hash(sb, hashval);
+       struct inode *inode;
+
+       RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
+                        "suspicious find_inode_rcu() usage");
+
+       hlist_for_each_entry_rcu(inode, head, i_hash) {
+               if (inode->i_sb == sb &&
+                   !(READ_ONCE(inode->i_state) & (I_FREEING | I_WILL_FREE)) &&
+                   test(inode, data))
+                       return inode;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(find_inode_rcu);
+
+/**
+ * find_inode_by_rcu - Find an inode in the inode cache
+ * @sb:                Super block of file system to search
+ * @ino:       The inode number to match
+ *
+ * Search for the inode specified by @hashval and @data in the inode cache,
+ * where the helper function @test will return 0 if the inode does not match
+ * and 1 if it does.  The @test function must be responsible for taking the
+ * i_lock spin_lock and checking i_state for an inode being freed or being
+ * initialized.
+ *
+ * If successful, this will return the inode for which the @test function
+ * returned 1 and NULL otherwise.
+ *
+ * The @test function is not permitted to take a ref on any inode presented.
+ * It is also not permitted to sleep.
+ *
+ * The caller must hold the RCU read lock.
+ */
+struct inode *find_inode_by_ino_rcu(struct super_block *sb,
+                                   unsigned long ino)
+{
+       struct hlist_head *head = inode_hashtable + hash(sb, ino);
+       struct inode *inode;
+
+       RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
+                        "suspicious find_inode_by_ino_rcu() usage");
+
+       hlist_for_each_entry_rcu(inode, head, i_hash) {
+               if (inode->i_ino == ino &&
+                   inode->i_sb == sb &&
+                   !(READ_ONCE(inode->i_state) & (I_FREEING | I_WILL_FREE)))
+                   return inode;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(find_inode_by_ino_rcu);
+
 int insert_inode_locked(struct inode *inode)
 {
        struct super_block *sb = inode->i_sb;
@@ -1480,7 +1555,7 @@ int insert_inode_locked(struct inode *inode)
                if (likely(!old)) {
                        spin_lock(&inode->i_lock);
                        inode->i_state |= I_NEW | I_CREATING;
-                       hlist_add_head(&inode->i_hash, head);
+                       hlist_add_head_rcu(&inode->i_hash, head);
                        spin_unlock(&inode->i_lock);
                        spin_unlock(&inode_hash_lock);
                        return 0;
@@ -1540,6 +1615,7 @@ static void iput_final(struct inode *inode)
 {
        struct super_block *sb = inode->i_sb;
        const struct super_operations *op = inode->i_sb->s_op;
+       unsigned long state;
        int drop;
 
        WARN_ON(inode->i_state & I_NEW);
@@ -1555,16 +1631,20 @@ static void iput_final(struct inode *inode)
                return;
        }
 
+       state = inode->i_state;
        if (!drop) {
-               inode->i_state |= I_WILL_FREE;
+               WRITE_ONCE(inode->i_state, state | I_WILL_FREE);
                spin_unlock(&inode->i_lock);
+
                write_inode_now(inode, 1);
+
                spin_lock(&inode->i_lock);
-               WARN_ON(inode->i_state & I_NEW);
-               inode->i_state &= ~I_WILL_FREE;
+               state = inode->i_state;
+               WARN_ON(state & I_NEW);
+               state &= ~I_WILL_FREE;
        }
 
-       inode->i_state |= I_FREEING;
+       WRITE_ONCE(inode->i_state, state | I_FREEING);
        if (!list_empty(&inode->i_lru))
                inode_lru_list_del(inode);
        spin_unlock(&inode->i_lock);