diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-25 11:00:12 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-05-26 07:26:32 -0400 |
commit | 9f1fafee9e42b73beb3aa51ab2d6a19bfddeb5fe (patch) | |
tree | 0c0251b271371e572daf29d2a2282c323c557e8c /fs/namei.c | |
parent | 19660af736ba00e1620970601dd313efedbbcfd2 (diff) |
merge handle_reval_dot and nameidata_drop_rcu_last
new helper: complete_walk(). Done on successful completion
of walk, drops out of RCU mode, does d_revalidate of final
result if that hadn't been done already.
handle_reval_dot() and nameidata_drop_rcu_last() subsumed into
that one; callers converted to use of complete_walk().
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 121 |
1 files changed, 40 insertions, 81 deletions
diff --git a/fs/namei.c b/fs/namei.c index 1039cbae0c12..9f594312d486 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -469,43 +469,6 @@ err_root: | |||
469 | } | 469 | } |
470 | 470 | ||
471 | /** | 471 | /** |
472 | * nameidata_drop_rcu_last - drop nameidata ending path walk out of rcu-walk | ||
473 | * @nd: nameidata pathwalk data to drop | ||
474 | * Returns: 0 on success, -ECHILD on failure | ||
475 | * | ||
476 | * nameidata_drop_rcu_last attempts to drop the current nd->path into ref-walk. | ||
477 | * nd->path should be the final element of the lookup, so nd->root is discarded. | ||
478 | * Must be called from rcu-walk context. | ||
479 | */ | ||
480 | static int nameidata_drop_rcu_last(struct nameidata *nd) | ||
481 | { | ||
482 | struct dentry *dentry = nd->path.dentry; | ||
483 | |||
484 | BUG_ON(!(nd->flags & LOOKUP_RCU)); | ||
485 | nd->flags &= ~LOOKUP_RCU; | ||
486 | if (!(nd->flags & LOOKUP_ROOT)) | ||
487 | nd->root.mnt = NULL; | ||
488 | spin_lock(&dentry->d_lock); | ||
489 | if (!__d_rcu_to_refcount(dentry, nd->seq)) | ||
490 | goto err_unlock; | ||
491 | BUG_ON(nd->inode != dentry->d_inode); | ||
492 | spin_unlock(&dentry->d_lock); | ||
493 | |||
494 | mntget(nd->path.mnt); | ||
495 | |||
496 | rcu_read_unlock(); | ||
497 | br_read_unlock(vfsmount_lock); | ||
498 | |||
499 | return 0; | ||
500 | |||
501 | err_unlock: | ||
502 | spin_unlock(&dentry->d_lock); | ||
503 | rcu_read_unlock(); | ||
504 | br_read_unlock(vfsmount_lock); | ||
505 | return -ECHILD; | ||
506 | } | ||
507 | |||
508 | /** | ||
509 | * release_open_intent - free up open intent resources | 472 | * release_open_intent - free up open intent resources |
510 | * @nd: pointer to nameidata | 473 | * @nd: pointer to nameidata |
511 | */ | 474 | */ |
@@ -548,26 +511,39 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
548 | return dentry; | 511 | return dentry; |
549 | } | 512 | } |
550 | 513 | ||
551 | /* | 514 | /** |
552 | * handle_reval_path - force revalidation of a dentry | 515 | * complete_walk - successful completion of path walk |
553 | * | 516 | * @nd: pointer nameidata |
554 | * In some situations the path walking code will trust dentries without | ||
555 | * revalidating them. This causes problems for filesystems that depend on | ||
556 | * d_revalidate to handle file opens (e.g. NFSv4). When FS_REVAL_DOT is set | ||
557 | * (which indicates that it's possible for the dentry to go stale), force | ||
558 | * a d_revalidate call before proceeding. | ||
559 | * | 517 | * |
560 | * Returns 0 if the revalidation was successful. If the revalidation fails, | 518 | * If we had been in RCU mode, drop out of it and legitimize nd->path. |
561 | * either return the error returned by d_revalidate or -ESTALE if the | 519 | * Revalidate the final result, unless we'd already done that during |
562 | * revalidation it just returned 0. If d_revalidate returns 0, we attempt to | 520 | * the path walk or the filesystem doesn't ask for it. Return 0 on |
563 | * invalidate the dentry. It's up to the caller to handle putting references | 521 | * success, -error on failure. In case of failure caller does not |
564 | * to the path if necessary. | 522 | * need to drop nd->path. |
565 | */ | 523 | */ |
566 | static inline int handle_reval_path(struct nameidata *nd) | 524 | static int complete_walk(struct nameidata *nd) |
567 | { | 525 | { |
568 | struct dentry *dentry = nd->path.dentry; | 526 | struct dentry *dentry = nd->path.dentry; |
569 | int status; | 527 | int status; |
570 | 528 | ||
529 | if (nd->flags & LOOKUP_RCU) { | ||
530 | nd->flags &= ~LOOKUP_RCU; | ||
531 | if (!(nd->flags & LOOKUP_ROOT)) | ||
532 | nd->root.mnt = NULL; | ||
533 | spin_lock(&dentry->d_lock); | ||
534 | if (unlikely(!__d_rcu_to_refcount(dentry, nd->seq))) { | ||
535 | spin_unlock(&dentry->d_lock); | ||
536 | rcu_read_unlock(); | ||
537 | br_read_unlock(vfsmount_lock); | ||
538 | return -ECHILD; | ||
539 | } | ||
540 | BUG_ON(nd->inode != dentry->d_inode); | ||
541 | spin_unlock(&dentry->d_lock); | ||
542 | mntget(nd->path.mnt); | ||
543 | rcu_read_unlock(); | ||
544 | br_read_unlock(vfsmount_lock); | ||
545 | } | ||
546 | |||
571 | if (likely(!(nd->flags & LOOKUP_JUMPED))) | 547 | if (likely(!(nd->flags & LOOKUP_JUMPED))) |
572 | return 0; | 548 | return 0; |
573 | 549 | ||
@@ -585,6 +561,7 @@ static inline int handle_reval_path(struct nameidata *nd) | |||
585 | if (!status) | 561 | if (!status) |
586 | status = -ESTALE; | 562 | status = -ESTALE; |
587 | 563 | ||
564 | path_put(&nd->path); | ||
588 | return status; | 565 | return status; |
589 | } | 566 | } |
590 | 567 | ||
@@ -1598,18 +1575,8 @@ static int path_lookupat(int dfd, const char *name, | |||
1598 | } | 1575 | } |
1599 | } | 1576 | } |
1600 | 1577 | ||
1601 | if (nd->flags & LOOKUP_RCU) { | 1578 | if (!err) |
1602 | /* went all way through without dropping RCU */ | 1579 | err = complete_walk(nd); |
1603 | BUG_ON(err); | ||
1604 | if (nameidata_drop_rcu_last(nd)) | ||
1605 | err = -ECHILD; | ||
1606 | } | ||
1607 | |||
1608 | if (!err) { | ||
1609 | err = handle_reval_path(nd); | ||
1610 | if (err) | ||
1611 | path_put(&nd->path); | ||
1612 | } | ||
1613 | 1580 | ||
1614 | if (!err && nd->flags & LOOKUP_DIRECTORY) { | 1581 | if (!err && nd->flags & LOOKUP_DIRECTORY) { |
1615 | if (!nd->inode->i_op->lookup) { | 1582 | if (!nd->inode->i_op->lookup) { |
@@ -2075,13 +2042,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2075 | return ERR_PTR(error); | 2042 | return ERR_PTR(error); |
2076 | /* fallthrough */ | 2043 | /* fallthrough */ |
2077 | case LAST_ROOT: | 2044 | case LAST_ROOT: |
2078 | if (nd->flags & LOOKUP_RCU) { | 2045 | error = complete_walk(nd); |
2079 | if (nameidata_drop_rcu_last(nd)) | ||
2080 | return ERR_PTR(-ECHILD); | ||
2081 | } | ||
2082 | error = handle_reval_path(nd); | ||
2083 | if (error) | 2046 | if (error) |
2084 | goto exit; | 2047 | return ERR_PTR(error); |
2085 | audit_inode(pathname, nd->path.dentry); | 2048 | audit_inode(pathname, nd->path.dentry); |
2086 | if (open_flag & O_CREAT) { | 2049 | if (open_flag & O_CREAT) { |
2087 | error = -EISDIR; | 2050 | error = -EISDIR; |
@@ -2089,10 +2052,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2089 | } | 2052 | } |
2090 | goto ok; | 2053 | goto ok; |
2091 | case LAST_BIND: | 2054 | case LAST_BIND: |
2092 | /* can't be RCU mode here */ | 2055 | error = complete_walk(nd); |
2093 | error = handle_reval_path(nd); | ||
2094 | if (error) | 2056 | if (error) |
2095 | goto exit; | 2057 | return ERR_PTR(error); |
2096 | audit_inode(pathname, dir); | 2058 | audit_inode(pathname, dir); |
2097 | goto ok; | 2059 | goto ok; |
2098 | } | 2060 | } |
@@ -2111,10 +2073,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2111 | if (error) /* symlink */ | 2073 | if (error) /* symlink */ |
2112 | return NULL; | 2074 | return NULL; |
2113 | /* sayonara */ | 2075 | /* sayonara */ |
2114 | if (nd->flags & LOOKUP_RCU) { | 2076 | error = complete_walk(nd); |
2115 | if (nameidata_drop_rcu_last(nd)) | 2077 | if (error) |
2116 | return ERR_PTR(-ECHILD); | 2078 | return ERR_PTR(-ECHILD); |
2117 | } | ||
2118 | 2079 | ||
2119 | error = -ENOTDIR; | 2080 | error = -ENOTDIR; |
2120 | if (nd->flags & LOOKUP_DIRECTORY) { | 2081 | if (nd->flags & LOOKUP_DIRECTORY) { |
@@ -2126,11 +2087,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2126 | } | 2087 | } |
2127 | 2088 | ||
2128 | /* create side of things */ | 2089 | /* create side of things */ |
2129 | 2090 | error = complete_walk(nd); | |
2130 | if (nd->flags & LOOKUP_RCU) { | 2091 | if (error) |
2131 | if (nameidata_drop_rcu_last(nd)) | 2092 | return ERR_PTR(error); |
2132 | return ERR_PTR(-ECHILD); | ||
2133 | } | ||
2134 | 2093 | ||
2135 | audit_inode(pathname, dir); | 2094 | audit_inode(pathname, dir); |
2136 | error = -EISDIR; | 2095 | error = -EISDIR; |