new helper: lookup_positive_unlocked()
[ Upstream commit 6c2d4798a8d16cf4f3a28c3cd4af4f1dcbbb4d04 ] Most of the callers of lookup_one_len_unlocked() treat negatives are ERR_PTR(-ENOENT). Provide a helper that would do just that. Note that a pinned positive dentry remains positive - it's ->d_inode is stable, etc.; a pinned _negative_ dentry can become positive at any point as long as you are not holding its parent at least shared. So using lookup_one_len_unlocked() needs to be careful; lookup_positive_unlocked() is safer and that's what the callers end up open-coding anyway. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Stable-dep-of: 0d5a4f8f775f ("fs: Fix error checking for d_hash_and_lookup()") Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
0a2b1eb8a9
commit
0c8c205381
@ -738,11 +738,6 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
|
||||
struct inode *dir = d_inode(dentry);
|
||||
struct dentry *child;
|
||||
|
||||
if (!dir) {
|
||||
dput(dentry);
|
||||
dentry = ERR_PTR(-ENOENT);
|
||||
break;
|
||||
}
|
||||
if (!S_ISDIR(dir->i_mode)) {
|
||||
dput(dentry);
|
||||
dentry = ERR_PTR(-ENOTDIR);
|
||||
@ -759,7 +754,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
|
||||
while (*s && *s != sep)
|
||||
s++;
|
||||
|
||||
child = lookup_one_len_unlocked(p, dentry, s - p);
|
||||
child = lookup_positive_unlocked(p, dentry, s - p);
|
||||
dput(dentry);
|
||||
dentry = child;
|
||||
} while (!IS_ERR(dentry));
|
||||
|
@ -299,13 +299,9 @@ struct dentry *debugfs_lookup(const char *name, struct dentry *parent)
|
||||
if (!parent)
|
||||
parent = debugfs_mount->mnt_root;
|
||||
|
||||
dentry = lookup_one_len_unlocked(name, parent, strlen(name));
|
||||
dentry = lookup_positive_unlocked(name, parent, strlen(name));
|
||||
if (IS_ERR(dentry))
|
||||
return NULL;
|
||||
if (!d_really_is_positive(dentry)) {
|
||||
dput(dentry);
|
||||
return NULL;
|
||||
}
|
||||
return dentry;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_lookup);
|
||||
|
@ -200,7 +200,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
|
||||
dput(dentry);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
dtmp = lookup_one_len_unlocked(kntmp->name, dentry,
|
||||
dtmp = lookup_positive_unlocked(kntmp->name, dentry,
|
||||
strlen(kntmp->name));
|
||||
dput(dentry);
|
||||
if (IS_ERR(dtmp))
|
||||
|
20
fs/namei.c
20
fs/namei.c
@ -2565,6 +2565,26 @@ struct dentry *lookup_one_len_unlocked(const char *name,
|
||||
}
|
||||
EXPORT_SYMBOL(lookup_one_len_unlocked);
|
||||
|
||||
/*
|
||||
* Like lookup_one_len_unlocked(), except that it yields ERR_PTR(-ENOENT)
|
||||
* on negatives. Returns known positive or ERR_PTR(); that's what
|
||||
* most of the users want. Note that pinned negative with unlocked parent
|
||||
* _can_ become positive at any time, so callers of lookup_one_len_unlocked()
|
||||
* need to be very careful; pinned positives have ->d_inode stable, so
|
||||
* this one avoids such problems.
|
||||
*/
|
||||
struct dentry *lookup_positive_unlocked(const char *name,
|
||||
struct dentry *base, int len)
|
||||
{
|
||||
struct dentry *ret = lookup_one_len_unlocked(name, base, len);
|
||||
if (!IS_ERR(ret) && d_is_negative(ret)) {
|
||||
dput(ret);
|
||||
ret = ERR_PTR(-ENOENT);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(lookup_positive_unlocked);
|
||||
|
||||
#ifdef CONFIG_UNIX98_PTYS
|
||||
int path_pts(struct path *path)
|
||||
{
|
||||
|
@ -868,13 +868,11 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
|
||||
} else
|
||||
dchild = dget(dparent);
|
||||
} else
|
||||
dchild = lookup_one_len_unlocked(name, dparent, namlen);
|
||||
dchild = lookup_positive_unlocked(name, dparent, namlen);
|
||||
if (IS_ERR(dchild))
|
||||
return rv;
|
||||
if (d_mountpoint(dchild))
|
||||
goto out;
|
||||
if (d_really_is_negative(dchild))
|
||||
goto out;
|
||||
if (dchild->d_inode->i_ino != ino)
|
||||
goto out;
|
||||
rv = fh_compose(fhp, exp, dchild, &cd->fh);
|
||||
|
@ -2991,18 +2991,9 @@ nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd,
|
||||
__be32 nfserr;
|
||||
int ignore_crossmnt = 0;
|
||||
|
||||
dentry = lookup_one_len_unlocked(name, cd->rd_fhp->fh_dentry, namlen);
|
||||
dentry = lookup_positive_unlocked(name, cd->rd_fhp->fh_dentry, namlen);
|
||||
if (IS_ERR(dentry))
|
||||
return nfserrno(PTR_ERR(dentry));
|
||||
if (d_really_is_negative(dentry)) {
|
||||
/*
|
||||
* we're not holding the i_mutex here, so there's
|
||||
* a window where this directory entry could have gone
|
||||
* away.
|
||||
*/
|
||||
dput(dentry);
|
||||
return nfserr_noent;
|
||||
}
|
||||
|
||||
exp_get(exp);
|
||||
/*
|
||||
|
@ -200,7 +200,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
|
||||
int err;
|
||||
bool last_element = !post[0];
|
||||
|
||||
this = lookup_one_len_unlocked(name, base, namelen);
|
||||
this = lookup_positive_unlocked(name, base, namelen);
|
||||
if (IS_ERR(this)) {
|
||||
err = PTR_ERR(this);
|
||||
this = NULL;
|
||||
@ -208,8 +208,6 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
|
||||
goto out;
|
||||
goto out_err;
|
||||
}
|
||||
if (!this->d_inode)
|
||||
goto put_and_out;
|
||||
|
||||
if (ovl_dentry_weird(this)) {
|
||||
/* Don't support traversing automounts and other weirdness */
|
||||
@ -659,7 +657,7 @@ struct dentry *ovl_get_index_fh(struct ovl_fs *ofs, struct ovl_fh *fh)
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
index = lookup_one_len_unlocked(name.name, ofs->indexdir, name.len);
|
||||
index = lookup_positive_unlocked(name.name, ofs->indexdir, name.len);
|
||||
kfree(name.name);
|
||||
if (IS_ERR(index)) {
|
||||
if (PTR_ERR(index) == -ENOENT)
|
||||
@ -667,9 +665,7 @@ struct dentry *ovl_get_index_fh(struct ovl_fs *ofs, struct ovl_fh *fh)
|
||||
return index;
|
||||
}
|
||||
|
||||
if (d_is_negative(index))
|
||||
err = 0;
|
||||
else if (ovl_is_whiteout(index))
|
||||
if (ovl_is_whiteout(index))
|
||||
err = -ESTALE;
|
||||
else if (ovl_dentry_weird(index))
|
||||
err = -EIO;
|
||||
@ -693,7 +689,7 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper,
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
index = lookup_one_len_unlocked(name.name, ofs->indexdir, name.len);
|
||||
index = lookup_positive_unlocked(name.name, ofs->indexdir, name.len);
|
||||
if (IS_ERR(index)) {
|
||||
err = PTR_ERR(index);
|
||||
if (err == -ENOENT) {
|
||||
@ -708,9 +704,7 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper,
|
||||
}
|
||||
|
||||
inode = d_inode(index);
|
||||
if (d_is_negative(index)) {
|
||||
goto out_dput;
|
||||
} else if (ovl_is_whiteout(index) && !verify) {
|
||||
if (ovl_is_whiteout(index) && !verify) {
|
||||
/*
|
||||
* When index lookup is called with !verify for decoding an
|
||||
* overlay file handle, a whiteout index implies that decode
|
||||
@ -1139,7 +1133,7 @@ bool ovl_lower_positive(struct dentry *dentry)
|
||||
struct dentry *this;
|
||||
struct dentry *lowerdir = poe->lowerstack[i].dentry;
|
||||
|
||||
this = lookup_one_len_unlocked(name->name, lowerdir,
|
||||
this = lookup_positive_unlocked(name->name, lowerdir,
|
||||
name->len);
|
||||
if (IS_ERR(this)) {
|
||||
switch (PTR_ERR(this)) {
|
||||
@ -1156,10 +1150,8 @@ bool ovl_lower_positive(struct dentry *dentry)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (this->d_inode) {
|
||||
positive = !ovl_is_whiteout(this);
|
||||
done = true;
|
||||
}
|
||||
positive = !ovl_is_whiteout(this);
|
||||
done = true;
|
||||
dput(this);
|
||||
}
|
||||
}
|
||||
|
@ -2543,21 +2543,15 @@ int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
|
||||
struct dentry *dentry;
|
||||
int error;
|
||||
|
||||
dentry = lookup_one_len_unlocked(qf_name, sb->s_root, strlen(qf_name));
|
||||
dentry = lookup_positive_unlocked(qf_name, sb->s_root, strlen(qf_name));
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
if (d_really_is_negative(dentry)) {
|
||||
error = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = security_quota_on(dentry);
|
||||
if (!error)
|
||||
error = vfs_load_quota_inode(d_inode(dentry), type, format_id,
|
||||
DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
|
||||
|
||||
out:
|
||||
dput(dentry);
|
||||
return error;
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int);
|
||||
extern struct dentry *try_lookup_one_len(const char *, struct dentry *, int);
|
||||
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
|
||||
extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int);
|
||||
extern struct dentry *lookup_positive_unlocked(const char *, struct dentry *, int);
|
||||
|
||||
extern int follow_down_one(struct path *);
|
||||
extern int follow_down(struct path *);
|
||||
|
Loading…
Reference in New Issue
Block a user