Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/lookup.c
          +++ new/usr/src/uts/common/fs/lookup.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24      - * Copyright 2016 Joyent, Inc.
       24 + * Copyright (c) 2015, Joyent, Inc. All rights reserved.
  25   25   * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  26   26   */
  27   27  
  28   28  /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
  29   29  /*        All Rights Reserved   */
  30   30  
  31   31  /*
  32   32   * University Copyright- Copyright (c) 1982, 1986, 1988
  33   33   * The Regents of the University of California
  34   34   * All Rights Reserved
  35   35   *
  36   36   * University Acknowledgment- Portions of this document are derived from
  37   37   * software developed by the University of California, Berkeley, and its
  38   38   * contributors.
  39   39   */
  40   40  
  41   41  #include <sys/types.h>
  42   42  #include <sys/param.h>
  43   43  #include <sys/systm.h>
  44   44  #include <sys/cpuvar.h>
  45   45  #include <sys/errno.h>
  46   46  #include <sys/cred.h>
  47   47  #include <sys/user.h>
  48   48  #include <sys/uio.h>
  49   49  #include <sys/vfs.h>
  50   50  #include <sys/vnode.h>
  51   51  #include <sys/pathname.h>
  52   52  #include <sys/proc.h>
  53   53  #include <sys/vtrace.h>
  54   54  #include <sys/sysmacros.h>
  55   55  #include <sys/debug.h>
  56   56  #include <sys/dirent.h>
  57   57  #include <c2/audit.h>
  58   58  #include <sys/zone.h>
  59   59  #include <sys/dnlc.h>
  60   60  #include <sys/fs/snode.h>
  61   61  #include <sys/brand.h>
  62   62  
  63   63  /* Controls whether paths are stored with vnodes. */
  64   64  int vfs_vnode_path = 1;
  65   65  
  66   66  int
  67   67  lookupname(
  68   68          char *fnamep,
  69   69          enum uio_seg seg,
  70   70          int followlink,
  71   71          vnode_t **dirvpp,
  72   72          vnode_t **compvpp)
  73   73  {
  74   74          return (lookupnameatcred(fnamep, seg, followlink, dirvpp, compvpp, NULL,
  75   75              CRED()));
  76   76  }
  77   77  
  78   78  /*
  79   79   * Lookup the user file name,
  80   80   * Handle allocation and freeing of pathname buffer, return error.
  81   81   */
  82   82  int
  83   83  lookupnameatcred(
  84   84          char *fnamep,                   /* user pathname */
  85   85          enum uio_seg seg,               /* addr space that name is in */
  86   86          int followlink,                 /* follow sym links */
  87   87          vnode_t **dirvpp,               /* ret for ptr to parent dir vnode */
  88   88          vnode_t **compvpp,              /* ret for ptr to component vnode */
  89   89          vnode_t *startvp,               /* start path search from vp */
  90   90          cred_t *cr)                     /* credential */
  91   91  {
  92   92          char namebuf[TYPICALMAXPATHLEN];
  93   93          struct pathname lookpn;
  94   94          int error;
  95   95  
  96   96          error = pn_get_buf(fnamep, seg, &lookpn, namebuf, sizeof (namebuf));
  97   97          if (error == 0) {
  98   98                  error = lookuppnatcred(&lookpn, NULL, followlink,
  99   99                      dirvpp, compvpp, startvp, cr);
 100  100          }
 101  101          if (error == ENAMETOOLONG) {
 102  102                  /*
 103  103                   * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
 104  104                   */
 105  105                  if (error = pn_get(fnamep, seg, &lookpn))
 106  106                          return (error);
 107  107                  error = lookuppnatcred(&lookpn, NULL, followlink,
 108  108                      dirvpp, compvpp, startvp, cr);
 109  109                  pn_free(&lookpn);
 110  110          }
 111  111  
 112  112          return (error);
 113  113  }
 114  114  
 115  115  int
 116  116  lookupnameat(char *fnamep, enum uio_seg seg, int followlink,
 117  117      vnode_t **dirvpp, vnode_t **compvpp, vnode_t *startvp)
 118  118  {
 119  119          return (lookupnameatcred(fnamep, seg, followlink, dirvpp, compvpp,
 120  120              startvp, CRED()));
 121  121  }
 122  122  
 123  123  int
 124  124  lookuppn(
 125  125          struct pathname *pnp,
 126  126          struct pathname *rpnp,
 127  127          int followlink,
 128  128          vnode_t **dirvpp,
 129  129          vnode_t **compvpp)
 130  130  {
 131  131          return (lookuppnatcred(pnp, rpnp, followlink, dirvpp, compvpp, NULL,
 132  132              CRED()));
 133  133  }
 134  134  
 135  135  /*
 136  136   * Lookup the user file name from a given vp, using a specific credential.
 137  137   */
 138  138  int
 139  139  lookuppnatcred(
 140  140          struct pathname *pnp,           /* pathname to lookup */
 141  141          struct pathname *rpnp,          /* if non-NULL, return resolved path */
 142  142          int followlink,                 /* (don't) follow sym links */
 143  143          vnode_t **dirvpp,               /* ptr for parent vnode */
 144  144          vnode_t **compvpp,              /* ptr for entry vnode */
 145  145          vnode_t *startvp,               /* start search from this vp */
 146  146          cred_t *cr)                     /* user credential */
 147  147  {
 148  148          vnode_t *vp;    /* current directory vp */
 149  149          vnode_t *rootvp;
 150  150          proc_t *p = curproc;
 151  151  
 152  152          if (pnp->pn_pathlen == 0)
 153  153                  return (ENOENT);
 154  154  
 155  155          mutex_enter(&p->p_lock);        /* for u_rdir and u_cdir */
 156  156          if ((rootvp = PTOU(p)->u_rdir) == NULL)
 157  157                  rootvp = rootdir;
 158  158          else if (rootvp != rootdir)     /* no need to VN_HOLD rootdir */
 159  159                  VN_HOLD(rootvp);
 160  160  
 161  161          if (pnp->pn_path[0] == '/') {
 162  162                  vp = rootvp;
 163  163          } else {
 164  164                  vp = (startvp == NULL) ? PTOU(p)->u_cdir : startvp;
 165  165          }
 166  166          VN_HOLD(vp);
 167  167          mutex_exit(&p->p_lock);
 168  168  
 169  169          /*
 170  170           * Skip over leading slashes
 171  171           */
 172  172          if (pnp->pn_path[0] == '/') {
 173  173                  do {
 174  174                          pnp->pn_path++;
 175  175                          pnp->pn_pathlen--;
 176  176                  } while (pnp->pn_path[0] == '/');
 177  177          }
 178  178  
 179  179          return (lookuppnvp(pnp, rpnp, followlink, dirvpp,
 180  180              compvpp, rootvp, vp, cr));
 181  181  }
 182  182  
 183  183  int
 184  184  lookuppnat(struct pathname *pnp, struct pathname *rpnp,
 185  185      int followlink, vnode_t **dirvpp, vnode_t **compvpp,
 186  186      vnode_t *startvp)
 187  187  {
 188  188          return (lookuppnatcred(pnp, rpnp, followlink, dirvpp, compvpp, startvp,
 189  189              CRED()));
 190  190  }
 191  191  
 192  192  /* Private flag to do our getcwd() dirty work */
 193  193  #define LOOKUP_CHECKREAD        0x10
 194  194  #define LOOKUP_MASK             (~LOOKUP_CHECKREAD)
 195  195  
 196  196  /*
 197  197   * Starting at current directory, translate pathname pnp to end.
 198  198   * Leave pathname of final component in pnp, return the vnode
 199  199   * for the final component in *compvpp, and return the vnode
 200  200   * for the parent of the final component in dirvpp.
 201  201   *
 202  202   * This is the central routine in pathname translation and handles
 203  203   * multiple components in pathnames, separating them at /'s.  It also
 204  204   * implements mounted file systems and processes symbolic links.
 205  205   *
 206  206   * vp is the vnode where the directory search should start.
 207  207   *
 208  208   * Reference counts: vp must be held prior to calling this function.  rootvp
 209  209   * should only be held if rootvp != rootdir.
 210  210   */
 211  211  int
 212  212  lookuppnvp(
 213  213          struct pathname *pnp,           /* pathname to lookup */
 214  214          struct pathname *rpnp,          /* if non-NULL, return resolved path */
 215  215          int flags,                      /* follow symlinks */
 216  216          vnode_t **dirvpp,               /* ptr for parent vnode */
 217  217          vnode_t **compvpp,              /* ptr for entry vnode */
 218  218          vnode_t *rootvp,                /* rootvp */
 219  219          vnode_t *vp,                    /* directory to start search at */
 220  220          cred_t *cr)                     /* user's credential */
 221  221  {
 222  222          vnode_t *cvp;   /* current component vp */
 223  223          char component[MAXNAMELEN];     /* buffer for component (incl null) */
 224  224          int error;
 225  225          int nlink;
 226  226          int lookup_flags;
 227  227          struct pathname presrvd; /* case preserved name */
 228  228          struct pathname *pp = NULL;
 229  229          vnode_t *startvp;
 230  230          vnode_t *zonevp = curproc->p_zone->zone_rootvp;         /* zone root */
 231  231          int must_be_directory = 0;
 232  232          boolean_t retry_with_kcred;
 233  233          uint32_t auditing = AU_AUDITING();
 234  234  
 235  235          CPU_STATS_ADDQ(CPU, sys, namei, 1);
 236  236          nlink = 0;
 237  237          cvp = NULL;
 238  238          if (rpnp)
 239  239                  rpnp->pn_pathlen = 0;
 240  240  
 241  241          lookup_flags = dirvpp ? LOOKUP_DIR : 0;
 242  242          if (flags & FIGNORECASE) {
 243  243                  lookup_flags |= FIGNORECASE;
 244  244                  pn_alloc(&presrvd);
 245  245                  pp = &presrvd;
 246  246          }
 247  247  
 248  248          if (auditing)
 249  249                  audit_anchorpath(pnp, vp == rootvp);
 250  250  
 251  251          /*
 252  252           * Eliminate any trailing slashes in the pathname.
 253  253           * If there are any, we must follow all symlinks.
 254  254           * Also, we must guarantee that the last component is a directory.
 255  255           */
 256  256          if (pn_fixslash(pnp)) {
 257  257                  flags |= FOLLOW;
 258  258                  must_be_directory = 1;
 259  259          }
 260  260  
 261  261          startvp = vp;
 262  262  next:
 263  263          retry_with_kcred = B_FALSE;
 264  264  
 265  265          /*
 266  266           * Make sure we have a directory.
 267  267           */
 268  268          if (vp->v_type != VDIR) {
 269  269                  error = ENOTDIR;
 270  270                  goto bad;
 271  271          }
 272  272  
 273  273          if (rpnp && VN_CMP(vp, rootvp))
 274  274                  (void) pn_set(rpnp, "/");
 275  275  
 276  276          /*
 277  277           * Process the next component of the pathname.
 278  278           */
 279  279          if (error = pn_getcomponent(pnp, component)) {
 280  280                  goto bad;
 281  281          }
 282  282  
 283  283          /*
 284  284           * Handle "..": two special cases.
 285  285           * 1. If we're at the root directory (e.g. after chroot or
 286  286           *    zone_enter) then change ".." to "." so we can't get
 287  287           *    out of this subtree.
 288  288           * 2. If this vnode is the root of a mounted file system,
 289  289           *    then replace it with the vnode that was mounted on
 290  290           *    so that we take the ".." in the other file system.
 291  291           */
 292  292          if (component[0] == '.' && component[1] == '.' && component[2] == 0) {
 293  293  checkforroot:
 294  294                  if (VN_CMP(vp, rootvp) || VN_CMP(vp, zonevp)) {
 295  295                          component[1] = '\0';
 296  296                  } else if (vp->v_flag & VROOT) {
 297  297                          vfs_t *vfsp;
 298  298                          cvp = vp;
 299  299  
 300  300                          /*
 301  301                           * While we deal with the vfs pointer from the vnode
 302  302                           * the filesystem could have been forcefully unmounted
 303  303                           * and the vnode's v_vfsp could have been invalidated
 304  304                           * by VFS_UNMOUNT. Hence, we cache v_vfsp and use it
 305  305                           * with vfs_rlock_wait/vfs_unlock.
 306  306                           * It is safe to use the v_vfsp even it is freed by
 307  307                           * VFS_UNMOUNT because vfs_rlock_wait/vfs_unlock
 308  308                           * do not dereference v_vfsp. It is just used as a
 309  309                           * magic cookie.
 310  310                           * One more corner case here is the memory getting
 311  311                           * reused for another vfs structure. In this case
 312  312                           * lookuppnvp's vfs_rlock_wait will succeed, domount's
 313  313                           * vfs_lock will fail and domount will bail out with an
 314  314                           * error (EBUSY).
 315  315                           */
 316  316                          vfsp = cvp->v_vfsp;
 317  317  
 318  318                          /*
 319  319                           * This lock is used to synchronize
 320  320                           * mounts/unmounts and lookups.
 321  321                           * Threads doing mounts/unmounts hold the
 322  322                           * writers version vfs_lock_wait().
 323  323                           */
 324  324  
 325  325                          vfs_rlock_wait(vfsp);
 326  326  
 327  327                          /*
 328  328                           * If this vnode is on a file system that
 329  329                           * has been forcibly unmounted,
 330  330                           * we can't proceed. Cancel this operation
 331  331                           * and return EIO.
 332  332                           *
 333  333                           * vfs_vnodecovered is NULL if unmounted.
 334  334                           * Currently, nfs uses VFS_UNMOUNTED to
 335  335                           * check if it's a forced-umount. Keep the
 336  336                           * same checking here as well even though it
 337  337                           * may not be needed.
 338  338                           */
 339  339                          if (((vp = cvp->v_vfsp->vfs_vnodecovered) == NULL) ||
 340  340                              (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) {
 341  341                                  vfs_unlock(vfsp);
 342  342                                  VN_RELE(cvp);
 343  343                                  if (pp)
 344  344                                          pn_free(pp);
 345  345                                  return (EIO);
 346  346                          }
 347  347                          VN_HOLD(vp);
 348  348                          vfs_unlock(vfsp);
 349  349                          VN_RELE(cvp);
 350  350                          cvp = NULL;
 351  351                          /*
 352  352                           * Crossing mount points. For eg: We are doing
 353  353                           * a lookup of ".." for file systems root vnode
 354  354                           * mounted here, and VOP_LOOKUP() (with covered vnode)
 355  355                           * will be on underlying file systems mount point
 356  356                           * vnode. Set retry_with_kcred flag as we might end
 357  357                           * up doing VOP_LOOKUP() with kcred if required.
 358  358                           */
 359  359                          retry_with_kcred = B_TRUE;
 360  360                          goto checkforroot;
 361  361                  }
 362  362          }
 363  363  
 364  364          /*
 365  365           * LOOKUP_CHECKREAD is a private flag used by vnodetopath() to indicate
 366  366           * that we need to have read permission on every directory in the entire
 367  367           * path.  This is used to ensure that a forward-lookup of a cached value
 368  368           * has the same effect as a reverse-lookup when the cached value cannot
 369  369           * be found.
 370  370           */
 371  371          if ((flags & LOOKUP_CHECKREAD) &&
 372  372              (error = VOP_ACCESS(vp, VREAD, 0, cr, NULL)) != 0)
 373  373                  goto bad;
 374  374  
 375  375          /*
 376  376           * Perform a lookup in the current directory.
 377  377           */
 378  378          error = VOP_LOOKUP(vp, component, &cvp, pnp, lookup_flags,
 379  379              rootvp, cr, NULL, NULL, pp);
 380  380  
 381  381          /*
 382  382           * Retry with kcred - If crossing mount points & error is EACCES.
 383  383           *
 384  384           * If we are crossing mount points here and doing ".." lookup,
 385  385           * VOP_LOOKUP() might fail if the underlying file systems
 386  386           * mount point has no execute permission. In cases like these,
 387  387           * we retry VOP_LOOKUP() by giving as much privilage as possible
 388  388           * by passing kcred credentials.
 389  389           *
 390  390           * In case of hierarchical file systems, passing kcred still may
 391  391           * or may not work.
 392  392           * For eg: UFS FS --> Mount NFS FS --> Again mount UFS on some
 393  393           *                      directory inside NFS FS.
 394  394           */
 395  395          if ((error == EACCES) && retry_with_kcred)
 396  396                  error = VOP_LOOKUP(vp, component, &cvp, pnp, lookup_flags,
 397  397                      rootvp, zone_kcred(), NULL, NULL, pp);
 398  398  
 399  399          if (error) {
 400  400                  cvp = NULL;
 401  401                  /*
 402  402                   * On error, return hard error if
 403  403                   * (a) we're not at the end of the pathname yet, or
 404  404                   * (b) the caller didn't want the parent directory, or
 405  405                   * (c) we failed for some reason other than a missing entry.
 406  406                   */
 407  407                  if (pn_pathleft(pnp) || dirvpp == NULL || error != ENOENT)
 408  408                          goto bad;
 409  409                  if (auditing) { /* directory access */
 410  410                          if (error = audit_savepath(pnp, vp, vp, error, cr))
 411  411                                  goto bad_noaudit;
 412  412                  }
 413  413  
 414  414                  pn_setlast(pnp);
 415  415                  /*
 416  416                   * We inform the caller that the desired entry must be
 417  417                   * a directory by adding a '/' to the component name.
 418  418                   */
 419  419                  if (must_be_directory && (error = pn_addslash(pnp)) != 0)
 420  420                          goto bad;
 421  421                  *dirvpp = vp;
 422  422                  if (compvpp != NULL)
 423  423                          *compvpp = NULL;
 424  424                  if (rootvp != rootdir)
 425  425                          VN_RELE(rootvp);
 426  426                  if (pp)
 427  427                          pn_free(pp);
 428  428                  return (0);
 429  429          }
 430  430  
 431  431          /*
 432  432           * Traverse mount points.
 433  433           * XXX why don't we need to hold a read lock here (call vn_vfsrlock)?
 434  434           * What prevents a concurrent update to v_vfsmountedhere?
 435  435           *      Possible answer: if mounting, we might not see the mount
 436  436           *      if it is concurrently coming into existence, but that's
 437  437           *      really not much different from the thread running a bit slower.
 438  438           *      If unmounting, we may get into traverse() when we shouldn't,
 439  439           *      but traverse() will catch this case for us.
 440  440           *      (For this to work, fetching v_vfsmountedhere had better
 441  441           *      be atomic!)
 442  442           */
 443  443          if (vn_mountedvfs(cvp) != NULL) {
 444  444                  if ((error = traverse(&cvp)) != 0)
 445  445                          goto bad;
 446  446          }
 447  447  
 448  448          /*
 449  449           * If we hit a symbolic link and there is more path to be
 450  450           * translated or this operation does not wish to apply
 451  451           * to a link, then place the contents of the link at the
 452  452           * front of the remaining pathname.
 453  453           */
 454  454          if (cvp->v_type == VLNK && ((flags & FOLLOW) || pn_pathleft(pnp))) {
 455  455                  struct pathname linkpath;
 456  456  
 457  457                  if (++nlink > MAXSYMLINKS) {
 458  458                          error = ELOOP;
 459  459                          goto bad;
 460  460                  }
 461  461                  pn_alloc(&linkpath);
 462  462                  if (error = pn_getsymlink(cvp, &linkpath, cr)) {
 463  463                          pn_free(&linkpath);
 464  464                          goto bad;
 465  465                  }
 466  466  
 467  467                  if (auditing)
 468  468                          audit_symlink(pnp, &linkpath);
 469  469  
 470  470                  if (pn_pathleft(&linkpath) == 0)
 471  471                          (void) pn_set(&linkpath, ".");
 472  472                  error = pn_insert(pnp, &linkpath, strlen(component));
 473  473                  pn_free(&linkpath);
 474  474                  if (error)
 475  475                          goto bad;
 476  476                  VN_RELE(cvp);
 477  477                  cvp = NULL;
 478  478                  if (pnp->pn_pathlen == 0) {
 479  479                          error = ENOENT;
 480  480                          goto bad;
 481  481                  }
 482  482                  if (pnp->pn_path[0] == '/') {
 483  483                          do {
 484  484                                  pnp->pn_path++;
 485  485                                  pnp->pn_pathlen--;
 486  486                          } while (pnp->pn_path[0] == '/');
 487  487                          VN_RELE(vp);
 488  488                          vp = rootvp;
 489  489                          VN_HOLD(vp);
 490  490                  }
 491  491                  if (auditing)
 492  492                          audit_anchorpath(pnp, vp == rootvp);
 493  493                  if (pn_fixslash(pnp)) {
 494  494                          flags |= FOLLOW;
 495  495                          must_be_directory = 1;
 496  496                  }
 497  497                  goto next;
 498  498          }
 499  499  
 500  500          /*
 501  501           * If rpnp is non-NULL, remember the resolved path name therein.
 502  502           * Do not include "." components.  Collapse occurrences of
 503  503           * "previous/..", so long as "previous" is not itself "..".
 504  504           * Exhausting rpnp results in error ENAMETOOLONG.
 505  505           */
 506  506          if (rpnp && strcmp(component, ".") != 0) {
 507  507                  size_t len;
 508  508  
 509  509                  if (strcmp(component, "..") == 0 &&
 510  510                      rpnp->pn_pathlen != 0 &&
 511  511                      !((rpnp->pn_pathlen > 2 &&
 512  512                      strncmp(rpnp->pn_path+rpnp->pn_pathlen-3, "/..", 3) == 0) ||
 513  513                      (rpnp->pn_pathlen == 2 &&
 514  514                      strncmp(rpnp->pn_path, "..", 2) == 0))) {
 515  515                          while (rpnp->pn_pathlen &&
 516  516                              rpnp->pn_path[rpnp->pn_pathlen-1] != '/')
 517  517                                  rpnp->pn_pathlen--;
 518  518                          if (rpnp->pn_pathlen > 1)
 519  519                                  rpnp->pn_pathlen--;
 520  520                          rpnp->pn_path[rpnp->pn_pathlen] = '\0';
 521  521                  } else {
 522  522                          if (rpnp->pn_pathlen != 0 &&
 523  523                              rpnp->pn_path[rpnp->pn_pathlen-1] != '/')
 524  524                                  rpnp->pn_path[rpnp->pn_pathlen++] = '/';
 525  525                          if (flags & FIGNORECASE) {
 526  526                                  /*
 527  527                                   * Return the case-preserved name
 528  528                                   * within the resolved path.
 529  529                                   */
 530  530                                  error = copystr(pp->pn_buf,
 531  531                                      rpnp->pn_path + rpnp->pn_pathlen,
 532  532                                      rpnp->pn_bufsize - rpnp->pn_pathlen, &len);
 533  533                          } else {
 534  534                                  error = copystr(component,
 535  535                                      rpnp->pn_path + rpnp->pn_pathlen,
 536  536                                      rpnp->pn_bufsize - rpnp->pn_pathlen, &len);
 537  537                          }
 538  538                          if (error)      /* copystr() returns ENAMETOOLONG */
 539  539                                  goto bad;
 540  540                          rpnp->pn_pathlen += (len - 1);
 541  541                          ASSERT(rpnp->pn_bufsize > rpnp->pn_pathlen);
 542  542                  }
 543  543          }
 544  544  
 545  545          /*
 546  546           * If no more components, return last directory (if wanted) and
 547  547           * last component (if wanted).
 548  548           */
 549  549          if (pn_pathleft(pnp) == 0) {
 550  550                  /*
 551  551                   * If there was a trailing slash in the pathname,
 552  552                   * make sure the last component is a directory.
 553  553                   */
 554  554                  if (must_be_directory && cvp->v_type != VDIR) {
 555  555                          error = ENOTDIR;
 556  556                          goto bad;
 557  557                  }
 558  558                  if (dirvpp != NULL) {
 559  559                          /*
 560  560                           * Check that we have the real parent and not
 561  561                           * an alias of the last component.
 562  562                           */
 563  563                          if (vn_compare(vp, cvp)) {
 564  564                                  if (auditing)
 565  565                                          (void) audit_savepath(pnp, cvp, vp,
 566  566                                              EINVAL, cr);
 567  567                                  pn_setlast(pnp);
 568  568                                  VN_RELE(vp);
 569  569                                  VN_RELE(cvp);
 570  570                                  if (rootvp != rootdir)
 571  571                                          VN_RELE(rootvp);
 572  572                                  if (pp)
 573  573                                          pn_free(pp);
 574  574                                  return (EINVAL);
 575  575                          }
 576  576                          *dirvpp = vp;
 577  577                  } else
 578  578                          VN_RELE(vp);
 579  579                  if (auditing)
 580  580                          (void) audit_savepath(pnp, cvp, vp, 0, cr);
 581  581                  if (pnp->pn_path == pnp->pn_buf)
 582  582                          (void) pn_set(pnp, ".");
 583  583                  else
 584  584                          pn_setlast(pnp);
 585  585                  if (rpnp) {
 586  586                          if (VN_CMP(cvp, rootvp))
 587  587                                  (void) pn_set(rpnp, "/");
 588  588                          else if (rpnp->pn_pathlen == 0)
 589  589                                  (void) pn_set(rpnp, ".");
 590  590                  }
 591  591  
 592  592                  if (compvpp != NULL)
 593  593                          *compvpp = cvp;
 594  594                  else
 595  595                          VN_RELE(cvp);
 596  596                  if (rootvp != rootdir)
 597  597                          VN_RELE(rootvp);
 598  598                  if (pp)
 599  599                          pn_free(pp);
 600  600                  return (0);
 601  601          }
 602  602  
 603  603          /*
 604  604           * Skip over slashes from end of last component.
 605  605           */
 606  606          while (pnp->pn_path[0] == '/') {
 607  607                  pnp->pn_path++;
 608  608                  pnp->pn_pathlen--;
 609  609          }
 610  610  
 611  611          /*
 612  612           * Searched through another level of directory:
 613  613           * release previous directory handle and save new (result
 614  614           * of lookup) as current directory.
 615  615           */
 616  616          VN_RELE(vp);
 617  617          vp = cvp;
 618  618          cvp = NULL;
 619  619          goto next;
 620  620  
 621  621  bad:
 622  622          if (auditing)   /* reached end of path */
 623  623                  (void) audit_savepath(pnp, cvp, vp, error, cr);
 624  624  bad_noaudit:
 625  625          /*
 626  626           * Error.  Release vnodes and return.
 627  627           */
 628  628          if (cvp)
 629  629                  VN_RELE(cvp);
 630  630          /*
 631  631           * If the error was ESTALE and the current directory to look in
 632  632           * was the root for this lookup, the root for a mounted file
 633  633           * system, or the starting directory for lookups, then
 634  634           * return ENOENT instead of ESTALE.  In this case, no recovery
 635  635           * is possible by the higher level.  If ESTALE was returned for
 636  636           * some intermediate directory along the path, then recovery
 637  637           * is potentially possible and retrying from the higher level
 638  638           * will either correct the situation by purging stale cache
 639  639           * entries or eventually get back to the point where no recovery
 640  640           * is possible.
 641  641           */
 642  642          if (error == ESTALE &&
 643  643              (VN_CMP(vp, rootvp) || (vp->v_flag & VROOT) || vp == startvp))
 644  644                  error = ENOENT;
 645  645          VN_RELE(vp);
 646  646          if (rootvp != rootdir)
 647  647                  VN_RELE(rootvp);
 648  648          if (pp)
 649  649                  pn_free(pp);
 650  650          return (error);
 651  651  }
 652  652  
 653  653  /*
 654  654   * Traverse a mount point.  Routine accepts a vnode pointer as a reference
 655  655   * parameter and performs the indirection, releasing the original vnode.
 656  656   */
 657  657  int
 658  658  traverse(vnode_t **cvpp)
 659  659  {
 660  660          int error = 0;
 661  661          vnode_t *cvp;
 662  662          vnode_t *tvp;
 663  663          vfs_t *vfsp;
 664  664  
 665  665          cvp = *cvpp;
 666  666  
 667  667          /*
 668  668           * If this vnode is mounted on, then we transparently indirect
 669  669           * to the vnode which is the root of the mounted file system.
 670  670           * Before we do this we must check that an unmount is not in
 671  671           * progress on this vnode.
 672  672           */
 673  673  
 674  674          for (;;) {
 675  675                  /*
 676  676                   * Try to read lock the vnode.  If this fails because
 677  677                   * the vnode is already write locked, then check to
 678  678                   * see whether it is the current thread which locked
 679  679                   * the vnode.  If it is not, then read lock the vnode
 680  680                   * by waiting to acquire the lock.
 681  681                   *
 682  682                   * The code path in domount() is an example of support
 683  683                   * which needs to look up two pathnames and locks one
 684  684                   * of them in between the two lookups.
 685  685                   */
 686  686                  error = vn_vfsrlock(cvp);
 687  687                  if (error) {
 688  688                          if (!vn_vfswlock_held(cvp))
 689  689                                  error = vn_vfsrlock_wait(cvp);
 690  690                          if (error != 0) {
 691  691                                  /*
 692  692                                   * lookuppn() expects a held vnode to be
 693  693                                   * returned because it promptly calls
 694  694                                   * VN_RELE after the error return
 695  695                                   */
 696  696                                  *cvpp = cvp;
 697  697                                  return (error);
 698  698                          }
 699  699                  }
 700  700  
 701  701                  /*
 702  702                   * Reached the end of the mount chain?
 703  703                   */
 704  704                  vfsp = vn_mountedvfs(cvp);
 705  705                  if (vfsp == NULL) {
 706  706                          vn_vfsunlock(cvp);
 707  707                          break;
 708  708                  }
 709  709  
 710  710                  /*
 711  711                   * The read lock must be held across the call to VFS_ROOT() to
 712  712                   * prevent a concurrent unmount from destroying the vfs.
 713  713                   */
 714  714                  error = VFS_ROOT(vfsp, &tvp);
 715  715                  vn_vfsunlock(cvp);
 716  716  
 717  717                  if (error)
 718  718                          break;
 719  719  
 720  720                  VN_RELE(cvp);
 721  721  
 722  722                  cvp = tvp;
 723  723          }
 724  724  
 725  725          *cvpp = cvp;
 726  726          return (error);
 727  727  }
 728  728  
 729  729  /*
 730  730   * Return the lowermost vnode if this is a mountpoint.
 731  731   */
 732  732  static vnode_t *
 733  733  vn_under(vnode_t *vp)
 734  734  {
 735  735          vnode_t *uvp;
 736  736          vfs_t *vfsp;
 737  737  
 738  738          while (vp->v_flag & VROOT) {
 739  739  
 740  740                  vfsp = vp->v_vfsp;
 741  741                  vfs_rlock_wait(vfsp);
 742  742                  if ((uvp = vfsp->vfs_vnodecovered) == NULL ||
 743  743                      (vfsp->vfs_flag & VFS_UNMOUNTED)) {
 744  744                          vfs_unlock(vfsp);
 745  745                          break;
 746  746                  }
 747  747                  VN_HOLD(uvp);
 748  748                  vfs_unlock(vfsp);
 749  749                  VN_RELE(vp);
 750  750                  vp = uvp;
 751  751          }
 752  752  
 753  753          return (vp);
 754  754  }
 755  755  
 756  756  static int
 757  757  vnode_match(vnode_t *v1, vnode_t *v2, cred_t *cr)
 758  758  {
 759  759          vattr_t v1attr, v2attr;
 760  760  
 761  761          /*
 762  762           * If we have a device file, check to see if is a cloned open of the
 763  763           * same device.  For self-cloning devices, the major numbers will match.
 764  764           * For devices cloned through the 'clone' driver, the minor number of
 765  765           * the source device will be the same as the major number of the cloned
 766  766           * device.
 767  767           */
 768  768          if ((v1->v_type == VCHR || v1->v_type == VBLK) &&
 769  769              v1->v_type == v2->v_type) {
 770  770                  if ((spec_is_selfclone(v1) || spec_is_selfclone(v2)) &&
 771  771                      getmajor(v1->v_rdev) == getmajor(v2->v_rdev))
 772  772                          return (1);
 773  773  
 774  774                  if (spec_is_clone(v1) &&
 775  775                      getmajor(v1->v_rdev) == getminor(v2->v_rdev))
 776  776                          return (1);
 777  777  
 778  778                  if (spec_is_clone(v2) &&
 779  779                      getmajor(v2->v_rdev) == getminor(v1->v_rdev))
 780  780                          return (1);
 781  781          }
 782  782  
 783  783          v1attr.va_mask = v2attr.va_mask = AT_TYPE;
 784  784  
 785  785          /*
 786  786           * This check for symbolic links handles the pseudo-symlinks in procfs.
 787  787           * These particular links have v_type of VDIR, but the attributes have a
 788  788           * type of VLNK.  We need to avoid these links because otherwise if we
 789  789           * are currently in '/proc/self/fd', then '/proc/self/cwd' will compare
 790  790           * as the same vnode.
 791  791           */
 792  792          if (VOP_GETATTR(v1, &v1attr, 0, cr, NULL) != 0 ||
 793  793              VOP_GETATTR(v2, &v2attr, 0, cr, NULL) != 0 ||
 794  794              v1attr.va_type == VLNK || v2attr.va_type == VLNK)
 795  795                  return (0);
 796  796  
 797  797          v1attr.va_mask = v2attr.va_mask = AT_TYPE | AT_FSID | AT_NODEID;
 798  798  
 799  799          if (VOP_GETATTR(v1, &v1attr, ATTR_REAL, cr, NULL) != 0 ||
 800  800              VOP_GETATTR(v2, &v2attr, ATTR_REAL, cr, NULL) != 0)
 801  801                  return (0);
 802  802  
 803  803          return (v1attr.va_fsid == v2attr.va_fsid &&
 804  804              v1attr.va_nodeid == v2attr.va_nodeid);
 805  805  }
 806  806  
 807  807  
 808  808  /*
 809  809   * Find the entry in the directory corresponding to the target vnode.
 810  810   */
 811  811  int
 812  812  dirfindvp(vnode_t *vrootp, vnode_t *dvp, vnode_t *tvp, cred_t *cr, char *dbuf,
 813  813      size_t dlen, dirent64_t **rdp)
 814  814  {
 815  815          size_t dbuflen;
 816  816          struct iovec iov;
 817  817          struct uio uio;
 818  818          int error;
 819  819          int eof;
 820  820          vnode_t *cmpvp;
 821  821          struct dirent64 *dp;
 822  822          pathname_t pnp;
 823  823  
 824  824          ASSERT(dvp->v_type == VDIR);
 825  825  
 826  826          /*
 827  827           * This is necessary because of the strange semantics of VOP_LOOKUP().
 828  828           */
 829  829          bzero(&pnp, sizeof (pnp));
 830  830  
 831  831          eof = 0;
 832  832  
 833  833          uio.uio_iov = &iov;
 834  834          uio.uio_iovcnt = 1;
 835  835          uio.uio_segflg = UIO_SYSSPACE;
 836  836          uio.uio_fmode = 0;
 837  837          uio.uio_extflg = UIO_COPY_CACHED;
 838  838          uio.uio_loffset = 0;
 839  839  
 840  840          if ((error = VOP_ACCESS(dvp, VREAD, 0, cr, NULL)) != 0)
 841  841                  return (error);
 842  842  
 843  843          while (!eof) {
 844  844                  uio.uio_resid = dlen;
 845  845                  iov.iov_base = dbuf;
 846  846                  iov.iov_len = dlen;
 847  847  
 848  848                  (void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL);
 849  849                  error = VOP_READDIR(dvp, &uio, cr, &eof, NULL, 0);
 850  850                  VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL);
 851  851  
 852  852                  dbuflen = dlen - uio.uio_resid;
 853  853  
 854  854                  if (error || dbuflen == 0)
 855  855                          break;
 856  856  
 857  857                  dp = (dirent64_t *)dbuf;
 858  858                  while ((intptr_t)dp < (intptr_t)dbuf + dbuflen) {
 859  859                          /*
 860  860                           * Ignore '.' and '..' entries
 861  861                           */
 862  862                          if (strcmp(dp->d_name, ".") == 0 ||
 863  863                              strcmp(dp->d_name, "..") == 0) {
 864  864                                  dp = (dirent64_t *)((intptr_t)dp +
 865  865                                      dp->d_reclen);
 866  866                                  continue;
 867  867                          }
 868  868  
 869  869                          error = VOP_LOOKUP(dvp, dp->d_name, &cmpvp, &pnp, 0,
 870  870                              vrootp, cr, NULL, NULL, NULL);
 871  871  
 872  872                          /*
 873  873                           * We only want to bail out if there was an error other
 874  874                           * than ENOENT.  Otherwise, it could be that someone
 875  875                           * just removed an entry since the readdir() call, and
 876  876                           * the entry we want is further on in the directory.
 877  877                           */
 878  878                          if (error == 0) {
 879  879                                  if (vnode_match(tvp, cmpvp, cr)) {
 880  880                                          VN_RELE(cmpvp);
 881  881                                          *rdp = dp;
 882  882                                          return (0);
 883  883                                  }
 884  884  
 885  885                                  VN_RELE(cmpvp);
 886  886                          } else if (error != ENOENT) {
 887  887                                  return (error);
 888  888                          }
 889  889  
 890  890                          dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen);
 891  891                  }
 892  892          }
 893  893  
 894  894          /*
 895  895           * Something strange has happened, this directory does not contain the
 896  896           * specified vnode.  This should never happen in the normal case, since
 897  897           * we ensured that dvp is the parent of vp.  This is possible in some
 898  898           * rare conditions (races and the special .zfs directory).
 899  899           */
 900  900          if (error == 0) {
 901  901                  error = VOP_LOOKUP(dvp, ".zfs", &cmpvp, &pnp, 0, vrootp, cr,
 902  902                      NULL, NULL, NULL);
 903  903                  if (error == 0) {
 904  904                          if (vnode_match(tvp, cmpvp, cr)) {
 905  905                                  (void) strcpy(dp->d_name, ".zfs");
 906  906                                  dp->d_reclen = strlen(".zfs");
 907  907                                  dp->d_off = 2;
 908  908                                  dp->d_ino = 1;
 909  909                                  *rdp = dp;
 910  910                          } else {
 911  911                                  error = ENOENT;
 912  912                          }
 913  913                          VN_RELE(cmpvp);
 914  914                  }
 915  915          }
 916  916  
 917  917          return (error);
 918  918  }
 919  919  
 920  920  /*
 921  921   * Given a global path (from rootdir), and a vnode that is the current root,
 922  922   * return the portion of the path that is beneath the current root or NULL on
 923  923   * failure.  The path MUST be a resolved path (no '..' entries or symlinks),
 924  924   * otherwise this function will fail.
 925  925   */
 926  926  static char *
 927  927  localpath(char *path, struct vnode *vrootp, cred_t *cr)
 928  928  {
 929  929          vnode_t *vp;
 930  930          vnode_t *cvp;
 931  931          char component[MAXNAMELEN];
 932  932          char *ret = NULL;
 933  933          pathname_t pn;
 934  934  
 935  935          /*
 936  936           * We use vn_compare() instead of VN_CMP() in order to detect lofs
 937  937           * mounts and stacked vnodes.
 938  938           */
 939  939          if (vn_compare(vrootp, rootdir))
 940  940                  return (path);
 941  941  
 942  942          if (pn_get(path, UIO_SYSSPACE, &pn) != 0)
 943  943                  return (NULL);
 944  944  
 945  945          vp = rootdir;
 946  946          VN_HOLD(vp);
 947  947  
 948  948          if (vn_ismntpt(vp) && traverse(&vp) != 0) {
 949  949                  VN_RELE(vp);
 950  950                  pn_free(&pn);
 951  951                  return (NULL);
 952  952          }
 953  953  
 954  954          while (pn_pathleft(&pn)) {
 955  955                  pn_skipslash(&pn);
 956  956  
 957  957                  if (pn_getcomponent(&pn, component) != 0)
 958  958                          break;
 959  959  
 960  960                  if (VOP_LOOKUP(vp, component, &cvp, &pn, 0, rootdir, cr,
 961  961                      NULL, NULL, NULL) != 0)
 962  962                          break;
 963  963                  VN_RELE(vp);
 964  964                  vp = cvp;
 965  965  
 966  966                  if (vn_ismntpt(vp) && traverse(&vp) != 0)
 967  967                          break;
 968  968  
 969  969                  if (vn_compare(vp, vrootp)) {
 970  970                          ret = path + (pn.pn_path - pn.pn_buf);
 971  971                          break;
  
    | 
      ↓ open down ↓ | 
    937 lines elided | 
    
      ↑ open up ↑ | 
  
 972  972                  }
 973  973          }
 974  974  
 975  975          VN_RELE(vp);
 976  976          pn_free(&pn);
 977  977  
 978  978          return (ret);
 979  979  }
 980  980  
 981  981  /*
 982      - * Clean a stale v_path from a vnode.  This is only performed if the v_path has
 983      - * not been altered since it was found to be stale
 984      - */
 985      -static void
 986      -vnode_clear_vpath(vnode_t *vp, char *vpath_old)
 987      -{
 988      -        mutex_enter(&vp->v_lock);
 989      -        if (vp->v_path != vn_vpath_empty && vp->v_path == vpath_old) {
 990      -                vp->v_path = vn_vpath_empty;
 991      -                mutex_exit(&vp->v_lock);
 992      -                kmem_free(vpath_old, strlen(vpath_old) + 1);
 993      -        } else {
 994      -                mutex_exit(&vp->v_lock);
 995      -        }
 996      -}
 997      -
 998      -/*
 999      - * Validate that a pathname refers to a given vnode.
1000      - */
1001      -static int
1002      -vnode_valid_pn(vnode_t *vp, vnode_t *vrootp, pathname_t *pn, pathname_t *rpn,
1003      -    int flags, cred_t *cr)
1004      -{
1005      -        vnode_t *compvp;
1006      -        /*
1007      -         * If we are in a zone or a chroot environment, then we have to
1008      -         * take additional steps, since the path to the root might not
1009      -         * be readable with the current credentials, even though the
1010      -         * process can legitmately access the file.  In this case, we
1011      -         * do the following:
1012      -         *
1013      -         * lookuppnvp() with all privileges to get the resolved path.
1014      -         * call localpath() to get the local portion of the path, and
1015      -         * continue as normal.
1016      -         *
1017      -         * If the the conversion to a local path fails, then we continue
1018      -         * as normal.  This is a heuristic to make process object file
1019      -         * paths available from within a zone.  Because lofs doesn't
1020      -         * support page operations, the vnode stored in the seg_t is
1021      -         * actually the underlying real vnode, not the lofs node itself.
1022      -         * Most of the time, the lofs path is the same as the underlying
1023      -         * vnode (for example, /usr/lib/libc.so.1).
1024      -         */
1025      -        if (vrootp != rootdir) {
1026      -                char *local = NULL;
1027      -
1028      -                VN_HOLD(rootdir);
1029      -                if (lookuppnvp(pn, rpn, FOLLOW, NULL, &compvp, rootdir,
1030      -                    rootdir, kcred) == 0) {
1031      -                        local = localpath(rpn->pn_path, vrootp, kcred);
1032      -                        VN_RELE(compvp);
1033      -                }
1034      -
1035      -                /*
1036      -                 * The original pn was changed through lookuppnvp().
1037      -                 * Set it to local for next validation attempt.
1038      -                 */
1039      -                if (local) {
1040      -                        (void) pn_set(pn, local);
1041      -                } else {
1042      -                        return (1);
1043      -                }
1044      -        }
1045      -
1046      -        /*
1047      -         * We should have a local path at this point, so start the search from
1048      -         * the root of the current process.
1049      -         */
1050      -        VN_HOLD(vrootp);
1051      -        if (vrootp != rootdir)
1052      -                VN_HOLD(vrootp);
1053      -        if (lookuppnvp(pn, rpn, FOLLOW | flags, NULL, &compvp, vrootp, vrootp,
1054      -            cr) == 0) {
1055      -                /*
1056      -                 * Check to see if the returned vnode is the same as the one we
1057      -                 * expect.
1058      -                 */
1059      -                if (vn_compare(vp, compvp) ||
1060      -                    vnode_match(vp, compvp, cr)) {
1061      -                        VN_RELE(compvp);
1062      -                        return (0);
1063      -                } else {
1064      -                        VN_RELE(compvp);
1065      -                }
1066      -        }
1067      -
1068      -        return (1);
1069      -}
1070      -
1071      -/*
1072      - * Struct for tracking vnodes with invalidated v_path entries during a
1073      - * dirtopath reverse lookup.  By keepeing adequate state, those vnode can be
1074      - * revisted to populate v_path.
1075      - */
1076      -struct dirpath_walk {
1077      -        struct dirpath_walk     *dw_next;
1078      -        vnode_t                 *dw_vnode;
1079      -        vnode_t                 *dw_pvnode;
1080      -        size_t                  dw_len;
1081      -        char                    *dw_name;
1082      -};
1083      -
1084      -/*
1085  982   * Given a directory, return the full, resolved path.  This looks up "..",
1086  983   * searches for the given vnode in the parent, appends the component, etc.  It
1087  984   * is used to implement vnodetopath() and getcwd() when the cached path fails.
1088  985   */
1089  986  static int
1090  987  dirtopath(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, int flags,
1091  988      cred_t *cr)
1092  989  {
1093      -        pathname_t      pn, rpn, emptypn;
1094      -        vnode_t         *pvp = NULL, *startvp = vp;
1095      -        int             err = 0;
1096      -        size_t          complen;
1097      -        dirent64_t      *dp;
1098      -        char            *bufloc, *dbuf;
1099      -        const size_t    dlen = DIRENT64_RECLEN(MAXPATHLEN);
1100      -        struct dirpath_walk *dw_chain = NULL, *dw_entry;
      990 +        pathname_t pn, rpn, emptypn;
      991 +        vnode_t *cmpvp, *pvp = NULL;
      992 +        vnode_t *startvp = vp;
      993 +        int err = 0, vprivs;
      994 +        size_t complen;
      995 +        char *dbuf;
      996 +        dirent64_t *dp;
      997 +        char            *bufloc;
      998 +        size_t          dlen = DIRENT64_RECLEN(MAXPATHLEN);
      999 +        refstr_t        *mntpt;
1101 1000  
1102 1001          /* Operation only allowed on directories */
1103 1002          ASSERT(vp->v_type == VDIR);
1104 1003  
1105 1004          /* We must have at least enough space for "/" */
1106 1005          if (buflen < 2)
1107 1006                  return (ENAMETOOLONG);
1108 1007  
1109 1008          /* Start at end of string with terminating null */
1110 1009          bufloc = &buf[buflen - 1];
1111 1010          *bufloc = '\0';
1112 1011  
1113 1012          pn_alloc(&pn);
1114 1013          pn_alloc(&rpn);
  
    | 
      ↓ open down ↓ | 
    4 lines elided | 
    
      ↑ open up ↑ | 
  
1115 1014          dbuf = kmem_alloc(dlen, KM_SLEEP);
1116 1015          bzero(&emptypn, sizeof (emptypn));
1117 1016  
1118 1017          /*
1119 1018           * Begin with an additional reference on vp.  This will be decremented
1120 1019           * during the loop.
1121 1020           */
1122 1021          VN_HOLD(vp);
1123 1022  
1124 1023          for (;;) {
1125      -                int vprivs;
1126      -                hrtime_t cached_stamp;
1127      -
1128 1024                  /*
1129 1025                   * Return if we've reached the root.  If the buffer is empty,
1130 1026                   * return '/'.  We explicitly don't use vn_compare(), since it
1131 1027                   * compares the real vnodes.  A lofs mount of '/' would produce
1132 1028                   * incorrect results otherwise.
1133 1029                   */
1134 1030                  if (VN_CMP(vrootp, vp)) {
1135 1031                          if (*bufloc == '\0')
1136 1032                                  *--bufloc = '/';
1137 1033                          break;
1138 1034                  }
1139 1035  
1140 1036                  /*
1141 1037                   * If we've reached the VFS root, something has gone wrong.  We
  
    | 
      ↓ open down ↓ | 
    4 lines elided | 
    
      ↑ open up ↑ | 
  
1142 1038                   * should have reached the root in the above check.  The only
1143 1039                   * explantation is that 'vp' is not contained withing the given
1144 1040                   * root, in which case we return EPERM.
1145 1041                   */
1146 1042                  if (VN_CMP(rootdir, vp)) {
1147 1043                          err = EPERM;
1148 1044                          goto out;
1149 1045                  }
1150 1046  
1151 1047                  /*
     1048 +                 * Shortcut: see if this vnode is a mountpoint.  If so,
     1049 +                 * grab the path information from the vfs_t.
     1050 +                 */
     1051 +                if (vp->v_flag & VROOT) {
     1052 +
     1053 +                        mntpt = vfs_getmntpoint(vp->v_vfsp);
     1054 +                        if ((err = pn_set(&pn, (char *)refstr_value(mntpt)))
     1055 +                            == 0) {
     1056 +                                refstr_rele(mntpt);
     1057 +                                rpn.pn_path = rpn.pn_buf;
     1058 +
     1059 +                                /*
     1060 +                                 * Ensure the mountpoint still exists.
     1061 +                                 */
     1062 +                                VN_HOLD(vrootp);
     1063 +                                if (vrootp != rootdir)
     1064 +                                        VN_HOLD(vrootp);
     1065 +                                if (lookuppnvp(&pn, &rpn, flags, NULL,
     1066 +                                    &cmpvp, vrootp, vrootp, cr) == 0) {
     1067 +
     1068 +                                        if (VN_CMP(vp, cmpvp)) {
     1069 +                                                VN_RELE(cmpvp);
     1070 +
     1071 +                                                complen = strlen(rpn.pn_path);
     1072 +                                                bufloc -= complen;
     1073 +                                                if (bufloc < buf) {
     1074 +                                                        err = ERANGE;
     1075 +                                                        goto out;
     1076 +                                                }
     1077 +                                                bcopy(rpn.pn_path, bufloc,
     1078 +                                                    complen);
     1079 +                                                break;
     1080 +                                        } else {
     1081 +                                                VN_RELE(cmpvp);
     1082 +                                        }
     1083 +                                }
     1084 +                        } else {
     1085 +                                refstr_rele(mntpt);
     1086 +                        }
     1087 +                }
     1088 +
     1089 +                /*
1152 1090                   * Shortcut: see if this vnode has correct v_path. If so,
1153 1091                   * we have the work done.
1154 1092                   */
1155 1093                  mutex_enter(&vp->v_lock);
1156      -                if (vp->v_path != vn_vpath_empty &&
1157      -                    pn_set(&pn, vp->v_path) == 0) {
1158      -                        cached_stamp = vp->v_path_stamp;
1159      -                        mutex_exit(&vp->v_lock);
1160      -                        rpn.pn_path = rpn.pn_buf;
     1094 +                if (vp->v_path != NULL) {
1161 1095  
1162      -                        /* Ensure the v_path pointing to correct vnode */
1163      -                        if (vnode_valid_pn(vp, vrootp, &pn, &rpn, flags,
1164      -                            cr) == 0) {
1165      -                                complen = strlen(rpn.pn_path);
1166      -                                bufloc -= complen;
1167      -                                if (bufloc < buf) {
1168      -                                        err = ERANGE;
1169      -                                        goto out;
1170      -                                }
1171      -                                bcopy(rpn.pn_path, bufloc, complen);
1172      -                                break;
1173      -                        } else {
     1096 +                        if ((err = pn_set(&pn, vp->v_path)) == 0) {
     1097 +                                mutex_exit(&vp->v_lock);
     1098 +                                rpn.pn_path = rpn.pn_buf;
     1099 +
1174 1100                                  /*
1175      -                                 * Immediately nuke cached v_path entries known
1176      -                                 * to be invalid.
     1101 +                                 * Ensure the v_path pointing to correct vnode
1177 1102                                   */
1178      -                                vn_clearpath(vp, cached_stamp);
     1103 +                                VN_HOLD(vrootp);
     1104 +                                if (vrootp != rootdir)
     1105 +                                        VN_HOLD(vrootp);
     1106 +                                if (lookuppnvp(&pn, &rpn, flags, NULL,
     1107 +                                    &cmpvp, vrootp, vrootp, cr) == 0) {
     1108 +
     1109 +                                        if (VN_CMP(vp, cmpvp)) {
     1110 +                                                VN_RELE(cmpvp);
     1111 +
     1112 +                                                complen = strlen(rpn.pn_path);
     1113 +                                                bufloc -= complen;
     1114 +                                                if (bufloc < buf) {
     1115 +                                                        err = ERANGE;
     1116 +                                                        goto out;
     1117 +                                                }
     1118 +                                                bcopy(rpn.pn_path, bufloc,
     1119 +                                                    complen);
     1120 +                                                break;
     1121 +                                        } else {
     1122 +                                                VN_RELE(cmpvp);
     1123 +                                        }
     1124 +                                }
     1125 +                        } else {
     1126 +                                mutex_exit(&vp->v_lock);
1179 1127                          }
1180 1128                  } else {
1181 1129                          mutex_exit(&vp->v_lock);
1182 1130                  }
1183 1131  
1184 1132                  /*
1185 1133                   * Shortcuts failed, search for this vnode in its parent.  If
1186 1134                   * this is a mountpoint, then get the vnode underneath.
1187 1135                   */
1188 1136                  if (vp->v_flag & VROOT)
1189 1137                          vp = vn_under(vp);
1190 1138                  if ((err = VOP_LOOKUP(vp, "..", &pvp, &emptypn, 0, vrootp, cr,
1191 1139                      NULL, NULL, NULL)) != 0)
1192 1140                          goto out;
1193 1141  
1194 1142                  /*
1195 1143                   * With extended attributes, it's possible for a directory to
1196 1144                   * have a parent that is a regular file.  Check for that here.
1197 1145                   */
1198 1146                  if (pvp->v_type != VDIR) {
1199 1147                          err = ENOTDIR;
1200 1148                          goto out;
1201 1149                  }
1202 1150  
1203 1151                  /*
1204 1152                   * If this is true, something strange has happened.  This is
1205 1153                   * only true if we are the root of a filesystem, which should
1206 1154                   * have been caught by the check above.
1207 1155                   */
1208 1156                  if (VN_CMP(pvp, vp)) {
1209 1157                          err = ENOENT;
1210 1158                          goto out;
1211 1159                  }
1212 1160  
  
    | 
      ↓ open down ↓ | 
    24 lines elided | 
    
      ↑ open up ↑ | 
  
1213 1161                  /*
1214 1162                   * Check if we have read and search privilege so, that
1215 1163                   * we can lookup the path in the directory
1216 1164                   */
1217 1165                  vprivs = (flags & LOOKUP_CHECKREAD) ? VREAD | VEXEC : VEXEC;
1218 1166                  if ((err = VOP_ACCESS(pvp, vprivs, 0, cr, NULL)) != 0) {
1219 1167                          goto out;
1220 1168                  }
1221 1169  
1222 1170                  /*
     1171 +                 * Try to obtain the path component from dnlc cache
     1172 +                 * before searching through the directory.
     1173 +                 */
     1174 +                if ((cmpvp = dnlc_reverse_lookup(vp, dbuf, dlen)) != NULL) {
     1175 +                        /*
     1176 +                         * If we got parent vnode as a result,
     1177 +                         * then the answered path is correct.
     1178 +                         */
     1179 +                        if (VN_CMP(cmpvp, pvp)) {
     1180 +                                VN_RELE(cmpvp);
     1181 +                                complen = strlen(dbuf);
     1182 +                                bufloc -= complen;
     1183 +                                if (bufloc <= buf) {
     1184 +                                        err = ENAMETOOLONG;
     1185 +                                        goto out;
     1186 +                                }
     1187 +                                bcopy(dbuf, bufloc, complen);
     1188 +
     1189 +                                /* Prepend a slash to the current path */
     1190 +                                *--bufloc = '/';
     1191 +
     1192 +                                /* And continue with the next component */
     1193 +                                VN_RELE(vp);
     1194 +                                vp = pvp;
     1195 +                                pvp = NULL;
     1196 +                                continue;
     1197 +                        } else {
     1198 +                                VN_RELE(cmpvp);
     1199 +                        }
     1200 +                }
     1201 +
     1202 +                /*
1223 1203                   * Search the parent directory for the entry corresponding to
1224 1204                   * this vnode.
1225 1205                   */
1226 1206                  if ((err = dirfindvp(vrootp, pvp, vp, cr, dbuf, dlen, &dp))
1227 1207                      != 0)
1228 1208                          goto out;
1229 1209                  complen = strlen(dp->d_name);
1230 1210                  bufloc -= complen;
1231 1211                  if (bufloc <= buf) {
1232 1212                          err = ENAMETOOLONG;
1233 1213                          goto out;
1234 1214                  }
1235 1215                  bcopy(dp->d_name, bufloc, complen);
1236 1216  
1237 1217                  /* Prepend a slash to the current path.  */
1238 1218                  *--bufloc = '/';
1239 1219  
1240      -                /*
1241      -                 * Record the name and directory for later reconstruction and
1242      -                 * link it up with the others.
1243      -                 */
1244      -                dw_entry = kmem_alloc(sizeof (*dw_entry), KM_SLEEP);
1245      -                dw_entry->dw_name = kmem_alloc(complen + 1, KM_SLEEP);
1246      -                VN_HOLD(dw_entry->dw_vnode = vp);
1247      -                VN_HOLD(dw_entry->dw_pvnode = pvp);
1248      -                bcopy(dp->d_name, dw_entry->dw_name, complen + 1);
1249      -                dw_entry->dw_len = complen;
1250      -                dw_entry->dw_next = dw_chain;
1251      -                dw_chain = dw_entry;
1252      -
1253 1220                  /* And continue with the next component */
1254 1221                  VN_RELE(vp);
1255 1222                  vp = pvp;
1256 1223                  pvp = NULL;
1257 1224          }
1258 1225  
1259 1226          /*
1260 1227           * Place the path at the beginning of the buffer.
1261 1228           */
1262 1229          if (bufloc != buf)
1263 1230                  ovbcopy(bufloc, buf, buflen - (bufloc - buf));
1264 1231  
1265 1232  out:
1266 1233          /*
1267      -         * Walk over encountered directory entries which were afflicted with a
1268      -         * stale or absent v_path.  If the dirtopath was successful, we should
1269      -         * possess the necessary information to populate all of them with a
1270      -         * valid v_path.
1271      -         *
1272      -         * While processing this list, it is safe to call vn_setpath despite
1273      -         * the fact that racing vnode actions may have altered v_path entries
1274      -         * while the above loopwas still executing.  Any updated entries will
1275      -         * have a newer v_path_stamp value which prevents an invalid overwrite.
1276      -         *
1277      -         * If an error was encountered during the search, freeing the chain is
1278      -         * still required.
1279      -         */
1280      -        dw_entry = dw_chain;
1281      -        while (dw_entry != NULL) {
1282      -                struct dirpath_walk *next = dw_entry->dw_next;
1283      -
1284      -                if (err == 0) {
1285      -                        vn_setpath(NULL, dw_entry->dw_pvnode,
1286      -                            dw_entry->dw_vnode, dw_entry->dw_name,
1287      -                            dw_entry->dw_len);
1288      -                }
1289      -
1290      -                VN_RELE(dw_entry->dw_vnode);
1291      -                VN_RELE(dw_entry->dw_pvnode);
1292      -                kmem_free(dw_entry->dw_name, dw_entry->dw_len + 1);
1293      -                kmem_free(dw_entry, sizeof (*dw_entry));
1294      -                dw_entry = next;
1295      -        }
1296      -
1297      -        /*
1298 1234           * If the error was ESTALE and the current directory to look in
1299 1235           * was the root for this lookup, the root for a mounted file
1300 1236           * system, or the starting directory for lookups, then
1301 1237           * return ENOENT instead of ESTALE.  In this case, no recovery
1302 1238           * is possible by the higher level.  If ESTALE was returned for
1303 1239           * some intermediate directory along the path, then recovery
1304 1240           * is potentially possible and retrying from the higher level
1305 1241           * will either correct the situation by purging stale cache
1306 1242           * entries or eventually get back to the point where no recovery
1307 1243           * is possible.
1308 1244           */
1309 1245          if (err == ESTALE &&
1310 1246              (VN_CMP(vp, vrootp) || (vp->v_flag & VROOT) || vp == startvp))
1311 1247                  err = ENOENT;
1312 1248  
1313 1249          kmem_free(dbuf, dlen);
1314 1250          VN_RELE(vp);
1315 1251          if (pvp)
1316 1252                  VN_RELE(pvp);
1317 1253          pn_free(&pn);
1318 1254          pn_free(&rpn);
1319 1255  
1320 1256          return (err);
1321 1257  }
1322 1258  
1323 1259  /*
1324 1260   * The additional flag, LOOKUP_CHECKREAD, is used to enforce artificial
1325 1261   * constraints in order to be standards compliant.  For example, if we have
1326 1262   * the cached path of '/foo/bar', and '/foo' has permissions 100 (execute
  
    | 
      ↓ open down ↓ | 
    19 lines elided | 
    
      ↑ open up ↑ | 
  
1327 1263   * only), then we can legitimately look up the path to the current working
1328 1264   * directory without needing read permission.  Existing standards tests,
1329 1265   * however, assume that we are determining the path by repeatedly looking up
1330 1266   * "..".  We need to keep this behavior in order to maintain backwards
1331 1267   * compatibility.
1332 1268   */
1333 1269  static int
1334 1270  vnodetopath_common(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen,
1335 1271      cred_t *cr, int flags)
1336 1272  {
1337      -        pathname_t pn;
1338      -        int ret = 0;
1339      -        vnode_t *realvp;
1340      -        boolean_t doclose = B_FALSE;
     1273 +        pathname_t pn, rpn;
     1274 +        int ret, len;
     1275 +        vnode_t *compvp, *pvp, *realvp;
     1276 +        proc_t *p = curproc;
     1277 +        char path[MAXNAMELEN];
     1278 +        int doclose = 0;
1341 1279  
1342 1280          /*
1343 1281           * If vrootp is NULL, get the root for curproc.  Callers with any other
1344 1282           * requirements should pass in a different vrootp.
1345 1283           */
1346 1284          if (vrootp == NULL) {
1347      -                proc_t *p = curproc;
1348      -
1349 1285                  mutex_enter(&p->p_lock);
1350 1286                  if ((vrootp = PTOU(p)->u_rdir) == NULL)
1351 1287                          vrootp = rootdir;
1352 1288                  VN_HOLD(vrootp);
1353 1289                  mutex_exit(&p->p_lock);
1354 1290          } else {
1355 1291                  VN_HOLD(vrootp);
1356 1292          }
1357 1293  
1358 1294          /*
1359 1295           * This is to get around an annoying artifact of the /proc filesystem,
  
    | 
      ↓ open down ↓ | 
    1 lines elided | 
    
      ↑ open up ↑ | 
  
1360 1296           * which is the behavior of {cwd/root}.  Trying to resolve this path
1361 1297           * will result in /proc/pid/cwd instead of whatever the real working
1362 1298           * directory is.  We can't rely on VOP_REALVP(), since that will break
1363 1299           * lofs.  The only difference between procfs and lofs is that opening
1364 1300           * the file will return the underling vnode in the case of procfs.
1365 1301           */
1366 1302          if (vp->v_type == VDIR && VOP_REALVP(vp, &realvp, NULL) == 0 &&
1367 1303              realvp != vp) {
1368 1304                  VN_HOLD(vp);
1369 1305                  if (VOP_OPEN(&vp, FREAD, cr, NULL) == 0)
1370      -                        doclose = B_TRUE;
     1306 +                        doclose = 1;
1371 1307                  else
1372 1308                          VN_RELE(vp);
1373 1309          }
1374 1310  
     1311 +        pn_alloc(&pn);
     1312 +
1375 1313          /*
1376      -         * Check to see if we have a valid cached path in the vnode.
     1314 +         * Check to see if we have a cached path in the vnode.
1377 1315           */
1378      -        pn_alloc(&pn);
1379 1316          mutex_enter(&vp->v_lock);
1380      -        if (vp->v_path != vn_vpath_empty) {
1381      -                hrtime_t cached_stamp;
1382      -                pathname_t rpn;
1383      -
1384      -                cached_stamp = vp->v_path_stamp;
     1317 +        if (vp->v_path != NULL) {
1385 1318                  (void) pn_set(&pn, vp->v_path);
1386 1319                  mutex_exit(&vp->v_lock);
1387 1320  
     1321 +                pn_alloc(&rpn);
     1322 +
1388 1323                  /* We should only cache absolute paths */
1389 1324                  ASSERT(pn.pn_buf[0] == '/');
1390 1325  
1391      -                pn_alloc(&rpn);
1392      -                if (vnode_valid_pn(vp, vrootp, &pn, &rpn, flags, cr) == 0) {
1393      -                        /* Return the result, if we're able. */
1394      -                        if (buflen > rpn.pn_pathlen) {
1395      -                                bcopy(rpn.pn_path, buf, rpn.pn_pathlen + 1);
     1326 +                /*
     1327 +                 * If we are in a zone or a chroot environment, then we have to
     1328 +                 * take additional steps, since the path to the root might not
     1329 +                 * be readable with the current credentials, even though the
     1330 +                 * process can legitmately access the file.  In this case, we
     1331 +                 * do the following:
     1332 +                 *
     1333 +                 * lookuppnvp() with all privileges to get the resolved path.
     1334 +                 * call localpath() to get the local portion of the path, and
     1335 +                 * continue as normal.
     1336 +                 *
     1337 +                 * If the the conversion to a local path fails, then we continue
     1338 +                 * as normal.  This is a heuristic to make process object file
     1339 +                 * paths available from within a zone.  Because lofs doesn't
     1340 +                 * support page operations, the vnode stored in the seg_t is
     1341 +                 * actually the underlying real vnode, not the lofs node itself.
     1342 +                 * Most of the time, the lofs path is the same as the underlying
     1343 +                 * vnode (for example, /usr/lib/libc.so.1).
     1344 +                 */
     1345 +                if (vrootp != rootdir) {
     1346 +                        char *local = NULL;
     1347 +                        VN_HOLD(rootdir);
     1348 +                        if (lookuppnvp(&pn, &rpn, FOLLOW,
     1349 +                            NULL, &compvp, rootdir, rootdir, kcred) == 0) {
     1350 +                                local = localpath(rpn.pn_path, vrootp,
     1351 +                                    kcred);
     1352 +                                VN_RELE(compvp);
     1353 +                        }
     1354 +
     1355 +                        /*
     1356 +                         * The original pn was changed through lookuppnvp().
     1357 +                         * Set it to local for next validation attempt.
     1358 +                         */
     1359 +                        if (local) {
     1360 +                                (void) pn_set(&pn, local);
1396 1361                          } else {
1397      -                                ret = ENAMETOOLONG;
     1362 +                                goto notcached;
1398 1363                          }
     1364 +                }
     1365 +
     1366 +                /*
     1367 +                 * We should have a local path at this point, so start the
     1368 +                 * search from the root of the current process.
     1369 +                 */
     1370 +                VN_HOLD(vrootp);
     1371 +                if (vrootp != rootdir)
     1372 +                        VN_HOLD(vrootp);
     1373 +                ret = lookuppnvp(&pn, &rpn, FOLLOW | flags, NULL,
     1374 +                    &compvp, vrootp, vrootp, cr);
     1375 +                if (ret == 0) {
     1376 +                        /*
     1377 +                         * Check to see if the returned vnode is the same as
     1378 +                         * the one we expect.  If not, give up.
     1379 +                         */
     1380 +                        if (!vn_compare(vp, compvp) &&
     1381 +                            !vnode_match(vp, compvp, cr)) {
     1382 +                                VN_RELE(compvp);
     1383 +                                goto notcached;
     1384 +                        }
     1385 +
     1386 +                        VN_RELE(compvp);
     1387 +
     1388 +                        /*
     1389 +                         * Return the result.
     1390 +                         */
     1391 +                        if (buflen <= rpn.pn_pathlen)
     1392 +                                goto notcached;
     1393 +
     1394 +                        bcopy(rpn.pn_path, buf, rpn.pn_pathlen + 1);
1399 1395                          pn_free(&pn);
1400 1396                          pn_free(&rpn);
1401      -                        goto out;
     1397 +                        VN_RELE(vrootp);
     1398 +                        if (doclose) {
     1399 +                                (void) VOP_CLOSE(vp, FREAD, 1, 0, cr, NULL);
     1400 +                                VN_RELE(vp);
     1401 +                        }
     1402 +                        return (0);
1402 1403                  }
     1404 +
     1405 +notcached:
1403 1406                  pn_free(&rpn);
1404      -                vn_clearpath(vp, cached_stamp);
1405 1407          } else {
1406 1408                  mutex_exit(&vp->v_lock);
1407 1409          }
     1410 +
1408 1411          pn_free(&pn);
1409 1412  
1410      -        if (vp->v_type != VDIR) {
     1413 +        if (PROC_IS_BRANDED(curproc)) {
1411 1414                  /*
1412      -                 * The reverse lookup tricks used by dirtopath aren't possible
1413      -                 * for non-directory entries.  The best which can be done is
1414      -                 * clearing any stale v_path so later lookups can potentially
1415      -                 * repopulate it with a valid path.
     1415 +                 * If v_path doesn't work out and we're in a branded zone,
     1416 +                 * we're not going to bother doing more work here:  because
     1417 +                 * directories from the global can be lofs mounted into odd
     1418 +                 * locations (e.g., /native in an lx zone), it is likely that
     1419 +                 * the DNLC reverse lookup will yield nothing.  Indeed, the
     1420 +                 * only certainty is that the DNLC reverse lookup will be
     1421 +                 * exceedingly painful; we save ourselves the substantial
     1422 +                 * grief of scanning the entire DNLC and kick out with ENOENT
     1423 +                 * in this case.
1416 1424                   */
1417 1425                  ret = ENOENT;
1418      -        } else {
     1426 +        } else if (vp->v_type != VDIR) {
     1427 +                /*
     1428 +                 * If we don't have a directory, try to find it in the dnlc via
     1429 +                 * reverse lookup.  Once this is found, we can use the regular
     1430 +                 * directory search to find the full path.
     1431 +                 */
     1432 +                if ((pvp = dnlc_reverse_lookup(vp, path, MAXNAMELEN)) != NULL) {
     1433 +                        /*
     1434 +                         * Check if we have read privilege so, that
     1435 +                         * we can lookup the path in the directory
     1436 +                         */
     1437 +                        ret = 0;
     1438 +                        if ((flags & LOOKUP_CHECKREAD)) {
     1439 +                                ret = VOP_ACCESS(pvp, VREAD, 0, cr, NULL);
     1440 +                        }
     1441 +                        if (ret == 0) {
     1442 +                                ret = dirtopath(vrootp, pvp, buf, buflen,
     1443 +                                    flags, cr);
     1444 +                        }
     1445 +                        if (ret == 0) {
     1446 +                                len = strlen(buf);
     1447 +                                if (len + strlen(path) + 1 >= buflen) {
     1448 +                                        ret = ENAMETOOLONG;
     1449 +                                } else {
     1450 +                                        if (buf[len - 1] != '/')
     1451 +                                                buf[len++] = '/';
     1452 +                                        bcopy(path, buf + len,
     1453 +                                            strlen(path) + 1);
     1454 +                                }
     1455 +                        }
     1456 +
     1457 +                        VN_RELE(pvp);
     1458 +                } else
     1459 +                        ret = ENOENT;
     1460 +        } else
1419 1461                  ret = dirtopath(vrootp, vp, buf, buflen, flags, cr);
1420      -        }
1421 1462  
1422      -out:
1423 1463          VN_RELE(vrootp);
1424 1464          if (doclose) {
1425 1465                  (void) VOP_CLOSE(vp, FREAD, 1, 0, cr, NULL);
1426 1466                  VN_RELE(vp);
1427 1467          }
1428 1468  
1429 1469          return (ret);
1430 1470  }
1431 1471  
1432 1472  int
1433 1473  vnodetopath(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, cred_t *cr)
1434 1474  {
1435 1475          return (vnodetopath_common(vrootp, vp, buf, buflen, cr, 0));
1436 1476  }
1437 1477  
1438 1478  int
1439 1479  dogetcwd(char *buf, size_t buflen)
1440 1480  {
1441 1481          int ret;
1442 1482          vnode_t *vp;
1443 1483          vnode_t *compvp;
1444 1484          refstr_t *cwd, *oldcwd;
1445 1485          const char *value;
1446 1486          pathname_t rpnp, pnp;
1447 1487          proc_t *p = curproc;
1448 1488  
1449 1489          /*
1450 1490           * Check to see if there is a cached version of the cwd.  If so, lookup
1451 1491           * the cached value and make sure it is the same vnode.
1452 1492           */
1453 1493          mutex_enter(&p->p_lock);
1454 1494          if ((cwd = PTOU(p)->u_cwd) != NULL)
1455 1495                  refstr_hold(cwd);
1456 1496          vp = PTOU(p)->u_cdir;
1457 1497          VN_HOLD(vp);
1458 1498          mutex_exit(&p->p_lock);
1459 1499  
1460 1500          /*
1461 1501           * Make sure we have permission to access the current directory.
1462 1502           */
1463 1503          if ((ret = VOP_ACCESS(vp, VEXEC, 0, CRED(), NULL)) != 0) {
1464 1504                  if (cwd != NULL)
1465 1505                          refstr_rele(cwd);
1466 1506                  VN_RELE(vp);
1467 1507                  return (ret);
1468 1508          }
1469 1509  
1470 1510          if (cwd) {
1471 1511                  value = refstr_value(cwd);
1472 1512                  if ((ret = pn_get((char *)value, UIO_SYSSPACE, &pnp)) != 0) {
1473 1513                          refstr_rele(cwd);
1474 1514                          VN_RELE(vp);
1475 1515                          return (ret);
1476 1516                  }
1477 1517  
1478 1518                  pn_alloc(&rpnp);
1479 1519  
1480 1520                  if (lookuppn(&pnp, &rpnp, NO_FOLLOW, NULL, &compvp) == 0) {
1481 1521  
1482 1522                          if (VN_CMP(vp, compvp) &&
1483 1523                              strcmp(value, rpnp.pn_path) == 0) {
1484 1524                                  VN_RELE(compvp);
1485 1525                                  VN_RELE(vp);
1486 1526                                  pn_free(&pnp);
1487 1527                                  pn_free(&rpnp);
1488 1528                                  if (strlen(value) + 1 > buflen) {
1489 1529                                          refstr_rele(cwd);
1490 1530                                          return (ENAMETOOLONG);
1491 1531                                  }
1492 1532                                  bcopy(value, buf, strlen(value) + 1);
1493 1533                                  refstr_rele(cwd);
1494 1534                                  return (0);
1495 1535                          }
1496 1536  
1497 1537                          VN_RELE(compvp);
1498 1538                  }
1499 1539  
1500 1540                  pn_free(&rpnp);
1501 1541                  pn_free(&pnp);
1502 1542  
1503 1543                  refstr_rele(cwd);
1504 1544          }
1505 1545  
1506 1546          ret = vnodetopath_common(NULL, vp, buf, buflen, CRED(),
1507 1547              LOOKUP_CHECKREAD);
1508 1548  
1509 1549          VN_RELE(vp);
1510 1550  
1511 1551          /*
1512 1552           * Store the new cwd and replace the existing cached copy.
1513 1553           */
1514 1554          if (ret == 0)
1515 1555                  cwd = refstr_alloc(buf);
1516 1556          else
1517 1557                  cwd = NULL;
1518 1558  
1519 1559          mutex_enter(&p->p_lock);
1520 1560          oldcwd = PTOU(p)->u_cwd;
1521 1561          PTOU(p)->u_cwd = cwd;
1522 1562          mutex_exit(&p->p_lock);
1523 1563  
1524 1564          if (oldcwd)
1525 1565                  refstr_rele(oldcwd);
1526 1566  
1527 1567          return (ret);
1528 1568  }
  
    | 
      ↓ open down ↓ | 
    96 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX