diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/dcache.c | 53 |
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 | ||
533 | static 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(); | ||
542 | again: | ||
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 |