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
↓ 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
↓ 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];
↓ 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;
↓ 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)
↓ 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.
↓ 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          /*
↓ 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
↓ open down ↓ 96 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX