There are 4 callers; two proceed to check if result is positive and fail with ENOENT if it isn't; one (in handle_lookup_down()) is guaranteed to yield positive and one (in lookup_fast()) is _preceded_ by positivity check. However, follow_managed() on a negative dentry is a (fairly cheap) no-op on anything other than autofs. And negative autofs dentries are never hashed, so lookup_fast() is not going to run into one of those. Moreover, successful follow_managed() on a _positive_ dentry never yields a negative one (and we significantly rely upon that in callers of lookup_fast()). In other words, we can easily transpose the positivity check and the call of follow_managed() in lookup_fast(). And that allows to fold the positivity check *into* follow_managed(), simplifying life for the code downstream of its calls.
Unified · Split
| @@ -1206,25 +1206,25 @@ static int follow_automount(struct path *path, struct nameidata *nd, · 1205 unmodified lines | |||
| 1206 | * - Flagged as automount point | 1206 | * - Flagged as automount point |
| 1207 | * | 1207 | * |
| 1208 | * This may only be called in refwalk mode. | 1208 | * This may only be called in refwalk mode. |
| 1209 | * On success path->dentry is known positive. | ||
| 1209 | * | 1210 | * |
| 1210 | * Serialization is taken care of in namespace.c | 1211 | * Serialization is taken care of in namespace.c |
| 1211 | */ | 1212 | */ |
| 1212 | static int follow_managed(struct path *path, struct nameidata *nd) | 1213 | static int follow_managed(struct path *path, struct nameidata *nd) |
| 1213 | { | 1214 | { |
| 1214 | struct vfsmount *mnt = path->mnt; /* held by caller, must be left alone */ | 1215 | struct vfsmount *mnt = path->mnt; /* held by caller, must be left alone */ |
| 1215 | unsigned managed; | 1216 | unsigned flags; |
| 1216 | bool need_mntput = false; | 1217 | bool need_mntput = false; |
| 1217 | int ret = 0; | 1218 | int ret = 0; |
| 1218 | 1219 | ||
| 1219 | /* Given that we're not holding a lock here, we retain the value in a | 1220 | /* Given that we're not holding a lock here, we retain the value in a |
| 1220 | * local variable for each dentry as we look at it so that we don't see | 1221 | * local variable for each dentry as we look at it so that we don't see |
| 1221 | * the components of that value change under us */ | 1222 | * the components of that value change under us */ |
| 1222 | while (managed = READ_ONCE(path->dentry->d_flags), | 1223 | while (flags = READ_ONCE(path->dentry->d_flags), |
| 1223 | managed &= DCACHE_MANAGED_DENTRY, | 1224 | unlikely(flags & DCACHE_MANAGED_DENTRY)) { |
| 1224 | unlikely(managed != 0)) { | ||
| 1225 | /* Allow the filesystem to manage the transit without i_mutex | 1225 | /* Allow the filesystem to manage the transit without i_mutex |
| 1226 | * being held. */ | 1226 | * being held. */ |
| 1227 | if (managed & DCACHE_MANAGE_TRANSIT) { | 1227 | if (flags & DCACHE_MANAGE_TRANSIT) { |
| 1228 | BUG_ON(!path->dentry->d_op); | 1228 | BUG_ON(!path->dentry->d_op); |
| 1229 | BUG_ON(!path->dentry->d_op->d_manage); | 1229 | BUG_ON(!path->dentry->d_op->d_manage); |
| 1230 | ret = path->dentry->d_op->d_manage(path, false); | 1230 | ret = path->dentry->d_op->d_manage(path, false); |
| @@ -1233,7 +1233,7 @@ static int follow_managed(struct path *path, struct nameidata *nd) · 2 unmodified lines | |||
| 1233 | } | 1233 | } |
| 1234 | 1234 | ||
| 1235 | /* Transit to a mounted filesystem. */ | 1235 | /* Transit to a mounted filesystem. */ |
| 1236 | if (managed & DCACHE_MOUNTED) { | 1236 | if (flags & DCACHE_MOUNTED) { |
| 1237 | struct vfsmount *mounted = lookup_mnt(path); | 1237 | struct vfsmount *mounted = lookup_mnt(path); |
| 1238 | if (mounted) { | 1238 | if (mounted) { |
| 1239 | dput(path->dentry); | 1239 | dput(path->dentry); |
| @@ -1252,7 +1252,7 @@ static int follow_managed(struct path *path, struct nameidata *nd) · 12 unmodified lines | |||
| 1252 | } | 1252 | } |
| 1253 | 1253 | ||
| 1254 | /* Handle an automount point */ | 1254 | /* Handle an automount point */ |
| 1255 | if (managed & DCACHE_NEED_AUTOMOUNT) { | 1255 | if (flags & DCACHE_NEED_AUTOMOUNT) { |
| 1256 | ret = follow_automount(path, nd, &need_mntput); | 1256 | ret = follow_automount(path, nd, &need_mntput); |
| 1257 | if (ret < 0) | 1257 | if (ret < 0) |
| 1258 | break; | 1258 | break; |
| @@ -1265,10 +1265,12 @@ static int follow_managed(struct path *path, struct nameidata *nd) · 6 unmodified lines | |||
| 1265 | 1265 | ||
| 1266 | if (need_mntput && path->mnt == mnt) | 1266 | if (need_mntput && path->mnt == mnt) |
| 1267 | mntput(path->mnt); | 1267 | mntput(path->mnt); |
| 1268 | if (ret == -EISDIR || !ret) | ||
| 1269 | ret = 1; | ||
| 1270 | if (need_mntput) | 1268 | if (need_mntput) |
| 1271 | nd->flags |= LOOKUP_JUMPED; | 1269 | nd->flags |= LOOKUP_JUMPED; |
| 1270 | if (ret == -EISDIR || !ret) | ||
| 1271 | ret = 1; | ||
| 1272 | if (ret > 0 && unlikely(d_flags_negative(flags))) | ||
| 1273 | ret = -ENOENT; | ||
| 1272 | if (unlikely(ret < 0)) | 1274 | if (unlikely(ret < 0)) |
| 1273 | path_put_conditional(path, nd); | 1275 | path_put_conditional(path, nd); |
| 1274 | return ret; | 1276 | return ret; |
| @@ -1617,10 +1619,6 @@ static int lookup_fast(struct nameidata *nd, · 342 unmodified lines | |||
| 1617 | dput(dentry); | 1619 | dput(dentry); |
| 1618 | return status; | 1620 | return status; |
| 1619 | } | 1621 | } |
| 1620 | if (unlikely(d_is_negative(dentry))) { | ||
| 1621 | dput(dentry); | ||
| 1622 | return -ENOENT; | ||
| 1623 | } | ||
| 1624 | 1622 | ||
| 1625 | path->mnt = mnt; | 1623 | path->mnt = mnt; |
| 1626 | path->dentry = dentry; | 1624 | path->dentry = dentry; |
| @@ -1807,11 +1805,6 @@ static int walk_component(struct nameidata *nd, int flags) · 180 unmodified lines | |||
| 1807 | if (unlikely(err < 0)) | 1805 | if (unlikely(err < 0)) |
| 1808 | return err; | 1806 | return err; |
| 1809 | 1807 | ||
| 1810 | if (unlikely(d_is_negative(path.dentry))) { | ||
| 1811 | path_to_nameidata(&path, nd); | ||
| 1812 | return -ENOENT; | ||
| 1813 | } | ||
| 1814 | |||
| 1815 | seq = 0; /* we are already out of RCU mode */ | 1808 | seq = 0; /* we are already out of RCU mode */ |
| 1816 | inode = d_backing_inode(path.dentry); | 1809 | inode = d_backing_inode(path.dentry); |
| 1817 | } | 1810 | } |
| @@ -3352,11 +3345,6 @@ static int do_last(struct nameidata *nd, · 1534 unmodified lines | |||
| 3352 | if (unlikely(error < 0)) | 3345 | if (unlikely(error < 0)) |
| 3353 | return error; | 3346 | return error; |
| 3354 | 3347 | ||
| 3355 | if (unlikely(d_is_negative(path.dentry))) { | ||
| 3356 | path_to_nameidata(&path, nd); | ||
| 3357 | return -ENOENT; | ||
| 3358 | } | ||
| 3359 | |||
| 3360 | /* | 3348 | /* |
| 3361 | * create/update audit record if it already exists. | 3349 | * create/update audit record if it already exists. |
| 3362 | */ | 3350 | */ |
| @@ -440,6 +440,11 @@ static inline bool d_is_negative(const struct dentry *dentry) · 439 unmodified lines | |||
| 440 | return d_is_miss(dentry); | 440 | return d_is_miss(dentry); |
| 441 | } | 441 | } |
| 442 | 442 | ||
| 443 | static inline bool d_flags_negative(unsigned flags) | ||
| 444 | { | ||
| 445 | return (flags & DCACHE_ENTRY_TYPE) == DCACHE_MISS_TYPE; | ||
| 446 | } | ||
| 447 | |||
| 443 | static inline bool d_is_positive(const struct dentry *dentry) | 448 | static inline bool d_is_positive(const struct dentry *dentry) |
| 444 | { | 449 | { |
| 445 | return !d_is_negative(dentry); | 450 | return !d_is_negative(dentry); |