History

fs/namei.c: pull positivity check into follow_managed()

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.

Al Viro committed 7 years ago

Commit d41efb51 parent 3e5aeec2 files · +16 −23Browse files

Unified · Split

2 files
  1. fs/namei.c +11 −23
  2. include/linux/dcache.h +5 −0
fs/namei.c+11−23
@@ -1206,25 +1206,25 @@ static int follow_automount(struct path *path, struct nameidata *nd, · 1205 unmodified lines
1206 * - Flagged as automount point1206 * - 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.c1211 * Serialization is taken care of in namespace.c
1211 */1212 */
1212static int follow_managed(struct path *path, struct nameidata *nd)1213static 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 a1220 /* 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 see1221 * 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_mutex1225 /* 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 */
include/linux/dcache.h+5−0
@@ -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
443static inline bool d_flags_negative(unsigned flags)
444{
445 return (flags & DCACHE_ENTRY_TYPE) == DCACHE_MISS_TYPE;
446}
447
443static inline bool d_is_positive(const struct dentry *dentry)448static inline bool d_is_positive(const struct dentry *dentry)
444{449{
445 return !d_is_negative(dentry);450 return !d_is_negative(dentry);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t