aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/dcache.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index c23f78a9d156..d54a99baf4f3 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -530,6 +530,38 @@ failed:
530 return dentry; /* try again with same dentry */ 530 return dentry; /* try again with same dentry */
531} 531}
532 532
533static inline struct dentry *lock_parent(struct dentry *dentry)
534{
535 struct dentry *parent = dentry->d_parent;
536 if (IS_ROOT(dentry))
537 return NULL;
538 if (likely(spin_trylock(&parent->d_lock)))
539 return parent;
540 spin_unlock(&dentry->d_lock);
541 rcu_read_lock();
542again:
543 parent = ACCESS_ONCE(dentry->d_parent);
544 spin_lock(&parent->d_lock);
545 /*
546 * We can't blindly lock dentry until we are sure
547 * that we won't violate the locking order.
548 * Any changes of dentry->d_parent must have
549 * been done with parent->d_lock held, so
550 * spin_lock() above is enough of a barrier
551 * for checking if it's still our child.
552 */
553 if (unlikely(parent != dentry->d_parent)) {
554 spin_unlock(&parent->d_lock);
555 goto again;
556 }
557 rcu_read_unlock();
558 if (parent != dentry)
559 spin_lock(&dentry->d_lock);
560 else
561 parent = NULL;
562 return parent;
563}
564
533/* 565/*
534 * This is dput 566 * This is dput
535 * 567 *
@@ -804,6 +836,8 @@ static void shrink_dentry_list(struct list_head *list)
804 struct inode *inode; 836 struct inode *inode;
805 dentry = list_entry(list->prev, struct dentry, d_lru); 837 dentry = list_entry(list->prev, struct dentry, d_lru);
806 spin_lock(&dentry->d_lock); 838 spin_lock(&dentry->d_lock);
839 parent = lock_parent(dentry);
840
807 /* 841 /*
808 * The dispose list is isolated and dentries are not accounted 842 * The dispose list is isolated and dentries are not accounted
809 * to the LRU here, so we can simply remove it from the list 843 * to the LRU here, so we can simply remove it from the list
@@ -817,6 +851,8 @@ static void shrink_dentry_list(struct list_head *list)
817 */ 851 */
818 if ((int)dentry->d_lockref.count > 0) { 852 if ((int)dentry->d_lockref.count > 0) {
819 spin_unlock(&dentry->d_lock); 853 spin_unlock(&dentry->d_lock);
854 if (parent)
855 spin_unlock(&parent->d_lock);
820 continue; 856 continue;
821 } 857 }
822 858
@@ -824,6 +860,8 @@ static void shrink_dentry_list(struct list_head *list)
824 if (unlikely(dentry->d_flags & DCACHE_DENTRY_KILLED)) { 860 if (unlikely(dentry->d_flags & DCACHE_DENTRY_KILLED)) {
825 bool can_free = dentry->d_flags & DCACHE_MAY_FREE; 861 bool can_free = dentry->d_flags & DCACHE_MAY_FREE;
826 spin_unlock(&dentry->d_lock); 862 spin_unlock(&dentry->d_lock);
863 if (parent)
864 spin_unlock(&parent->d_lock);
827 if (can_free) 865 if (can_free)
828 dentry_free(dentry); 866 dentry_free(dentry);
829 continue; 867 continue;
@@ -833,22 +871,13 @@ static void shrink_dentry_list(struct list_head *list)
833 if (inode && unlikely(!spin_trylock(&inode->i_lock))) { 871 if (inode && unlikely(!spin_trylock(&inode->i_lock))) {
834 d_shrink_add(dentry, list); 872 d_shrink_add(dentry, list);
835 spin_unlock(&dentry->d_lock); 873 spin_unlock(&dentry->d_lock);
874 if (parent)
875 spin_unlock(&parent->d_lock);
836 continue; 876 continue;
837 } 877 }
838 878
839 parent = NULL;
840 if (!IS_ROOT(dentry)) {
841 parent = dentry->d_parent;
842 if (unlikely(!spin_trylock(&parent->d_lock))) {
843 if (inode)
844 spin_unlock(&inode->i_lock);
845 d_shrink_add(dentry, list);
846 spin_unlock(&dentry->d_lock);
847 continue;
848 }
849 }
850
851 __dentry_kill(dentry); 879 __dentry_kill(dentry);
880
852 /* 881 /*
853 * We need to prune ancestors too. This is necessary to prevent 882 * We need to prune ancestors too. This is necessary to prevent
854 * quadratic behavior of shrink_dcache_parent(), but is also 883 * quadratic behavior of shrink_dcache_parent(), but is also