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