Commit 873feea09ebc980cbd3631b767356ce1eee65ec1
1 parent
ceb5bdc2d2
Exists in
master
and in
4 other branches
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>
Showing 9 changed files with 67 additions and 60 deletions Side-by-side Diff
fs/9p/vfs_inode.c
... | ... | @@ -277,11 +277,11 @@ |
277 | 277 | { |
278 | 278 | struct dentry *dentry; |
279 | 279 | |
280 | - spin_lock(&dcache_inode_lock); | |
280 | + spin_lock(&inode->i_lock); | |
281 | 281 | /* Directory should have only one entry. */ |
282 | 282 | BUG_ON(S_ISDIR(inode->i_mode) && !list_is_singular(&inode->i_dentry)); |
283 | 283 | dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias); |
284 | - spin_unlock(&dcache_inode_lock); | |
284 | + spin_unlock(&inode->i_lock); | |
285 | 285 | return dentry; |
286 | 286 | } |
287 | 287 |
fs/affs/amigaffs.c
... | ... | @@ -128,7 +128,7 @@ |
128 | 128 | void *data = dentry->d_fsdata; |
129 | 129 | struct list_head *head, *next; |
130 | 130 | |
131 | - spin_lock(&dcache_inode_lock); | |
131 | + spin_lock(&inode->i_lock); | |
132 | 132 | head = &inode->i_dentry; |
133 | 133 | next = head->next; |
134 | 134 | while (next != head) { |
... | ... | @@ -139,7 +139,7 @@ |
139 | 139 | } |
140 | 140 | next = next->next; |
141 | 141 | } |
142 | - spin_unlock(&dcache_inode_lock); | |
142 | + spin_unlock(&inode->i_lock); | |
143 | 143 | } |
144 | 144 | |
145 | 145 |
fs/cifs/inode.c
... | ... | @@ -809,14 +809,14 @@ |
809 | 809 | { |
810 | 810 | struct dentry *dentry; |
811 | 811 | |
812 | - spin_lock(&dcache_inode_lock); | |
812 | + spin_lock(&inode->i_lock); | |
813 | 813 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { |
814 | 814 | if (!d_unhashed(dentry) || IS_ROOT(dentry)) { |
815 | - spin_unlock(&dcache_inode_lock); | |
815 | + spin_unlock(&inode->i_lock); | |
816 | 816 | return true; |
817 | 817 | } |
818 | 818 | } |
819 | - spin_unlock(&dcache_inode_lock); | |
819 | + spin_unlock(&inode->i_lock); | |
820 | 820 | return false; |
821 | 821 | } |
822 | 822 |
fs/dcache.c
... | ... | @@ -39,8 +39,8 @@ |
39 | 39 | |
40 | 40 | /* |
41 | 41 | * Usage: |
42 | - * dcache_inode_lock protects: | |
43 | - * - i_dentry, d_alias, d_inode | |
42 | + * dcache->d_inode->i_lock protects: | |
43 | + * - i_dentry, d_alias, d_inode of aliases | |
44 | 44 | * dcache_hash_bucket lock protects: |
45 | 45 | * - the dcache hash table |
46 | 46 | * s_anon bl list spinlock protects: |
... | ... | @@ -58,7 +58,7 @@ |
58 | 58 | * - d_alias, d_inode |
59 | 59 | * |
60 | 60 | * Ordering: |
61 | - * dcache_inode_lock | |
61 | + * dentry->d_inode->i_lock | |
62 | 62 | * dentry->d_lock |
63 | 63 | * dcache_lru_lock |
64 | 64 | * dcache_hash_bucket lock |
65 | 65 | |
... | ... | @@ -78,12 +78,10 @@ |
78 | 78 | int sysctl_vfs_cache_pressure __read_mostly = 100; |
79 | 79 | EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); |
80 | 80 | |
81 | -__cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_inode_lock); | |
82 | 81 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lru_lock); |
83 | 82 | __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); |
84 | 83 | |
85 | 84 | EXPORT_SYMBOL(rename_lock); |
86 | -EXPORT_SYMBOL(dcache_inode_lock); | |
87 | 85 | |
88 | 86 | static struct kmem_cache *dentry_cache __read_mostly; |
89 | 87 | |
90 | 88 | |
... | ... | @@ -196,14 +194,14 @@ |
196 | 194 | */ |
197 | 195 | static void dentry_iput(struct dentry * dentry) |
198 | 196 | __releases(dentry->d_lock) |
199 | - __releases(dcache_inode_lock) | |
197 | + __releases(dentry->d_inode->i_lock) | |
200 | 198 | { |
201 | 199 | struct inode *inode = dentry->d_inode; |
202 | 200 | if (inode) { |
203 | 201 | dentry->d_inode = NULL; |
204 | 202 | list_del_init(&dentry->d_alias); |
205 | 203 | spin_unlock(&dentry->d_lock); |
206 | - spin_unlock(&dcache_inode_lock); | |
204 | + spin_unlock(&inode->i_lock); | |
207 | 205 | if (!inode->i_nlink) |
208 | 206 | fsnotify_inoderemove(inode); |
209 | 207 | if (dentry->d_op && dentry->d_op->d_iput) |
... | ... | @@ -212,7 +210,6 @@ |
212 | 210 | iput(inode); |
213 | 211 | } else { |
214 | 212 | spin_unlock(&dentry->d_lock); |
215 | - spin_unlock(&dcache_inode_lock); | |
216 | 213 | } |
217 | 214 | } |
218 | 215 | |
219 | 216 | |
... | ... | @@ -222,14 +219,14 @@ |
222 | 219 | */ |
223 | 220 | static void dentry_unlink_inode(struct dentry * dentry) |
224 | 221 | __releases(dentry->d_lock) |
225 | - __releases(dcache_inode_lock) | |
222 | + __releases(dentry->d_inode->i_lock) | |
226 | 223 | { |
227 | 224 | struct inode *inode = dentry->d_inode; |
228 | 225 | dentry->d_inode = NULL; |
229 | 226 | list_del_init(&dentry->d_alias); |
230 | 227 | dentry_rcuwalk_barrier(dentry); |
231 | 228 | spin_unlock(&dentry->d_lock); |
232 | - spin_unlock(&dcache_inode_lock); | |
229 | + spin_unlock(&inode->i_lock); | |
233 | 230 | if (!inode->i_nlink) |
234 | 231 | fsnotify_inoderemove(inode); |
235 | 232 | if (dentry->d_op && dentry->d_op->d_iput) |
... | ... | @@ -295,7 +292,7 @@ |
295 | 292 | static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) |
296 | 293 | __releases(dentry->d_lock) |
297 | 294 | __releases(parent->d_lock) |
298 | - __releases(dcache_inode_lock) | |
295 | + __releases(dentry->d_inode->i_lock) | |
299 | 296 | { |
300 | 297 | dentry->d_parent = NULL; |
301 | 298 | list_del(&dentry->d_u.d_child); |
302 | 299 | |
... | ... | @@ -370,9 +367,11 @@ |
370 | 367 | static inline struct dentry *dentry_kill(struct dentry *dentry, int ref) |
371 | 368 | __releases(dentry->d_lock) |
372 | 369 | { |
370 | + struct inode *inode; | |
373 | 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 | 375 | relock: |
377 | 376 | spin_unlock(&dentry->d_lock); |
378 | 377 | cpu_relax(); |
... | ... | @@ -383,7 +382,8 @@ |
383 | 382 | else |
384 | 383 | parent = dentry->d_parent; |
385 | 384 | if (parent && !spin_trylock(&parent->d_lock)) { |
386 | - spin_unlock(&dcache_inode_lock); | |
385 | + if (inode) | |
386 | + spin_unlock(&inode->i_lock); | |
387 | 387 | goto relock; |
388 | 388 | } |
389 | 389 | |
390 | 390 | |
... | ... | @@ -618,9 +618,9 @@ |
618 | 618 | struct dentry *de = NULL; |
619 | 619 | |
620 | 620 | if (!list_empty(&inode->i_dentry)) { |
621 | - spin_lock(&dcache_inode_lock); | |
621 | + spin_lock(&inode->i_lock); | |
622 | 622 | de = __d_find_alias(inode, 0); |
623 | - spin_unlock(&dcache_inode_lock); | |
623 | + spin_unlock(&inode->i_lock); | |
624 | 624 | } |
625 | 625 | return de; |
626 | 626 | } |
627 | 627 | |
628 | 628 | |
... | ... | @@ -634,20 +634,20 @@ |
634 | 634 | { |
635 | 635 | struct dentry *dentry; |
636 | 636 | restart: |
637 | - spin_lock(&dcache_inode_lock); | |
637 | + spin_lock(&inode->i_lock); | |
638 | 638 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { |
639 | 639 | spin_lock(&dentry->d_lock); |
640 | 640 | if (!dentry->d_count) { |
641 | 641 | __dget_dlock(dentry); |
642 | 642 | __d_drop(dentry); |
643 | 643 | spin_unlock(&dentry->d_lock); |
644 | - spin_unlock(&dcache_inode_lock); | |
644 | + spin_unlock(&inode->i_lock); | |
645 | 645 | dput(dentry); |
646 | 646 | goto restart; |
647 | 647 | } |
648 | 648 | spin_unlock(&dentry->d_lock); |
649 | 649 | } |
650 | - spin_unlock(&dcache_inode_lock); | |
650 | + spin_unlock(&inode->i_lock); | |
651 | 651 | } |
652 | 652 | EXPORT_SYMBOL(d_prune_aliases); |
653 | 653 | |
654 | 654 | |
... | ... | @@ -1392,9 +1392,11 @@ |
1392 | 1392 | void d_instantiate(struct dentry *entry, struct inode * inode) |
1393 | 1393 | { |
1394 | 1394 | BUG_ON(!list_empty(&entry->d_alias)); |
1395 | - spin_lock(&dcache_inode_lock); | |
1395 | + if (inode) | |
1396 | + spin_lock(&inode->i_lock); | |
1396 | 1397 | __d_instantiate(entry, inode); |
1397 | - spin_unlock(&dcache_inode_lock); | |
1398 | + if (inode) | |
1399 | + spin_unlock(&inode->i_lock); | |
1398 | 1400 | security_d_instantiate(entry, inode); |
1399 | 1401 | } |
1400 | 1402 | EXPORT_SYMBOL(d_instantiate); |
1401 | 1403 | |
... | ... | @@ -1458,9 +1460,11 @@ |
1458 | 1460 | |
1459 | 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 | 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 | 1469 | if (!result) { |
1466 | 1470 | security_d_instantiate(entry, inode); |
1467 | 1471 | |
... | ... | @@ -1542,10 +1546,10 @@ |
1542 | 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 | 1550 | res = __d_find_alias(inode, 0); |
1547 | 1551 | if (res) { |
1548 | - spin_unlock(&dcache_inode_lock); | |
1552 | + spin_unlock(&inode->i_lock); | |
1549 | 1553 | dput(tmp); |
1550 | 1554 | goto out_iput; |
1551 | 1555 | } |
... | ... | @@ -1561,7 +1565,7 @@ |
1561 | 1565 | hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); |
1562 | 1566 | __bit_spin_unlock(0, (unsigned long *)&tmp->d_sb->s_anon.first); |
1563 | 1567 | spin_unlock(&tmp->d_lock); |
1564 | - spin_unlock(&dcache_inode_lock); | |
1568 | + spin_unlock(&inode->i_lock); | |
1565 | 1569 | |
1566 | 1570 | return tmp; |
1567 | 1571 | |
1568 | 1572 | |
1569 | 1573 | |
1570 | 1574 | |
... | ... | @@ -1592,18 +1596,18 @@ |
1592 | 1596 | struct dentry *new = NULL; |
1593 | 1597 | |
1594 | 1598 | if (inode && S_ISDIR(inode->i_mode)) { |
1595 | - spin_lock(&dcache_inode_lock); | |
1599 | + spin_lock(&inode->i_lock); | |
1596 | 1600 | new = __d_find_alias(inode, 1); |
1597 | 1601 | if (new) { |
1598 | 1602 | BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED)); |
1599 | - spin_unlock(&dcache_inode_lock); | |
1603 | + spin_unlock(&inode->i_lock); | |
1600 | 1604 | security_d_instantiate(new, inode); |
1601 | 1605 | d_move(new, dentry); |
1602 | 1606 | iput(inode); |
1603 | 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 | 1609 | __d_instantiate(dentry, inode); |
1606 | - spin_unlock(&dcache_inode_lock); | |
1610 | + spin_unlock(&inode->i_lock); | |
1607 | 1611 | security_d_instantiate(dentry, inode); |
1608 | 1612 | d_rehash(dentry); |
1609 | 1613 | } |
1610 | 1614 | |
... | ... | @@ -1676,10 +1680,10 @@ |
1676 | 1680 | * Negative dentry: instantiate it unless the inode is a directory and |
1677 | 1681 | * already has a dentry. |
1678 | 1682 | */ |
1679 | - spin_lock(&dcache_inode_lock); | |
1683 | + spin_lock(&inode->i_lock); | |
1680 | 1684 | if (!S_ISDIR(inode->i_mode) || list_empty(&inode->i_dentry)) { |
1681 | 1685 | __d_instantiate(found, inode); |
1682 | - spin_unlock(&dcache_inode_lock); | |
1686 | + spin_unlock(&inode->i_lock); | |
1683 | 1687 | security_d_instantiate(found, inode); |
1684 | 1688 | return found; |
1685 | 1689 | } |
... | ... | @@ -1690,7 +1694,7 @@ |
1690 | 1694 | */ |
1691 | 1695 | new = list_entry(inode->i_dentry.next, struct dentry, d_alias); |
1692 | 1696 | __dget(new); |
1693 | - spin_unlock(&dcache_inode_lock); | |
1697 | + spin_unlock(&inode->i_lock); | |
1694 | 1698 | security_d_instantiate(found, inode); |
1695 | 1699 | d_move(new, found); |
1696 | 1700 | iput(inode); |
1697 | 1701 | |
1698 | 1702 | |
... | ... | @@ -2004,15 +2008,17 @@ |
2004 | 2008 | |
2005 | 2009 | void d_delete(struct dentry * dentry) |
2006 | 2010 | { |
2011 | + struct inode *inode; | |
2007 | 2012 | int isdir = 0; |
2008 | 2013 | /* |
2009 | 2014 | * Are we the only user? |
2010 | 2015 | */ |
2011 | 2016 | again: |
2012 | 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 | 2020 | if (dentry->d_count == 1) { |
2015 | - if (!spin_trylock(&dcache_inode_lock)) { | |
2021 | + if (inode && !spin_trylock(&inode->i_lock)) { | |
2016 | 2022 | spin_unlock(&dentry->d_lock); |
2017 | 2023 | cpu_relax(); |
2018 | 2024 | goto again; |
2019 | 2025 | |
... | ... | @@ -2266,13 +2272,13 @@ |
2266 | 2272 | * This helper attempts to cope with remotely renamed directories |
2267 | 2273 | * |
2268 | 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 | 2277 | * Note: If ever the locking in lock_rename() changes, then please |
2272 | 2278 | * remember to update this too... |
2273 | 2279 | */ |
2274 | -static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias) | |
2275 | - __releases(dcache_inode_lock) | |
2280 | +static struct dentry *__d_unalias(struct inode *inode, | |
2281 | + struct dentry *dentry, struct dentry *alias) | |
2276 | 2282 | { |
2277 | 2283 | struct mutex *m1 = NULL, *m2 = NULL; |
2278 | 2284 | struct dentry *ret; |
... | ... | @@ -2298,7 +2304,7 @@ |
2298 | 2304 | d_move(alias, dentry); |
2299 | 2305 | ret = alias; |
2300 | 2306 | out_err: |
2301 | - spin_unlock(&dcache_inode_lock); | |
2307 | + spin_unlock(&inode->i_lock); | |
2302 | 2308 | if (m2) |
2303 | 2309 | mutex_unlock(m2); |
2304 | 2310 | if (m1) |
... | ... | @@ -2371,7 +2377,7 @@ |
2371 | 2377 | goto out_nolock; |
2372 | 2378 | } |
2373 | 2379 | |
2374 | - spin_lock(&dcache_inode_lock); | |
2380 | + spin_lock(&inode->i_lock); | |
2375 | 2381 | |
2376 | 2382 | if (S_ISDIR(inode->i_mode)) { |
2377 | 2383 | struct dentry *alias; |
... | ... | @@ -2388,7 +2394,7 @@ |
2388 | 2394 | goto found; |
2389 | 2395 | } |
2390 | 2396 | /* Nope, but we must(!) avoid directory aliasing */ |
2391 | - actual = __d_unalias(dentry, alias); | |
2397 | + actual = __d_unalias(inode, dentry, alias); | |
2392 | 2398 | if (IS_ERR(actual)) |
2393 | 2399 | dput(alias); |
2394 | 2400 | goto out_nolock; |
... | ... | @@ -2406,7 +2412,7 @@ |
2406 | 2412 | found: |
2407 | 2413 | _d_rehash(actual); |
2408 | 2414 | spin_unlock(&actual->d_lock); |
2409 | - spin_unlock(&dcache_inode_lock); | |
2415 | + spin_unlock(&inode->i_lock); | |
2410 | 2416 | out_nolock: |
2411 | 2417 | if (actual == dentry) { |
2412 | 2418 | security_d_instantiate(dentry, inode); |
fs/exportfs/expfs.c
... | ... | @@ -43,24 +43,26 @@ |
43 | 43 | void *context) |
44 | 44 | { |
45 | 45 | struct dentry *dentry, *toput = NULL; |
46 | + struct inode *inode; | |
46 | 47 | |
47 | 48 | if (acceptable(context, result)) |
48 | 49 | return result; |
49 | 50 | |
50 | - spin_lock(&dcache_inode_lock); | |
51 | - list_for_each_entry(dentry, &result->d_inode->i_dentry, d_alias) { | |
51 | + inode = result->d_inode; | |
52 | + spin_lock(&inode->i_lock); | |
53 | + list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | |
52 | 54 | dget(dentry); |
53 | - spin_unlock(&dcache_inode_lock); | |
55 | + spin_unlock(&inode->i_lock); | |
54 | 56 | if (toput) |
55 | 57 | dput(toput); |
56 | 58 | if (dentry != result && acceptable(context, dentry)) { |
57 | 59 | dput(result); |
58 | 60 | return dentry; |
59 | 61 | } |
60 | - spin_lock(&dcache_inode_lock); | |
62 | + spin_lock(&inode->i_lock); | |
61 | 63 | toput = dentry; |
62 | 64 | } |
63 | - spin_unlock(&dcache_inode_lock); | |
65 | + spin_unlock(&inode->i_lock); | |
64 | 66 | |
65 | 67 | if (toput) |
66 | 68 | dput(toput); |
fs/nfs/getroot.c
... | ... | @@ -63,11 +63,11 @@ |
63 | 63 | * This again causes shrink_dcache_for_umount_subtree() to |
64 | 64 | * Oops, since the test for IS_ROOT() will fail. |
65 | 65 | */ |
66 | - spin_lock(&dcache_inode_lock); | |
66 | + spin_lock(&sb->s_root->d_inode->i_lock); | |
67 | 67 | spin_lock(&sb->s_root->d_lock); |
68 | 68 | list_del_init(&sb->s_root->d_alias); |
69 | 69 | spin_unlock(&sb->s_root->d_lock); |
70 | - spin_unlock(&dcache_inode_lock); | |
70 | + spin_unlock(&sb->s_root->d_inode->i_lock); | |
71 | 71 | } |
72 | 72 | return 0; |
73 | 73 | } |
fs/notify/fsnotify.c
... | ... | @@ -59,7 +59,7 @@ |
59 | 59 | /* determine if the children should tell inode about their events */ |
60 | 60 | watched = fsnotify_inode_watches_children(inode); |
61 | 61 | |
62 | - spin_lock(&dcache_inode_lock); | |
62 | + spin_lock(&inode->i_lock); | |
63 | 63 | /* run all of the dentries associated with this inode. Since this is a |
64 | 64 | * directory, there damn well better only be one item on this list */ |
65 | 65 | list_for_each_entry(alias, &inode->i_dentry, d_alias) { |
... | ... | @@ -82,7 +82,7 @@ |
82 | 82 | } |
83 | 83 | spin_unlock(&alias->d_lock); |
84 | 84 | } |
85 | - spin_unlock(&dcache_inode_lock); | |
85 | + spin_unlock(&inode->i_lock); | |
86 | 86 | } |
87 | 87 | |
88 | 88 | /* Notify this dentry's parent about a child's events. */ |
fs/ocfs2/dcache.c
... | ... | @@ -175,7 +175,7 @@ |
175 | 175 | struct list_head *p; |
176 | 176 | struct dentry *dentry = NULL; |
177 | 177 | |
178 | - spin_lock(&dcache_inode_lock); | |
178 | + spin_lock(&inode->i_lock); | |
179 | 179 | list_for_each(p, &inode->i_dentry) { |
180 | 180 | dentry = list_entry(p, struct dentry, d_alias); |
181 | 181 | |
... | ... | @@ -193,7 +193,7 @@ |
193 | 193 | dentry = NULL; |
194 | 194 | } |
195 | 195 | |
196 | - spin_unlock(&dcache_inode_lock); | |
196 | + spin_unlock(&inode->i_lock); | |
197 | 197 | |
198 | 198 | return dentry; |
199 | 199 | } |
include/linux/dcache.h