summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/inode.c31
1 files changed, 25 insertions, 6 deletions
diff --git a/fs/inode.c b/fs/inode.c
index 0571983755dc..a4876e561953 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1053,13 +1053,22 @@ int insert_inode_locked(struct inode *inode)
struct super_block *sb = inode->i_sb;
ino_t ino = inode->i_ino;
struct hlist_head *head = inode_hashtable + hash(sb, ino);
- struct inode *old;
inode->i_state |= I_LOCK|I_NEW;
while (1) {
+ struct hlist_node *node;
+ struct inode *old = NULL;
spin_lock(&inode_lock);
- old = find_inode_fast(sb, head, ino);
- if (likely(!old)) {
+ hlist_for_each_entry(old, node, head, i_hash) {
+ if (old->i_ino != ino)
+ continue;
+ if (old->i_sb != sb)
+ continue;
+ if (old->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE))
+ continue;
+ break;
+ }
+ if (likely(!node)) {
hlist_add_head(&inode->i_hash, head);
spin_unlock(&inode_lock);
return 0;
@@ -1081,14 +1090,24 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,
{
struct super_block *sb = inode->i_sb;
struct hlist_head *head = inode_hashtable + hash(sb, hashval);
- struct inode *old;
inode->i_state |= I_LOCK|I_NEW;
while (1) {
+ struct hlist_node *node;
+ struct inode *old = NULL;
+
spin_lock(&inode_lock);
- old = find_inode(sb, head, test, data);
- if (likely(!old)) {
+ hlist_for_each_entry(old, node, head, i_hash) {
+ if (old->i_sb != sb)
+ continue;
+ if (!test(old, data))
+ continue;
+ if (old->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE))
+ continue;
+ break;
+ }
+ if (likely(!node)) {
hlist_add_head(&inode->i_hash, head);
spin_unlock(&inode_lock);
return 0;