aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/dcache.c88
1 files changed, 37 insertions, 51 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 611ffe928c03..361882a14ccb 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1012,6 +1012,34 @@ void shrink_dcache_for_umount(struct super_block *sb)
1012} 1012}
1013 1013
1014/* 1014/*
1015 * This tries to ascend one level of parenthood, but
1016 * we can race with renaming, so we need to re-check
1017 * the parenthood after dropping the lock and check
1018 * that the sequence number still matches.
1019 */
1020static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq)
1021{
1022 struct dentry *new = old->d_parent;
1023
1024 rcu_read_lock();
1025 spin_unlock(&old->d_lock);
1026 spin_lock(&new->d_lock);
1027
1028 /*
1029 * might go back up the wrong parent if we have had a rename
1030 * or deletion
1031 */
1032 if (new != old->d_parent ||
1033 (!locked && read_seqretry(&rename_lock, seq))) {
1034 spin_unlock(&new->d_lock);
1035 new = NULL;
1036 }
1037 rcu_read_unlock();
1038 return new;
1039}
1040
1041
1042/*
1015 * Search for at least 1 mount point in the dentry's subdirs. 1043 * Search for at least 1 mount point in the dentry's subdirs.
1016 * We descend to the next level whenever the d_subdirs 1044 * We descend to the next level whenever the d_subdirs
1017 * list is non-empty and continue searching. 1045 * list is non-empty and continue searching.
@@ -1066,24 +1094,10 @@ resume:
1066 * All done at this level ... ascend and resume the search. 1094 * All done at this level ... ascend and resume the search.
1067 */ 1095 */
1068 if (this_parent != parent) { 1096 if (this_parent != parent) {
1069 struct dentry *tmp; 1097 struct dentry *child = this_parent;
1070 struct dentry *child; 1098 this_parent = try_to_ascend(this_parent, locked, seq);
1071 1099 if (!this_parent)
1072 tmp = this_parent->d_parent;
1073 rcu_read_lock();
1074 spin_unlock(&this_parent->d_lock);
1075 child = this_parent;
1076 this_parent = tmp;
1077 spin_lock(&this_parent->d_lock);
1078 /* might go back up the wrong parent if we have had a rename
1079 * or deletion */
1080 if (this_parent != child->d_parent ||
1081 (!locked && read_seqretry(&rename_lock, seq))) {
1082 spin_unlock(&this_parent->d_lock);
1083 rcu_read_unlock();
1084 goto rename_retry; 1100 goto rename_retry;
1085 }
1086 rcu_read_unlock();
1087 next = child->d_u.d_child.next; 1101 next = child->d_u.d_child.next;
1088 goto resume; 1102 goto resume;
1089 } 1103 }
@@ -1181,24 +1195,10 @@ resume:
1181 * All done at this level ... ascend and resume the search. 1195 * All done at this level ... ascend and resume the search.
1182 */ 1196 */
1183 if (this_parent != parent) { 1197 if (this_parent != parent) {
1184 struct dentry *tmp; 1198 struct dentry *child = this_parent;
1185 struct dentry *child; 1199 this_parent = try_to_ascend(this_parent, locked, seq);
1186 1200 if (!this_parent)
1187 tmp = this_parent->d_parent;
1188 rcu_read_lock();
1189 spin_unlock(&this_parent->d_lock);
1190 child = this_parent;
1191 this_parent = tmp;
1192 spin_lock(&this_parent->d_lock);
1193 /* might go back up the wrong parent if we have had a rename
1194 * or deletion */
1195 if (this_parent != child->d_parent ||
1196 (!locked && read_seqretry(&rename_lock, seq))) {
1197 spin_unlock(&this_parent->d_lock);
1198 rcu_read_unlock();
1199 goto rename_retry; 1201 goto rename_retry;
1200 }
1201 rcu_read_unlock();
1202 next = child->d_u.d_child.next; 1202 next = child->d_u.d_child.next;
1203 goto resume; 1203 goto resume;
1204 } 1204 }
@@ -2942,28 +2942,14 @@ resume:
2942 spin_unlock(&dentry->d_lock); 2942 spin_unlock(&dentry->d_lock);
2943 } 2943 }
2944 if (this_parent != root) { 2944 if (this_parent != root) {
2945 struct dentry *tmp; 2945 struct dentry *child = this_parent;
2946 struct dentry *child;
2947
2948 tmp = this_parent->d_parent;
2949 if (!(this_parent->d_flags & DCACHE_GENOCIDE)) { 2946 if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
2950 this_parent->d_flags |= DCACHE_GENOCIDE; 2947 this_parent->d_flags |= DCACHE_GENOCIDE;
2951 this_parent->d_count--; 2948 this_parent->d_count--;
2952 } 2949 }
2953 rcu_read_lock(); 2950 this_parent = try_to_ascend(this_parent, locked, seq);
2954 spin_unlock(&this_parent->d_lock); 2951 if (!this_parent)
2955 child = this_parent;
2956 this_parent = tmp;
2957 spin_lock(&this_parent->d_lock);
2958 /* might go back up the wrong parent if we have had a rename
2959 * or deletion */
2960 if (this_parent != child->d_parent ||
2961 (!locked && read_seqretry(&rename_lock, seq))) {
2962 spin_unlock(&this_parent->d_lock);
2963 rcu_read_unlock();
2964 goto rename_retry; 2952 goto rename_retry;
2965 }
2966 rcu_read_unlock();
2967 next = child->d_u.d_child.next; 2953 next = child->d_u.d_child.next;
2968 goto resume; 2954 goto resume;
2969 } 2955 }