Skip to content

Commit

Permalink
namei: d_is_negative() should be checked before ->d_seq validation
Browse files Browse the repository at this point in the history
Fetching ->d_inode, verifying ->d_seq and finding d_is_negative() to
be true does *not* mean that inode we'd fetched had been NULL - that
holds only while ->d_seq is still unchanged.

Shift d_is_negative() checks into lookup_fast() prior to ->d_seq
verification.

Reported-by: Steven Rostedt <[email protected]>
Tested-by: Steven Rostedt <[email protected]>
Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
Al Viro committed May 9, 2015
1 parent 5ebe6af commit 766c4cb
Showing 1 changed file with 13 additions and 6 deletions.
19 changes: 13 additions & 6 deletions fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -1415,6 +1415,7 @@ static int lookup_fast(struct nameidata *nd,
*/
if (nd->flags & LOOKUP_RCU) {
unsigned seq;
bool negative;
dentry = __d_lookup_rcu(parent, &nd->last, &seq);
if (!dentry)
goto unlazy;
Expand All @@ -1424,8 +1425,11 @@ static int lookup_fast(struct nameidata *nd,
* the dentry name information from lookup.
*/
*inode = dentry->d_inode;
negative = d_is_negative(dentry);
if (read_seqcount_retry(&dentry->d_seq, seq))
return -ECHILD;
if (negative)
return -ENOENT;

/*
* This sequence count validates that the parent had no
Expand Down Expand Up @@ -1472,6 +1476,10 @@ static int lookup_fast(struct nameidata *nd,
goto need_lookup;
}

if (unlikely(d_is_negative(dentry))) {
dput(dentry);
return -ENOENT;
}
path->mnt = mnt;
path->dentry = dentry;
err = follow_managed(path, nd->flags);
Expand Down Expand Up @@ -1583,10 +1591,10 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
goto out_err;

inode = path->dentry->d_inode;
err = -ENOENT;
if (d_is_negative(path->dentry))
goto out_path_put;
}
err = -ENOENT;
if (d_is_negative(path->dentry))
goto out_path_put;

if (should_follow_link(path->dentry, follow)) {
if (nd->flags & LOOKUP_RCU) {
Expand Down Expand Up @@ -3036,14 +3044,13 @@ static int do_last(struct nameidata *nd, struct path *path,

BUG_ON(nd->flags & LOOKUP_RCU);
inode = path->dentry->d_inode;
finish_lookup:
/* we _can_ be in RCU mode here */
error = -ENOENT;
if (d_is_negative(path->dentry)) {
path_to_nameidata(path, nd);
goto out;
}

finish_lookup:
/* we _can_ be in RCU mode here */
if (should_follow_link(path->dentry, !symlink_ok)) {
if (nd->flags & LOOKUP_RCU) {
if (unlikely(nd->path.mnt != path->mnt ||
Expand Down

0 comments on commit 766c4cb

Please sign in to comment.