aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-15 18:29:21 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-15 18:29:21 -0400
commitc826cb7dfce80512c26c984350077a25046bd215 (patch)
tree6230dc7babebfa008d67bd309de7562a0292ab8b /fs/dcache.c
parent76ca07832842100b14a31ad8996dab7b0c28aa42 (diff)
dcache.c: create helper function for duplicated functionality
This creates a helper function for he "try to ascend into the parent directory" case, which was written out in triplicate before. With all the locking and subtle sequence number stuff, we really don't want to duplicate that kind of code. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/dcache.c')
-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 }