diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-11 04:44:53 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-14 09:15:27 -0400 |
commit | 5a18fff2090c3af830d699c8ccb230498a1e37e5 (patch) | |
tree | 388675113818a8d14e7cd7dc25185e1be55354f9 | |
parent | 40b39136f07279fdc868a36cba050f4e84ce0ace (diff) |
untangle do_lookup()
That thing has devolved into rats nest of gotos; sane use of unlikely()
gets rid of that horror and gives much more readable structure:
* make a fast attempt to find a dentry; false negatives are OK.
In RCU mode if everything went fine, we are done, otherwise just drop
out of RCU. If we'd done (RCU) ->d_revalidate() and it had not refused
outright (i.e. didn't give us -ECHILD), remember its result.
* now we are not in RCU mode and hopefully have a dentry. If we
do not, lock parent, do full d_lookup() and if that has not found anything,
allocate and call ->lookup(). If we'd done that ->lookup(), remember that
dentry is good and we don't need to revalidate it.
* now we have a dentry. If it has ->d_revalidate() and we can't
skip it, call it.
* hopefully dentry is good; if not, either fail (in case of error)
or try to invalidate it. If d_invalidate() has succeeded, drop it and
retry everything as if original attempt had not found a dentry.
* now we can finish it up - deal with mountpoint crossing and
automount.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/namei.c | 141 |
1 files changed, 56 insertions, 85 deletions
diff --git a/fs/namei.c b/fs/namei.c index ca9a06a65704..0bebd13e5cb7 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -589,29 +589,6 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
589 | return dentry; | 589 | return dentry; |
590 | } | 590 | } |
591 | 591 | ||
592 | static inline struct dentry * | ||
593 | do_revalidate_rcu(struct dentry *dentry, struct nameidata *nd) | ||
594 | { | ||
595 | int status = d_revalidate(dentry, nd); | ||
596 | if (likely(status > 0)) | ||
597 | return dentry; | ||
598 | if (status == -ECHILD) { | ||
599 | if (nameidata_dentry_drop_rcu(nd, dentry)) | ||
600 | return ERR_PTR(-ECHILD); | ||
601 | return do_revalidate(dentry, nd); | ||
602 | } | ||
603 | if (status < 0) | ||
604 | return ERR_PTR(status); | ||
605 | /* Don't d_invalidate in rcu-walk mode */ | ||
606 | if (nameidata_dentry_drop_rcu(nd, dentry)) | ||
607 | return ERR_PTR(-ECHILD); | ||
608 | if (!d_invalidate(dentry)) { | ||
609 | dput(dentry); | ||
610 | dentry = NULL; | ||
611 | } | ||
612 | return dentry; | ||
613 | } | ||
614 | |||
615 | /* | 592 | /* |
616 | * handle_reval_path - force revalidation of a dentry | 593 | * handle_reval_path - force revalidation of a dentry |
617 | * | 594 | * |
@@ -1213,7 +1190,8 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, | |||
1213 | { | 1190 | { |
1214 | struct vfsmount *mnt = nd->path.mnt; | 1191 | struct vfsmount *mnt = nd->path.mnt; |
1215 | struct dentry *dentry, *parent = nd->path.dentry; | 1192 | struct dentry *dentry, *parent = nd->path.dentry; |
1216 | struct inode *dir; | 1193 | int need_reval = 1; |
1194 | int status = 1; | ||
1217 | int err; | 1195 | int err; |
1218 | 1196 | ||
1219 | /* | 1197 | /* |
@@ -1223,48 +1201,74 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, | |||
1223 | */ | 1201 | */ |
1224 | if (nd->flags & LOOKUP_RCU) { | 1202 | if (nd->flags & LOOKUP_RCU) { |
1225 | unsigned seq; | 1203 | unsigned seq; |
1226 | |||
1227 | *inode = nd->inode; | 1204 | *inode = nd->inode; |
1228 | dentry = __d_lookup_rcu(parent, name, &seq, inode); | 1205 | dentry = __d_lookup_rcu(parent, name, &seq, inode); |
1229 | if (!dentry) { | 1206 | if (!dentry) |
1230 | if (nameidata_drop_rcu(nd)) | 1207 | goto unlazy; |
1231 | return -ECHILD; | 1208 | |
1232 | goto need_lookup; | ||
1233 | } | ||
1234 | /* Memory barrier in read_seqcount_begin of child is enough */ | 1209 | /* Memory barrier in read_seqcount_begin of child is enough */ |
1235 | if (__read_seqcount_retry(&parent->d_seq, nd->seq)) | 1210 | if (__read_seqcount_retry(&parent->d_seq, nd->seq)) |
1236 | return -ECHILD; | 1211 | return -ECHILD; |
1237 | |||
1238 | nd->seq = seq; | 1212 | nd->seq = seq; |
1213 | |||
1239 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) { | 1214 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) { |
1240 | dentry = do_revalidate_rcu(dentry, nd); | 1215 | status = d_revalidate(dentry, nd); |
1241 | if (!dentry) | 1216 | if (unlikely(status <= 0)) { |
1242 | goto need_lookup; | 1217 | if (status != -ECHILD) |
1243 | if (IS_ERR(dentry)) | 1218 | need_reval = 0; |
1244 | goto fail; | 1219 | goto unlazy; |
1245 | if (!(nd->flags & LOOKUP_RCU)) | 1220 | } |
1246 | goto done; | ||
1247 | } | 1221 | } |
1248 | path->mnt = mnt; | 1222 | path->mnt = mnt; |
1249 | path->dentry = dentry; | 1223 | path->dentry = dentry; |
1250 | if (likely(__follow_mount_rcu(nd, path, inode, false))) | 1224 | if (likely(__follow_mount_rcu(nd, path, inode, false))) |
1251 | return 0; | 1225 | return 0; |
1252 | if (nameidata_drop_rcu(nd)) | 1226 | unlazy: |
1253 | return -ECHILD; | 1227 | if (dentry) { |
1254 | /* fallthru */ | 1228 | if (nameidata_dentry_drop_rcu(nd, dentry)) |
1229 | return -ECHILD; | ||
1230 | } else { | ||
1231 | if (nameidata_drop_rcu(nd)) | ||
1232 | return -ECHILD; | ||
1233 | } | ||
1234 | } else { | ||
1235 | dentry = __d_lookup(parent, name); | ||
1255 | } | 1236 | } |
1256 | dentry = __d_lookup(parent, name); | 1237 | |
1257 | if (!dentry) | 1238 | retry: |
1258 | goto need_lookup; | 1239 | if (unlikely(!dentry)) { |
1259 | found: | 1240 | struct inode *dir = parent->d_inode; |
1260 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) { | 1241 | BUG_ON(nd->inode != dir); |
1261 | dentry = do_revalidate(dentry, nd); | 1242 | |
1262 | if (!dentry) | 1243 | mutex_lock(&dir->i_mutex); |
1263 | goto need_lookup; | 1244 | dentry = d_lookup(parent, name); |
1264 | if (IS_ERR(dentry)) | 1245 | if (likely(!dentry)) { |
1265 | goto fail; | 1246 | dentry = d_alloc_and_lookup(parent, name, nd); |
1247 | if (IS_ERR(dentry)) { | ||
1248 | mutex_unlock(&dir->i_mutex); | ||
1249 | return PTR_ERR(dentry); | ||
1250 | } | ||
1251 | /* known good */ | ||
1252 | need_reval = 0; | ||
1253 | status = 1; | ||
1254 | } | ||
1255 | mutex_unlock(&dir->i_mutex); | ||
1256 | } | ||
1257 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE) && need_reval) | ||
1258 | status = d_revalidate(dentry, nd); | ||
1259 | if (unlikely(status <= 0)) { | ||
1260 | if (status < 0) { | ||
1261 | dput(dentry); | ||
1262 | return status; | ||
1263 | } | ||
1264 | if (!d_invalidate(dentry)) { | ||
1265 | dput(dentry); | ||
1266 | dentry = NULL; | ||
1267 | need_reval = 1; | ||
1268 | goto retry; | ||
1269 | } | ||
1266 | } | 1270 | } |
1267 | done: | 1271 | |
1268 | path->mnt = mnt; | 1272 | path->mnt = mnt; |
1269 | path->dentry = dentry; | 1273 | path->dentry = dentry; |
1270 | err = follow_managed(path, nd->flags); | 1274 | err = follow_managed(path, nd->flags); |
@@ -1274,39 +1278,6 @@ done: | |||
1274 | } | 1278 | } |
1275 | *inode = path->dentry->d_inode; | 1279 | *inode = path->dentry->d_inode; |
1276 | return 0; | 1280 | return 0; |
1277 | |||
1278 | need_lookup: | ||
1279 | dir = parent->d_inode; | ||
1280 | BUG_ON(nd->inode != dir); | ||
1281 | |||
1282 | mutex_lock(&dir->i_mutex); | ||
1283 | /* | ||
1284 | * First re-do the cached lookup just in case it was created | ||
1285 | * while we waited for the directory semaphore, or the first | ||
1286 | * lookup failed due to an unrelated rename. | ||
1287 | * | ||
1288 | * This could use version numbering or similar to avoid unnecessary | ||
1289 | * cache lookups, but then we'd have to do the first lookup in the | ||
1290 | * non-racy way. However in the common case here, everything should | ||
1291 | * be hot in cache, so would it be a big win? | ||
1292 | */ | ||
1293 | dentry = d_lookup(parent, name); | ||
1294 | if (likely(!dentry)) { | ||
1295 | dentry = d_alloc_and_lookup(parent, name, nd); | ||
1296 | mutex_unlock(&dir->i_mutex); | ||
1297 | if (IS_ERR(dentry)) | ||
1298 | goto fail; | ||
1299 | goto done; | ||
1300 | } | ||
1301 | /* | ||
1302 | * Uhhuh! Nasty case: the cache was re-populated while | ||
1303 | * we waited on the semaphore. Need to revalidate. | ||
1304 | */ | ||
1305 | mutex_unlock(&dir->i_mutex); | ||
1306 | goto found; | ||
1307 | |||
1308 | fail: | ||
1309 | return PTR_ERR(dentry); | ||
1310 | } | 1281 | } |
1311 | 1282 | ||
1312 | static inline int may_lookup(struct nameidata *nd) | 1283 | static inline int may_lookup(struct nameidata *nd) |