Commit 9f1fafee9e42b73beb3aa51ab2d6a19bfddeb5fe

Authored by Al Viro
1 parent 19660af736

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>

Showing 1 changed file with 40 additions and 81 deletions Side-by-side Diff

... ... @@ -469,43 +469,6 @@
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 472 * release_open_intent - free up open intent resources
510 473 * @nd: pointer to nameidata
511 474 */
512 475  
513 476  
514 477  
... ... @@ -548,26 +511,39 @@
548 511 return dentry;
549 512 }
550 513  
551   -/*
552   - * handle_reval_path - force revalidation of a dentry
  514 +/**
  515 + * complete_walk - successful completion of path walk
  516 + * @nd: pointer nameidata
553 517 *
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   - *
560   - * Returns 0 if the revalidation was successful. If the revalidation fails,
561   - * either return the error returned by d_revalidate or -ESTALE if the
562   - * revalidation it just returned 0. If d_revalidate returns 0, we attempt to
563   - * invalidate the dentry. It's up to the caller to handle putting references
564   - * to the path if necessary.
  518 + * If we had been in RCU mode, drop out of it and legitimize nd->path.
  519 + * Revalidate the final result, unless we'd already done that during
  520 + * the path walk or the filesystem doesn't ask for it. Return 0 on
  521 + * success, -error on failure. In case of failure caller does not
  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 526 struct dentry *dentry = nd->path.dentry;
569 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 547 if (likely(!(nd->flags & LOOKUP_JUMPED)))
572 548 return 0;
573 549  
... ... @@ -585,6 +561,7 @@
585 561 if (!status)
586 562 status = -ESTALE;
587 563  
  564 + path_put(&nd->path);
588 565 return status;
589 566 }
590 567  
591 568  
... ... @@ -1598,19 +1575,9 @@
1598 1575 }
1599 1576 }
1600 1577  
1601   - if (nd->flags & LOOKUP_RCU) {
1602   - /* went all way through without dropping RCU */
1603   - BUG_ON(err);
1604   - if (nameidata_drop_rcu_last(nd))
1605   - err = -ECHILD;
1606   - }
  1578 + if (!err)
  1579 + err = complete_walk(nd);
1607 1580  
1608   - if (!err) {
1609   - err = handle_reval_path(nd);
1610   - if (err)
1611   - path_put(&nd->path);
1612   - }
1613   -
1614 1581 if (!err && nd->flags & LOOKUP_DIRECTORY) {
1615 1582 if (!nd->inode->i_op->lookup) {
1616 1583 path_put(&nd->path);
1617 1584  
... ... @@ -2075,13 +2042,9 @@
2075 2042 return ERR_PTR(error);
2076 2043 /* fallthrough */
2077 2044 case LAST_ROOT:
2078   - if (nd->flags & LOOKUP_RCU) {
2079   - if (nameidata_drop_rcu_last(nd))
2080   - return ERR_PTR(-ECHILD);
2081   - }
2082   - error = handle_reval_path(nd);
  2045 + error = complete_walk(nd);
2083 2046 if (error)
2084   - goto exit;
  2047 + return ERR_PTR(error);
2085 2048 audit_inode(pathname, nd->path.dentry);
2086 2049 if (open_flag & O_CREAT) {
2087 2050 error = -EISDIR;
2088 2051  
... ... @@ -2089,10 +2052,9 @@
2089 2052 }
2090 2053 goto ok;
2091 2054 case LAST_BIND:
2092   - /* can't be RCU mode here */
2093   - error = handle_reval_path(nd);
  2055 + error = complete_walk(nd);
2094 2056 if (error)
2095   - goto exit;
  2057 + return ERR_PTR(error);
2096 2058 audit_inode(pathname, dir);
2097 2059 goto ok;
2098 2060 }
... ... @@ -2111,10 +2073,9 @@
2111 2073 if (error) /* symlink */
2112 2074 return NULL;
2113 2075 /* sayonara */
2114   - if (nd->flags & LOOKUP_RCU) {
2115   - if (nameidata_drop_rcu_last(nd))
2116   - return ERR_PTR(-ECHILD);
2117   - }
  2076 + error = complete_walk(nd);
  2077 + if (error)
  2078 + return ERR_PTR(-ECHILD);
2118 2079  
2119 2080 error = -ENOTDIR;
2120 2081 if (nd->flags & LOOKUP_DIRECTORY) {
... ... @@ -2126,11 +2087,9 @@
2126 2087 }
2127 2088  
2128 2089 /* create side of things */
2129   -
2130   - if (nd->flags & LOOKUP_RCU) {
2131   - if (nameidata_drop_rcu_last(nd))
2132   - return ERR_PTR(-ECHILD);
2133   - }
  2090 + error = complete_walk(nd);
  2091 + if (error)
  2092 + return ERR_PTR(error);
2134 2093  
2135 2094 audit_inode(pathname, dir);
2136 2095 error = -EISDIR;