aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2011-01-07 01:49:30 -0500
committerNick Piggin <npiggin@kernel.dk>2011-01-07 01:50:20 -0500
commit789680d1ee9311cdf095241dc02bd9784d799cd1 (patch)
treee6a984b0aa4791918f1b665f45210c2ab762969c /fs/dcache.c
parentec2447c278ee973d35f38e53ca16ba7f965ae33d (diff)
fs: dcache scale hash
Add a new lock, dcache_hash_lock, to protect the dcache hash table from concurrent modification. d_hash is also protected by d_lock. Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c73
1 files changed, 62 insertions, 11 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 61beb40dd6bf..1e124d4673c6 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -35,10 +35,24 @@
35#include <linux/hardirq.h> 35#include <linux/hardirq.h>
36#include "internal.h" 36#include "internal.h"
37 37
38/*
39 * Usage:
40 * dcache_hash_lock protects dcache hash table, s_anon lists
41 *
42 * Ordering:
43 * dcache_lock
44 * dentry->d_lock
45 * dcache_hash_lock
46 *
47 * if (dentry1 < dentry2)
48 * dentry1->d_lock
49 * dentry2->d_lock
50 */
38int sysctl_vfs_cache_pressure __read_mostly = 100; 51int sysctl_vfs_cache_pressure __read_mostly = 100;
39EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); 52EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
40 53
41 __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock); 54static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_hash_lock);
55__cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock);
42__cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); 56__cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
43 57
44EXPORT_SYMBOL(dcache_lock); 58EXPORT_SYMBOL(dcache_lock);
@@ -196,6 +210,42 @@ static struct dentry *d_kill(struct dentry *dentry)
196 return parent; 210 return parent;
197} 211}
198 212
213/**
214 * d_drop - drop a dentry
215 * @dentry: dentry to drop
216 *
217 * d_drop() unhashes the entry from the parent dentry hashes, so that it won't
218 * be found through a VFS lookup any more. Note that this is different from
219 * deleting the dentry - d_delete will try to mark the dentry negative if
220 * possible, giving a successful _negative_ lookup, while d_drop will
221 * just make the cache lookup fail.
222 *
223 * d_drop() is used mainly for stuff that wants to invalidate a dentry for some
224 * reason (NFS timeouts or autofs deletes).
225 *
226 * __d_drop requires dentry->d_lock.
227 */
228void __d_drop(struct dentry *dentry)
229{
230 if (!(dentry->d_flags & DCACHE_UNHASHED)) {
231 dentry->d_flags |= DCACHE_UNHASHED;
232 spin_lock(&dcache_hash_lock);
233 hlist_del_rcu(&dentry->d_hash);
234 spin_unlock(&dcache_hash_lock);
235 }
236}
237EXPORT_SYMBOL(__d_drop);
238
239void d_drop(struct dentry *dentry)
240{
241 spin_lock(&dcache_lock);
242 spin_lock(&dentry->d_lock);
243 __d_drop(dentry);
244 spin_unlock(&dentry->d_lock);
245 spin_unlock(&dcache_lock);
246}
247EXPORT_SYMBOL(d_drop);
248
199/* 249/*
200 * This is dput 250 * This is dput
201 * 251 *
@@ -1199,7 +1249,9 @@ struct dentry *d_obtain_alias(struct inode *inode)
1199 tmp->d_flags |= DCACHE_DISCONNECTED; 1249 tmp->d_flags |= DCACHE_DISCONNECTED;
1200 tmp->d_flags &= ~DCACHE_UNHASHED; 1250 tmp->d_flags &= ~DCACHE_UNHASHED;
1201 list_add(&tmp->d_alias, &inode->i_dentry); 1251 list_add(&tmp->d_alias, &inode->i_dentry);
1252 spin_lock(&dcache_hash_lock);
1202 hlist_add_head(&tmp->d_hash, &inode->i_sb->s_anon); 1253 hlist_add_head(&tmp->d_hash, &inode->i_sb->s_anon);
1254 spin_unlock(&dcache_hash_lock);
1203 spin_unlock(&tmp->d_lock); 1255 spin_unlock(&tmp->d_lock);
1204 1256
1205 spin_unlock(&dcache_lock); 1257 spin_unlock(&dcache_lock);
@@ -1585,7 +1637,9 @@ void d_rehash(struct dentry * entry)
1585{ 1637{
1586 spin_lock(&dcache_lock); 1638 spin_lock(&dcache_lock);
1587 spin_lock(&entry->d_lock); 1639 spin_lock(&entry->d_lock);
1640 spin_lock(&dcache_hash_lock);
1588 _d_rehash(entry); 1641 _d_rehash(entry);
1642 spin_unlock(&dcache_hash_lock);
1589 spin_unlock(&entry->d_lock); 1643 spin_unlock(&entry->d_lock);
1590 spin_unlock(&dcache_lock); 1644 spin_unlock(&dcache_lock);
1591} 1645}
@@ -1692,8 +1746,6 @@ static void switch_names(struct dentry *dentry, struct dentry *target)
1692 */ 1746 */
1693static void d_move_locked(struct dentry * dentry, struct dentry * target) 1747static void d_move_locked(struct dentry * dentry, struct dentry * target)
1694{ 1748{
1695 struct hlist_head *list;
1696
1697 if (!dentry->d_inode) 1749 if (!dentry->d_inode)
1698 printk(KERN_WARNING "VFS: moving negative dcache entry\n"); 1750 printk(KERN_WARNING "VFS: moving negative dcache entry\n");
1699 1751
@@ -1710,14 +1762,11 @@ static void d_move_locked(struct dentry * dentry, struct dentry * target)
1710 } 1762 }
1711 1763
1712 /* Move the dentry to the target hash queue, if on different bucket */ 1764 /* Move the dentry to the target hash queue, if on different bucket */
1713 if (d_unhashed(dentry)) 1765 spin_lock(&dcache_hash_lock);
1714 goto already_unhashed; 1766 if (!d_unhashed(dentry))
1715 1767 hlist_del_rcu(&dentry->d_hash);
1716 hlist_del_rcu(&dentry->d_hash); 1768 __d_rehash(dentry, d_hash(target->d_parent, target->d_name.hash));
1717 1769 spin_unlock(&dcache_hash_lock);
1718already_unhashed:
1719 list = d_hash(target->d_parent, target->d_name.hash);
1720 __d_rehash(dentry, list);
1721 1770
1722 /* Unhash the target: dput() will then get rid of it */ 1771 /* Unhash the target: dput() will then get rid of it */
1723 __d_drop(target); 1772 __d_drop(target);
@@ -1914,7 +1963,9 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
1914found_lock: 1963found_lock:
1915 spin_lock(&actual->d_lock); 1964 spin_lock(&actual->d_lock);
1916found: 1965found:
1966 spin_lock(&dcache_hash_lock);
1917 _d_rehash(actual); 1967 _d_rehash(actual);
1968 spin_unlock(&dcache_hash_lock);
1918 spin_unlock(&actual->d_lock); 1969 spin_unlock(&actual->d_lock);
1919 spin_unlock(&dcache_lock); 1970 spin_unlock(&dcache_lock);
1920out_nolock: 1971out_nolock: