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:
Miklos Szeredi 2012-03-26 12:54:24 +02:00 committed by Al Viro
parent 81e6f52089
commit bad6118978

View File

@ -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;
} }
/* /*