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,24 +604,39 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -606,24 +604,39 @@ 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 */ dput(dentry);
if (!(nd->flags & LOOKUP_RCU))
dput(dentry);
dentry = ERR_PTR(status); dentry = ERR_PTR(status);
} else if (!d_invalidate(dentry)) {
} else { dput(dentry);
/* Don't d_invalidate in rcu-walk mode */ dentry = NULL;
if (nameidata_dentry_drop_rcu_maybe(nd, dentry))
return ERR_PTR(-ECHILD);
if (!d_invalidate(dentry)) {
dput(dentry);
dentry = NULL;
}
} }
} }
return dentry; return dentry;
} }
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 */
if (nameidata_dentry_drop_rcu(nd, dentry))
return ERR_PTR(-ECHILD);
if (!d_invalidate(dentry)) {
dput(dentry);
dentry = NULL;
}
return dentry;
}
static inline int need_reval_dot(struct dentry *dentry) static inline int need_reval_dot(struct dentry *dentry)
{ {
if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE))) if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE)))
...@@ -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