aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2011-01-07 01:49:33 -0500
committerNick Piggin <npiggin@kernel.dk>2011-01-07 01:50:21 -0500
commitda5029563a0a026c64821b09e8e7b4fd81d3fe1b (patch)
tree5d5618e0cb382390073377b1be7d0aa76879ac54 /fs/dcache.c
parentb7ab39f631f505edc2bbdb86620d5493f995c9da (diff)
fs: dcache scale d_unhashed
Protect d_unhashed(dentry) condition with d_lock. This means keeping DCACHE_UNHASHED bit in synch with hash manipulations. Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c74
1 files changed, 50 insertions, 24 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 81e91502b294..ee127f9ab274 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -46,6 +46,7 @@
46 * - d_name 46 * - d_name
47 * - d_lru 47 * - d_lru
48 * - d_count 48 * - d_count
49 * - d_unhashed()
49 * 50 *
50 * Ordering: 51 * Ordering:
51 * dcache_lock 52 * dcache_lock
@@ -53,6 +54,13 @@
53 * dcache_lru_lock 54 * dcache_lru_lock
54 * dcache_hash_lock 55 * dcache_hash_lock
55 * 56 *
57 * If there is an ancestor relationship:
58 * dentry->d_parent->...->d_parent->d_lock
59 * ...
60 * dentry->d_parent->d_lock
61 * dentry->d_lock
62 *
63 * If no ancestor relationship:
56 * if (dentry1 < dentry2) 64 * if (dentry1 < dentry2)
57 * dentry1->d_lock 65 * dentry1->d_lock
58 * dentry2->d_lock 66 * dentry2->d_lock
@@ -379,7 +387,9 @@ int d_invalidate(struct dentry * dentry)
379 * If it's already been dropped, return OK. 387 * If it's already been dropped, return OK.
380 */ 388 */
381 spin_lock(&dcache_lock); 389 spin_lock(&dcache_lock);
390 spin_lock(&dentry->d_lock);
382 if (d_unhashed(dentry)) { 391 if (d_unhashed(dentry)) {
392 spin_unlock(&dentry->d_lock);
383 spin_unlock(&dcache_lock); 393 spin_unlock(&dcache_lock);
384 return 0; 394 return 0;
385 } 395 }
@@ -388,9 +398,11 @@ int d_invalidate(struct dentry * dentry)
388 * to get rid of unused child entries. 398 * to get rid of unused child entries.
389 */ 399 */
390 if (!list_empty(&dentry->d_subdirs)) { 400 if (!list_empty(&dentry->d_subdirs)) {
401 spin_unlock(&dentry->d_lock);
391 spin_unlock(&dcache_lock); 402 spin_unlock(&dcache_lock);
392 shrink_dcache_parent(dentry); 403 shrink_dcache_parent(dentry);
393 spin_lock(&dcache_lock); 404 spin_lock(&dcache_lock);
405 spin_lock(&dentry->d_lock);
394 } 406 }
395 407
396 /* 408 /*
@@ -403,7 +415,6 @@ int d_invalidate(struct dentry * dentry)
403 * we might still populate it if it was a 415 * we might still populate it if it was a
404 * working directory or similar). 416 * working directory or similar).
405 */ 417 */
406 spin_lock(&dentry->d_lock);
407 if (dentry->d_count > 1) { 418 if (dentry->d_count > 1) {
408 if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { 419 if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
409 spin_unlock(&dentry->d_lock); 420 spin_unlock(&dentry->d_lock);
@@ -490,35 +501,44 @@ EXPORT_SYMBOL(dget_parent);
490 * any other hashed alias over that one unless @want_discon is set, 501 * any other hashed alias over that one unless @want_discon is set,
491 * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias. 502 * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias.
492 */ 503 */
493 504static struct dentry *__d_find_alias(struct inode *inode, int want_discon)
494static struct dentry * __d_find_alias(struct inode *inode, int want_discon)
495{ 505{
496 struct list_head *head, *next, *tmp; 506 struct dentry *alias, *discon_alias;
497 struct dentry *alias, *discon_alias=NULL;
498 507
499 head = &inode->i_dentry; 508again:
500 next = inode->i_dentry.next; 509 discon_alias = NULL;
501 while (next != head) { 510 list_for_each_entry(alias, &inode->i_dentry, d_alias) {
502 tmp = next; 511 spin_lock(&alias->d_lock);
503 next = tmp->next;
504 prefetch(next);
505 alias = list_entry(tmp, struct dentry, d_alias);
506 if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { 512 if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
507 if (IS_ROOT(alias) && 513 if (IS_ROOT(alias) &&
508 (alias->d_flags & DCACHE_DISCONNECTED)) 514 (alias->d_flags & DCACHE_DISCONNECTED)) {
509 discon_alias = alias; 515 discon_alias = alias;
510 else if (!want_discon) { 516 } else if (!want_discon) {
511 __dget_locked(alias); 517 __dget_locked_dlock(alias);
518 spin_unlock(&alias->d_lock);
519 return alias;
520 }
521 }
522 spin_unlock(&alias->d_lock);
523 }
524 if (discon_alias) {
525 alias = discon_alias;
526 spin_lock(&alias->d_lock);
527 if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
528 if (IS_ROOT(alias) &&
529 (alias->d_flags & DCACHE_DISCONNECTED)) {
530 __dget_locked_dlock(alias);
531 spin_unlock(&alias->d_lock);
512 return alias; 532 return alias;
513 } 533 }
514 } 534 }
535 spin_unlock(&alias->d_lock);
536 goto again;
515 } 537 }
516 if (discon_alias) 538 return NULL;
517 __dget_locked(discon_alias);
518 return discon_alias;
519} 539}
520 540
521struct dentry * d_find_alias(struct inode *inode) 541struct dentry *d_find_alias(struct inode *inode)
522{ 542{
523 struct dentry *de = NULL; 543 struct dentry *de = NULL;
524 544
@@ -801,8 +821,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
801 spin_lock(&dcache_lock); 821 spin_lock(&dcache_lock);
802 spin_lock(&dentry->d_lock); 822 spin_lock(&dentry->d_lock);
803 dentry_lru_del(dentry); 823 dentry_lru_del(dentry);
804 spin_unlock(&dentry->d_lock);
805 __d_drop(dentry); 824 __d_drop(dentry);
825 spin_unlock(&dentry->d_lock);
806 spin_unlock(&dcache_lock); 826 spin_unlock(&dcache_lock);
807 827
808 for (;;) { 828 for (;;) {
@@ -817,8 +837,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
817 d_u.d_child) { 837 d_u.d_child) {
818 spin_lock(&loop->d_lock); 838 spin_lock(&loop->d_lock);
819 dentry_lru_del(loop); 839 dentry_lru_del(loop);
820 spin_unlock(&loop->d_lock);
821 __d_drop(loop); 840 __d_drop(loop);
841 spin_unlock(&loop->d_lock);
822 cond_resched_lock(&dcache_lock); 842 cond_resched_lock(&dcache_lock);
823 } 843 }
824 spin_unlock(&dcache_lock); 844 spin_unlock(&dcache_lock);
@@ -1863,7 +1883,10 @@ static void d_move_locked(struct dentry * dentry, struct dentry * target)
1863 /* 1883 /*
1864 * XXXX: do we really need to take target->d_lock? 1884 * XXXX: do we really need to take target->d_lock?
1865 */ 1885 */
1866 if (target < dentry) { 1886 if (d_ancestor(dentry, target)) {
1887 spin_lock(&dentry->d_lock);
1888 spin_lock_nested(&target->d_lock, DENTRY_D_LOCK_NESTED);
1889 } else if (d_ancestor(target, dentry) || target < dentry) {
1867 spin_lock(&target->d_lock); 1890 spin_lock(&target->d_lock);
1868 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); 1891 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
1869 } else { 1892 } else {
@@ -2542,13 +2565,16 @@ resume:
2542 struct list_head *tmp = next; 2565 struct list_head *tmp = next;
2543 struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); 2566 struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
2544 next = tmp->next; 2567 next = tmp->next;
2545 if (d_unhashed(dentry)||!dentry->d_inode) 2568 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
2569 if (d_unhashed(dentry) || !dentry->d_inode) {
2570 spin_unlock(&dentry->d_lock);
2546 continue; 2571 continue;
2572 }
2547 if (!list_empty(&dentry->d_subdirs)) { 2573 if (!list_empty(&dentry->d_subdirs)) {
2574 spin_unlock(&dentry->d_lock);
2548 this_parent = dentry; 2575 this_parent = dentry;
2549 goto repeat; 2576 goto repeat;
2550 } 2577 }
2551 spin_lock(&dentry->d_lock);
2552 dentry->d_count--; 2578 dentry->d_count--;
2553 spin_unlock(&dentry->d_lock); 2579 spin_unlock(&dentry->d_lock);
2554 } 2580 }