diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-07 17:36:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-07 17:36:57 -0400 |
commit | dc0755cdb16cb129c4054c85d62bce83a18bcbcf (patch) | |
tree | 17f585ce18524ec029cb1169cdba256c83288101 | |
parent | c7c4591db64dbd1e504bc4e2806d7ef290a3c81b (diff) | |
parent | f0d3b3ded999daae1cf451d051018038c0a05bae (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs pile 2 (of many) from Al Viro:
"Mostly Miklos' series this time"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
constify dcache.c inlined helpers where possible
fuse: drop dentry on failed revalidate
fuse: clean up return in fuse_dentry_revalidate()
fuse: use d_materialise_unique()
sysfs: use check_submounts_and_drop()
nfs: use check_submounts_and_drop()
gfs2: use check_submounts_and_drop()
afs: use check_submounts_and_drop()
vfs: check unlinked ancestors before mount
vfs: check submounts and drop atomically
vfs: add d_walk()
vfs: restructure d_genocide()
-rw-r--r-- | fs/afs/dir.c | 10 | ||||
-rw-r--r-- | fs/dcache.c | 411 | ||||
-rw-r--r-- | fs/fuse/dir.c | 97 | ||||
-rw-r--r-- | fs/gfs2/dentry.c | 9 | ||||
-rw-r--r-- | fs/internal.h | 1 | ||||
-rw-r--r-- | fs/namespace.c | 11 | ||||
-rw-r--r-- | fs/nfs/dir.c | 9 | ||||
-rw-r--r-- | fs/sysfs/dir.c | 20 | ||||
-rw-r--r-- | include/linux/dcache.h | 13 |
9 files changed, 323 insertions, 258 deletions
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 34494fbead0a..0b74d3176ab7 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -685,16 +685,12 @@ not_found: | |||
685 | spin_unlock(&dentry->d_lock); | 685 | spin_unlock(&dentry->d_lock); |
686 | 686 | ||
687 | out_bad: | 687 | out_bad: |
688 | if (dentry->d_inode) { | 688 | /* don't unhash if we have submounts */ |
689 | /* don't unhash if we have submounts */ | 689 | if (check_submounts_and_drop(dentry) != 0) |
690 | if (have_submounts(dentry)) | 690 | goto out_skip; |
691 | goto out_skip; | ||
692 | } | ||
693 | 691 | ||
694 | _debug("dropping dentry %s/%s", | 692 | _debug("dropping dentry %s/%s", |
695 | parent->d_name.name, dentry->d_name.name); | 693 | parent->d_name.name, dentry->d_name.name); |
696 | shrink_dcache_parent(dentry); | ||
697 | d_drop(dentry); | ||
698 | dput(parent); | 694 | dput(parent); |
699 | key_put(key); | 695 | key_put(key); |
700 | 696 | ||
diff --git a/fs/dcache.c b/fs/dcache.c index 5aa53bc056ba..761e31bacbc2 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -1031,34 +1031,56 @@ static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq | |||
1031 | return new; | 1031 | return new; |
1032 | } | 1032 | } |
1033 | 1033 | ||
1034 | /** | ||
1035 | * enum d_walk_ret - action to talke during tree walk | ||
1036 | * @D_WALK_CONTINUE: contrinue walk | ||
1037 | * @D_WALK_QUIT: quit walk | ||
1038 | * @D_WALK_NORETRY: quit when retry is needed | ||
1039 | * @D_WALK_SKIP: skip this dentry and its children | ||
1040 | */ | ||
1041 | enum d_walk_ret { | ||
1042 | D_WALK_CONTINUE, | ||
1043 | D_WALK_QUIT, | ||
1044 | D_WALK_NORETRY, | ||
1045 | D_WALK_SKIP, | ||
1046 | }; | ||
1034 | 1047 | ||
1035 | /* | ||
1036 | * Search for at least 1 mount point in the dentry's subdirs. | ||
1037 | * We descend to the next level whenever the d_subdirs | ||
1038 | * list is non-empty and continue searching. | ||
1039 | */ | ||
1040 | |||
1041 | /** | 1048 | /** |
1042 | * have_submounts - check for mounts over a dentry | 1049 | * d_walk - walk the dentry tree |
1043 | * @parent: dentry to check. | 1050 | * @parent: start of walk |
1051 | * @data: data passed to @enter() and @finish() | ||
1052 | * @enter: callback when first entering the dentry | ||
1053 | * @finish: callback when successfully finished the walk | ||
1044 | * | 1054 | * |
1045 | * Return true if the parent or its subdirectories contain | 1055 | * The @enter() and @finish() callbacks are called with d_lock held. |
1046 | * a mount point | ||
1047 | */ | 1056 | */ |
1048 | int have_submounts(struct dentry *parent) | 1057 | static void d_walk(struct dentry *parent, void *data, |
1058 | enum d_walk_ret (*enter)(void *, struct dentry *), | ||
1059 | void (*finish)(void *)) | ||
1049 | { | 1060 | { |
1050 | struct dentry *this_parent; | 1061 | struct dentry *this_parent; |
1051 | struct list_head *next; | 1062 | struct list_head *next; |
1052 | unsigned seq; | 1063 | unsigned seq; |
1053 | int locked = 0; | 1064 | int locked = 0; |
1065 | enum d_walk_ret ret; | ||
1066 | bool retry = true; | ||
1054 | 1067 | ||
1055 | seq = read_seqbegin(&rename_lock); | 1068 | seq = read_seqbegin(&rename_lock); |
1056 | again: | 1069 | again: |
1057 | this_parent = parent; | 1070 | this_parent = parent; |
1058 | |||
1059 | if (d_mountpoint(parent)) | ||
1060 | goto positive; | ||
1061 | spin_lock(&this_parent->d_lock); | 1071 | spin_lock(&this_parent->d_lock); |
1072 | |||
1073 | ret = enter(data, this_parent); | ||
1074 | switch (ret) { | ||
1075 | case D_WALK_CONTINUE: | ||
1076 | break; | ||
1077 | case D_WALK_QUIT: | ||
1078 | case D_WALK_SKIP: | ||
1079 | goto out_unlock; | ||
1080 | case D_WALK_NORETRY: | ||
1081 | retry = false; | ||
1082 | break; | ||
1083 | } | ||
1062 | repeat: | 1084 | repeat: |
1063 | next = this_parent->d_subdirs.next; | 1085 | next = this_parent->d_subdirs.next; |
1064 | resume: | 1086 | resume: |
@@ -1068,12 +1090,22 @@ resume: | |||
1068 | next = tmp->next; | 1090 | next = tmp->next; |
1069 | 1091 | ||
1070 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | 1092 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); |
1071 | /* Have we found a mount point ? */ | 1093 | |
1072 | if (d_mountpoint(dentry)) { | 1094 | ret = enter(data, dentry); |
1095 | switch (ret) { | ||
1096 | case D_WALK_CONTINUE: | ||
1097 | break; | ||
1098 | case D_WALK_QUIT: | ||
1073 | spin_unlock(&dentry->d_lock); | 1099 | spin_unlock(&dentry->d_lock); |
1074 | spin_unlock(&this_parent->d_lock); | 1100 | goto out_unlock; |
1075 | goto positive; | 1101 | case D_WALK_NORETRY: |
1102 | retry = false; | ||
1103 | break; | ||
1104 | case D_WALK_SKIP: | ||
1105 | spin_unlock(&dentry->d_lock); | ||
1106 | continue; | ||
1076 | } | 1107 | } |
1108 | |||
1077 | if (!list_empty(&dentry->d_subdirs)) { | 1109 | if (!list_empty(&dentry->d_subdirs)) { |
1078 | spin_unlock(&this_parent->d_lock); | 1110 | spin_unlock(&this_parent->d_lock); |
1079 | spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); | 1111 | spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); |
@@ -1094,29 +1126,97 @@ resume: | |||
1094 | next = child->d_u.d_child.next; | 1126 | next = child->d_u.d_child.next; |
1095 | goto resume; | 1127 | goto resume; |
1096 | } | 1128 | } |
1097 | spin_unlock(&this_parent->d_lock); | 1129 | if (!locked && read_seqretry(&rename_lock, seq)) { |
1098 | if (!locked && read_seqretry(&rename_lock, seq)) | 1130 | spin_unlock(&this_parent->d_lock); |
1099 | goto rename_retry; | ||
1100 | if (locked) | ||
1101 | write_sequnlock(&rename_lock); | ||
1102 | return 0; /* No mount points found in tree */ | ||
1103 | positive: | ||
1104 | if (!locked && read_seqretry(&rename_lock, seq)) | ||
1105 | goto rename_retry; | 1131 | goto rename_retry; |
1132 | } | ||
1133 | if (finish) | ||
1134 | finish(data); | ||
1135 | |||
1136 | out_unlock: | ||
1137 | spin_unlock(&this_parent->d_lock); | ||
1106 | if (locked) | 1138 | if (locked) |
1107 | write_sequnlock(&rename_lock); | 1139 | write_sequnlock(&rename_lock); |
1108 | return 1; | 1140 | return; |
1109 | 1141 | ||
1110 | rename_retry: | 1142 | rename_retry: |
1143 | if (!retry) | ||
1144 | return; | ||
1111 | if (locked) | 1145 | if (locked) |
1112 | goto again; | 1146 | goto again; |
1113 | locked = 1; | 1147 | locked = 1; |
1114 | write_seqlock(&rename_lock); | 1148 | write_seqlock(&rename_lock); |
1115 | goto again; | 1149 | goto again; |
1116 | } | 1150 | } |
1151 | |||
1152 | /* | ||
1153 | * Search for at least 1 mount point in the dentry's subdirs. | ||
1154 | * We descend to the next level whenever the d_subdirs | ||
1155 | * list is non-empty and continue searching. | ||
1156 | */ | ||
1157 | |||
1158 | /** | ||
1159 | * have_submounts - check for mounts over a dentry | ||
1160 | * @parent: dentry to check. | ||
1161 | * | ||
1162 | * Return true if the parent or its subdirectories contain | ||
1163 | * a mount point | ||
1164 | */ | ||
1165 | |||
1166 | static enum d_walk_ret check_mount(void *data, struct dentry *dentry) | ||
1167 | { | ||
1168 | int *ret = data; | ||
1169 | if (d_mountpoint(dentry)) { | ||
1170 | *ret = 1; | ||
1171 | return D_WALK_QUIT; | ||
1172 | } | ||
1173 | return D_WALK_CONTINUE; | ||
1174 | } | ||
1175 | |||
1176 | int have_submounts(struct dentry *parent) | ||
1177 | { | ||
1178 | int ret = 0; | ||
1179 | |||
1180 | d_walk(parent, &ret, check_mount, NULL); | ||
1181 | |||
1182 | return ret; | ||
1183 | } | ||
1117 | EXPORT_SYMBOL(have_submounts); | 1184 | EXPORT_SYMBOL(have_submounts); |
1118 | 1185 | ||
1119 | /* | 1186 | /* |
1187 | * Called by mount code to set a mountpoint and check if the mountpoint is | ||
1188 | * reachable (e.g. NFS can unhash a directory dentry and then the complete | ||
1189 | * subtree can become unreachable). | ||
1190 | * | ||
1191 | * Only one of check_submounts_and_drop() and d_set_mounted() must succeed. For | ||
1192 | * this reason take rename_lock and d_lock on dentry and ancestors. | ||
1193 | */ | ||
1194 | int d_set_mounted(struct dentry *dentry) | ||
1195 | { | ||
1196 | struct dentry *p; | ||
1197 | int ret = -ENOENT; | ||
1198 | write_seqlock(&rename_lock); | ||
1199 | for (p = dentry->d_parent; !IS_ROOT(p); p = p->d_parent) { | ||
1200 | /* Need exclusion wrt. check_submounts_and_drop() */ | ||
1201 | spin_lock(&p->d_lock); | ||
1202 | if (unlikely(d_unhashed(p))) { | ||
1203 | spin_unlock(&p->d_lock); | ||
1204 | goto out; | ||
1205 | } | ||
1206 | spin_unlock(&p->d_lock); | ||
1207 | } | ||
1208 | spin_lock(&dentry->d_lock); | ||
1209 | if (!d_unlinked(dentry)) { | ||
1210 | dentry->d_flags |= DCACHE_MOUNTED; | ||
1211 | ret = 0; | ||
1212 | } | ||
1213 | spin_unlock(&dentry->d_lock); | ||
1214 | out: | ||
1215 | write_sequnlock(&rename_lock); | ||
1216 | return ret; | ||
1217 | } | ||
1218 | |||
1219 | /* | ||
1120 | * Search the dentry child list of the specified parent, | 1220 | * Search the dentry child list of the specified parent, |
1121 | * and move any unused dentries to the end of the unused | 1221 | * and move any unused dentries to the end of the unused |
1122 | * list for prune_dcache(). We descend to the next level | 1222 | * list for prune_dcache(). We descend to the next level |
@@ -1130,93 +1230,46 @@ EXPORT_SYMBOL(have_submounts); | |||
1130 | * drop the lock and return early due to latency | 1230 | * drop the lock and return early due to latency |
1131 | * constraints. | 1231 | * constraints. |
1132 | */ | 1232 | */ |
1133 | static int select_parent(struct dentry *parent, struct list_head *dispose) | ||
1134 | { | ||
1135 | struct dentry *this_parent; | ||
1136 | struct list_head *next; | ||
1137 | unsigned seq; | ||
1138 | int found = 0; | ||
1139 | int locked = 0; | ||
1140 | 1233 | ||
1141 | seq = read_seqbegin(&rename_lock); | 1234 | struct select_data { |
1142 | again: | 1235 | struct dentry *start; |
1143 | this_parent = parent; | 1236 | struct list_head dispose; |
1144 | spin_lock(&this_parent->d_lock); | 1237 | int found; |
1145 | repeat: | 1238 | }; |
1146 | next = this_parent->d_subdirs.next; | ||
1147 | resume: | ||
1148 | while (next != &this_parent->d_subdirs) { | ||
1149 | struct list_head *tmp = next; | ||
1150 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); | ||
1151 | next = tmp->next; | ||
1152 | |||
1153 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
1154 | 1239 | ||
1155 | /* | 1240 | static enum d_walk_ret select_collect(void *_data, struct dentry *dentry) |
1156 | * move only zero ref count dentries to the dispose list. | 1241 | { |
1157 | * | 1242 | struct select_data *data = _data; |
1158 | * Those which are presently on the shrink list, being processed | 1243 | enum d_walk_ret ret = D_WALK_CONTINUE; |
1159 | * by shrink_dentry_list(), shouldn't be moved. Otherwise the | ||
1160 | * loop in shrink_dcache_parent() might not make any progress | ||
1161 | * and loop forever. | ||
1162 | */ | ||
1163 | if (dentry->d_lockref.count) { | ||
1164 | dentry_lru_del(dentry); | ||
1165 | } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) { | ||
1166 | dentry_lru_move_list(dentry, dispose); | ||
1167 | dentry->d_flags |= DCACHE_SHRINK_LIST; | ||
1168 | found++; | ||
1169 | } | ||
1170 | /* | ||
1171 | * We can return to the caller if we have found some (this | ||
1172 | * ensures forward progress). We'll be coming back to find | ||
1173 | * the rest. | ||
1174 | */ | ||
1175 | if (found && need_resched()) { | ||
1176 | spin_unlock(&dentry->d_lock); | ||
1177 | goto out; | ||
1178 | } | ||
1179 | 1244 | ||
1180 | /* | 1245 | if (data->start == dentry) |
1181 | * Descend a level if the d_subdirs list is non-empty. | 1246 | goto out; |
1182 | */ | ||
1183 | if (!list_empty(&dentry->d_subdirs)) { | ||
1184 | spin_unlock(&this_parent->d_lock); | ||
1185 | spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); | ||
1186 | this_parent = dentry; | ||
1187 | spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); | ||
1188 | goto repeat; | ||
1189 | } | ||
1190 | 1247 | ||
1191 | spin_unlock(&dentry->d_lock); | ||
1192 | } | ||
1193 | /* | 1248 | /* |
1194 | * All done at this level ... ascend and resume the search. | 1249 | * move only zero ref count dentries to the dispose list. |
1250 | * | ||
1251 | * Those which are presently on the shrink list, being processed | ||
1252 | * by shrink_dentry_list(), shouldn't be moved. Otherwise the | ||
1253 | * loop in shrink_dcache_parent() might not make any progress | ||
1254 | * and loop forever. | ||
1195 | */ | 1255 | */ |
1196 | if (this_parent != parent) { | 1256 | if (dentry->d_lockref.count) { |
1197 | struct dentry *child = this_parent; | 1257 | dentry_lru_del(dentry); |
1198 | this_parent = try_to_ascend(this_parent, locked, seq); | 1258 | } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) { |
1199 | if (!this_parent) | 1259 | dentry_lru_move_list(dentry, &data->dispose); |
1200 | goto rename_retry; | 1260 | dentry->d_flags |= DCACHE_SHRINK_LIST; |
1201 | next = child->d_u.d_child.next; | 1261 | data->found++; |
1202 | goto resume; | 1262 | ret = D_WALK_NORETRY; |
1203 | } | 1263 | } |
1264 | /* | ||
1265 | * We can return to the caller if we have found some (this | ||
1266 | * ensures forward progress). We'll be coming back to find | ||
1267 | * the rest. | ||
1268 | */ | ||
1269 | if (data->found && need_resched()) | ||
1270 | ret = D_WALK_QUIT; | ||
1204 | out: | 1271 | out: |
1205 | spin_unlock(&this_parent->d_lock); | 1272 | return ret; |
1206 | if (!locked && read_seqretry(&rename_lock, seq)) | ||
1207 | goto rename_retry; | ||
1208 | if (locked) | ||
1209 | write_sequnlock(&rename_lock); | ||
1210 | return found; | ||
1211 | |||
1212 | rename_retry: | ||
1213 | if (found) | ||
1214 | return found; | ||
1215 | if (locked) | ||
1216 | goto again; | ||
1217 | locked = 1; | ||
1218 | write_seqlock(&rename_lock); | ||
1219 | goto again; | ||
1220 | } | 1273 | } |
1221 | 1274 | ||
1222 | /** | 1275 | /** |
@@ -1225,18 +1278,90 @@ rename_retry: | |||
1225 | * | 1278 | * |
1226 | * Prune the dcache to remove unused children of the parent dentry. | 1279 | * Prune the dcache to remove unused children of the parent dentry. |
1227 | */ | 1280 | */ |
1228 | void shrink_dcache_parent(struct dentry * parent) | 1281 | void shrink_dcache_parent(struct dentry *parent) |
1229 | { | 1282 | { |
1230 | LIST_HEAD(dispose); | 1283 | for (;;) { |
1231 | int found; | 1284 | struct select_data data; |
1285 | |||
1286 | INIT_LIST_HEAD(&data.dispose); | ||
1287 | data.start = parent; | ||
1288 | data.found = 0; | ||
1232 | 1289 | ||
1233 | while ((found = select_parent(parent, &dispose)) != 0) { | 1290 | d_walk(parent, &data, select_collect, NULL); |
1234 | shrink_dentry_list(&dispose); | 1291 | if (!data.found) |
1292 | break; | ||
1293 | |||
1294 | shrink_dentry_list(&data.dispose); | ||
1235 | cond_resched(); | 1295 | cond_resched(); |
1236 | } | 1296 | } |
1237 | } | 1297 | } |
1238 | EXPORT_SYMBOL(shrink_dcache_parent); | 1298 | EXPORT_SYMBOL(shrink_dcache_parent); |
1239 | 1299 | ||
1300 | static enum d_walk_ret check_and_collect(void *_data, struct dentry *dentry) | ||
1301 | { | ||
1302 | struct select_data *data = _data; | ||
1303 | |||
1304 | if (d_mountpoint(dentry)) { | ||
1305 | data->found = -EBUSY; | ||
1306 | return D_WALK_QUIT; | ||
1307 | } | ||
1308 | |||
1309 | return select_collect(_data, dentry); | ||
1310 | } | ||
1311 | |||
1312 | static void check_and_drop(void *_data) | ||
1313 | { | ||
1314 | struct select_data *data = _data; | ||
1315 | |||
1316 | if (d_mountpoint(data->start)) | ||
1317 | data->found = -EBUSY; | ||
1318 | if (!data->found) | ||
1319 | __d_drop(data->start); | ||
1320 | } | ||
1321 | |||
1322 | /** | ||
1323 | * check_submounts_and_drop - prune dcache, check for submounts and drop | ||
1324 | * | ||
1325 | * All done as a single atomic operation relative to has_unlinked_ancestor(). | ||
1326 | * Returns 0 if successfully unhashed @parent. If there were submounts then | ||
1327 | * return -EBUSY. | ||
1328 | * | ||
1329 | * @dentry: dentry to prune and drop | ||
1330 | */ | ||
1331 | int check_submounts_and_drop(struct dentry *dentry) | ||
1332 | { | ||
1333 | int ret = 0; | ||
1334 | |||
1335 | /* Negative dentries can be dropped without further checks */ | ||
1336 | if (!dentry->d_inode) { | ||
1337 | d_drop(dentry); | ||
1338 | goto out; | ||
1339 | } | ||
1340 | |||
1341 | for (;;) { | ||
1342 | struct select_data data; | ||
1343 | |||
1344 | INIT_LIST_HEAD(&data.dispose); | ||
1345 | data.start = dentry; | ||
1346 | data.found = 0; | ||
1347 | |||
1348 | d_walk(dentry, &data, check_and_collect, check_and_drop); | ||
1349 | ret = data.found; | ||
1350 | |||
1351 | if (!list_empty(&data.dispose)) | ||
1352 | shrink_dentry_list(&data.dispose); | ||
1353 | |||
1354 | if (ret <= 0) | ||
1355 | break; | ||
1356 | |||
1357 | cond_resched(); | ||
1358 | } | ||
1359 | |||
1360 | out: | ||
1361 | return ret; | ||
1362 | } | ||
1363 | EXPORT_SYMBOL(check_submounts_and_drop); | ||
1364 | |||
1240 | /** | 1365 | /** |
1241 | * __d_alloc - allocate a dcache entry | 1366 | * __d_alloc - allocate a dcache entry |
1242 | * @sb: filesystem it will belong to | 1367 | * @sb: filesystem it will belong to |
@@ -2928,68 +3053,24 @@ int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry) | |||
2928 | return result; | 3053 | return result; |
2929 | } | 3054 | } |
2930 | 3055 | ||
2931 | void d_genocide(struct dentry *root) | 3056 | static enum d_walk_ret d_genocide_kill(void *data, struct dentry *dentry) |
2932 | { | 3057 | { |
2933 | struct dentry *this_parent; | 3058 | struct dentry *root = data; |
2934 | struct list_head *next; | 3059 | if (dentry != root) { |
2935 | unsigned seq; | 3060 | if (d_unhashed(dentry) || !dentry->d_inode) |
2936 | int locked = 0; | 3061 | return D_WALK_SKIP; |
2937 | 3062 | ||
2938 | seq = read_seqbegin(&rename_lock); | ||
2939 | again: | ||
2940 | this_parent = root; | ||
2941 | spin_lock(&this_parent->d_lock); | ||
2942 | repeat: | ||
2943 | next = this_parent->d_subdirs.next; | ||
2944 | resume: | ||
2945 | while (next != &this_parent->d_subdirs) { | ||
2946 | struct list_head *tmp = next; | ||
2947 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); | ||
2948 | next = tmp->next; | ||
2949 | |||
2950 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
2951 | if (d_unhashed(dentry) || !dentry->d_inode) { | ||
2952 | spin_unlock(&dentry->d_lock); | ||
2953 | continue; | ||
2954 | } | ||
2955 | if (!list_empty(&dentry->d_subdirs)) { | ||
2956 | spin_unlock(&this_parent->d_lock); | ||
2957 | spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); | ||
2958 | this_parent = dentry; | ||
2959 | spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); | ||
2960 | goto repeat; | ||
2961 | } | ||
2962 | if (!(dentry->d_flags & DCACHE_GENOCIDE)) { | 3063 | if (!(dentry->d_flags & DCACHE_GENOCIDE)) { |
2963 | dentry->d_flags |= DCACHE_GENOCIDE; | 3064 | dentry->d_flags |= DCACHE_GENOCIDE; |
2964 | dentry->d_lockref.count--; | 3065 | dentry->d_lockref.count--; |
2965 | } | 3066 | } |
2966 | spin_unlock(&dentry->d_lock); | ||
2967 | } | ||
2968 | if (this_parent != root) { | ||
2969 | struct dentry *child = this_parent; | ||
2970 | if (!(this_parent->d_flags & DCACHE_GENOCIDE)) { | ||
2971 | this_parent->d_flags |= DCACHE_GENOCIDE; | ||
2972 | this_parent->d_lockref.count--; | ||
2973 | } | ||
2974 | this_parent = try_to_ascend(this_parent, locked, seq); | ||
2975 | if (!this_parent) | ||
2976 | goto rename_retry; | ||
2977 | next = child->d_u.d_child.next; | ||
2978 | goto resume; | ||
2979 | } | 3067 | } |
2980 | spin_unlock(&this_parent->d_lock); | 3068 | return D_WALK_CONTINUE; |
2981 | if (!locked && read_seqretry(&rename_lock, seq)) | 3069 | } |
2982 | goto rename_retry; | ||
2983 | if (locked) | ||
2984 | write_sequnlock(&rename_lock); | ||
2985 | return; | ||
2986 | 3070 | ||
2987 | rename_retry: | 3071 | void d_genocide(struct dentry *parent) |
2988 | if (locked) | 3072 | { |
2989 | goto again; | 3073 | d_walk(parent, parent, d_genocide_kill, NULL); |
2990 | locked = 1; | ||
2991 | write_seqlock(&rename_lock); | ||
2992 | goto again; | ||
2993 | } | 3074 | } |
2994 | 3075 | ||
2995 | void d_tmpfile(struct dentry *dentry, struct inode *inode) | 3076 | void d_tmpfile(struct dentry *dentry, struct inode *inode) |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 72a5d5b04494..0e6961aae6c0 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -182,10 +182,11 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) | |||
182 | struct inode *inode; | 182 | struct inode *inode; |
183 | struct dentry *parent; | 183 | struct dentry *parent; |
184 | struct fuse_conn *fc; | 184 | struct fuse_conn *fc; |
185 | int ret; | ||
185 | 186 | ||
186 | inode = ACCESS_ONCE(entry->d_inode); | 187 | inode = ACCESS_ONCE(entry->d_inode); |
187 | if (inode && is_bad_inode(inode)) | 188 | if (inode && is_bad_inode(inode)) |
188 | return 0; | 189 | goto invalid; |
189 | else if (fuse_dentry_time(entry) < get_jiffies_64()) { | 190 | else if (fuse_dentry_time(entry) < get_jiffies_64()) { |
190 | int err; | 191 | int err; |
191 | struct fuse_entry_out outarg; | 192 | struct fuse_entry_out outarg; |
@@ -195,20 +196,23 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) | |||
195 | 196 | ||
196 | /* For negative dentries, always do a fresh lookup */ | 197 | /* For negative dentries, always do a fresh lookup */ |
197 | if (!inode) | 198 | if (!inode) |
198 | return 0; | 199 | goto invalid; |
199 | 200 | ||
201 | ret = -ECHILD; | ||
200 | if (flags & LOOKUP_RCU) | 202 | if (flags & LOOKUP_RCU) |
201 | return -ECHILD; | 203 | goto out; |
202 | 204 | ||
203 | fc = get_fuse_conn(inode); | 205 | fc = get_fuse_conn(inode); |
204 | req = fuse_get_req_nopages(fc); | 206 | req = fuse_get_req_nopages(fc); |
207 | ret = PTR_ERR(req); | ||
205 | if (IS_ERR(req)) | 208 | if (IS_ERR(req)) |
206 | return 0; | 209 | goto out; |
207 | 210 | ||
208 | forget = fuse_alloc_forget(); | 211 | forget = fuse_alloc_forget(); |
209 | if (!forget) { | 212 | if (!forget) { |
210 | fuse_put_request(fc, req); | 213 | fuse_put_request(fc, req); |
211 | return 0; | 214 | ret = -ENOMEM; |
215 | goto out; | ||
212 | } | 216 | } |
213 | 217 | ||
214 | attr_version = fuse_get_attr_version(fc); | 218 | attr_version = fuse_get_attr_version(fc); |
@@ -227,7 +231,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) | |||
227 | struct fuse_inode *fi = get_fuse_inode(inode); | 231 | struct fuse_inode *fi = get_fuse_inode(inode); |
228 | if (outarg.nodeid != get_node_id(inode)) { | 232 | if (outarg.nodeid != get_node_id(inode)) { |
229 | fuse_queue_forget(fc, forget, outarg.nodeid, 1); | 233 | fuse_queue_forget(fc, forget, outarg.nodeid, 1); |
230 | return 0; | 234 | goto invalid; |
231 | } | 235 | } |
232 | spin_lock(&fc->lock); | 236 | spin_lock(&fc->lock); |
233 | fi->nlookup++; | 237 | fi->nlookup++; |
@@ -235,7 +239,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) | |||
235 | } | 239 | } |
236 | kfree(forget); | 240 | kfree(forget); |
237 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) | 241 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) |
238 | return 0; | 242 | goto invalid; |
239 | 243 | ||
240 | fuse_change_attributes(inode, &outarg.attr, | 244 | fuse_change_attributes(inode, &outarg.attr, |
241 | entry_attr_timeout(&outarg), | 245 | entry_attr_timeout(&outarg), |
@@ -249,7 +253,15 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) | |||
249 | dput(parent); | 253 | dput(parent); |
250 | } | 254 | } |
251 | } | 255 | } |
252 | return 1; | 256 | ret = 1; |
257 | out: | ||
258 | return ret; | ||
259 | |||
260 | invalid: | ||
261 | ret = 0; | ||
262 | if (check_submounts_and_drop(entry) != 0) | ||
263 | ret = 1; | ||
264 | goto out; | ||
253 | } | 265 | } |
254 | 266 | ||
255 | static int invalid_nodeid(u64 nodeid) | 267 | static int invalid_nodeid(u64 nodeid) |
@@ -267,26 +279,6 @@ int fuse_valid_type(int m) | |||
267 | S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); | 279 | S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); |
268 | } | 280 | } |
269 | 281 | ||
270 | /* | ||
271 | * Add a directory inode to a dentry, ensuring that no other dentry | ||
272 | * refers to this inode. Called with fc->inst_mutex. | ||
273 | */ | ||
274 | static struct dentry *fuse_d_add_directory(struct dentry *entry, | ||
275 | struct inode *inode) | ||
276 | { | ||
277 | struct dentry *alias = d_find_alias(inode); | ||
278 | if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) { | ||
279 | /* This tries to shrink the subtree below alias */ | ||
280 | fuse_invalidate_entry(alias); | ||
281 | dput(alias); | ||
282 | if (!hlist_empty(&inode->i_dentry)) | ||
283 | return ERR_PTR(-EBUSY); | ||
284 | } else { | ||
285 | dput(alias); | ||
286 | } | ||
287 | return d_splice_alias(inode, entry); | ||
288 | } | ||
289 | |||
290 | int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | 282 | int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, |
291 | struct fuse_entry_out *outarg, struct inode **inode) | 283 | struct fuse_entry_out *outarg, struct inode **inode) |
292 | { | 284 | { |
@@ -345,6 +337,24 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
345 | return err; | 337 | return err; |
346 | } | 338 | } |
347 | 339 | ||
340 | static struct dentry *fuse_materialise_dentry(struct dentry *dentry, | ||
341 | struct inode *inode) | ||
342 | { | ||
343 | struct dentry *newent; | ||
344 | |||
345 | if (inode && S_ISDIR(inode->i_mode)) { | ||
346 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
347 | |||
348 | mutex_lock(&fc->inst_mutex); | ||
349 | newent = d_materialise_unique(dentry, inode); | ||
350 | mutex_unlock(&fc->inst_mutex); | ||
351 | } else { | ||
352 | newent = d_materialise_unique(dentry, inode); | ||
353 | } | ||
354 | |||
355 | return newent; | ||
356 | } | ||
357 | |||
348 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | 358 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, |
349 | unsigned int flags) | 359 | unsigned int flags) |
350 | { | 360 | { |
@@ -352,7 +362,6 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
352 | struct fuse_entry_out outarg; | 362 | struct fuse_entry_out outarg; |
353 | struct inode *inode; | 363 | struct inode *inode; |
354 | struct dentry *newent; | 364 | struct dentry *newent; |
355 | struct fuse_conn *fc = get_fuse_conn(dir); | ||
356 | bool outarg_valid = true; | 365 | bool outarg_valid = true; |
357 | 366 | ||
358 | err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name, | 367 | err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name, |
@@ -368,16 +377,10 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
368 | if (inode && get_node_id(inode) == FUSE_ROOT_ID) | 377 | if (inode && get_node_id(inode) == FUSE_ROOT_ID) |
369 | goto out_iput; | 378 | goto out_iput; |
370 | 379 | ||
371 | if (inode && S_ISDIR(inode->i_mode)) { | 380 | newent = fuse_materialise_dentry(entry, inode); |
372 | mutex_lock(&fc->inst_mutex); | 381 | err = PTR_ERR(newent); |
373 | newent = fuse_d_add_directory(entry, inode); | 382 | if (IS_ERR(newent)) |
374 | mutex_unlock(&fc->inst_mutex); | 383 | goto out_err; |
375 | err = PTR_ERR(newent); | ||
376 | if (IS_ERR(newent)) | ||
377 | goto out_iput; | ||
378 | } else { | ||
379 | newent = d_splice_alias(inode, entry); | ||
380 | } | ||
381 | 384 | ||
382 | entry = newent ? newent : entry; | 385 | entry = newent ? newent : entry; |
383 | if (outarg_valid) | 386 | if (outarg_valid) |
@@ -1275,18 +1278,10 @@ static int fuse_direntplus_link(struct file *file, | |||
1275 | if (!inode) | 1278 | if (!inode) |
1276 | goto out; | 1279 | goto out; |
1277 | 1280 | ||
1278 | if (S_ISDIR(inode->i_mode)) { | 1281 | alias = fuse_materialise_dentry(dentry, inode); |
1279 | mutex_lock(&fc->inst_mutex); | 1282 | err = PTR_ERR(alias); |
1280 | alias = fuse_d_add_directory(dentry, inode); | 1283 | if (IS_ERR(alias)) |
1281 | mutex_unlock(&fc->inst_mutex); | 1284 | goto out; |
1282 | err = PTR_ERR(alias); | ||
1283 | if (IS_ERR(alias)) { | ||
1284 | iput(inode); | ||
1285 | goto out; | ||
1286 | } | ||
1287 | } else { | ||
1288 | alias = d_splice_alias(inode, dentry); | ||
1289 | } | ||
1290 | 1285 | ||
1291 | if (alias) { | 1286 | if (alias) { |
1292 | dput(dentry); | 1287 | dput(dentry); |
diff --git a/fs/gfs2/dentry.c b/fs/gfs2/dentry.c index f2448ab2aac5..d3a5d4e29ba5 100644 --- a/fs/gfs2/dentry.c +++ b/fs/gfs2/dentry.c | |||
@@ -93,12 +93,9 @@ invalid_gunlock: | |||
93 | if (!had_lock) | 93 | if (!had_lock) |
94 | gfs2_glock_dq_uninit(&d_gh); | 94 | gfs2_glock_dq_uninit(&d_gh); |
95 | invalid: | 95 | invalid: |
96 | if (inode && S_ISDIR(inode->i_mode)) { | 96 | if (check_submounts_and_drop(dentry) != 0) |
97 | if (have_submounts(dentry)) | 97 | goto valid; |
98 | goto valid; | 98 | |
99 | shrink_dcache_parent(dentry); | ||
100 | } | ||
101 | d_drop(dentry); | ||
102 | dput(parent); | 99 | dput(parent); |
103 | return 0; | 100 | return 0; |
104 | 101 | ||
diff --git a/fs/internal.h b/fs/internal.h index 7c5f01cf619d..d20893795526 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -126,6 +126,7 @@ extern int invalidate_inodes(struct super_block *, bool); | |||
126 | * dcache.c | 126 | * dcache.c |
127 | */ | 127 | */ |
128 | extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); | 128 | extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); |
129 | extern int d_set_mounted(struct dentry *dentry); | ||
129 | 130 | ||
130 | /* | 131 | /* |
131 | * read_write.c | 132 | * read_write.c |
diff --git a/fs/namespace.c b/fs/namespace.c index ef69fa5d2e5b..fc2b5226278d 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -611,6 +611,7 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry) | |||
611 | { | 611 | { |
612 | struct list_head *chain = mountpoint_hashtable + hash(NULL, dentry); | 612 | struct list_head *chain = mountpoint_hashtable + hash(NULL, dentry); |
613 | struct mountpoint *mp; | 613 | struct mountpoint *mp; |
614 | int ret; | ||
614 | 615 | ||
615 | list_for_each_entry(mp, chain, m_hash) { | 616 | list_for_each_entry(mp, chain, m_hash) { |
616 | if (mp->m_dentry == dentry) { | 617 | if (mp->m_dentry == dentry) { |
@@ -626,14 +627,12 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry) | |||
626 | if (!mp) | 627 | if (!mp) |
627 | return ERR_PTR(-ENOMEM); | 628 | return ERR_PTR(-ENOMEM); |
628 | 629 | ||
629 | spin_lock(&dentry->d_lock); | 630 | ret = d_set_mounted(dentry); |
630 | if (d_unlinked(dentry)) { | 631 | if (ret) { |
631 | spin_unlock(&dentry->d_lock); | ||
632 | kfree(mp); | 632 | kfree(mp); |
633 | return ERR_PTR(-ENOENT); | 633 | return ERR_PTR(ret); |
634 | } | 634 | } |
635 | dentry->d_flags |= DCACHE_MOUNTED; | 635 | |
636 | spin_unlock(&dentry->d_lock); | ||
637 | mp->m_dentry = dentry; | 636 | mp->m_dentry = dentry; |
638 | mp->m_count = 1; | 637 | mp->m_count = 1; |
639 | list_add(&mp->m_hash, chain); | 638 | list_add(&mp->m_hash, chain); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index e474ca2b2bfe..7468735d299e 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1135,14 +1135,13 @@ out_zap_parent: | |||
1135 | if (inode && S_ISDIR(inode->i_mode)) { | 1135 | if (inode && S_ISDIR(inode->i_mode)) { |
1136 | /* Purge readdir caches. */ | 1136 | /* Purge readdir caches. */ |
1137 | nfs_zap_caches(inode); | 1137 | nfs_zap_caches(inode); |
1138 | /* If we have submounts, don't unhash ! */ | ||
1139 | if (have_submounts(dentry)) | ||
1140 | goto out_valid; | ||
1141 | if (dentry->d_flags & DCACHE_DISCONNECTED) | 1138 | if (dentry->d_flags & DCACHE_DISCONNECTED) |
1142 | goto out_valid; | 1139 | goto out_valid; |
1143 | shrink_dcache_parent(dentry); | ||
1144 | } | 1140 | } |
1145 | d_drop(dentry); | 1141 | /* If we have submounts, don't unhash ! */ |
1142 | if (check_submounts_and_drop(dentry) != 0) | ||
1143 | goto out_valid; | ||
1144 | |||
1146 | dput(parent); | 1145 | dput(parent); |
1147 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", | 1146 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", |
1148 | __func__, dentry->d_parent->d_name.name, | 1147 | __func__, dentry->d_parent->d_name.name, |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 99ec5b40e977..4d83cedb9fcb 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -297,7 +297,6 @@ static int sysfs_dentry_delete(const struct dentry *dentry) | |||
297 | static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) | 297 | static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) |
298 | { | 298 | { |
299 | struct sysfs_dirent *sd; | 299 | struct sysfs_dirent *sd; |
300 | int is_dir; | ||
301 | int type; | 300 | int type; |
302 | 301 | ||
303 | if (flags & LOOKUP_RCU) | 302 | if (flags & LOOKUP_RCU) |
@@ -341,18 +340,15 @@ out_bad: | |||
341 | * is performed at its new name the dentry will be readded | 340 | * is performed at its new name the dentry will be readded |
342 | * to the dcache hashes. | 341 | * to the dcache hashes. |
343 | */ | 342 | */ |
344 | is_dir = (sysfs_type(sd) == SYSFS_DIR); | ||
345 | mutex_unlock(&sysfs_mutex); | 343 | mutex_unlock(&sysfs_mutex); |
346 | if (is_dir) { | 344 | |
347 | /* If we have submounts we must allow the vfs caches | 345 | /* If we have submounts we must allow the vfs caches |
348 | * to lie about the state of the filesystem to prevent | 346 | * to lie about the state of the filesystem to prevent |
349 | * leaks and other nasty things. | 347 | * leaks and other nasty things. |
350 | */ | 348 | */ |
351 | if (have_submounts(dentry)) | 349 | if (check_submounts_and_drop(dentry) != 0) |
352 | goto out_valid; | 350 | goto out_valid; |
353 | shrink_dcache_parent(dentry); | 351 | |
354 | } | ||
355 | d_drop(dentry); | ||
356 | return 0; | 352 | return 0; |
357 | } | 353 | } |
358 | 354 | ||
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 9169b91ea2d2..fe50f3db3af9 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -212,7 +212,7 @@ struct dentry_operations { | |||
212 | 212 | ||
213 | extern seqlock_t rename_lock; | 213 | extern seqlock_t rename_lock; |
214 | 214 | ||
215 | static inline int dname_external(struct dentry *dentry) | 215 | static inline int dname_external(const struct dentry *dentry) |
216 | { | 216 | { |
217 | return dentry->d_name.name != dentry->d_iname; | 217 | return dentry->d_name.name != dentry->d_iname; |
218 | } | 218 | } |
@@ -253,6 +253,7 @@ extern void d_prune_aliases(struct inode *); | |||
253 | 253 | ||
254 | /* test whether we have any submounts in a subdir tree */ | 254 | /* test whether we have any submounts in a subdir tree */ |
255 | extern int have_submounts(struct dentry *); | 255 | extern int have_submounts(struct dentry *); |
256 | extern int check_submounts_and_drop(struct dentry *); | ||
256 | 257 | ||
257 | /* | 258 | /* |
258 | * This adds the entry to the hash queues. | 259 | * This adds the entry to the hash queues. |
@@ -357,17 +358,17 @@ extern struct dentry *dget_parent(struct dentry *dentry); | |||
357 | * Returns true if the dentry passed is not currently hashed. | 358 | * Returns true if the dentry passed is not currently hashed. |
358 | */ | 359 | */ |
359 | 360 | ||
360 | static inline int d_unhashed(struct dentry *dentry) | 361 | static inline int d_unhashed(const struct dentry *dentry) |
361 | { | 362 | { |
362 | return hlist_bl_unhashed(&dentry->d_hash); | 363 | return hlist_bl_unhashed(&dentry->d_hash); |
363 | } | 364 | } |
364 | 365 | ||
365 | static inline int d_unlinked(struct dentry *dentry) | 366 | static inline int d_unlinked(const struct dentry *dentry) |
366 | { | 367 | { |
367 | return d_unhashed(dentry) && !IS_ROOT(dentry); | 368 | return d_unhashed(dentry) && !IS_ROOT(dentry); |
368 | } | 369 | } |
369 | 370 | ||
370 | static inline int cant_mount(struct dentry *dentry) | 371 | static inline int cant_mount(const struct dentry *dentry) |
371 | { | 372 | { |
372 | return (dentry->d_flags & DCACHE_CANT_MOUNT); | 373 | return (dentry->d_flags & DCACHE_CANT_MOUNT); |
373 | } | 374 | } |
@@ -381,12 +382,12 @@ static inline void dont_mount(struct dentry *dentry) | |||
381 | 382 | ||
382 | extern void dput(struct dentry *); | 383 | extern void dput(struct dentry *); |
383 | 384 | ||
384 | static inline bool d_managed(struct dentry *dentry) | 385 | static inline bool d_managed(const struct dentry *dentry) |
385 | { | 386 | { |
386 | return dentry->d_flags & DCACHE_MANAGED_DENTRY; | 387 | return dentry->d_flags & DCACHE_MANAGED_DENTRY; |
387 | } | 388 | } |
388 | 389 | ||
389 | static inline bool d_mountpoint(struct dentry *dentry) | 390 | static inline bool d_mountpoint(const struct dentry *dentry) |
390 | { | 391 | { |
391 | return dentry->d_flags & DCACHE_MOUNTED; | 392 | return dentry->d_flags & DCACHE_MOUNTED; |
392 | } | 393 | } |