diff options
| -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 |
