Print this page
        
*** 19,29 ****
   * CDDL HEADER END
   */
  
  /*
   * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
!  * Copyright 2016, Joyent, Inc.
   */
  
  /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
  /*        All Rights Reserved   */
  
--- 19,29 ----
   * CDDL HEADER END
   */
  
  /*
   * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
!  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
   */
  
  /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
  /*        All Rights Reserved   */
  
*** 64,75 ****
  #include <sys/nbmlock.h>
  #include <sys/fcntl.h>
  #include <fs/fs_subr.h>
  #include <sys/taskq.h>
  #include <fs/fs_reparse.h>
- #include <sys/time.h>
- #include <sys/sdt.h>
  
  /* Determine if this vnode is a file that is read-only */
  #define ISROFILE(vp)    \
          ((vp)->v_type != VCHR && (vp)->v_type != VBLK && \
              (vp)->v_type != VFIFO && vn_is_readonly(vp))
--- 64,73 ----
*** 102,114 ****
  kmutex_t        vskstat_tree_lock;
  
  /* Global variable which enables/disables the vopstats collection */
  int vopstats_enabled = 1;
  
- /* Global used for empty/invalid v_path */
- char *vn_vpath_empty = "";
- 
  /*
   * forward declarations for internal vnode specific data (vsd)
   */
  static void *vsd_realloc(void *, size_t, size_t);
  
--- 100,109 ----
*** 206,216 ****
          }
  
  #define VOP_LATENCY_10MS        10000000
  #define VOP_LATENCY_100MS       100000000
  #define VOP_LATENCY_1S          1000000000
- #define VOP_LATENCY_10S         10000000000
  
  /*
   * Convert stat(2) formats to vnode types and vice versa.  (Knows about
   * numerical order of S_IFMT and vnode types.)
   */
--- 201,210 ----
*** 2292,2303 ****
          mutex_init(&vp->v_lock, NULL, MUTEX_DEFAULT, NULL);
          mutex_init(&vp->v_vsd_lock, NULL, MUTEX_DEFAULT, NULL);
          cv_init(&vp->v_cv, NULL, CV_DEFAULT, NULL);
          rw_init(&vp->v_nbllock, NULL, RW_DEFAULT, NULL);
          vp->v_femhead = NULL;   /* Must be done before vn_reinit() */
!         vp->v_path = vn_vpath_empty;
!         vp->v_path_stamp = 0;
          vp->v_mpssdata = NULL;
          vp->v_vsd = NULL;
          vp->v_fopdata = NULL;
  
          return (0);
--- 2286,2296 ----
          mutex_init(&vp->v_lock, NULL, MUTEX_DEFAULT, NULL);
          mutex_init(&vp->v_vsd_lock, NULL, MUTEX_DEFAULT, NULL);
          cv_init(&vp->v_cv, NULL, CV_DEFAULT, NULL);
          rw_init(&vp->v_nbllock, NULL, RW_DEFAULT, NULL);
          vp->v_femhead = NULL;   /* Must be done before vn_reinit() */
!         vp->v_path = NULL;
          vp->v_mpssdata = NULL;
          vp->v_vsd = NULL;
          vp->v_fopdata = NULL;
  
          return (0);
*** 2340,2350 ****
   */
  void
  vn_recycle(vnode_t *vp)
  {
          ASSERT(vp->v_pages == NULL);
-         VERIFY(vp->v_path != NULL);
  
          /*
           * XXX - This really belongs in vn_reinit(), but we have some issues
           * with the counts.  Best to have it here for clean initialization.
           */
--- 2333,2342 ----
*** 2363,2377 ****
                  ASSERT(vp->v_femhead->femh_list == NULL);
                  mutex_destroy(&vp->v_femhead->femh_lock);
                  kmem_free(vp->v_femhead, sizeof (*(vp->v_femhead)));
                  vp->v_femhead = NULL;
          }
!         if (vp->v_path != vn_vpath_empty) {
                  kmem_free(vp->v_path, strlen(vp->v_path) + 1);
!                 vp->v_path = vn_vpath_empty;
          }
-         vp->v_path_stamp = 0;
  
          if (vp->v_fopdata != NULL) {
                  free_fopdata(vp);
          }
          vp->v_mpssdata = NULL;
--- 2355,2368 ----
                  ASSERT(vp->v_femhead->femh_list == NULL);
                  mutex_destroy(&vp->v_femhead->femh_lock);
                  kmem_free(vp->v_femhead, sizeof (*(vp->v_femhead)));
                  vp->v_femhead = NULL;
          }
!         if (vp->v_path) {
                  kmem_free(vp->v_path, strlen(vp->v_path) + 1);
!                 vp->v_path = NULL;
          }
  
          if (vp->v_fopdata != NULL) {
                  free_fopdata(vp);
          }
          vp->v_mpssdata = NULL;
*** 2438,2451 ****
           * some with v_count of 1.  In any case, the value should
           * never be anything else.
           */
          ASSERT((vp->v_count == 0) || (vp->v_count == 1));
          ASSERT(vp->v_count_dnlc == 0);
!         VERIFY(vp->v_path != NULL);
!         if (vp->v_path != vn_vpath_empty) {
                  kmem_free(vp->v_path, strlen(vp->v_path) + 1);
!                 vp->v_path = vn_vpath_empty;
          }
  
          /* If FEM was in use, make sure everything gets cleaned up */
          if (vp->v_femhead) {
                  /* XXX - There should be a free_femhead() that does all this */
--- 2429,2441 ----
           * some with v_count of 1.  In any case, the value should
           * never be anything else.
           */
          ASSERT((vp->v_count == 0) || (vp->v_count == 1));
          ASSERT(vp->v_count_dnlc == 0);
!         if (vp->v_path != NULL) {
                  kmem_free(vp->v_path, strlen(vp->v_path) + 1);
!                 vp->v_path = NULL;
          }
  
          /* If FEM was in use, make sure everything gets cleaned up */
          if (vp->v_femhead) {
                  /* XXX - There should be a free_femhead() that does all this */
*** 2975,3217 ****
  
          return ((u_longlong_t)atomic_inc_64_nv(&next_caller_id));
  }
  
  /*
!  * The value stored in v_path is relative to rootdir, located in the global
!  * zone.  Zones or chroot environments which reside deeper inside the VFS
!  * hierarchy will have a relative view of MAXPATHLEN since they are unaware of
!  * what lies below their perceived root.  In order to keep v_path usable for
!  * these child environments, its allocations are allowed to exceed MAXPATHLEN.
!  *
!  * An upper bound of max_vnode_path is placed upon v_path allocations to
!  * prevent the system from going too wild at the behest of pathological
!  * behavior from the operator.
   */
  size_t max_vnode_path = 4 * MAXPATHLEN;
  
- 
  void
! vn_clearpath(vnode_t *vp, hrtime_t compare_stamp)
  {
!         char *buf;
  
!         mutex_enter(&vp->v_lock);
!         /*
!          * If the snapshot of v_path_stamp passed in via compare_stamp does not
!          * match the present value on the vnode, it indicates that subsequent
!          * changes have occurred.  The v_path value is not cleared in this case
!          * since the new value may be valid.
!          */
!         if (compare_stamp != 0 && vp->v_path_stamp != compare_stamp) {
!                 mutex_exit(&vp->v_lock);
!                 return;
          }
-         buf = vp->v_path;
-         vp->v_path = vn_vpath_empty;
-         vp->v_path_stamp = 0;
-         mutex_exit(&vp->v_lock);
-         if (buf != vn_vpath_empty) {
-                 kmem_free(buf, strlen(buf) + 1);
-         }
- }
  
- static void
- vn_setpath_common(vnode_t *pvp, vnode_t *vp, const char *name, size_t len,
-     boolean_t is_rename)
- {
-         char *buf, *oldbuf;
-         hrtime_t pstamp;
-         size_t baselen, buflen = 0;
- 
-         /* Handle the vn_setpath_str case. */
-         if (pvp == NULL) {
-                 if (len + 1 > max_vnode_path) {
-                         DTRACE_PROBE4(vn__setpath__too__long, vnode_t *, pvp,
-                             vnode_t *, vp, char *, name, size_t, len + 1);
-                         return;
-                 }
-                 buf = kmem_alloc(len + 1, KM_SLEEP);
-                 bcopy(name, buf, len);
-                 buf[len] = '\0';
- 
-                 mutex_enter(&vp->v_lock);
-                 oldbuf = vp->v_path;
-                 vp->v_path = buf;
-                 vp->v_path_stamp = gethrtime();
-                 mutex_exit(&vp->v_lock);
-                 if (oldbuf != vn_vpath_empty) {
-                         kmem_free(oldbuf, strlen(oldbuf) + 1);
-                 }
-                 return;
-         }
- 
-         /* Take snapshot of parent dir */
-         mutex_enter(&pvp->v_lock);
- retrybuf:
-         if (pvp->v_path == vn_vpath_empty) {
                  /*
!                  * Without v_path from the parent directory, generating a child
!                  * path from the name is impossible.
                   */
!                 if (len > 0) {
!                         pstamp = pvp->v_path_stamp;
!                         mutex_exit(&pvp->v_lock);
!                         vn_clearpath(vp, pstamp);
                          return;
                  }
  
                  /*
!                  * The only feasible case here is where a NUL lookup is being
!                  * performed on rootdir prior to its v_path being populated.
                   */
!                 ASSERT(pvp->v_path_stamp = 0);
!                 baselen = 0;
!                 pstamp = 0;
!         } else {
!                 pstamp = pvp->v_path_stamp;
!                 baselen = strlen(pvp->v_path);
!                 /* ignore a trailing slash if present */
!                 if (pvp->v_path[baselen - 1] == '/') {
!                         /* This should only the be case for rootdir */
!                         ASSERT(baselen == 1 && pvp == rootdir);
!                         baselen--;
!                 }
!         }
!         mutex_exit(&pvp->v_lock);
  
!         if (buflen != 0) {
!                 /* Free the existing (mis-sized) buffer in case of retry */
!                 kmem_free(buf, buflen);
!         }
!         /* base, '/', name and trailing NUL */
!         buflen = baselen + len + 2;
!         if (buflen > max_vnode_path) {
!                 DTRACE_PROBE4(vn__setpath_too__long, vnode_t *, pvp,
!                     vnode_t *, vp, char *, name, size_t, buflen);
                  return;
-         }
-         buf = kmem_alloc(buflen, KM_SLEEP);
  
!         mutex_enter(&pvp->v_lock);
!         if (pvp->v_path_stamp != pstamp) {
!                 size_t vlen;
  
!                 /*
!                  * Since v_path_stamp changed on the parent, it is likely that
!                  * v_path has been altered as well.  If the length does not
!                  * exactly match what was previously measured, the buffer
!                  * allocation must be repeated for proper sizing.
!                  */
!                 if (pvp->v_path == vn_vpath_empty) {
!                         /* Give up if parent lack v_path */
!                         mutex_exit(&pvp->v_lock);
!                         kmem_free(buf, buflen);
                          return;
                  }
!                 vlen = strlen(pvp->v_path);
!                 if (pvp->v_path[vlen - 1] == '/') {
!                         vlen--;
!                 }
!                 if (vlen != baselen) {
!                         goto retrybuf;
!                 }
!         }
!         bcopy(pvp->v_path, buf, baselen);
!         mutex_exit(&pvp->v_lock);
  
!         buf[baselen] = '/';
!         baselen++;
!         bcopy(name, &buf[baselen], len + 1);
  
          mutex_enter(&vp->v_lock);
!         if (vp->v_path_stamp == 0) {
!                 /* never-visited vnode can inherit stamp from parent */
!                 ASSERT(vp->v_path == vn_vpath_empty);
!                 vp->v_path_stamp = pstamp;
!                 vp->v_path = buf;
                  mutex_exit(&vp->v_lock);
!         } else if (vp->v_path_stamp < pstamp || is_rename) {
!                 /*
!                  * Install the updated path and stamp, ensuring that the v_path
!                  * pointer is valid at all times for dtrace.
!                  */
!                 oldbuf = vp->v_path;
!                 vp->v_path = buf;
!                 vp->v_path_stamp = gethrtime();
!                 mutex_exit(&vp->v_lock);
!                 kmem_free(oldbuf, strlen(oldbuf) + 1);
          } else {
!                 /*
!                  * If the timestamp matches or is greater, it means another
!                  * thread performed the update first while locks were dropped
!                  * here to make the allocation.  We defer to the newer value.
!                  */
                  mutex_exit(&vp->v_lock);
-                 kmem_free(buf, buflen);
          }
-         ASSERT(MUTEX_NOT_HELD(&vp->v_lock));
  }
  
  void
! vn_updatepath(vnode_t *pvp, vnode_t *vp, const char *name)
  {
!         size_t len;
  
!         /*
!          * If the parent is older or empty, there's nothing further to do.
!          */
!         if (pvp->v_path == vn_vpath_empty ||
!             pvp->v_path_stamp <= vp->v_path_stamp) {
                  return;
          }
  
!         /*
!          * Given the lack of appropriate context, meaningful updates to v_path
!          * cannot be made for during lookups for the '.' or '..' entries.
!          */
!         len = strlen(name);
!         if (len == 0 || (len == 1 && name[0] == '.') ||
!             (len == 2 && name[0] == '.' && name[1] == '.')) {
!                 return;
!         }
  
!         vn_setpath_common(pvp, vp, name, len, B_FALSE);
  }
  
  /*
-  * Given a starting vnode and a path, updates the path in the target vnode in
-  * a safe manner.  If the vnode already has path information embedded, then the
-  * cached path is left untouched.
-  */
- /* ARGSUSED */
- void
- vn_setpath(vnode_t *rootvp, vnode_t *pvp, vnode_t *vp, const char *name,
-     size_t len)
- {
-         vn_setpath_common(pvp, vp, name, len, B_FALSE);
- }
- 
- /*
-  * Sets the path to the vnode to be the given string, regardless of current
-  * context.  The string must be a complete path from rootdir.  This is only used
-  * by fsop_root() for setting the path based on the mountpoint.
-  */
- void
- vn_setpath_str(vnode_t *vp, const char *str, size_t len)
- {
-         vn_setpath_common(NULL, vp, str, len, B_FALSE);
- }
- 
- /*
   * Called from within filesystem's vop_rename() to handle renames once the
   * target vnode is available.
   */
  void
! vn_renamepath(vnode_t *pvp, vnode_t *vp, const char *name, size_t len)
  {
!         vn_setpath_common(pvp, vp, name, len, B_TRUE);
  }
  
  /*
   * Similar to vn_setpath_str(), this function sets the path of the destination
   * vnode to the be the same as the source vnode.
--- 2965,3093 ----
  
          return ((u_longlong_t)atomic_inc_64_nv(&next_caller_id));
  }
  
  /*
!  * Given a starting vnode and a path, updates the path in the target vnode in
!  * a safe manner.  If the vnode already has path information embedded, then the
!  * cached path is left untouched.
   */
+ 
  size_t max_vnode_path = 4 * MAXPATHLEN;
  
  void
! vn_setpath(vnode_t *rootvp, struct vnode *startvp, struct vnode *vp,
!     const char *path, size_t plen)
  {
!         char    *rpath;
!         vnode_t *base;
!         size_t  rpathlen, rpathalloc;
!         int     doslash = 1;
  
!         if (*path == '/') {
!                 base = rootvp;
!                 path++;
!                 plen--;
!         } else {
!                 base = startvp;
          }
  
          /*
!          * We cannot grab base->v_lock while we hold vp->v_lock because of
!          * the potential for deadlock.
           */
!         mutex_enter(&base->v_lock);
!         if (base->v_path == NULL) {
!                 mutex_exit(&base->v_lock);
                  return;
          }
  
+         rpathlen = strlen(base->v_path);
+         rpathalloc = rpathlen + plen + 1;
+         /* Avoid adding a slash if there's already one there */
+         if (base->v_path[rpathlen-1] == '/')
+                 doslash = 0;
+         else
+                 rpathalloc++;
+ 
          /*
!          * We don't want to call kmem_alloc(KM_SLEEP) with kernel locks held,
!          * so we must do this dance.  If, by chance, something changes the path,
!          * just give up since there is no real harm.
           */
!         mutex_exit(&base->v_lock);
  
!         /* Paths should stay within reason */
!         if (rpathalloc > max_vnode_path)
                  return;
  
!         rpath = kmem_alloc(rpathalloc, KM_SLEEP);
  
!         mutex_enter(&base->v_lock);
!         if (base->v_path == NULL || strlen(base->v_path) != rpathlen) {
!                 mutex_exit(&base->v_lock);
!                 kmem_free(rpath, rpathalloc);
                  return;
          }
!         bcopy(base->v_path, rpath, rpathlen);
!         mutex_exit(&base->v_lock);
  
!         if (doslash)
!                 rpath[rpathlen++] = '/';
!         bcopy(path, rpath + rpathlen, plen);
!         rpath[rpathlen + plen] = '\0';
  
          mutex_enter(&vp->v_lock);
!         if (vp->v_path != NULL) {
                  mutex_exit(&vp->v_lock);
!                 kmem_free(rpath, rpathalloc);
          } else {
!                 vp->v_path = rpath;
                  mutex_exit(&vp->v_lock);
          }
  }
  
+ /*
+  * Sets the path to the vnode to be the given string, regardless of current
+  * context.  The string must be a complete path from rootdir.  This is only used
+  * by fsop_root() for setting the path based on the mountpoint.
+  */
  void
! vn_setpath_str(struct vnode *vp, const char *str, size_t len)
  {
!         char *buf = kmem_alloc(len + 1, KM_SLEEP);
  
!         mutex_enter(&vp->v_lock);
!         if (vp->v_path != NULL) {
!                 mutex_exit(&vp->v_lock);
!                 kmem_free(buf, len + 1);
                  return;
          }
  
!         vp->v_path = buf;
!         bcopy(str, vp->v_path, len);
!         vp->v_path[len] = '\0';
  
!         mutex_exit(&vp->v_lock);
  }
  
  /*
   * Called from within filesystem's vop_rename() to handle renames once the
   * target vnode is available.
   */
  void
! vn_renamepath(vnode_t *dvp, vnode_t *vp, const char *nm, size_t len)
  {
!         char *tmp;
! 
!         mutex_enter(&vp->v_lock);
!         tmp = vp->v_path;
!         vp->v_path = NULL;
!         mutex_exit(&vp->v_lock);
!         vn_setpath(rootdir, dvp, vp, nm, len);
!         if (tmp != NULL)
!                 kmem_free(tmp, strlen(tmp) + 1);
  }
  
  /*
   * Similar to vn_setpath_str(), this function sets the path of the destination
   * vnode to the be the same as the source vnode.
*** 3218,3263 ****
   */
  void
  vn_copypath(struct vnode *src, struct vnode *dst)
  {
          char *buf;
!         hrtime_t stamp;
!         size_t buflen;
  
          mutex_enter(&src->v_lock);
!         if (src->v_path == vn_vpath_empty) {
                  mutex_exit(&src->v_lock);
                  return;
          }
!         buflen = strlen(src->v_path) + 1;
!         mutex_exit(&src->v_lock);
  
!         buf = kmem_alloc(buflen, KM_SLEEP);
! 
          mutex_enter(&src->v_lock);
!         if (src->v_path == vn_vpath_empty ||
!             strlen(src->v_path) + 1 != buflen) {
                  mutex_exit(&src->v_lock);
!                 kmem_free(buf, buflen);
                  return;
          }
!         bcopy(src->v_path, buf, buflen);
!         stamp = src->v_path_stamp;
          mutex_exit(&src->v_lock);
  
          mutex_enter(&dst->v_lock);
!         if (dst->v_path != vn_vpath_empty) {
                  mutex_exit(&dst->v_lock);
!                 kmem_free(buf, buflen);
                  return;
          }
          dst->v_path = buf;
-         dst->v_path_stamp = stamp;
          mutex_exit(&dst->v_lock);
  }
  
- 
  /*
   * XXX Private interface for segvn routines that handle vnode
   * large page segments.
   *
   * return 1 if vp's file system VOP_PAGEIO() implementation
--- 3094,3134 ----
   */
  void
  vn_copypath(struct vnode *src, struct vnode *dst)
  {
          char *buf;
!         int alloc;
  
          mutex_enter(&src->v_lock);
!         if (src->v_path == NULL) {
                  mutex_exit(&src->v_lock);
                  return;
          }
!         alloc = strlen(src->v_path) + 1;
  
!         /* avoid kmem_alloc() with lock held */
!         mutex_exit(&src->v_lock);
!         buf = kmem_alloc(alloc, KM_SLEEP);
          mutex_enter(&src->v_lock);
!         if (src->v_path == NULL || strlen(src->v_path) + 1 != alloc) {
                  mutex_exit(&src->v_lock);
!                 kmem_free(buf, alloc);
                  return;
          }
!         bcopy(src->v_path, buf, alloc);
          mutex_exit(&src->v_lock);
  
          mutex_enter(&dst->v_lock);
!         if (dst->v_path != NULL) {
                  mutex_exit(&dst->v_lock);
!                 kmem_free(buf, alloc);
                  return;
          }
          dst->v_path = buf;
          mutex_exit(&dst->v_lock);
  }
  
  /*
   * XXX Private interface for segvn routines that handle vnode
   * large page segments.
   *
   * return 1 if vp's file system VOP_PAGEIO() implementation
*** 3442,3460 ****
                          if (lat < VOP_LATENCY_100MS)
                                  atomic_inc_64(&zvp->zv_10ms_ops.value.ui64);
                          else if (lat < VOP_LATENCY_1S) {
                                  atomic_inc_64(&zvp->zv_10ms_ops.value.ui64);
                                  atomic_inc_64(&zvp->zv_100ms_ops.value.ui64);
-                         } else if (lat < VOP_LATENCY_10S) {
-                                 atomic_inc_64(&zvp->zv_10ms_ops.value.ui64);
-                                 atomic_inc_64(&zvp->zv_100ms_ops.value.ui64);
-                                 atomic_inc_64(&zvp->zv_1s_ops.value.ui64);
                          } else {
                                  atomic_inc_64(&zvp->zv_10ms_ops.value.ui64);
                                  atomic_inc_64(&zvp->zv_100ms_ops.value.ui64);
                                  atomic_inc_64(&zvp->zv_1s_ops.value.ui64);
-                                 atomic_inc_64(&zvp->zv_10s_ops.value.ui64);
                          }
                  }
          }
  
          return (err);
--- 3313,3326 ----
*** 3510,3528 ****
                          if (lat < VOP_LATENCY_100MS)
                                  atomic_inc_64(&zvp->zv_10ms_ops.value.ui64);
                          else if (lat < VOP_LATENCY_1S) {
                                  atomic_inc_64(&zvp->zv_10ms_ops.value.ui64);
                                  atomic_inc_64(&zvp->zv_100ms_ops.value.ui64);
-                         } else if (lat < VOP_LATENCY_10S) {
-                                 atomic_inc_64(&zvp->zv_10ms_ops.value.ui64);
-                                 atomic_inc_64(&zvp->zv_100ms_ops.value.ui64);
-                                 atomic_inc_64(&zvp->zv_1s_ops.value.ui64);
                          } else {
                                  atomic_inc_64(&zvp->zv_10ms_ops.value.ui64);
                                  atomic_inc_64(&zvp->zv_100ms_ops.value.ui64);
                                  atomic_inc_64(&zvp->zv_1s_ops.value.ui64);
-                                 atomic_inc_64(&zvp->zv_10s_ops.value.ui64);
                          }
                  }
          }
  
          return (err);
--- 3376,3389 ----
*** 3686,3697 ****
                  ret = (*(dvp)->v_op->vop_lookup)
                      (dvp, nm, vpp, pnp, flags, rdir, cr, ct, deflags, ppnp);
          }
          if (ret == 0 && *vpp) {
                  VOPSTATS_UPDATE(*vpp, lookup);
!                 vn_updatepath(dvp, *vpp, nm);
          }
  
          return (ret);
  }
  
  int
--- 3547,3560 ----
                  ret = (*(dvp)->v_op->vop_lookup)
                      (dvp, nm, vpp, pnp, flags, rdir, cr, ct, deflags, ppnp);
          }
          if (ret == 0 && *vpp) {
                  VOPSTATS_UPDATE(*vpp, lookup);
!                 if ((*vpp)->v_path == NULL) {
!                         vn_setpath(rootdir, dvp, *vpp, nm, strlen(nm));
                  }
+         }
  
          return (ret);
  }
  
  int
*** 3726,3737 ****
  
          ret = (*(dvp)->v_op->vop_create)
              (dvp, name, vap, excl, mode, vpp, cr, flags, ct, vsecp);
          if (ret == 0 && *vpp) {
                  VOPSTATS_UPDATE(*vpp, create);
!                 vn_updatepath(dvp, *vpp, name);
          }
  
          return (ret);
  }
  
  int
--- 3589,3602 ----
  
          ret = (*(dvp)->v_op->vop_create)
              (dvp, name, vap, excl, mode, vpp, cr, flags, ct, vsecp);
          if (ret == 0 && *vpp) {
                  VOPSTATS_UPDATE(*vpp, create);
!                 if ((*vpp)->v_path == NULL) {
!                         vn_setpath(rootdir, dvp, *vpp, name, strlen(name));
                  }
+         }
  
          return (ret);
  }
  
  int
*** 3846,3857 ****
  
          ret = (*(dvp)->v_op->vop_mkdir)
              (dvp, dirname, vap, vpp, cr, ct, flags, vsecp);
          if (ret == 0 && *vpp) {
                  VOPSTATS_UPDATE(*vpp, mkdir);
!                 vn_updatepath(dvp, *vpp, dirname);
          }
  
          return (ret);
  }
  
  int
--- 3711,3725 ----
  
          ret = (*(dvp)->v_op->vop_mkdir)
              (dvp, dirname, vap, vpp, cr, ct, flags, vsecp);
          if (ret == 0 && *vpp) {
                  VOPSTATS_UPDATE(*vpp, mkdir);
!                 if ((*vpp)->v_path == NULL) {
!                         vn_setpath(rootdir, dvp, *vpp, dirname,
!                             strlen(dirname));
                  }
+         }
  
          return (ret);
  }
  
  int