forked from Minki/linux
vfs: split __lookup_hash
Split __lookup_hash into two component functions: lookup_dcache - tries cached lookup, returns whether real lookup is needed lookup_real - calls i_op->lookup This eliminates code duplication between d_alloc_and_lookup() and d_inode_lookup(). Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
81e6f52089
commit
bad6118978
108
fs/namei.c
108
fs/namei.c
@ -1054,53 +1054,65 @@ static void follow_dotdot(struct nameidata *nd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate a dentry with name and parent, and perform a parent
|
* This looks up the name in dcache, possibly revalidates the old dentry and
|
||||||
* directory ->lookup on it. Returns the new dentry, or ERR_PTR
|
* allocates a new one if not found or not valid. In the need_lookup argument
|
||||||
* on error. parent->d_inode->i_mutex must be held. d_lookup must
|
* returns whether i_op->lookup is necessary.
|
||||||
* have verified that no child exists while under i_mutex.
|
*
|
||||||
|
* dir->d_inode->i_mutex must be held
|
||||||
*/
|
*/
|
||||||
static struct dentry *d_alloc_and_lookup(struct dentry *parent,
|
static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
|
||||||
struct qstr *name, struct nameidata *nd)
|
struct nameidata *nd, bool *need_lookup)
|
||||||
{
|
{
|
||||||
struct inode *inode = parent->d_inode;
|
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
struct dentry *old;
|
int error;
|
||||||
|
|
||||||
/* Don't create child dentry for a dead directory. */
|
*need_lookup = false;
|
||||||
if (unlikely(IS_DEADDIR(inode)))
|
dentry = d_lookup(dir, name);
|
||||||
return ERR_PTR(-ENOENT);
|
if (dentry) {
|
||||||
|
if (d_need_lookup(dentry)) {
|
||||||
|
*need_lookup = true;
|
||||||
|
} else if (dentry->d_flags & DCACHE_OP_REVALIDATE) {
|
||||||
|
error = d_revalidate(dentry, nd);
|
||||||
|
if (unlikely(error <= 0)) {
|
||||||
|
if (error < 0) {
|
||||||
|
dput(dentry);
|
||||||
|
return ERR_PTR(error);
|
||||||
|
} else if (!d_invalidate(dentry)) {
|
||||||
|
dput(dentry);
|
||||||
|
dentry = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dentry = d_alloc(parent, name);
|
if (!dentry) {
|
||||||
if (unlikely(!dentry))
|
dentry = d_alloc(dir, name);
|
||||||
return ERR_PTR(-ENOMEM);
|
if (unlikely(!dentry))
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
old = inode->i_op->lookup(inode, dentry, nd);
|
*need_lookup = true;
|
||||||
if (unlikely(old)) {
|
|
||||||
dput(dentry);
|
|
||||||
dentry = old;
|
|
||||||
}
|
}
|
||||||
return dentry;
|
return dentry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We already have a dentry, but require a lookup to be performed on the parent
|
* Call i_op->lookup on the dentry. The dentry must be negative but may be
|
||||||
* directory to fill in d_inode. Returns the new dentry, or ERR_PTR on error.
|
* hashed if it was pouplated with DCACHE_NEED_LOOKUP.
|
||||||
* parent->d_inode->i_mutex must be held. d_lookup must have verified that no
|
*
|
||||||
* child exists while under i_mutex.
|
* dir->d_inode->i_mutex must be held
|
||||||
*/
|
*/
|
||||||
static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentry,
|
static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
|
||||||
struct nameidata *nd)
|
struct nameidata *nd)
|
||||||
{
|
{
|
||||||
struct inode *inode = parent->d_inode;
|
|
||||||
struct dentry *old;
|
struct dentry *old;
|
||||||
|
|
||||||
/* Don't create child dentry for a dead directory. */
|
/* Don't create child dentry for a dead directory. */
|
||||||
if (unlikely(IS_DEADDIR(inode))) {
|
if (unlikely(IS_DEADDIR(dir))) {
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
old = inode->i_op->lookup(inode, dentry, nd);
|
old = dir->i_op->lookup(dir, dentry, nd);
|
||||||
if (unlikely(old)) {
|
if (unlikely(old)) {
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
dentry = old;
|
dentry = old;
|
||||||
@ -1111,46 +1123,14 @@ static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentr
|
|||||||
static struct dentry *__lookup_hash(struct qstr *name,
|
static struct dentry *__lookup_hash(struct qstr *name,
|
||||||
struct dentry *base, struct nameidata *nd)
|
struct dentry *base, struct nameidata *nd)
|
||||||
{
|
{
|
||||||
|
bool need_lookup;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
|
|
||||||
/*
|
dentry = lookup_dcache(name, base, nd, &need_lookup);
|
||||||
* Don't bother with __d_lookup: callers are for creat as
|
if (!need_lookup)
|
||||||
* well as unlink, so a lot of the time it would cost
|
return dentry;
|
||||||
* a double lookup.
|
|
||||||
*/
|
|
||||||
dentry = d_lookup(base, name);
|
|
||||||
|
|
||||||
if (dentry && d_need_lookup(dentry)) {
|
return lookup_real(base->d_inode, dentry, nd);
|
||||||
/*
|
|
||||||
* __lookup_hash is called with the parent dir's i_mutex already
|
|
||||||
* held, so we are good to go here.
|
|
||||||
*/
|
|
||||||
return d_inode_lookup(base, dentry, nd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) {
|
|
||||||
int status = d_revalidate(dentry, nd);
|
|
||||||
if (unlikely(status <= 0)) {
|
|
||||||
/*
|
|
||||||
* The dentry failed validation.
|
|
||||||
* If d_revalidate returned 0 attempt to invalidate
|
|
||||||
* the dentry otherwise d_revalidate is asking us
|
|
||||||
* to return a fail status.
|
|
||||||
*/
|
|
||||||
if (status < 0) {
|
|
||||||
dput(dentry);
|
|
||||||
return ERR_PTR(status);
|
|
||||||
} else if (!d_invalidate(dentry)) {
|
|
||||||
dput(dentry);
|
|
||||||
dentry = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dentry)
|
|
||||||
dentry = d_alloc_and_lookup(base, name, nd);
|
|
||||||
|
|
||||||
return dentry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user