aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/dcache.c46
1 files changed, 25 insertions, 21 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index fe8f28a2878e..d1840b30c673 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -615,16 +615,16 @@ static void shrink_dentry_list(struct list_head *list)
615{ 615{
616 struct dentry *dentry; 616 struct dentry *dentry;
617 617
618 while (!list_empty(list)) { 618 rcu_read_lock();
619 for (;;) {
619 struct dentry *parent; 620 struct dentry *parent;
620 621
621 dentry = list_entry(list->prev, struct dentry, d_lru); 622 dentry = list_entry_rcu(list->prev, struct dentry, d_lru);
622 623 if (&dentry->d_lru == list)
623 if (!spin_trylock(&dentry->d_lock)) { 624 break; /* empty */
624relock1: 625 spin_lock(&dentry->d_lock);
625 spin_unlock(&dcache_lru_lock); 626 if (dentry != list_entry(list->prev, struct dentry, d_lru)) {
626 cpu_relax(); 627 spin_unlock(&dentry->d_lock);
627 spin_lock(&dcache_lru_lock);
628 continue; 628 continue;
629 } 629 }
630 630
@@ -634,14 +634,16 @@ relock1:
634 * it - just keep it off the LRU list. 634 * it - just keep it off the LRU list.
635 */ 635 */
636 if (dentry->d_count) { 636 if (dentry->d_count) {
637 __dentry_lru_del(dentry); 637 dentry_lru_del(dentry);
638 spin_unlock(&dentry->d_lock); 638 spin_unlock(&dentry->d_lock);
639 continue; 639 continue;
640 } 640 }
641
641 if (!spin_trylock(&dcache_inode_lock)) { 642 if (!spin_trylock(&dcache_inode_lock)) {
642relock2: 643relock:
643 spin_unlock(&dentry->d_lock); 644 spin_unlock(&dentry->d_lock);
644 goto relock1; 645 cpu_relax();
646 continue;
645 } 647 }
646 if (IS_ROOT(dentry)) 648 if (IS_ROOT(dentry))
647 parent = NULL; 649 parent = NULL;
@@ -649,15 +651,15 @@ relock2:
649 parent = dentry->d_parent; 651 parent = dentry->d_parent;
650 if (parent && !spin_trylock(&parent->d_lock)) { 652 if (parent && !spin_trylock(&parent->d_lock)) {
651 spin_unlock(&dcache_inode_lock); 653 spin_unlock(&dcache_inode_lock);
652 goto relock2; 654 goto relock;
653 } 655 }
654 __dentry_lru_del(dentry); 656 dentry_lru_del(dentry);
655 spin_unlock(&dcache_lru_lock);
656 657
658 rcu_read_unlock();
657 prune_one_dentry(dentry, parent); 659 prune_one_dentry(dentry, parent);
658 /* dcache_inode_lock and dentry->d_lock dropped */ 660 rcu_read_lock();
659 spin_lock(&dcache_lru_lock);
660 } 661 }
662 rcu_read_unlock();
661} 663}
662 664
663/** 665/**
@@ -705,15 +707,15 @@ relock:
705 if (!--cnt) 707 if (!--cnt)
706 break; 708 break;
707 } 709 }
708 /* XXX: re-add cond_resched_lock when dcache_lock goes away */ 710 cond_resched_lock(&dcache_lru_lock);
709 } 711 }
710
711 *count = cnt;
712 shrink_dentry_list(&tmp);
713
714 if (!list_empty(&referenced)) 712 if (!list_empty(&referenced))
715 list_splice(&referenced, &sb->s_dentry_lru); 713 list_splice(&referenced, &sb->s_dentry_lru);
716 spin_unlock(&dcache_lru_lock); 714 spin_unlock(&dcache_lru_lock);
715
716 shrink_dentry_list(&tmp);
717
718 *count = cnt;
717} 719}
718 720
719/** 721/**
@@ -805,7 +807,9 @@ void shrink_dcache_sb(struct super_block *sb)
805 spin_lock(&dcache_lru_lock); 807 spin_lock(&dcache_lru_lock);
806 while (!list_empty(&sb->s_dentry_lru)) { 808 while (!list_empty(&sb->s_dentry_lru)) {
807 list_splice_init(&sb->s_dentry_lru, &tmp); 809 list_splice_init(&sb->s_dentry_lru, &tmp);
810 spin_unlock(&dcache_lru_lock);
808 shrink_dentry_list(&tmp); 811 shrink_dentry_list(&tmp);
812 spin_lock(&dcache_lru_lock);
809 } 813 }
810 spin_unlock(&dcache_lru_lock); 814 spin_unlock(&dcache_lru_lock);
811} 815}