diff options
author | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:49:30 -0500 |
---|---|---|
committer | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:50:20 -0500 |
commit | 789680d1ee9311cdf095241dc02bd9784d799cd1 (patch) | |
tree | e6a984b0aa4791918f1b665f45210c2ab762969c /fs/dcache.c | |
parent | ec2447c278ee973d35f38e53ca16ba7f965ae33d (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.c | 73 |
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 | */ | ||
38 | int sysctl_vfs_cache_pressure __read_mostly = 100; | 51 | int sysctl_vfs_cache_pressure __read_mostly = 100; |
39 | EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); | 52 | EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); |
40 | 53 | ||
41 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock); | 54 | static __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 | ||
44 | EXPORT_SYMBOL(dcache_lock); | 58 | EXPORT_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 | */ | ||
228 | void __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 | } | ||
237 | EXPORT_SYMBOL(__d_drop); | ||
238 | |||
239 | void 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 | } | ||
247 | EXPORT_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 | */ |
1693 | static void d_move_locked(struct dentry * dentry, struct dentry * target) | 1747 | static 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); | |
1718 | already_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) | |||
1914 | found_lock: | 1963 | found_lock: |
1915 | spin_lock(&actual->d_lock); | 1964 | spin_lock(&actual->d_lock); |
1916 | found: | 1965 | found: |
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); |
1920 | out_nolock: | 1971 | out_nolock: |