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
1 changed files with 44 additions and 64 deletions
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
|
||||
* 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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue