aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-02-15 01:32:55 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2011-02-15 02:26:54 -0500
commitf5e1c1c1afc1d979e2ac6a24cc99ba7143639f4d (patch)
tree48dad00e6bead517191094c0c05ef7b01c226e25 /fs/namei.c
parent24643087e748bf192f1182766716e522dc1c972f (diff)
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>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c47
1 files changed, 30 insertions, 17 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 7609bacc7046..a98f7f141780 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -592,12 +592,10 @@ static int d_revalidate(struct dentry *dentry, struct nameidata *nd)
592 return status; 592 return status;
593} 593}
594 594
595static inline struct dentry * 595static struct dentry *
596do_revalidate(struct dentry *dentry, struct nameidata *nd) 596do_revalidate(struct dentry *dentry, struct nameidata *nd)
597{ 597{
598 int status; 598 int status = d_revalidate(dentry, nd);
599
600 status = d_revalidate(dentry, nd);
601 if (unlikely(status <= 0)) { 599 if (unlikely(status <= 0)) {
602 /* 600 /*
603 * The dentry failed validation. 601 * The dentry failed validation.
@@ -606,24 +604,39 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd)
606 * to return a fail status. 604 * to return a fail status.
607 */ 605 */
608 if (status < 0) { 606 if (status < 0) {
609 /* If we're in rcu-walk, we don't have a ref */ 607 dput(dentry);
610 if (!(nd->flags & LOOKUP_RCU))
611 dput(dentry);
612 dentry = ERR_PTR(status); 608 dentry = ERR_PTR(status);
613 609 } else if (!d_invalidate(dentry)) {
614 } else { 610 dput(dentry);
615 /* Don't d_invalidate in rcu-walk mode */ 611 dentry = NULL;
616 if (nameidata_dentry_drop_rcu_maybe(nd, dentry))
617 return ERR_PTR(-ECHILD);
618 if (!d_invalidate(dentry)) {
619 dput(dentry);
620 dentry = NULL;
621 }
622 } 612 }
623 } 613 }
624 return dentry; 614 return dentry;
625} 615}
626 616
617static inline struct dentry *
618do_revalidate_rcu(struct dentry *dentry, struct nameidata *nd)
619{
620 int status = dentry->d_op->d_revalidate(dentry, nd);
621 if (likely(status > 0))
622 return dentry;
623 if (status == -ECHILD) {
624 if (nameidata_dentry_drop_rcu(nd, dentry))
625 return ERR_PTR(-ECHILD);
626 return do_revalidate(dentry, nd);
627 }
628 if (status < 0)
629 return ERR_PTR(status);
630 /* Don't d_invalidate in rcu-walk mode */
631 if (nameidata_dentry_drop_rcu(nd, dentry))
632 return ERR_PTR(-ECHILD);
633 if (!d_invalidate(dentry)) {
634 dput(dentry);
635 dentry = NULL;
636 }
637 return dentry;
638}
639
627static inline int need_reval_dot(struct dentry *dentry) 640static inline int need_reval_dot(struct dentry *dentry)
628{ 641{
629 if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE))) 642 if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE)))
@@ -1260,7 +1273,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
1260 1273
1261 nd->seq = seq; 1274 nd->seq = seq;
1262 if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) { 1275 if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
1263 dentry = do_revalidate(dentry, nd); 1276 dentry = do_revalidate_rcu(dentry, nd);
1264 if (!dentry) 1277 if (!dentry)
1265 goto need_lookup; 1278 goto need_lookup;
1266 if (IS_ERR(dentry)) 1279 if (IS_ERR(dentry))