|
|
|
@ -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)) |
|
|
|
|