diff options
author | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:50:06 -0500 |
---|---|---|
committer | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:50:31 -0500 |
commit | 873feea09ebc980cbd3631b767356ce1eee65ec1 (patch) | |
tree | 59a8fce9b138086abee7cf845f62ff70a390cf81 /fs/dcache.c | |
parent | ceb5bdc2d246f6d81cf61ed70f325308a11821d2 (diff) |
fs: dcache per-inode inode alias locking
dcache_inode_lock can be replaced with per-inode locking. Use existing
inode->i_lock for this. This is slightly non-trivial because we sometimes
need to find the inode from the dentry, which requires d_inode to be
stabilised (either with refcount or d_lock).
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 88 |
1 files changed, 47 insertions, 41 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 9f04e1ba75b7..09ec945f3c98 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -39,8 +39,8 @@ | |||
39 | 39 | ||
40 | /* | 40 | /* |
41 | * Usage: | 41 | * Usage: |
42 | * dcache_inode_lock protects: | 42 | * dcache->d_inode->i_lock protects: |
43 | * - i_dentry, d_alias, d_inode | 43 | * - i_dentry, d_alias, d_inode of aliases |
44 | * dcache_hash_bucket lock protects: | 44 | * dcache_hash_bucket lock protects: |
45 | * - the dcache hash table | 45 | * - the dcache hash table |
46 | * s_anon bl list spinlock protects: | 46 | * s_anon bl list spinlock protects: |
@@ -58,7 +58,7 @@ | |||
58 | * - d_alias, d_inode | 58 | * - d_alias, d_inode |
59 | * | 59 | * |
60 | * Ordering: | 60 | * Ordering: |
61 | * dcache_inode_lock | 61 | * dentry->d_inode->i_lock |
62 | * dentry->d_lock | 62 | * dentry->d_lock |
63 | * dcache_lru_lock | 63 | * dcache_lru_lock |
64 | * dcache_hash_bucket lock | 64 | * dcache_hash_bucket lock |
@@ -78,12 +78,10 @@ | |||
78 | int sysctl_vfs_cache_pressure __read_mostly = 100; | 78 | int sysctl_vfs_cache_pressure __read_mostly = 100; |
79 | EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); | 79 | EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); |
80 | 80 | ||
81 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_inode_lock); | ||
82 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lru_lock); | 81 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lru_lock); |
83 | __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); | 82 | __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); |
84 | 83 | ||
85 | EXPORT_SYMBOL(rename_lock); | 84 | EXPORT_SYMBOL(rename_lock); |
86 | EXPORT_SYMBOL(dcache_inode_lock); | ||
87 | 85 | ||
88 | static struct kmem_cache *dentry_cache __read_mostly; | 86 | static struct kmem_cache *dentry_cache __read_mostly; |
89 | 87 | ||
@@ -196,14 +194,14 @@ static inline void dentry_rcuwalk_barrier(struct dentry *dentry) | |||
196 | */ | 194 | */ |
197 | static void dentry_iput(struct dentry * dentry) | 195 | static void dentry_iput(struct dentry * dentry) |
198 | __releases(dentry->d_lock) | 196 | __releases(dentry->d_lock) |
199 | __releases(dcache_inode_lock) | 197 | __releases(dentry->d_inode->i_lock) |
200 | { | 198 | { |
201 | struct inode *inode = dentry->d_inode; | 199 | struct inode *inode = dentry->d_inode; |
202 | if (inode) { | 200 | if (inode) { |
203 | dentry->d_inode = NULL; | 201 | dentry->d_inode = NULL; |
204 | list_del_init(&dentry->d_alias); | 202 | list_del_init(&dentry->d_alias); |
205 | spin_unlock(&dentry->d_lock); | 203 | spin_unlock(&dentry->d_lock); |
206 | spin_unlock(&dcache_inode_lock); | 204 | spin_unlock(&inode->i_lock); |
207 | if (!inode->i_nlink) | 205 | if (!inode->i_nlink) |
208 | fsnotify_inoderemove(inode); | 206 | fsnotify_inoderemove(inode); |
209 | if (dentry->d_op && dentry->d_op->d_iput) | 207 | if (dentry->d_op && dentry->d_op->d_iput) |
@@ -212,7 +210,6 @@ static void dentry_iput(struct dentry * dentry) | |||
212 | iput(inode); | 210 | iput(inode); |
213 | } else { | 211 | } else { |
214 | spin_unlock(&dentry->d_lock); | 212 | spin_unlock(&dentry->d_lock); |
215 | spin_unlock(&dcache_inode_lock); | ||
216 | } | 213 | } |
217 | } | 214 | } |
218 | 215 | ||
@@ -222,14 +219,14 @@ static void dentry_iput(struct dentry * dentry) | |||
222 | */ | 219 | */ |
223 | static void dentry_unlink_inode(struct dentry * dentry) | 220 | static void dentry_unlink_inode(struct dentry * dentry) |
224 | __releases(dentry->d_lock) | 221 | __releases(dentry->d_lock) |
225 | __releases(dcache_inode_lock) | 222 | __releases(dentry->d_inode->i_lock) |
226 | { | 223 | { |
227 | struct inode *inode = dentry->d_inode; | 224 | struct inode *inode = dentry->d_inode; |
228 | dentry->d_inode = NULL; | 225 | dentry->d_inode = NULL; |
229 | list_del_init(&dentry->d_alias); | 226 | list_del_init(&dentry->d_alias); |
230 | dentry_rcuwalk_barrier(dentry); | 227 | dentry_rcuwalk_barrier(dentry); |
231 | spin_unlock(&dentry->d_lock); | 228 | spin_unlock(&dentry->d_lock); |
232 | spin_unlock(&dcache_inode_lock); | 229 | spin_unlock(&inode->i_lock); |
233 | if (!inode->i_nlink) | 230 | if (!inode->i_nlink) |
234 | fsnotify_inoderemove(inode); | 231 | fsnotify_inoderemove(inode); |
235 | if (dentry->d_op && dentry->d_op->d_iput) | 232 | if (dentry->d_op && dentry->d_op->d_iput) |
@@ -295,7 +292,7 @@ static void dentry_lru_move_tail(struct dentry *dentry) | |||
295 | static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) | 292 | static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) |
296 | __releases(dentry->d_lock) | 293 | __releases(dentry->d_lock) |
297 | __releases(parent->d_lock) | 294 | __releases(parent->d_lock) |
298 | __releases(dcache_inode_lock) | 295 | __releases(dentry->d_inode->i_lock) |
299 | { | 296 | { |
300 | dentry->d_parent = NULL; | 297 | dentry->d_parent = NULL; |
301 | list_del(&dentry->d_u.d_child); | 298 | list_del(&dentry->d_u.d_child); |
@@ -370,9 +367,11 @@ EXPORT_SYMBOL(d_drop); | |||
370 | static inline struct dentry *dentry_kill(struct dentry *dentry, int ref) | 367 | static inline struct dentry *dentry_kill(struct dentry *dentry, int ref) |
371 | __releases(dentry->d_lock) | 368 | __releases(dentry->d_lock) |
372 | { | 369 | { |
370 | struct inode *inode; | ||
373 | struct dentry *parent; | 371 | struct dentry *parent; |
374 | 372 | ||
375 | if (!spin_trylock(&dcache_inode_lock)) { | 373 | inode = dentry->d_inode; |
374 | if (inode && !spin_trylock(&inode->i_lock)) { | ||
376 | relock: | 375 | relock: |
377 | spin_unlock(&dentry->d_lock); | 376 | spin_unlock(&dentry->d_lock); |
378 | cpu_relax(); | 377 | cpu_relax(); |
@@ -383,7 +382,8 @@ relock: | |||
383 | else | 382 | else |
384 | parent = dentry->d_parent; | 383 | parent = dentry->d_parent; |
385 | if (parent && !spin_trylock(&parent->d_lock)) { | 384 | if (parent && !spin_trylock(&parent->d_lock)) { |
386 | spin_unlock(&dcache_inode_lock); | 385 | if (inode) |
386 | spin_unlock(&inode->i_lock); | ||
387 | goto relock; | 387 | goto relock; |
388 | } | 388 | } |
389 | 389 | ||
@@ -618,9 +618,9 @@ struct dentry *d_find_alias(struct inode *inode) | |||
618 | struct dentry *de = NULL; | 618 | struct dentry *de = NULL; |
619 | 619 | ||
620 | if (!list_empty(&inode->i_dentry)) { | 620 | if (!list_empty(&inode->i_dentry)) { |
621 | spin_lock(&dcache_inode_lock); | 621 | spin_lock(&inode->i_lock); |
622 | de = __d_find_alias(inode, 0); | 622 | de = __d_find_alias(inode, 0); |
623 | spin_unlock(&dcache_inode_lock); | 623 | spin_unlock(&inode->i_lock); |
624 | } | 624 | } |
625 | return de; | 625 | return de; |
626 | } | 626 | } |
@@ -634,20 +634,20 @@ void d_prune_aliases(struct inode *inode) | |||
634 | { | 634 | { |
635 | struct dentry *dentry; | 635 | struct dentry *dentry; |
636 | restart: | 636 | restart: |
637 | spin_lock(&dcache_inode_lock); | 637 | spin_lock(&inode->i_lock); |
638 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | 638 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { |
639 | spin_lock(&dentry->d_lock); | 639 | spin_lock(&dentry->d_lock); |
640 | if (!dentry->d_count) { | 640 | if (!dentry->d_count) { |
641 | __dget_dlock(dentry); | 641 | __dget_dlock(dentry); |
642 | __d_drop(dentry); | 642 | __d_drop(dentry); |
643 | spin_unlock(&dentry->d_lock); | 643 | spin_unlock(&dentry->d_lock); |
644 | spin_unlock(&dcache_inode_lock); | 644 | spin_unlock(&inode->i_lock); |
645 | dput(dentry); | 645 | dput(dentry); |
646 | goto restart; | 646 | goto restart; |
647 | } | 647 | } |
648 | spin_unlock(&dentry->d_lock); | 648 | spin_unlock(&dentry->d_lock); |
649 | } | 649 | } |
650 | spin_unlock(&dcache_inode_lock); | 650 | spin_unlock(&inode->i_lock); |
651 | } | 651 | } |
652 | EXPORT_SYMBOL(d_prune_aliases); | 652 | EXPORT_SYMBOL(d_prune_aliases); |
653 | 653 | ||
@@ -1392,9 +1392,11 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode) | |||
1392 | void d_instantiate(struct dentry *entry, struct inode * inode) | 1392 | void d_instantiate(struct dentry *entry, struct inode * inode) |
1393 | { | 1393 | { |
1394 | BUG_ON(!list_empty(&entry->d_alias)); | 1394 | BUG_ON(!list_empty(&entry->d_alias)); |
1395 | spin_lock(&dcache_inode_lock); | 1395 | if (inode) |
1396 | spin_lock(&inode->i_lock); | ||
1396 | __d_instantiate(entry, inode); | 1397 | __d_instantiate(entry, inode); |
1397 | spin_unlock(&dcache_inode_lock); | 1398 | if (inode) |
1399 | spin_unlock(&inode->i_lock); | ||
1398 | security_d_instantiate(entry, inode); | 1400 | security_d_instantiate(entry, inode); |
1399 | } | 1401 | } |
1400 | EXPORT_SYMBOL(d_instantiate); | 1402 | EXPORT_SYMBOL(d_instantiate); |
@@ -1458,9 +1460,11 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) | |||
1458 | 1460 | ||
1459 | BUG_ON(!list_empty(&entry->d_alias)); | 1461 | BUG_ON(!list_empty(&entry->d_alias)); |
1460 | 1462 | ||
1461 | spin_lock(&dcache_inode_lock); | 1463 | if (inode) |
1464 | spin_lock(&inode->i_lock); | ||
1462 | result = __d_instantiate_unique(entry, inode); | 1465 | result = __d_instantiate_unique(entry, inode); |
1463 | spin_unlock(&dcache_inode_lock); | 1466 | if (inode) |
1467 | spin_unlock(&inode->i_lock); | ||
1464 | 1468 | ||
1465 | if (!result) { | 1469 | if (!result) { |
1466 | security_d_instantiate(entry, inode); | 1470 | security_d_instantiate(entry, inode); |
@@ -1542,10 +1546,10 @@ struct dentry *d_obtain_alias(struct inode *inode) | |||
1542 | tmp->d_parent = tmp; /* make sure dput doesn't croak */ | 1546 | tmp->d_parent = tmp; /* make sure dput doesn't croak */ |
1543 | 1547 | ||
1544 | 1548 | ||
1545 | spin_lock(&dcache_inode_lock); | 1549 | spin_lock(&inode->i_lock); |
1546 | res = __d_find_alias(inode, 0); | 1550 | res = __d_find_alias(inode, 0); |
1547 | if (res) { | 1551 | if (res) { |
1548 | spin_unlock(&dcache_inode_lock); | 1552 | spin_unlock(&inode->i_lock); |
1549 | dput(tmp); | 1553 | dput(tmp); |
1550 | goto out_iput; | 1554 | goto out_iput; |
1551 | } | 1555 | } |
@@ -1561,7 +1565,7 @@ struct dentry *d_obtain_alias(struct inode *inode) | |||
1561 | hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); | 1565 | hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); |
1562 | __bit_spin_unlock(0, (unsigned long *)&tmp->d_sb->s_anon.first); | 1566 | __bit_spin_unlock(0, (unsigned long *)&tmp->d_sb->s_anon.first); |
1563 | spin_unlock(&tmp->d_lock); | 1567 | spin_unlock(&tmp->d_lock); |
1564 | spin_unlock(&dcache_inode_lock); | 1568 | spin_unlock(&inode->i_lock); |
1565 | 1569 | ||
1566 | return tmp; | 1570 | return tmp; |
1567 | 1571 | ||
@@ -1592,18 +1596,18 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) | |||
1592 | struct dentry *new = NULL; | 1596 | struct dentry *new = NULL; |
1593 | 1597 | ||
1594 | if (inode && S_ISDIR(inode->i_mode)) { | 1598 | if (inode && S_ISDIR(inode->i_mode)) { |
1595 | spin_lock(&dcache_inode_lock); | 1599 | spin_lock(&inode->i_lock); |
1596 | new = __d_find_alias(inode, 1); | 1600 | new = __d_find_alias(inode, 1); |
1597 | if (new) { | 1601 | if (new) { |
1598 | BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED)); | 1602 | BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED)); |
1599 | spin_unlock(&dcache_inode_lock); | 1603 | spin_unlock(&inode->i_lock); |
1600 | security_d_instantiate(new, inode); | 1604 | security_d_instantiate(new, inode); |
1601 | d_move(new, dentry); | 1605 | d_move(new, dentry); |
1602 | iput(inode); | 1606 | iput(inode); |
1603 | } else { | 1607 | } else { |
1604 | /* already got dcache_inode_lock, so d_add() by hand */ | 1608 | /* already taking inode->i_lock, so d_add() by hand */ |
1605 | __d_instantiate(dentry, inode); | 1609 | __d_instantiate(dentry, inode); |
1606 | spin_unlock(&dcache_inode_lock); | 1610 | spin_unlock(&inode->i_lock); |
1607 | security_d_instantiate(dentry, inode); | 1611 | security_d_instantiate(dentry, inode); |
1608 | d_rehash(dentry); | 1612 | d_rehash(dentry); |
1609 | } | 1613 | } |
@@ -1676,10 +1680,10 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, | |||
1676 | * Negative dentry: instantiate it unless the inode is a directory and | 1680 | * Negative dentry: instantiate it unless the inode is a directory and |
1677 | * already has a dentry. | 1681 | * already has a dentry. |
1678 | */ | 1682 | */ |
1679 | spin_lock(&dcache_inode_lock); | 1683 | spin_lock(&inode->i_lock); |
1680 | if (!S_ISDIR(inode->i_mode) || list_empty(&inode->i_dentry)) { | 1684 | if (!S_ISDIR(inode->i_mode) || list_empty(&inode->i_dentry)) { |
1681 | __d_instantiate(found, inode); | 1685 | __d_instantiate(found, inode); |
1682 | spin_unlock(&dcache_inode_lock); | 1686 | spin_unlock(&inode->i_lock); |
1683 | security_d_instantiate(found, inode); | 1687 | security_d_instantiate(found, inode); |
1684 | return found; | 1688 | return found; |
1685 | } | 1689 | } |
@@ -1690,7 +1694,7 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, | |||
1690 | */ | 1694 | */ |
1691 | new = list_entry(inode->i_dentry.next, struct dentry, d_alias); | 1695 | new = list_entry(inode->i_dentry.next, struct dentry, d_alias); |
1692 | __dget(new); | 1696 | __dget(new); |
1693 | spin_unlock(&dcache_inode_lock); | 1697 | spin_unlock(&inode->i_lock); |
1694 | security_d_instantiate(found, inode); | 1698 | security_d_instantiate(found, inode); |
1695 | d_move(new, found); | 1699 | d_move(new, found); |
1696 | iput(inode); | 1700 | iput(inode); |
@@ -2004,15 +2008,17 @@ EXPORT_SYMBOL(d_validate); | |||
2004 | 2008 | ||
2005 | void d_delete(struct dentry * dentry) | 2009 | void d_delete(struct dentry * dentry) |
2006 | { | 2010 | { |
2011 | struct inode *inode; | ||
2007 | int isdir = 0; | 2012 | int isdir = 0; |
2008 | /* | 2013 | /* |
2009 | * Are we the only user? | 2014 | * Are we the only user? |
2010 | */ | 2015 | */ |
2011 | again: | 2016 | again: |
2012 | spin_lock(&dentry->d_lock); | 2017 | spin_lock(&dentry->d_lock); |
2013 | isdir = S_ISDIR(dentry->d_inode->i_mode); | 2018 | inode = dentry->d_inode; |
2019 | isdir = S_ISDIR(inode->i_mode); | ||
2014 | if (dentry->d_count == 1) { | 2020 | if (dentry->d_count == 1) { |
2015 | if (!spin_trylock(&dcache_inode_lock)) { | 2021 | if (inode && !spin_trylock(&inode->i_lock)) { |
2016 | spin_unlock(&dentry->d_lock); | 2022 | spin_unlock(&dentry->d_lock); |
2017 | cpu_relax(); | 2023 | cpu_relax(); |
2018 | goto again; | 2024 | goto again; |
@@ -2266,13 +2272,13 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2) | |||
2266 | * This helper attempts to cope with remotely renamed directories | 2272 | * This helper attempts to cope with remotely renamed directories |
2267 | * | 2273 | * |
2268 | * It assumes that the caller is already holding | 2274 | * It assumes that the caller is already holding |
2269 | * dentry->d_parent->d_inode->i_mutex and the dcache_inode_lock | 2275 | * dentry->d_parent->d_inode->i_mutex and the inode->i_lock |
2270 | * | 2276 | * |
2271 | * Note: If ever the locking in lock_rename() changes, then please | 2277 | * Note: If ever the locking in lock_rename() changes, then please |
2272 | * remember to update this too... | 2278 | * remember to update this too... |
2273 | */ | 2279 | */ |
2274 | static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias) | 2280 | static struct dentry *__d_unalias(struct inode *inode, |
2275 | __releases(dcache_inode_lock) | 2281 | struct dentry *dentry, struct dentry *alias) |
2276 | { | 2282 | { |
2277 | struct mutex *m1 = NULL, *m2 = NULL; | 2283 | struct mutex *m1 = NULL, *m2 = NULL; |
2278 | struct dentry *ret; | 2284 | struct dentry *ret; |
@@ -2298,7 +2304,7 @@ out_unalias: | |||
2298 | d_move(alias, dentry); | 2304 | d_move(alias, dentry); |
2299 | ret = alias; | 2305 | ret = alias; |
2300 | out_err: | 2306 | out_err: |
2301 | spin_unlock(&dcache_inode_lock); | 2307 | spin_unlock(&inode->i_lock); |
2302 | if (m2) | 2308 | if (m2) |
2303 | mutex_unlock(m2); | 2309 | mutex_unlock(m2); |
2304 | if (m1) | 2310 | if (m1) |
@@ -2371,7 +2377,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | |||
2371 | goto out_nolock; | 2377 | goto out_nolock; |
2372 | } | 2378 | } |
2373 | 2379 | ||
2374 | spin_lock(&dcache_inode_lock); | 2380 | spin_lock(&inode->i_lock); |
2375 | 2381 | ||
2376 | if (S_ISDIR(inode->i_mode)) { | 2382 | if (S_ISDIR(inode->i_mode)) { |
2377 | struct dentry *alias; | 2383 | struct dentry *alias; |
@@ -2388,7 +2394,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | |||
2388 | goto found; | 2394 | goto found; |
2389 | } | 2395 | } |
2390 | /* Nope, but we must(!) avoid directory aliasing */ | 2396 | /* Nope, but we must(!) avoid directory aliasing */ |
2391 | actual = __d_unalias(dentry, alias); | 2397 | actual = __d_unalias(inode, dentry, alias); |
2392 | if (IS_ERR(actual)) | 2398 | if (IS_ERR(actual)) |
2393 | dput(alias); | 2399 | dput(alias); |
2394 | goto out_nolock; | 2400 | goto out_nolock; |
@@ -2406,7 +2412,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | |||
2406 | found: | 2412 | found: |
2407 | _d_rehash(actual); | 2413 | _d_rehash(actual); |
2408 | spin_unlock(&actual->d_lock); | 2414 | spin_unlock(&actual->d_lock); |
2409 | spin_unlock(&dcache_inode_lock); | 2415 | spin_unlock(&inode->i_lock); |
2410 | out_nolock: | 2416 | out_nolock: |
2411 | if (actual == dentry) { | 2417 | if (actual == dentry) { |
2412 | security_d_instantiate(dentry, inode); | 2418 | security_d_instantiate(dentry, inode); |