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 | 1206 | * - Flagged as automount point |
| 1207 | 1207 | * |
| 1208 | 1208 | * This may only be called in refwalk mode. |
| 1209 | + * On success path->dentry is known positive. | |
| 1209 | 1210 | * |
| 1210 | 1211 | * Serialization is taken care of in namespace.c |
| 1211 | 1212 | */ |
| 1212 | 1213 | static int follow_managed(struct path *path, struct nameidata *nd) |
| 1213 | 1214 | { |
| 1214 | 1215 | struct vfsmount *mnt = path->mnt; /* held by caller, must be left alone */ |
| 1215 | − unsigned managed; | |
| 1216 | + unsigned flags; | |
| 1216 | 1217 | bool need_mntput = false; |
| 1217 | 1218 | int ret = 0; |
| 1218 | 1219 | |
| 1219 | 1220 | /* Given that we're not holding a lock here, we retain the value in a |
| 1220 | 1221 | * local variable for each dentry as we look at it so that we don't see |
| 1221 | 1222 | * the components of that value change under us */ |
| 1222 | − while (managed = READ_ONCE(path->dentry->d_flags), | |
| 1223 | − managed &= DCACHE_MANAGED_DENTRY, | |
| 1224 | − unlikely(managed != 0)) { | |
| 1223 | + while (flags = READ_ONCE(path->dentry->d_flags), | |
| 1224 | + unlikely(flags & DCACHE_MANAGED_DENTRY)) { | |
| 1225 | 1225 | /* Allow the filesystem to manage the transit without i_mutex |
| 1226 | 1226 | * being held. */ |
| 1227 | − if (managed & DCACHE_MANAGE_TRANSIT) { | |
| 1227 | + if (flags & DCACHE_MANAGE_TRANSIT) { | |
| 1228 | 1228 | BUG_ON(!path->dentry->d_op); |
| 1229 | 1229 | BUG_ON(!path->dentry->d_op->d_manage); |
| 1230 | 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 | 1235 | /* Transit to a mounted filesystem. */ |
| 1236 | − if (managed & DCACHE_MOUNTED) { | |
| 1236 | + if (flags & DCACHE_MOUNTED) { | |
| 1237 | 1237 | struct vfsmount *mounted = lookup_mnt(path); |
| 1238 | 1238 | if (mounted) { |
| 1239 | 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 | 1254 | /* Handle an automount point */ |
| 1255 | − if (managed & DCACHE_NEED_AUTOMOUNT) { | |
| 1255 | + if (flags & DCACHE_NEED_AUTOMOUNT) { | |
| 1256 | 1256 | ret = follow_automount(path, nd, &need_mntput); |
| 1257 | 1257 | if (ret < 0) |
| 1258 | 1258 | break; |
| @@ -1265,10 +1265,12 @@ static int follow_managed(struct path *path, struct nameidata *nd) · 6 unmodified lines | ||
| 1265 | 1265 | |
| 1266 | 1266 | if (need_mntput && path->mnt == mnt) |
| 1267 | 1267 | mntput(path->mnt); |
| 1268 | − if (ret == -EISDIR || !ret) | |
| 1269 | − ret = 1; | |
| 1270 | 1268 | if (need_mntput) |
| 1271 | 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 | 1274 | if (unlikely(ret < 0)) |
| 1273 | 1275 | path_put_conditional(path, nd); |
| 1274 | 1276 | return ret; |
| @@ -1617,10 +1619,6 @@ static int lookup_fast(struct nameidata *nd, · 342 unmodified lines | ||
| 1617 | 1619 | dput(dentry); |
| 1618 | 1620 | return status; |
| 1619 | 1621 | } |
| 1620 | − if (unlikely(d_is_negative(dentry))) { | |
| 1621 | − dput(dentry); | |
| 1622 | − return -ENOENT; | |
| 1623 | − } | |
| 1624 | 1622 | |
| 1625 | 1623 | path->mnt = mnt; |
| 1626 | 1624 | path->dentry = dentry; |
| @@ -1807,11 +1805,6 @@ static int walk_component(struct nameidata *nd, int flags) · 180 unmodified lines | ||
| 1807 | 1805 | if (unlikely(err < 0)) |
| 1808 | 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 | 1808 | seq = 0; /* we are already out of RCU mode */ |
| 1816 | 1809 | inode = d_backing_inode(path.dentry); |
| 1817 | 1810 | } |
| @@ -3352,11 +3345,6 @@ static int do_last(struct nameidata *nd, · 1534 unmodified lines | ||
| 3352 | 3345 | if (unlikely(error < 0)) |
| 3353 | 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 | 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 | 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 | 448 | static inline bool d_is_positive(const struct dentry *dentry) |
| 444 | 449 | { |
| 445 | 450 | return !d_is_negative(dentry); |