diff options
author | Nick Piggin <npiggin@suse.de> | 2010-01-29 15:38:27 -0800 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2010-04-27 17:32:41 +0200 |
commit | 97e747df2591f082b4a3964ac5ff784f0ff181f1 (patch) | |
tree | 181171e33be62bc4a402f8333a26009656a13a13 | |
parent | bea12790ba6dbab68571e58cd3e74585888850ee (diff) | |
download | lwn-97e747df2591f082b4a3964ac5ff784f0ff181f1.tar.gz lwn-97e747df2591f082b4a3964ac5ff784f0ff181f1.zip |
fs-inode_lock-scale-2
Add a new lock, inode_hash_lock, to protect the inode hash table lists.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: John Stultz <johnstul@us.ibm.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | fs/inode.c | 29 | ||||
-rw-r--r-- | include/linux/writeback.h | 1 |
2 files changed, 29 insertions, 1 deletions
diff --git a/fs/inode.c b/fs/inode.c index 2f42696e14ab..d6ad2ab68e93 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -86,6 +86,7 @@ static struct hlist_head *inode_hashtable __read_mostly; */ DEFINE_SPINLOCK(inode_lock); DEFINE_SPINLOCK(sb_inode_list_lock); +DEFINE_SPINLOCK(inode_hash_lock); /* * iprune_sem provides exclusion between the kswapd or try_to_free_pages @@ -348,7 +349,9 @@ static void dispose_list(struct list_head *head) clear_inode(inode); spin_lock(&inode_lock); + spin_lock(&inode_hash_lock); hlist_del_init(&inode->i_hash); + spin_unlock(&inode_hash_lock); spin_lock(&sb_inode_list_lock); list_del_init(&inode->i_sb_list); spin_unlock(&sb_inode_list_lock); @@ -558,17 +561,20 @@ static struct inode *find_inode(struct super_block *sb, struct inode *inode = NULL; repeat: + spin_lock(&inode_hash_lock); hlist_for_each_entry(inode, node, head, i_hash) { if (inode->i_sb != sb) continue; if (!test(inode, data)) continue; if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) { + spin_unlock(&inode_hash_lock); __wait_on_freeing_inode(inode); goto repeat; } break; } + spin_unlock(&inode_hash_lock); return node ? inode : NULL; } @@ -583,17 +589,20 @@ static struct inode *find_inode_fast(struct super_block *sb, struct inode *inode = NULL; repeat: + spin_lock(&inode_hash_lock); hlist_for_each_entry(inode, node, head, i_hash) { if (inode->i_ino != ino) continue; if (inode->i_sb != sb) continue; if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) { + spin_unlock(&inode_hash_lock); __wait_on_freeing_inode(inode); goto repeat; } break; } + spin_unlock(&inode_hash_lock); return node ? inode : NULL; } @@ -616,8 +625,11 @@ __inode_add_to_lists(struct super_block *sb, struct hlist_head *head, spin_lock(&sb_inode_list_lock); list_add(&inode->i_sb_list, &sb->s_inodes); spin_unlock(&sb_inode_list_lock); - if (head) + if (head) { + spin_lock(&inode_hash_lock); hlist_add_head(&inode->i_hash, head); + spin_unlock(&inode_hash_lock); + } } /** @@ -1095,7 +1107,9 @@ int insert_inode_locked(struct inode *inode) while (1) { struct hlist_node *node; struct inode *old = NULL; + spin_lock(&inode_lock); + spin_lock(&inode_hash_lock); hlist_for_each_entry(old, node, head, i_hash) { if (old->i_ino != ino) continue; @@ -1107,9 +1121,11 @@ int insert_inode_locked(struct inode *inode) } if (likely(!node)) { hlist_add_head(&inode->i_hash, head); + spin_unlock(&inode_hash_lock); spin_unlock(&inode_lock); return 0; } + spin_unlock(&inode_hash_lock); __iget(old); spin_unlock(&inode_lock); wait_on_inode(old); @@ -1135,6 +1151,7 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval, struct inode *old = NULL; spin_lock(&inode_lock); + spin_lock(&inode_hash_lock); hlist_for_each_entry(old, node, head, i_hash) { if (old->i_sb != sb) continue; @@ -1146,9 +1163,11 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval, } if (likely(!node)) { hlist_add_head(&inode->i_hash, head); + spin_unlock(&inode_hash_lock); spin_unlock(&inode_lock); return 0; } + spin_unlock(&inode_hash_lock); __iget(old); spin_unlock(&inode_lock); wait_on_inode(old); @@ -1173,7 +1192,9 @@ void __insert_inode_hash(struct inode *inode, unsigned long hashval) { struct hlist_head *head = inode_hashtable + hash(inode->i_sb, hashval); spin_lock(&inode_lock); + spin_lock(&inode_hash_lock); hlist_add_head(&inode->i_hash, head); + spin_unlock(&inode_hash_lock); spin_unlock(&inode_lock); } EXPORT_SYMBOL(__insert_inode_hash); @@ -1187,7 +1208,9 @@ EXPORT_SYMBOL(__insert_inode_hash); void remove_inode_hash(struct inode *inode) { spin_lock(&inode_lock); + spin_lock(&inode_hash_lock); hlist_del_init(&inode->i_hash); + spin_unlock(&inode_hash_lock); spin_unlock(&inode_lock); } EXPORT_SYMBOL(remove_inode_hash); @@ -1233,7 +1256,9 @@ void generic_delete_inode(struct inode *inode) clear_inode(inode); } spin_lock(&inode_lock); + spin_lock(&inode_hash_lock); hlist_del_init(&inode->i_hash); + spin_unlock(&inode_hash_lock); spin_unlock(&inode_lock); wake_up_inode(inode); BUG_ON(inode->i_state != I_CLEAR); @@ -1270,7 +1295,9 @@ int generic_detach_inode(struct inode *inode) WARN_ON(inode->i_state & I_NEW); inode->i_state &= ~I_WILL_FREE; inodes_stat.nr_unused--; + spin_lock(&inode_hash_lock); hlist_del_init(&inode->i_hash); + spin_unlock(&inode_hash_lock); } list_del_init(&inode->i_list); spin_lock(&sb_inode_list_lock); diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 544363be9933..5b9178fbb261 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -11,6 +11,7 @@ struct backing_dev_info; extern spinlock_t inode_lock; extern spinlock_t sb_inode_list_lock; +extern spinlock_t inode_hash_lock; extern struct list_head inode_in_use; extern struct list_head inode_unused; |