new helper: lookup_positive_unlocked()
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>
This commit is contained in:
parent
d41efb522e
commit
6c2d4798a8
|
@ -719,11 +719,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);
|
||||
|
@ -740,7 +735,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
|
@ -2557,6 +2557,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)
|
||||
{
|
||||
|
|
|
@ -863,13 +863,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 */
|
||||
|
@ -651,7 +649,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)
|
||||
|
@ -659,9 +657,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;
|
||||
|
@ -685,7 +681,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) {
|
||||
|
@ -700,9 +696,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
|
||||
|
@ -1131,7 +1125,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)) {
|
||||
|
@ -1148,10 +1142,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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2507,15 +2507,10 @@ 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,
|
||||
|
|
|
@ -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