Commit f5e1c1c1 authored by Al Viro's avatar Al Viro

split do_revalidate() into RCU and non-RCU cases

fixing oopsen in lookup_one_len()
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 24643087
...@@ -592,12 +592,10 @@ static int d_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -592,12 +592,10 @@ static int d_revalidate(struct dentry *dentry, struct nameidata *nd)
return status; return status;
} }
static inline struct dentry * static struct dentry *
do_revalidate(struct dentry *dentry, struct nameidata *nd) do_revalidate(struct dentry *dentry, struct nameidata *nd)
{ {
int status; int status = d_revalidate(dentry, nd);
status = d_revalidate(dentry, nd);
if (unlikely(status <= 0)) { if (unlikely(status <= 0)) {
/* /*
* The dentry failed validation. * The dentry failed validation.
...@@ -606,21 +604,36 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -606,21 +604,36 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd)
* to return a fail status. * to return a fail status.
*/ */
if (status < 0) { if (status < 0) {
/* If we're in rcu-walk, we don't have a ref */
if (!(nd->flags & LOOKUP_RCU))
dput(dentry); dput(dentry);
dentry = ERR_PTR(status); dentry = ERR_PTR(status);
} else if (!d_invalidate(dentry)) {
dput(dentry);
dentry = NULL;
}
}
return dentry;
}
} else { static inline struct dentry *
do_revalidate_rcu(struct dentry *dentry, struct nameidata *nd)
{
int status = dentry->d_op->d_revalidate(dentry, nd);
if (likely(status > 0))
return dentry;
if (status == -ECHILD) {
if (nameidata_dentry_drop_rcu(nd, dentry))
return ERR_PTR(-ECHILD);
return do_revalidate(dentry, nd);
}
if (status < 0)
return ERR_PTR(status);
/* Don't d_invalidate in rcu-walk mode */ /* Don't d_invalidate in rcu-walk mode */
if (nameidata_dentry_drop_rcu_maybe(nd, dentry)) if (nameidata_dentry_drop_rcu(nd, dentry))
return ERR_PTR(-ECHILD); return ERR_PTR(-ECHILD);
if (!d_invalidate(dentry)) { if (!d_invalidate(dentry)) {
dput(dentry); dput(dentry);
dentry = NULL; dentry = NULL;
} }
}
}
return dentry; return dentry;
} }
...@@ -1260,7 +1273,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, ...@@ -1260,7 +1273,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
nd->seq = seq; nd->seq = seq;
if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) { if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
dentry = do_revalidate(dentry, nd); dentry = do_revalidate_rcu(dentry, nd);
if (!dentry) if (!dentry)
goto need_lookup; goto need_lookup;
if (IS_ERR(dentry)) if (IS_ERR(dentry))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment