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