Skip to content

Commit

Permalink
vfs: split __lookup_hash
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
Miklos Szeredi authored and Al Viro committed Mar 31, 2012
1 parent 81e6f52 commit bad6118
Showing 1 changed file with 44 additions and 64 deletions.
108 changes: 44 additions & 64 deletions fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -1054,53 +1054,65 @@ static void follow_dotdot(struct nameidata *nd)
}

/*
* Allocate a dentry with name and parent, and perform a parent
* directory ->lookup on it. Returns the new dentry, or ERR_PTR
* on error. parent->d_inode->i_mutex must be held. d_lookup must
* have verified that no child exists while under i_mutex.
* This looks up the name in dcache, possibly revalidates the old dentry and
* allocates a new one if not found or not valid. In the need_lookup argument
* returns whether i_op->lookup is necessary.
*
* dir->d_inode->i_mutex must be held
*/
static struct dentry *d_alloc_and_lookup(struct dentry *parent,
struct qstr *name, struct nameidata *nd)
static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
struct nameidata *nd, bool *need_lookup)
{
struct inode *inode = parent->d_inode;
struct dentry *dentry;
struct dentry *old;
int error;

/* Don't create child dentry for a dead directory. */
if (unlikely(IS_DEADDIR(inode)))
return ERR_PTR(-ENOENT);
*need_lookup = false;
dentry = d_lookup(dir, name);
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 (unlikely(!dentry))
return ERR_PTR(-ENOMEM);
if (!dentry) {
dentry = d_alloc(dir, name);
if (unlikely(!dentry))
return ERR_PTR(-ENOMEM);

old = inode->i_op->lookup(inode, dentry, nd);
if (unlikely(old)) {
dput(dentry);
dentry = old;
*need_lookup = true;
}
return dentry;
}

/*
* We already have a dentry, but require a lookup to be performed on the parent
* directory to fill in d_inode. Returns the new dentry, or ERR_PTR on error.
* parent->d_inode->i_mutex must be held. d_lookup must have verified that no
* child exists while under i_mutex.
* Call i_op->lookup on the dentry. The dentry must be negative but may be
* hashed if it was pouplated with DCACHE_NEED_LOOKUP.
*
* dir->d_inode->i_mutex must be held
*/
static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentry,
struct nameidata *nd)
static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
struct inode *inode = parent->d_inode;
struct dentry *old;

/* Don't create child dentry for a dead directory. */
if (unlikely(IS_DEADDIR(inode))) {
if (unlikely(IS_DEADDIR(dir))) {
dput(dentry);
return ERR_PTR(-ENOENT);
}

old = inode->i_op->lookup(inode, dentry, nd);
old = dir->i_op->lookup(dir, dentry, nd);
if (unlikely(old)) {
dput(dentry);
dentry = old;
Expand All @@ -1111,46 +1123,14 @@ static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentr
static struct dentry *__lookup_hash(struct qstr *name,
struct dentry *base, struct nameidata *nd)
{
bool need_lookup;
struct dentry *dentry;

/*
* Don't bother with __d_lookup: callers are for creat as
* well as unlink, so a lot of the time it would cost
* a double lookup.
*/
dentry = d_lookup(base, name);
dentry = lookup_dcache(name, base, nd, &need_lookup);
if (!need_lookup)
return dentry;

if (dentry && d_need_lookup(dentry)) {
/*
* __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;
return lookup_real(base->d_inode, dentry, nd);
}

/*
Expand Down

0 comments on commit bad6118

Please sign in to comment.