split do_revalidate() into RCU and non-RCU cases
fixing oopsen in lookup_one_len() Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Родитель
24643087e7
Коммит
f5e1c1c1af
47
fs/namei.c
47
fs/namei.c
|
@ -592,12 +592,10 @@ static int d_revalidate(struct dentry *dentry, struct nameidata *nd)
|
|||
return status;
|
||||
}
|
||||
|
||||
static inline struct dentry *
|
||||
static struct dentry *
|
||||
do_revalidate(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = d_revalidate(dentry, nd);
|
||||
int status = d_revalidate(dentry, nd);
|
||||
if (unlikely(status <= 0)) {
|
||||
/*
|
||||
* The dentry failed validation.
|
||||
|
@ -606,24 +604,39 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd)
|
|||
* to return a fail status.
|
||||
*/
|
||||
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);
|
||||
|
||||
} else {
|
||||
/* Don't d_invalidate in rcu-walk mode */
|
||||
if (nameidata_dentry_drop_rcu_maybe(nd, dentry))
|
||||
return ERR_PTR(-ECHILD);
|
||||
if (!d_invalidate(dentry)) {
|
||||
dput(dentry);
|
||||
dentry = NULL;
|
||||
}
|
||||
} else if (!d_invalidate(dentry)) {
|
||||
dput(dentry);
|
||||
dentry = NULL;
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE)))
|
||||
|
@ -1260,7 +1273,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
|
|||
|
||||
nd->seq = seq;
|
||||
if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
|
||||
dentry = do_revalidate(dentry, nd);
|
||||
dentry = do_revalidate_rcu(dentry, nd);
|
||||
if (!dentry)
|
||||
goto need_lookup;
|
||||
if (IS_ERR(dentry))
|
||||
|
|
Загрузка…
Ссылка в новой задаче