diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 121 |
1 files changed, 67 insertions, 54 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 79802bd790e4..8b1f8425549f 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -296,8 +296,12 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) | |||
296 | __releases(parent->d_lock) | 296 | __releases(parent->d_lock) |
297 | __releases(dentry->d_inode->i_lock) | 297 | __releases(dentry->d_inode->i_lock) |
298 | { | 298 | { |
299 | dentry->d_parent = NULL; | ||
300 | list_del(&dentry->d_u.d_child); | 299 | list_del(&dentry->d_u.d_child); |
300 | /* | ||
301 | * Inform try_to_ascend() that we are no longer attached to the | ||
302 | * dentry tree | ||
303 | */ | ||
304 | dentry->d_flags |= DCACHE_DISCONNECTED; | ||
301 | if (parent) | 305 | if (parent) |
302 | spin_unlock(&parent->d_lock); | 306 | spin_unlock(&parent->d_lock); |
303 | dentry_iput(dentry); | 307 | dentry_iput(dentry); |
@@ -1012,6 +1016,35 @@ void shrink_dcache_for_umount(struct super_block *sb) | |||
1012 | } | 1016 | } |
1013 | 1017 | ||
1014 | /* | 1018 | /* |
1019 | * This tries to ascend one level of parenthood, but | ||
1020 | * we can race with renaming, so we need to re-check | ||
1021 | * the parenthood after dropping the lock and check | ||
1022 | * that the sequence number still matches. | ||
1023 | */ | ||
1024 | static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq) | ||
1025 | { | ||
1026 | struct dentry *new = old->d_parent; | ||
1027 | |||
1028 | rcu_read_lock(); | ||
1029 | spin_unlock(&old->d_lock); | ||
1030 | spin_lock(&new->d_lock); | ||
1031 | |||
1032 | /* | ||
1033 | * might go back up the wrong parent if we have had a rename | ||
1034 | * or deletion | ||
1035 | */ | ||
1036 | if (new != old->d_parent || | ||
1037 | (old->d_flags & DCACHE_DISCONNECTED) || | ||
1038 | (!locked && read_seqretry(&rename_lock, seq))) { | ||
1039 | spin_unlock(&new->d_lock); | ||
1040 | new = NULL; | ||
1041 | } | ||
1042 | rcu_read_unlock(); | ||
1043 | return new; | ||
1044 | } | ||
1045 | |||
1046 | |||
1047 | /* | ||
1015 | * Search for at least 1 mount point in the dentry's subdirs. | 1048 | * Search for at least 1 mount point in the dentry's subdirs. |
1016 | * We descend to the next level whenever the d_subdirs | 1049 | * We descend to the next level whenever the d_subdirs |
1017 | * list is non-empty and continue searching. | 1050 | * list is non-empty and continue searching. |
@@ -1066,24 +1099,10 @@ resume: | |||
1066 | * All done at this level ... ascend and resume the search. | 1099 | * All done at this level ... ascend and resume the search. |
1067 | */ | 1100 | */ |
1068 | if (this_parent != parent) { | 1101 | if (this_parent != parent) { |
1069 | struct dentry *tmp; | 1102 | struct dentry *child = this_parent; |
1070 | struct dentry *child; | 1103 | this_parent = try_to_ascend(this_parent, locked, seq); |
1071 | 1104 | 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; | 1105 | goto rename_retry; |
1085 | } | ||
1086 | rcu_read_unlock(); | ||
1087 | next = child->d_u.d_child.next; | 1106 | next = child->d_u.d_child.next; |
1088 | goto resume; | 1107 | goto resume; |
1089 | } | 1108 | } |
@@ -1181,24 +1200,10 @@ resume: | |||
1181 | * All done at this level ... ascend and resume the search. | 1200 | * All done at this level ... ascend and resume the search. |
1182 | */ | 1201 | */ |
1183 | if (this_parent != parent) { | 1202 | if (this_parent != parent) { |
1184 | struct dentry *tmp; | 1203 | struct dentry *child = this_parent; |
1185 | struct dentry *child; | 1204 | this_parent = try_to_ascend(this_parent, locked, seq); |
1186 | 1205 | 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; | 1206 | goto rename_retry; |
1200 | } | ||
1201 | rcu_read_unlock(); | ||
1202 | next = child->d_u.d_child.next; | 1207 | next = child->d_u.d_child.next; |
1203 | goto resume; | 1208 | goto resume; |
1204 | } | 1209 | } |
@@ -1523,6 +1528,28 @@ struct dentry * d_alloc_root(struct inode * root_inode) | |||
1523 | } | 1528 | } |
1524 | EXPORT_SYMBOL(d_alloc_root); | 1529 | EXPORT_SYMBOL(d_alloc_root); |
1525 | 1530 | ||
1531 | static struct dentry * __d_find_any_alias(struct inode *inode) | ||
1532 | { | ||
1533 | struct dentry *alias; | ||
1534 | |||
1535 | if (list_empty(&inode->i_dentry)) | ||
1536 | return NULL; | ||
1537 | alias = list_first_entry(&inode->i_dentry, struct dentry, d_alias); | ||
1538 | __dget(alias); | ||
1539 | return alias; | ||
1540 | } | ||
1541 | |||
1542 | static struct dentry * d_find_any_alias(struct inode *inode) | ||
1543 | { | ||
1544 | struct dentry *de; | ||
1545 | |||
1546 | spin_lock(&inode->i_lock); | ||
1547 | de = __d_find_any_alias(inode); | ||
1548 | spin_unlock(&inode->i_lock); | ||
1549 | return de; | ||
1550 | } | ||
1551 | |||
1552 | |||
1526 | /** | 1553 | /** |
1527 | * d_obtain_alias - find or allocate a dentry for a given inode | 1554 | * d_obtain_alias - find or allocate a dentry for a given inode |
1528 | * @inode: inode to allocate the dentry for | 1555 | * @inode: inode to allocate the dentry for |
@@ -1552,7 +1579,7 @@ struct dentry *d_obtain_alias(struct inode *inode) | |||
1552 | if (IS_ERR(inode)) | 1579 | if (IS_ERR(inode)) |
1553 | return ERR_CAST(inode); | 1580 | return ERR_CAST(inode); |
1554 | 1581 | ||
1555 | res = d_find_alias(inode); | 1582 | res = d_find_any_alias(inode); |
1556 | if (res) | 1583 | if (res) |
1557 | goto out_iput; | 1584 | goto out_iput; |
1558 | 1585 | ||
@@ -1565,7 +1592,7 @@ struct dentry *d_obtain_alias(struct inode *inode) | |||
1565 | 1592 | ||
1566 | 1593 | ||
1567 | spin_lock(&inode->i_lock); | 1594 | spin_lock(&inode->i_lock); |
1568 | res = __d_find_alias(inode, 0); | 1595 | res = __d_find_any_alias(inode); |
1569 | if (res) { | 1596 | if (res) { |
1570 | spin_unlock(&inode->i_lock); | 1597 | spin_unlock(&inode->i_lock); |
1571 | dput(tmp); | 1598 | dput(tmp); |
@@ -2920,28 +2947,14 @@ resume: | |||
2920 | spin_unlock(&dentry->d_lock); | 2947 | spin_unlock(&dentry->d_lock); |
2921 | } | 2948 | } |
2922 | if (this_parent != root) { | 2949 | if (this_parent != root) { |
2923 | struct dentry *tmp; | 2950 | struct dentry *child = this_parent; |
2924 | struct dentry *child; | ||
2925 | |||
2926 | tmp = this_parent->d_parent; | ||
2927 | if (!(this_parent->d_flags & DCACHE_GENOCIDE)) { | 2951 | if (!(this_parent->d_flags & DCACHE_GENOCIDE)) { |
2928 | this_parent->d_flags |= DCACHE_GENOCIDE; | 2952 | this_parent->d_flags |= DCACHE_GENOCIDE; |
2929 | this_parent->d_count--; | 2953 | this_parent->d_count--; |
2930 | } | 2954 | } |
2931 | rcu_read_lock(); | 2955 | this_parent = try_to_ascend(this_parent, locked, seq); |
2932 | spin_unlock(&this_parent->d_lock); | 2956 | if (!this_parent) |
2933 | child = this_parent; | ||
2934 | this_parent = tmp; | ||
2935 | spin_lock(&this_parent->d_lock); | ||
2936 | /* might go back up the wrong parent if we have had a rename | ||
2937 | * or deletion */ | ||
2938 | if (this_parent != child->d_parent || | ||
2939 | (!locked && read_seqretry(&rename_lock, seq))) { | ||
2940 | spin_unlock(&this_parent->d_lock); | ||
2941 | rcu_read_unlock(); | ||
2942 | goto rename_retry; | 2957 | goto rename_retry; |
2943 | } | ||
2944 | rcu_read_unlock(); | ||
2945 | next = child->d_u.d_child.next; | 2958 | next = child->d_u.d_child.next; |
2946 | goto resume; | 2959 | goto resume; |
2947 | } | 2960 | } |