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  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * lxpr_vnops.c:  Vnode operations for the lx /proc file system
  28  *
  29  * Assumptions and Gotchas:
  30  *
  31  * In order to preserve Solaris' security policy. This file system's
  32  * functionality does not override Solaris' security policies even if
  33  * that means breaking Linux compatibility.
  34  *
  35  * Linux has no concept of lwps so we only implement procs here as in the
  36  * old /proc interface.
  37  */
  38 
  39 #include <sys/cpupart.h>
  40 #include <sys/cpuvar.h>
  41 #include <sys/session.h>
  42 #include <sys/vmparam.h>
  43 #include <sys/mman.h>
  44 #include <vm/rm.h>
  45 #include <vm/seg_vn.h>
  46 #include <sys/sdt.h>
  47 #include <lx_signum.h>
  48 #include <sys/strlog.h>
  49 #include <sys/stropts.h>
  50 #include <sys/cmn_err.h>
  51 #include <sys/lx_brand.h>
  52 #include <sys/x86_archext.h>
  53 #include <sys/archsystm.h>
  54 #include <sys/fp.h>
  55 #include <sys/pool_pset.h>
  56 #include <sys/pset.h>
  57 #include <sys/zone.h>
  58 #include <sys/pghw.h>
  59 #include <sys/vfs_opreg.h>
  60 
  61 /* Dependent on the Solaris procfs */
  62 extern kthread_t *prchoose(proc_t *);
  63 
  64 #include "lx_proc.h"
  65 
  66 extern pgcnt_t swapfs_minfree;
  67 extern time_t boot_time;
  68 
  69 /*
  70  * Pointer to the vnode ops vector for this fs.
  71  * This is instantiated in lxprinit() in lxpr_vfsops.c
  72  */
  73 vnodeops_t *lxpr_vnodeops;
  74 
  75 static int lxpr_open(vnode_t **, int, cred_t *, caller_context_t *);
  76 static int lxpr_close(vnode_t *, int, int, offset_t, cred_t *,
  77     caller_context_t *);
  78 static int lxpr_read(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
  79 static int lxpr_getattr(vnode_t *, vattr_t *, int, cred_t *,
  80     caller_context_t *);
  81 static int lxpr_access(vnode_t *, int, int, cred_t *, caller_context_t *);
  82 static int lxpr_lookup(vnode_t *, char *, vnode_t **,
  83     pathname_t *, int, vnode_t *, cred_t *, caller_context_t *, int *,
  84     pathname_t *);
  85 static int lxpr_readdir(vnode_t *, uio_t *, cred_t *, int *,
  86     caller_context_t *, int);
  87 static int lxpr_readlink(vnode_t *, uio_t *, cred_t *, caller_context_t *);
  88 static int lxpr_cmp(vnode_t *, vnode_t *, caller_context_t *);
  89 static int lxpr_realvp(vnode_t *, vnode_t **, caller_context_t *);
  90 static int lxpr_sync(void);
  91 static void lxpr_inactive(vnode_t *, cred_t *, caller_context_t *);
  92 
  93 static vnode_t *lxpr_lookup_procdir(vnode_t *, char *);
  94 static vnode_t *lxpr_lookup_piddir(vnode_t *, char *);
  95 static vnode_t *lxpr_lookup_not_a_dir(vnode_t *, char *);
  96 static vnode_t *lxpr_lookup_fddir(vnode_t *, char *);
  97 static vnode_t *lxpr_lookup_netdir(vnode_t *, char *);
  98 
  99 static int lxpr_readdir_procdir(lxpr_node_t *, uio_t *, int *);
 100 static int lxpr_readdir_piddir(lxpr_node_t *, uio_t *, int *);
 101 static int lxpr_readdir_not_a_dir(lxpr_node_t *, uio_t *, int *);
 102 static int lxpr_readdir_fddir(lxpr_node_t *, uio_t *, int *);
 103 static int lxpr_readdir_netdir(lxpr_node_t *, uio_t *, int *);
 104 
 105 static void lxpr_read_invalid(lxpr_node_t *, lxpr_uiobuf_t *);
 106 static void lxpr_read_empty(lxpr_node_t *, lxpr_uiobuf_t *);
 107 static void lxpr_read_cpuinfo(lxpr_node_t *, lxpr_uiobuf_t *);
 108 static void lxpr_read_isdir(lxpr_node_t *, lxpr_uiobuf_t *);
 109 static void lxpr_read_fd(lxpr_node_t *, lxpr_uiobuf_t *);
 110 static void lxpr_read_kmsg(lxpr_node_t *, lxpr_uiobuf_t *);
 111 static void lxpr_read_loadavg(lxpr_node_t *, lxpr_uiobuf_t *);
 112 static void lxpr_read_meminfo(lxpr_node_t *, lxpr_uiobuf_t *);
 113 static void lxpr_read_mounts(lxpr_node_t *, lxpr_uiobuf_t *);
 114 static void lxpr_read_partitions(lxpr_node_t *, lxpr_uiobuf_t *);
 115 static void lxpr_read_stat(lxpr_node_t *, lxpr_uiobuf_t *);
 116 static void lxpr_read_uptime(lxpr_node_t *, lxpr_uiobuf_t *);
 117 static void lxpr_read_version(lxpr_node_t *, lxpr_uiobuf_t *);
 118 
 119 static void lxpr_read_pid_cmdline(lxpr_node_t *, lxpr_uiobuf_t *);
 120 static void lxpr_read_pid_maps(lxpr_node_t *, lxpr_uiobuf_t *);
 121 static void lxpr_read_pid_stat(lxpr_node_t *, lxpr_uiobuf_t *);
 122 static void lxpr_read_pid_statm(lxpr_node_t *, lxpr_uiobuf_t *);
 123 static void lxpr_read_pid_status(lxpr_node_t *, lxpr_uiobuf_t *);
 124 
 125 static void lxpr_read_net_arp(lxpr_node_t *, lxpr_uiobuf_t *);
 126 static void lxpr_read_net_dev(lxpr_node_t *, lxpr_uiobuf_t *);
 127 static void lxpr_read_net_dev_mcast(lxpr_node_t *, lxpr_uiobuf_t *);
 128 static void lxpr_read_net_igmp(lxpr_node_t *, lxpr_uiobuf_t *);
 129 static void lxpr_read_net_ip_mr_cache(lxpr_node_t *, lxpr_uiobuf_t *);
 130 static void lxpr_read_net_ip_mr_vif(lxpr_node_t *, lxpr_uiobuf_t *);
 131 static void lxpr_read_net_mcfilter(lxpr_node_t *, lxpr_uiobuf_t *);
 132 static void lxpr_read_net_netstat(lxpr_node_t *, lxpr_uiobuf_t *);
 133 static void lxpr_read_net_raw(lxpr_node_t *, lxpr_uiobuf_t *);
 134 static void lxpr_read_net_route(lxpr_node_t *, lxpr_uiobuf_t *);
 135 static void lxpr_read_net_rpc(lxpr_node_t *, lxpr_uiobuf_t *);
 136 static void lxpr_read_net_rt_cache(lxpr_node_t *, lxpr_uiobuf_t *);
 137 static void lxpr_read_net_sockstat(lxpr_node_t *, lxpr_uiobuf_t *);
 138 static void lxpr_read_net_snmp(lxpr_node_t *, lxpr_uiobuf_t *);
 139 static void lxpr_read_net_stat(lxpr_node_t *, lxpr_uiobuf_t *);
 140 static void lxpr_read_net_tcp(lxpr_node_t *, lxpr_uiobuf_t *);
 141 static void lxpr_read_net_udp(lxpr_node_t *, lxpr_uiobuf_t *);
 142 static void lxpr_read_net_unix(lxpr_node_t *, lxpr_uiobuf_t *);
 143 
 144 /*
 145  * Simple conversion
 146  */
 147 #define btok(x) ((x) >> 10)                       /* bytes to kbytes */
 148 #define ptok(x) ((x) << (PAGESHIFT - 10)) /* pages to kbytes */
 149 
 150 /*
 151  * The lx /proc vnode operations vector
 152  */
 153 const fs_operation_def_t lxpr_vnodeops_template[] = {
 154         VOPNAME_OPEN,           { .vop_open = lxpr_open },
 155         VOPNAME_CLOSE,          { .vop_close = lxpr_close },
 156         VOPNAME_READ,           { .vop_read = lxpr_read },
 157         VOPNAME_GETATTR,        { .vop_getattr = lxpr_getattr },
 158         VOPNAME_ACCESS,         { .vop_access = lxpr_access },
 159         VOPNAME_LOOKUP,         { .vop_lookup = lxpr_lookup },
 160         VOPNAME_READDIR,        { .vop_readdir = lxpr_readdir },
 161         VOPNAME_READLINK,       { .vop_readlink = lxpr_readlink },
 162         VOPNAME_FSYNC,          { .error = lxpr_sync },
 163         VOPNAME_SEEK,           { .error = lxpr_sync },
 164         VOPNAME_INACTIVE,       { .vop_inactive = lxpr_inactive },
 165         VOPNAME_CMP,            { .vop_cmp = lxpr_cmp },
 166         VOPNAME_REALVP,         { .vop_realvp = lxpr_realvp },
 167         NULL,                   NULL
 168 };
 169 
 170 
 171 /*
 172  * file contents of an lx /proc directory.
 173  */
 174 static lxpr_dirent_t lx_procdir[] = {
 175         { LXPR_CMDLINE,         "cmdline" },
 176         { LXPR_CPUINFO,         "cpuinfo" },
 177         { LXPR_DEVICES,         "devices" },
 178         { LXPR_DMA,             "dma" },
 179         { LXPR_FILESYSTEMS,     "filesystems" },
 180         { LXPR_INTERRUPTS,      "interrupts" },
 181         { LXPR_IOPORTS,         "ioports" },
 182         { LXPR_KCORE,           "kcore" },
 183         { LXPR_KMSG,            "kmsg" },
 184         { LXPR_LOADAVG,         "loadavg" },
 185         { LXPR_MEMINFO,         "meminfo" },
 186         { LXPR_MOUNTS,          "mounts" },
 187         { LXPR_NETDIR,          "net" },
 188         { LXPR_PARTITIONS,      "partitions" },
 189         { LXPR_SELF,            "self" },
 190         { LXPR_STAT,            "stat" },
 191         { LXPR_UPTIME,          "uptime" },
 192         { LXPR_VERSION,         "version" }
 193 };
 194 
 195 #define PROCDIRFILES    (sizeof (lx_procdir) / sizeof (lx_procdir[0]))
 196 
 197 /*
 198  * Contents of an lx /proc/<pid> directory.
 199  */
 200 static lxpr_dirent_t piddir[] = {
 201         { LXPR_PID_CMDLINE,     "cmdline" },
 202         { LXPR_PID_CPU,         "cpu" },
 203         { LXPR_PID_CURDIR,      "cwd" },
 204         { LXPR_PID_ENV,         "environ" },
 205         { LXPR_PID_EXE,         "exe" },
 206         { LXPR_PID_MAPS,        "maps" },
 207         { LXPR_PID_MEM,         "mem" },
 208         { LXPR_PID_ROOTDIR,     "root" },
 209         { LXPR_PID_STAT,        "stat" },
 210         { LXPR_PID_STATM,       "statm" },
 211         { LXPR_PID_STATUS,      "status" },
 212         { LXPR_PID_FDDIR,       "fd" }
 213 };
 214 
 215 #define PIDDIRFILES     (sizeof (piddir) / sizeof (piddir[0]))
 216 
 217 /*
 218  * contents of lx /proc/net directory
 219  */
 220 static lxpr_dirent_t netdir[] = {
 221         { LXPR_NET_ARP,         "arp" },
 222         { LXPR_NET_DEV,         "dev" },
 223         { LXPR_NET_DEV_MCAST,   "dev_mcast" },
 224         { LXPR_NET_IGMP,        "igmp" },
 225         { LXPR_NET_IP_MR_CACHE, "ip_mr_cache" },
 226         { LXPR_NET_IP_MR_VIF,   "ip_mr_vif" },
 227         { LXPR_NET_MCFILTER,    "mcfilter" },
 228         { LXPR_NET_NETSTAT,     "netstat" },
 229         { LXPR_NET_RAW,         "raw" },
 230         { LXPR_NET_ROUTE,       "route" },
 231         { LXPR_NET_RPC,         "rpc" },
 232         { LXPR_NET_RT_CACHE,    "rt_cache" },
 233         { LXPR_NET_SOCKSTAT,    "sockstat" },
 234         { LXPR_NET_SNMP,        "snmp" },
 235         { LXPR_NET_STAT,        "stat" },
 236         { LXPR_NET_TCP,         "tcp" },
 237         { LXPR_NET_UDP,         "udp" },
 238         { LXPR_NET_UNIX,        "unix" }
 239 };
 240 
 241 #define NETDIRFILES     (sizeof (netdir) / sizeof (netdir[0]))
 242 
 243 /*
 244  * lxpr_open(): Vnode operation for VOP_OPEN()
 245  */
 246 static int
 247 lxpr_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
 248 {
 249         vnode_t         *vp = *vpp;
 250         lxpr_node_t     *lxpnp = VTOLXP(vp);
 251         lxpr_nodetype_t type = lxpnp->lxpr_type;
 252         vnode_t         *rvp;
 253         int             error = 0;
 254 
 255         /*
 256          * We only allow reading in this file systrem
 257          */
 258         if (flag & FWRITE)
 259                 return (EROFS);
 260 
 261         /*
 262          * If we are opening an underlying file only allow regular files
 263          * reject the open for anything but a regular file.
 264          * Just do it if we are opening the current or root directory.
 265          */
 266         if (lxpnp->lxpr_realvp != NULL) {
 267                 rvp = lxpnp->lxpr_realvp;
 268 
 269                 if (type == LXPR_PID_FD_FD && rvp->v_type != VREG)
 270                         error = EACCES;
 271                 else {
 272                         /*
 273                          * Need to hold rvp since VOP_OPEN() may release it.
 274                          */
 275                         VN_HOLD(rvp);
 276                         error = VOP_OPEN(&rvp, flag, cr, ct);
 277                         if (error) {
 278                                 VN_RELE(rvp);
 279                         } else {
 280                                 *vpp = rvp;
 281                                 VN_RELE(vp);
 282                         }
 283                 }
 284         }
 285 
 286         if (type == LXPR_KMSG) {
 287                 ldi_ident_t     li = VTOLXPM(vp)->lxprm_li;
 288                 struct strioctl str;
 289                 int             rv;
 290 
 291                 /*
 292                  * Open the zone's console device using the layered driver
 293                  * interface.
 294                  */
 295                 if ((error = ldi_open_by_name("/dev/log", FREAD, cr,
 296                     &lxpnp->lxpr_cons_ldih, li)) != 0)
 297                         return (error);
 298 
 299                 /*
 300                  * Send an ioctl to the underlying console device, letting it
 301                  * know we're interested in getting console messages.
 302                  */
 303                 str.ic_cmd = I_CONSLOG;
 304                 str.ic_timout = 0;
 305                 str.ic_len = 0;
 306                 str.ic_dp = NULL;
 307                 if ((error = ldi_ioctl(lxpnp->lxpr_cons_ldih, I_STR,
 308                     (intptr_t)&str, FKIOCTL, cr, &rv)) != 0)
 309                         return (error);
 310         }
 311 
 312         return (error);
 313 }
 314 
 315 
 316 /*
 317  * lxpr_close(): Vnode operation for VOP_CLOSE()
 318  */
 319 /* ARGSUSED */
 320 static int
 321 lxpr_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
 322     caller_context_t *ct)
 323 {
 324         lxpr_node_t     *lxpr = VTOLXP(vp);
 325         lxpr_nodetype_t type = lxpr->lxpr_type;
 326         int             err;
 327 
 328         /*
 329          * we should never get here because the close is done on the realvp
 330          * for these nodes
 331          */
 332         ASSERT(type != LXPR_PID_FD_FD &&
 333             type != LXPR_PID_CURDIR &&
 334             type != LXPR_PID_ROOTDIR &&
 335             type != LXPR_PID_EXE);
 336 
 337         if (type == LXPR_KMSG) {
 338                 if ((err = ldi_close(lxpr->lxpr_cons_ldih, 0, cr)) != 0)
 339                         return (err);
 340         }
 341 
 342         return (0);
 343 }
 344 
 345 static void (*lxpr_read_function[LXPR_NFILES])() = {
 346         lxpr_read_isdir,                /* /proc                */
 347         lxpr_read_isdir,                /* /proc/<pid>            */
 348         lxpr_read_pid_cmdline,          /* /proc/<pid>/cmdline    */
 349         lxpr_read_empty,                /* /proc/<pid>/cpu        */
 350         lxpr_read_invalid,              /* /proc/<pid>/cwd        */
 351         lxpr_read_empty,                /* /proc/<pid>/environ    */
 352         lxpr_read_invalid,              /* /proc/<pid>/exe        */
 353         lxpr_read_pid_maps,             /* /proc/<pid>/maps       */
 354         lxpr_read_empty,                /* /proc/<pid>/mem        */
 355         lxpr_read_invalid,              /* /proc/<pid>/root       */
 356         lxpr_read_pid_stat,             /* /proc/<pid>/stat       */
 357         lxpr_read_pid_statm,            /* /proc/<pid>/statm      */
 358         lxpr_read_pid_status,           /* /proc/<pid>/status     */
 359         lxpr_read_isdir,                /* /proc/<pid>/fd */
 360         lxpr_read_fd,                   /* /proc/<pid>/fd/nn      */
 361         lxpr_read_empty,                /* /proc/cmdline        */
 362         lxpr_read_cpuinfo,              /* /proc/cpuinfo        */
 363         lxpr_read_empty,                /* /proc/devices        */
 364         lxpr_read_empty,                /* /proc/dma            */
 365         lxpr_read_empty,                /* /proc/filesystems    */
 366         lxpr_read_empty,                /* /proc/interrupts     */
 367         lxpr_read_empty,                /* /proc/ioports        */
 368         lxpr_read_empty,                /* /proc/kcore          */
 369         lxpr_read_kmsg,                 /* /proc/kmsg           */
 370         lxpr_read_loadavg,              /* /proc/loadavg        */
 371         lxpr_read_meminfo,              /* /proc/meminfo        */
 372         lxpr_read_mounts,               /* /proc/mounts         */
 373         lxpr_read_isdir,                /* /proc/net            */
 374         lxpr_read_net_arp,              /* /proc/net/arp        */
 375         lxpr_read_net_dev,              /* /proc/net/dev        */
 376         lxpr_read_net_dev_mcast,        /* /proc/net/dev_mcast  */
 377         lxpr_read_net_igmp,             /* /proc/net/igmp       */
 378         lxpr_read_net_ip_mr_cache,      /* /proc/net/ip_mr_cache */
 379         lxpr_read_net_ip_mr_vif,        /* /proc/net/ip_mr_vif  */
 380         lxpr_read_net_mcfilter,         /* /proc/net/mcfilter   */
 381         lxpr_read_net_netstat,          /* /proc/net/netstat    */
 382         lxpr_read_net_raw,              /* /proc/net/raw        */
 383         lxpr_read_net_route,            /* /proc/net/route      */
 384         lxpr_read_net_rpc,              /* /proc/net/rpc        */
 385         lxpr_read_net_rt_cache,         /* /proc/net/rt_cache   */
 386         lxpr_read_net_sockstat,         /* /proc/net/sockstat   */
 387         lxpr_read_net_snmp,             /* /proc/net/snmp       */
 388         lxpr_read_net_stat,             /* /proc/net/stat       */
 389         lxpr_read_net_tcp,              /* /proc/net/tcp        */
 390         lxpr_read_net_udp,              /* /proc/net/udp        */
 391         lxpr_read_net_unix,             /* /proc/net/unix       */
 392         lxpr_read_partitions,           /* /proc/partitions     */
 393         lxpr_read_invalid,              /* /proc/self           */
 394         lxpr_read_stat,                 /* /proc/stat           */
 395         lxpr_read_uptime,               /* /proc/uptime         */
 396         lxpr_read_version,              /* /proc/version        */
 397 };
 398 
 399 /*
 400  * Array of lookup functions, indexed by lx /proc file type.
 401  */
 402 static vnode_t *(*lxpr_lookup_function[LXPR_NFILES])() = {
 403         lxpr_lookup_procdir,            /* /proc                */
 404         lxpr_lookup_piddir,             /* /proc/<pid>            */
 405         lxpr_lookup_not_a_dir,          /* /proc/<pid>/cmdline    */
 406         lxpr_lookup_not_a_dir,          /* /proc/<pid>/cpu        */
 407         lxpr_lookup_not_a_dir,          /* /proc/<pid>/cwd        */
 408         lxpr_lookup_not_a_dir,          /* /proc/<pid>/environ    */
 409         lxpr_lookup_not_a_dir,          /* /proc/<pid>/exe        */
 410         lxpr_lookup_not_a_dir,          /* /proc/<pid>/maps       */
 411         lxpr_lookup_not_a_dir,          /* /proc/<pid>/mem        */
 412         lxpr_lookup_not_a_dir,          /* /proc/<pid>/root       */
 413         lxpr_lookup_not_a_dir,          /* /proc/<pid>/stat       */
 414         lxpr_lookup_not_a_dir,          /* /proc/<pid>/statm      */
 415         lxpr_lookup_not_a_dir,          /* /proc/<pid>/status     */
 416         lxpr_lookup_fddir,              /* /proc/<pid>/fd */
 417         lxpr_lookup_not_a_dir,          /* /proc/<pid>/fd/nn      */
 418         lxpr_lookup_not_a_dir,          /* /proc/cmdline        */
 419         lxpr_lookup_not_a_dir,          /* /proc/cpuinfo        */
 420         lxpr_lookup_not_a_dir,          /* /proc/devices        */
 421         lxpr_lookup_not_a_dir,          /* /proc/dma            */
 422         lxpr_lookup_not_a_dir,          /* /proc/filesystems    */
 423         lxpr_lookup_not_a_dir,          /* /proc/interrupts     */
 424         lxpr_lookup_not_a_dir,          /* /proc/ioports        */
 425         lxpr_lookup_not_a_dir,          /* /proc/kcore          */
 426         lxpr_lookup_not_a_dir,          /* /proc/kmsg           */
 427         lxpr_lookup_not_a_dir,          /* /proc/loadavg        */
 428         lxpr_lookup_not_a_dir,          /* /proc/meminfo        */
 429         lxpr_lookup_not_a_dir,          /* /proc/mounts         */
 430         lxpr_lookup_netdir,             /* /proc/net            */
 431         lxpr_lookup_not_a_dir,          /* /proc/net/arp        */
 432         lxpr_lookup_not_a_dir,          /* /proc/net/dev        */
 433         lxpr_lookup_not_a_dir,          /* /proc/net/dev_mcast  */
 434         lxpr_lookup_not_a_dir,          /* /proc/net/igmp       */
 435         lxpr_lookup_not_a_dir,          /* /proc/net/ip_mr_cache */
 436         lxpr_lookup_not_a_dir,          /* /proc/net/ip_mr_vif  */
 437         lxpr_lookup_not_a_dir,          /* /proc/net/mcfilter   */
 438         lxpr_lookup_not_a_dir,          /* /proc/net/netstat    */
 439         lxpr_lookup_not_a_dir,          /* /proc/net/raw        */
 440         lxpr_lookup_not_a_dir,          /* /proc/net/route      */
 441         lxpr_lookup_not_a_dir,          /* /proc/net/rpc        */
 442         lxpr_lookup_not_a_dir,          /* /proc/net/rt_cache   */
 443         lxpr_lookup_not_a_dir,          /* /proc/net/sockstat   */
 444         lxpr_lookup_not_a_dir,          /* /proc/net/snmp       */
 445         lxpr_lookup_not_a_dir,          /* /proc/net/stat       */
 446         lxpr_lookup_not_a_dir,          /* /proc/net/tcp        */
 447         lxpr_lookup_not_a_dir,          /* /proc/net/udp        */
 448         lxpr_lookup_not_a_dir,          /* /proc/net/unix       */
 449         lxpr_lookup_not_a_dir,          /* /proc/partitions     */
 450         lxpr_lookup_not_a_dir,          /* /proc/self           */
 451         lxpr_lookup_not_a_dir,          /* /proc/stat           */
 452         lxpr_lookup_not_a_dir,          /* /proc/uptime         */
 453         lxpr_lookup_not_a_dir,          /* /proc/version        */
 454 };
 455 
 456 /*
 457  * Array of readdir functions, indexed by /proc file type.
 458  */
 459 static int (*lxpr_readdir_function[LXPR_NFILES])() = {
 460         lxpr_readdir_procdir,           /* /proc                */
 461         lxpr_readdir_piddir,            /* /proc/<pid>            */
 462         lxpr_readdir_not_a_dir,         /* /proc/<pid>/cmdline    */
 463         lxpr_readdir_not_a_dir,         /* /proc/<pid>/cpu        */
 464         lxpr_readdir_not_a_dir,         /* /proc/<pid>/cwd        */
 465         lxpr_readdir_not_a_dir,         /* /proc/<pid>/environ    */
 466         lxpr_readdir_not_a_dir,         /* /proc/<pid>/exe        */
 467         lxpr_readdir_not_a_dir,         /* /proc/<pid>/maps       */
 468         lxpr_readdir_not_a_dir,         /* /proc/<pid>/mem        */
 469         lxpr_readdir_not_a_dir,         /* /proc/<pid>/root       */
 470         lxpr_readdir_not_a_dir,         /* /proc/<pid>/stat       */
 471         lxpr_readdir_not_a_dir,         /* /proc/<pid>/statm      */
 472         lxpr_readdir_not_a_dir,         /* /proc/<pid>/status     */
 473         lxpr_readdir_fddir,             /* /proc/<pid>/fd */
 474         lxpr_readdir_not_a_dir,         /* /proc/<pid>/fd/nn      */
 475         lxpr_readdir_not_a_dir,         /* /proc/cmdline        */
 476         lxpr_readdir_not_a_dir,         /* /proc/cpuinfo        */
 477         lxpr_readdir_not_a_dir,         /* /proc/devices        */
 478         lxpr_readdir_not_a_dir,         /* /proc/dma            */
 479         lxpr_readdir_not_a_dir,         /* /proc/filesystems    */
 480         lxpr_readdir_not_a_dir,         /* /proc/interrupts     */
 481         lxpr_readdir_not_a_dir,         /* /proc/ioports        */
 482         lxpr_readdir_not_a_dir,         /* /proc/kcore          */
 483         lxpr_readdir_not_a_dir,         /* /proc/kmsg           */
 484         lxpr_readdir_not_a_dir,         /* /proc/loadavg        */
 485         lxpr_readdir_not_a_dir,         /* /proc/meminfo        */
 486         lxpr_readdir_not_a_dir,         /* /proc/mounts         */
 487         lxpr_readdir_netdir,            /* /proc/net            */
 488         lxpr_readdir_not_a_dir,         /* /proc/net/arp        */
 489         lxpr_readdir_not_a_dir,         /* /proc/net/dev        */
 490         lxpr_readdir_not_a_dir,         /* /proc/net/dev_mcast  */
 491         lxpr_readdir_not_a_dir,         /* /proc/net/igmp       */
 492         lxpr_readdir_not_a_dir,         /* /proc/net/ip_mr_cache */
 493         lxpr_readdir_not_a_dir,         /* /proc/net/ip_mr_vif  */
 494         lxpr_readdir_not_a_dir,         /* /proc/net/mcfilter   */
 495         lxpr_readdir_not_a_dir,         /* /proc/net/netstat    */
 496         lxpr_readdir_not_a_dir,         /* /proc/net/raw        */
 497         lxpr_readdir_not_a_dir,         /* /proc/net/route      */
 498         lxpr_readdir_not_a_dir,         /* /proc/net/rpc        */
 499         lxpr_readdir_not_a_dir,         /* /proc/net/rt_cache   */
 500         lxpr_readdir_not_a_dir,         /* /proc/net/sockstat   */
 501         lxpr_readdir_not_a_dir,         /* /proc/net/snmp       */
 502         lxpr_readdir_not_a_dir,         /* /proc/net/stat       */
 503         lxpr_readdir_not_a_dir,         /* /proc/net/tcp        */
 504         lxpr_readdir_not_a_dir,         /* /proc/net/udp        */
 505         lxpr_readdir_not_a_dir,         /* /proc/net/unix       */
 506         lxpr_readdir_not_a_dir,         /* /proc/partitions     */
 507         lxpr_readdir_not_a_dir,         /* /proc/self           */
 508         lxpr_readdir_not_a_dir,         /* /proc/stat           */
 509         lxpr_readdir_not_a_dir,         /* /proc/uptime         */
 510         lxpr_readdir_not_a_dir,         /* /proc/version        */
 511 };
 512 
 513 
 514 /*
 515  * lxpr_read(): Vnode operation for VOP_READ()
 516  *
 517  * As the format of all the files that can be read in the lx procfs is human
 518  * readable and not binary structures there do not have to be different
 519  * read variants depending on whether the reading process model is 32 or 64 bits
 520  * (at least in general, and certainly the difference is unlikely to be enough
 521  * to justify have different routines for 32 and 64 bit reads
 522  */
 523 /* ARGSUSED */
 524 static int
 525 lxpr_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
 526     caller_context_t *ct)
 527 {
 528         lxpr_node_t *lxpnp = VTOLXP(vp);
 529         lxpr_nodetype_t type = lxpnp->lxpr_type;
 530         lxpr_uiobuf_t *uiobuf = lxpr_uiobuf_new(uiop);
 531         int error;
 532 
 533         ASSERT(type >= 0 && type < LXPR_NFILES);
 534 
 535         lxpr_read_function[type](lxpnp, uiobuf);
 536 
 537         error = lxpr_uiobuf_flush(uiobuf);
 538         lxpr_uiobuf_free(uiobuf);
 539 
 540         return (error);
 541 }
 542 
 543 
 544 /*
 545  * lxpr_read_invalid(), lxpr_read_isdir(), lxpr_read_empty()
 546  *
 547  * Various special case reads:
 548  * - trying to read a directory
 549  * - invalid file (used to mean a file that should be implemented,
 550  *   but isn't yet)
 551  * - empty file
 552  * - wait to be able to read a file that will never have anything to read
 553  */
 554 /* ARGSUSED */
 555 static void
 556 lxpr_read_isdir(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
 557 {
 558         lxpr_uiobuf_seterr(uiobuf, EISDIR);
 559 }
 560 
 561 /* ARGSUSED */
 562 static void
 563 lxpr_read_invalid(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
 564 {
 565         lxpr_uiobuf_seterr(uiobuf, EINVAL);
 566 }
 567 
 568 /* ARGSUSED */
 569 static void
 570 lxpr_read_empty(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
 571 {
 572 }
 573 
 574 /*
 575  * lxpr_read_pid_cmdline():
 576  *
 577  * This is not precisely compatible with linux:
 578  *
 579  * The linux cmdline returns argv with the correct separation
 580  * using \0 between the arguments, we cannot do that without
 581  * copying the real argv from the correct process context.
 582  * This is too difficult to attempt so we pretend that the
 583  * entire cmdline is just argv[0]. This is good enough for
 584  * ps to display correctly, but might cause some other things
 585  * not to work correctly.
 586  */
 587 static void
 588 lxpr_read_pid_cmdline(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
 589 {
 590         proc_t *p;
 591 
 592         ASSERT(lxpnp->lxpr_type == LXPR_PID_CMDLINE);
 593 
 594         p = lxpr_lock(lxpnp->lxpr_pid);
 595         if (p == NULL) {
 596                 lxpr_uiobuf_seterr(uiobuf, EINVAL);
 597                 return;
 598         }
 599 
 600         if (PTOU(p)->u_argv != 0) {
 601                 char *buff = PTOU(p)->u_psargs;
 602                 int len = strlen(buff);
 603                 lxpr_unlock(p);
 604                 lxpr_uiobuf_write(uiobuf, buff, len+1);
 605         } else {
 606                 lxpr_unlock(p);
 607         }
 608 }
 609 
 610 
 611 /*
 612  * lxpr_read_pid_maps(): memory map file
 613  */
 614 static void
 615 lxpr_read_pid_maps(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
 616 {
 617         proc_t *p;
 618         struct as *as;
 619         struct seg *seg;
 620         char *buf;
 621         int buflen = MAXPATHLEN;
 622         struct print_data {
 623                 caddr_t saddr;
 624                 caddr_t eaddr;
 625                 int type;
 626                 char prot[5];
 627                 uint32_t offset;
 628                 vnode_t *vp;
 629                 struct print_data *next;
 630         } *print_head = NULL;
 631         struct print_data **print_tail = &print_head;
 632         struct print_data *pbuf;
 633 
 634         ASSERT(lxpnp->lxpr_type == LXPR_PID_MAPS);
 635 
 636         p = lxpr_lock(lxpnp->lxpr_pid);
 637         if (p == NULL) {
 638                 lxpr_uiobuf_seterr(uiobuf, EINVAL);
 639                 return;
 640         }
 641 
 642         as = p->p_as;
 643 
 644         if (as == &kas) {
 645                 lxpr_unlock(p);
 646                 return;
 647         }
 648 
 649         mutex_exit(&p->p_lock);
 650 
 651         /* Iterate over all segments in the address space */
 652         AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
 653         for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
 654                 vnode_t *vp;
 655                 uint_t protbits;
 656 
 657                 pbuf = kmem_alloc(sizeof (*pbuf), KM_SLEEP);
 658 
 659                 pbuf->saddr = seg->s_base;
 660                 pbuf->eaddr = seg->s_base+seg->s_size;
 661                 pbuf->type = SEGOP_GETTYPE(seg, seg->s_base);
 662 
 663                 /*
 664                  * Cheat and only use the protection bits of the first page
 665                  * in the segment
 666                  */
 667                 (void) strncpy(pbuf->prot, "----", sizeof (pbuf->prot));
 668                 (void) SEGOP_GETPROT(seg, seg->s_base, 0, &protbits);
 669 
 670                 if (protbits & PROT_READ)      pbuf->prot[0] = 'r';
 671                 if (protbits & PROT_WRITE)     pbuf->prot[1] = 'w';
 672                 if (protbits & PROT_EXEC)      pbuf->prot[2] = 'x';
 673                 if (pbuf->type & MAP_SHARED)        pbuf->prot[3] = 's';
 674                 else if (pbuf->type & MAP_PRIVATE) pbuf->prot[3] = 'p';
 675 
 676                 if (seg->s_ops == &segvn_ops &&
 677                     SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
 678                     vp != NULL && vp->v_type == VREG) {
 679                         VN_HOLD(vp);
 680                         pbuf->vp = vp;
 681                 } else {
 682                         pbuf->vp = NULL;
 683                 }
 684 
 685                 pbuf->offset = (uint32_t)SEGOP_GETOFFSET(seg, pbuf->saddr);
 686 
 687                 pbuf->next = NULL;
 688                 *print_tail = pbuf;
 689                 print_tail = &pbuf->next;
 690         }
 691         AS_LOCK_EXIT(as, &as->a_lock);
 692         mutex_enter(&p->p_lock);
 693         lxpr_unlock(p);
 694 
 695         buf = kmem_alloc(buflen, KM_SLEEP);
 696 
 697         /* print the data we've extracted */
 698         pbuf = print_head;
 699         while (pbuf != NULL) {
 700                 struct print_data *pbuf_next;
 701                 vattr_t vattr;
 702 
 703                 int maj = 0;
 704                 int min = 0;
 705                 int inode = 0;
 706 
 707                 *buf = '\0';
 708                 if (pbuf->vp != NULL) {
 709                         vattr.va_mask = AT_FSID | AT_NODEID;
 710                         if (VOP_GETATTR(pbuf->vp, &vattr, 0, CRED(),
 711                             NULL) == 0) {
 712                                 maj = getmajor(vattr.va_fsid);
 713                                 min = getminor(vattr.va_fsid);
 714                                 inode = vattr.va_nodeid;
 715                         }
 716                         (void) vnodetopath(NULL, pbuf->vp, buf, buflen, CRED());
 717                         VN_RELE(pbuf->vp);
 718                 }
 719 
 720                 if (*buf != '\0') {
 721                         lxpr_uiobuf_printf(uiobuf,
 722                             "%08x-%08x %s %08x %02d:%03d %d %s\n",
 723                             pbuf->saddr, pbuf->eaddr, pbuf->prot, pbuf->offset,
 724                             maj, min, inode, buf);
 725                 } else {
 726                         lxpr_uiobuf_printf(uiobuf,
 727                             "%08x-%08x %s %08x %02d:%03d %d\n",
 728                             pbuf->saddr, pbuf->eaddr, pbuf->prot, pbuf->offset,
 729                             maj, min, inode);
 730                 }
 731 
 732                 pbuf_next = pbuf->next;
 733                 kmem_free(pbuf, sizeof (*pbuf));
 734                 pbuf = pbuf_next;
 735         }
 736 
 737         kmem_free(buf, buflen);
 738 }
 739 
 740 /*
 741  * lxpr_read_pid_statm(): memory status file
 742  */
 743 static void
 744 lxpr_read_pid_statm(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
 745 {
 746         proc_t *p;
 747         struct as *as;
 748         size_t vsize;
 749         size_t rss;
 750 
 751         ASSERT(lxpnp->lxpr_type == LXPR_PID_STATM);
 752 
 753         p = lxpr_lock(lxpnp->lxpr_pid);
 754         if (p == NULL) {
 755                 lxpr_uiobuf_seterr(uiobuf, EINVAL);
 756                 return;
 757         }
 758 
 759         as = p->p_as;
 760 
 761         mutex_exit(&p->p_lock);
 762 
 763         AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
 764         vsize = btopr(as->a_resvsize);
 765         rss = rm_asrss(as);
 766         AS_LOCK_EXIT(as, &as->a_lock);
 767 
 768         mutex_enter(&p->p_lock);
 769         lxpr_unlock(p);
 770 
 771         lxpr_uiobuf_printf(uiobuf,
 772             "%lu %lu %lu %lu %lu %lu %lu\n",
 773             vsize, rss, 0l, rss, 0l, 0l, 0l);
 774 }
 775 
 776 /*
 777  * lxpr_read_pid_status(): status file
 778  */
 779 static void
 780 lxpr_read_pid_status(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
 781 {
 782         proc_t *p;
 783         kthread_t *t;
 784         user_t *up;
 785         cred_t *cr;
 786         const gid_t *groups;
 787         int    ngroups;
 788         struct as *as;
 789         char *status;
 790         pid_t pid, ppid;
 791         size_t vsize;
 792         size_t rss;
 793         k_sigset_t current, ignore, handle;
 794         int    i, lx_sig;
 795 
 796         ASSERT(lxpnp->lxpr_type == LXPR_PID_STATUS);
 797 
 798         p = lxpr_lock(lxpnp->lxpr_pid);
 799         if (p == NULL) {
 800                 lxpr_uiobuf_seterr(uiobuf, EINVAL);
 801                 return;
 802         }
 803 
 804         pid = p->p_pid;
 805 
 806         /*
 807          * Convert pid to the Linux default of 1 if we're the zone's init
 808          * process
 809          */
 810         if (pid == curproc->p_zone->zone_proc_initpid) {
 811                 pid = 1;
 812                 ppid = 0;       /* parent pid for init is 0 */
 813         } else {
 814                 /*
 815                  * Make sure not to reference parent PIDs that reside outside
 816                  * the zone
 817                  */
 818                 ppid = ((p->p_flag & SZONETOP)
 819                     ? curproc->p_zone->zone_zsched->p_pid : p->p_ppid);
 820 
 821                 /*
 822                  * Convert ppid to the Linux default of 1 if our parent is the
 823                  * zone's init process
 824                  */
 825                 if (ppid == curproc->p_zone->zone_proc_initpid)
 826                         ppid = 1;
 827         }
 828 
 829         t = prchoose(p);
 830         if (t != NULL) {
 831                 switch (t->t_state) {
 832                 case TS_SLEEP:
 833                         status = "S (sleeping)";
 834                         break;
 835                 case TS_RUN:
 836                 case TS_ONPROC:
 837                         status = "R (running)";
 838                         break;
 839                 case TS_ZOMB:
 840                         status = "Z (zombie)";
 841                         break;
 842                 case TS_STOPPED:
 843                         status = "T (stopped)";
 844                         break;
 845                 default:
 846                         status = "! (unknown)";
 847                         break;
 848                 }
 849                 thread_unlock(t);
 850         } else {
 851                 /*
 852                  * there is a hole in the exit code, where a proc can have
 853                  * no threads but it is yet to be flagged SZOMB. We will
 854                  * assume we are about to become a zombie
 855                  */
 856                 status = "Z (zombie)";
 857         }
 858 
 859         up = PTOU(p);
 860         mutex_enter(&p->p_crlock);
 861         crhold(cr = p->p_cred);
 862         mutex_exit(&p->p_crlock);
 863 
 864         lxpr_uiobuf_printf(uiobuf,
 865             "Name:\t%s\n"
 866             "State:\t%s\n"
 867             "Tgid:\t%d\n"
 868             "Pid:\t%d\n"
 869             "PPid:\t%d\n"
 870             "TracerPid:\t%d\n"
 871             "Uid:\t%u\t%u\t%u\t%u\n"
 872             "Gid:\t%u\t%u\t%u\t%u\n"
 873             "FDSize:\t%d\n"
 874             "Groups:\t",
 875             up->u_comm,
 876             status,
 877             pid, /* thread group id - same as pid until we map lwps to procs */
 878             pid,
 879             ppid,
 880             0,
 881             crgetruid(cr), crgetuid(cr), crgetsuid(cr), crgetuid(cr),
 882             crgetrgid(cr), crgetgid(cr), crgetsgid(cr), crgetgid(cr),
 883             p->p_fno_ctl);
 884 
 885         ngroups = crgetngroups(cr);
 886         groups  = crgetgroups(cr);
 887         for (i = 0; i < ngroups; i++) {
 888                 lxpr_uiobuf_printf(uiobuf,
 889                     "%u ",
 890                     groups[i]);
 891         }
 892         crfree(cr);
 893 
 894         as = p->p_as;
 895         if ((p->p_stat != SZOMB) && !(p->p_flag & SSYS) && (as != &kas)) {
 896                 mutex_exit(&p->p_lock);
 897                 AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
 898                 vsize = as->a_resvsize;
 899                 rss = rm_asrss(as);
 900                 AS_LOCK_EXIT(as, &as->a_lock);
 901                 mutex_enter(&p->p_lock);
 902 
 903                 lxpr_uiobuf_printf(uiobuf,
 904                     "\n"
 905                     "VmSize:\t%8lu kB\n"
 906                     "VmLck:\t%8lu kB\n"
 907                     "VmRSS:\t%8lu kB\n"
 908                     "VmData:\t%8lu kB\n"
 909                     "VmStk:\t%8lu kB\n"
 910                     "VmExe:\t%8lu kB\n"
 911                     "VmLib:\t%8lu kB",
 912                     btok(vsize),
 913                     0l,
 914                     ptok(rss),
 915                     0l,
 916                     btok(p->p_stksize),
 917                     ptok(rss),
 918                     0l);
 919         }
 920 
 921         sigemptyset(&current);
 922         sigemptyset(&ignore);
 923         sigemptyset(&handle);
 924 
 925         for (i = 1; i < NSIG; i++) {
 926                 lx_sig = stol_signo[i];
 927 
 928                 if ((lx_sig > 0) && (lx_sig < LX_NSIG)) {
 929                         if (sigismember(&p->p_sig, i))
 930                                 sigaddset(&current, lx_sig);
 931 
 932                         if (up->u_signal[i - 1] == SIG_IGN)
 933                                 sigaddset(&ignore, lx_sig);
 934                         else if (up->u_signal[i - 1] != SIG_DFL)
 935                                 sigaddset(&handle, lx_sig);
 936                 }
 937         }
 938 
 939         lxpr_uiobuf_printf(uiobuf,
 940             "\n"
 941             "SigPnd:\t%08x%08x\n"
 942             "SigBlk:\t%08x%08x\n"
 943             "SigIgn:\t%08x%08x\n"
 944             "SigCgt:\t%08x%08x\n"
 945             "CapInh:\t%016x\n"
 946             "CapPrm:\t%016x\n"
 947             "CapEff:\t%016x\n",
 948             current.__sigbits[1], current.__sigbits[0],
 949             0, 0, /* signals blocked on per thread basis */
 950             ignore.__sigbits[1], ignore.__sigbits[0],
 951             handle.__sigbits[1], handle.__sigbits[0],
 952             /* Can't do anything with linux capabilities */
 953             0,
 954             0,
 955             0);
 956 
 957         lxpr_unlock(p);
 958 }
 959 
 960 
 961 /*
 962  * lxpr_read_pid_stat(): pid stat file
 963  */
 964 static void
 965 lxpr_read_pid_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
 966 {
 967         proc_t *p;
 968         kthread_t *t;
 969         struct as *as;
 970         char stat;
 971         pid_t pid, ppid, pgpid, spid;
 972         gid_t psgid;
 973         dev_t psdev;
 974         size_t rss, vsize;
 975         int nice, pri;
 976         caddr_t wchan;
 977         processorid_t cpu;
 978 
 979         ASSERT(lxpnp->lxpr_type == LXPR_PID_STAT);
 980 
 981         p = lxpr_lock(lxpnp->lxpr_pid);
 982         if (p == NULL) {
 983                 lxpr_uiobuf_seterr(uiobuf, EINVAL);
 984                 return;
 985         }
 986 
 987         pid = p->p_pid;
 988 
 989         /*
 990          * Set Linux defaults if we're the zone's init process
 991          */
 992         if (pid == curproc->p_zone->zone_proc_initpid) {
 993                 pid = 1;                /* PID for init */
 994                 ppid = 0;               /* parent PID for init is 0 */
 995                 pgpid = 0;              /* process group for init is 0 */
 996                 psgid = (gid_t)-1;      /* credential GID for init is -1 */
 997                 spid = 0;               /* session id for init is 0 */
 998                 psdev = 0;              /* session device for init is 0 */
 999         } else {
1000                 /*
1001                  * Make sure not to reference parent PIDs that reside outside
1002                  * the zone
1003                  */
1004                 ppid = ((p->p_flag & SZONETOP)
1005                     ? curproc->p_zone->zone_zsched->p_pid : p->p_ppid);
1006 
1007                 /*
1008                  * Convert ppid to the Linux default of 1 if our parent is the
1009                  * zone's init process
1010                  */
1011                 if (ppid == curproc->p_zone->zone_proc_initpid)
1012                         ppid = 1;
1013 
1014                 pgpid = p->p_pgrp;
1015 
1016                 mutex_enter(&p->p_splock);
1017                 mutex_enter(&p->p_sessp->s_lock);
1018                 spid = p->p_sessp->s_sid;
1019                 /* XXBRAND psdev = DEV_TO_LXDEV(p->p_sessp->s_dev, VCHR); */
1020                 psdev = p->p_sessp->s_dev;
1021                 if (p->p_sessp->s_cred)
1022                         psgid = crgetgid(p->p_sessp->s_cred);
1023                 else
1024                         psgid = crgetgid(p->p_cred);
1025 
1026                 mutex_exit(&p->p_sessp->s_lock);
1027                 mutex_exit(&p->p_splock);
1028         }
1029 
1030         t = prchoose(p);
1031         if (t != NULL) {
1032                 switch (t->t_state) {
1033                 case TS_SLEEP:
1034                         stat = 'S'; break;
1035                 case TS_RUN:
1036                 case TS_ONPROC:
1037                         stat = 'R'; break;
1038                 case TS_ZOMB:
1039                         stat = 'Z'; break;
1040                 case TS_STOPPED:
1041                         stat = 'T'; break;
1042                 default:
1043                         stat = '!'; break;
1044                 }
1045 
1046                 if (CL_DONICE(t, NULL, 0, &nice) != 0)
1047                         nice = 0;
1048 
1049                 pri = v.v_maxsyspri - t->t_pri;
1050                 wchan = t->t_wchan;
1051                 cpu = t->t_cpu->cpu_seqid;
1052                 thread_unlock(t);
1053         } else {
1054                 /* Only zombies have no threads */
1055                 stat = 'Z';
1056                 nice = 0;
1057                 pri = 0;
1058                 wchan = 0;
1059                 cpu = 0;
1060         }
1061         as = p->p_as;
1062         mutex_exit(&p->p_lock);
1063         AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
1064         vsize = as->a_resvsize;
1065         rss = rm_asrss(as);
1066         AS_LOCK_EXIT(as, &as->a_lock);
1067         mutex_enter(&p->p_lock);
1068 
1069         lxpr_uiobuf_printf(uiobuf,
1070             "%d (%s) %c %d %d %d %d %d "
1071             "%lu %lu %lu %lu %lu "
1072             "%lu %lu %ld %ld "
1073             "%d %d "
1074             "0 "
1075             "%ld %lu "
1076             "%lu %ld %llu "
1077             "%lu %lu %u "
1078             "%lu %lu "
1079             "%lu %lu %lu %lu "
1080             "%lu "
1081             "%lu %lu "
1082             "%d "
1083             "%d"
1084             "\n",
1085             pid,
1086             PTOU(p)->u_comm,
1087             stat,
1088             ppid, pgpid,
1089             spid, psdev, psgid,
1090             0l, 0l, 0l, 0l, 0l, /* flags, minflt, cminflt, majflt, cmajflt */
1091             p->p_utime, p->p_stime, p->p_cutime, p->p_cstime,
1092             pri, nice,
1093             0l, PTOU(p)->u_ticks, /* ticks till next SIGALARM, start time */
1094             vsize, rss, p->p_vmem_ctl,
1095             0l, 0l, USRSTACK, /* startcode, endcode, startstack */
1096             0l, 0l, /* kstkesp, kstkeip */
1097             0l, 0l, 0l, 0l, /* signal, blocked, sigignore, sigcatch */
1098             wchan,
1099             0l, 0l, /* nswap, cnswap */
1100             0, /* exit_signal */
1101             cpu);
1102 
1103         lxpr_unlock(p);
1104 }
1105 
1106 /* ARGSUSED */
1107 static void
1108 lxpr_read_net_arp(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1109 {
1110 }
1111 
1112 /* ARGSUSED */
1113 static void
1114 lxpr_read_net_dev(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1115 {
1116         lxpr_uiobuf_printf(uiobuf, "Inter-|   Receive                   "
1117             "                             |  Transmit\n");
1118         lxpr_uiobuf_printf(uiobuf, " face |bytes    packets errs drop fifo"
1119             " frame compressed multicast|bytes    packets errs drop fifo"
1120             " colls carrier compressed\n");
1121 
1122         /*
1123          * XXX: data about each interface should go here, but we'll wait to
1124          * see if anybody wants to use it.
1125          */
1126 }
1127 
1128 /* ARGSUSED */
1129 static void
1130 lxpr_read_net_dev_mcast(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1131 {
1132 }
1133 
1134 /* ARGSUSED */
1135 static void
1136 lxpr_read_net_igmp(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1137 {
1138 }
1139 
1140 /* ARGSUSED */
1141 static void
1142 lxpr_read_net_ip_mr_cache(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1143 {
1144 }
1145 
1146 /* ARGSUSED */
1147 static void
1148 lxpr_read_net_ip_mr_vif(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1149 {
1150 }
1151 
1152 /* ARGSUSED */
1153 static void
1154 lxpr_read_net_mcfilter(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1155 {
1156 }
1157 
1158 /* ARGSUSED */
1159 static void
1160 lxpr_read_net_netstat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1161 {
1162 }
1163 
1164 /* ARGSUSED */
1165 static void
1166 lxpr_read_net_raw(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1167 {
1168 }
1169 
1170 /* ARGSUSED */
1171 static void
1172 lxpr_read_net_route(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1173 {
1174 }
1175 
1176 /* ARGSUSED */
1177 static void
1178 lxpr_read_net_rpc(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1179 {
1180 }
1181 
1182 /* ARGSUSED */
1183 static void
1184 lxpr_read_net_rt_cache(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1185 {
1186 }
1187 
1188 /* ARGSUSED */
1189 static void
1190 lxpr_read_net_sockstat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1191 {
1192 }
1193 
1194 /* ARGSUSED */
1195 static void
1196 lxpr_read_net_snmp(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1197 {
1198 }
1199 
1200 /* ARGSUSED */
1201 static void
1202 lxpr_read_net_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1203 {
1204 }
1205 
1206 /* ARGSUSED */
1207 static void
1208 lxpr_read_net_tcp(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1209 {
1210 }
1211 
1212 /* ARGSUSED */
1213 static void
1214 lxpr_read_net_udp(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1215 {
1216 }
1217 
1218 /* ARGSUSED */
1219 static void
1220 lxpr_read_net_unix(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1221 {
1222 }
1223 
1224 /*
1225  * lxpr_read_kmsg(): read the contents of the kernel message queue. We
1226  * translate this into the reception of console messages for this lx zone; each
1227  * read copies out a single zone console message, or blocks until the next one
1228  * is produced.
1229  */
1230 
1231 #define LX_KMSG_PRI     "<0>"
1232 
1233 static void
1234 lxpr_read_kmsg(lxpr_node_t *lxpnp, struct lxpr_uiobuf *uiobuf)
1235 {
1236         ldi_handle_t    lh = lxpnp->lxpr_cons_ldih;
1237         mblk_t          *mp;
1238 
1239         if (ldi_getmsg(lh, &mp, NULL) == 0) {
1240                 /*
1241                  * lx procfs doesn't like successive reads to the same file
1242                  * descriptor unless we do an explicit rewind each time.
1243                  */
1244                 lxpr_uiobuf_seek(uiobuf, 0);
1245 
1246                 lxpr_uiobuf_printf(uiobuf, "%s%s", LX_KMSG_PRI,
1247                     mp->b_cont->b_rptr);
1248 
1249                 freemsg(mp);
1250         }
1251 }
1252 
1253 /*
1254  * lxpr_read_loadavg(): read the contents of the "loadavg" file.
1255  *
1256  * Just enough for uptime to work
1257  */
1258 extern int nthread;
1259 
1260 static void
1261 lxpr_read_loadavg(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1262 {
1263         ulong_t avenrun1;
1264         ulong_t avenrun5;
1265         ulong_t avenrun15;
1266         ulong_t avenrun1_cs;
1267         ulong_t avenrun5_cs;
1268         ulong_t avenrun15_cs;
1269         int loadavg[3];
1270         int *loadbuf;
1271         cpupart_t *cp;
1272 
1273         uint_t nrunnable = 0;
1274         rctl_qty_t nlwps;
1275 
1276         ASSERT(lxpnp->lxpr_type == LXPR_LOADAVG);
1277 
1278         mutex_enter(&cpu_lock);
1279 
1280         /*
1281          * Need to add up values over all CPU partitions. If pools are active,
1282          * only report the values of the zone's partition, which by definition
1283          * includes the current CPU.
1284          */
1285         if (pool_pset_enabled()) {
1286                 psetid_t psetid = zone_pset_get(curproc->p_zone);
1287 
1288                 ASSERT(curproc->p_zone != &zone0);
1289                 cp = CPU->cpu_part;
1290 
1291                 nrunnable = cp->cp_nrunning + cp->cp_nrunnable;
1292                 (void) cpupart_get_loadavg(psetid, &loadavg[0], 3);
1293                 loadbuf = &loadavg[0];
1294 
1295                 /*
1296                  * We'll report the total number of lwps in the zone for the
1297                  * "nproc" parameter of /proc/loadavg; good enough for lx.
1298                  */
1299                 nlwps = curproc->p_zone->zone_nlwps;
1300         } else {
1301                 cp = cp_list_head;
1302                 do {
1303                         nrunnable += cp->cp_nrunning + cp->cp_nrunnable;
1304                 } while ((cp = cp->cp_next) != cp_list_head);
1305 
1306                 loadbuf = &avenrun[0];
1307 
1308                 /*
1309                  * This will report kernel threads as well as user lwps, but it
1310                  * should be good enough for lx consumers.
1311                  */
1312                 nlwps = nthread;
1313         }
1314 
1315         mutex_exit(&cpu_lock);
1316 
1317         avenrun1 = loadbuf[0] >> FSHIFT;
1318         avenrun1_cs = ((loadbuf[0] & (FSCALE-1)) * 100) >> FSHIFT;
1319         avenrun5 = loadbuf[1] >> FSHIFT;
1320         avenrun5_cs = ((loadbuf[1] & (FSCALE-1)) * 100) >> FSHIFT;
1321         avenrun15 = loadbuf[2] >> FSHIFT;
1322         avenrun15_cs = ((loadbuf[2] & (FSCALE-1)) * 100) >> FSHIFT;
1323 
1324         lxpr_uiobuf_printf(uiobuf,
1325             "%ld.%02d %ld.%02d %ld.%02d %d/%d %d\n",
1326             avenrun1, avenrun1_cs,
1327             avenrun5, avenrun5_cs,
1328             avenrun15, avenrun15_cs,
1329             nrunnable, nlwps, 0);
1330 }
1331 
1332 /*
1333  * lxpr_read_meminfo(): read the contents of the "meminfo" file.
1334  */
1335 static void
1336 lxpr_read_meminfo(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1337 {
1338         long total_mem = physmem * PAGESIZE;
1339         long free_mem = freemem * PAGESIZE;
1340         long total_swap = k_anoninfo.ani_max * PAGESIZE;
1341         long used_swap = k_anoninfo.ani_phys_resv * PAGESIZE;
1342 
1343         ASSERT(lxpnp->lxpr_type == LXPR_MEMINFO);
1344 
1345         lxpr_uiobuf_printf(uiobuf,
1346             "        total:     used:    free:  shared: buffers:  cached:\n"
1347             "Mem:  %8lu %8lu %8lu %8u %8u %8u\n"
1348             "Swap: %8lu %8lu %8lu\n"
1349             "MemTotal:  %8lu kB\n"
1350             "MemFree:   %8lu kB\n"
1351             "MemShared: %8u kB\n"
1352             "Buffers:   %8u kB\n"
1353             "Cached:    %8u kB\n"
1354             "SwapCached:%8u kB\n"
1355             "Active:    %8u kB\n"
1356             "Inactive:  %8u kB\n"
1357             "HighTotal: %8u kB\n"
1358             "HighFree:  %8u kB\n"
1359             "LowTotal:  %8u kB\n"
1360             "LowFree:   %8u kB\n"
1361             "SwapTotal: %8lu kB\n"
1362             "SwapFree:  %8lu kB\n",
1363             total_mem, total_mem - free_mem, free_mem, 0, 0, 0,
1364             total_swap, used_swap, total_swap - used_swap,
1365             btok(total_mem),                            /* MemTotal */
1366             btok(free_mem),                             /* MemFree */
1367             0,                                          /* MemShared */
1368             0,                                          /* Buffers */
1369             0,                                          /* Cached */
1370             0,                                          /* SwapCached */
1371             0,                                          /* Active */
1372             0,                                          /* Inactive */
1373             0,                                          /* HighTotal */
1374             0,                                          /* HighFree */
1375             btok(total_mem),                            /* LowTotal */
1376             btok(free_mem),                             /* LowFree */
1377             btok(total_swap),                           /* SwapTotal */
1378             btok(total_swap - used_swap));              /* SwapFree */
1379 }
1380 
1381 /*
1382  * lxpr_read_mounts():
1383  */
1384 /* ARGSUSED */
1385 static void
1386 lxpr_read_mounts(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1387 {
1388         struct vfs *vfsp;
1389         struct vfs *vfslist;
1390         zone_t *zone = LXPTOZ(lxpnp);
1391         struct print_data {
1392                 refstr_t *vfs_mntpt;
1393                 refstr_t *vfs_resource;
1394                 uint_t vfs_flag;
1395                 int vfs_fstype;
1396                 struct print_data *next;
1397         } *print_head = NULL;
1398         struct print_data **print_tail = &print_head;
1399         struct print_data *printp;
1400 
1401         vfs_list_read_lock();
1402 
1403         if (zone == global_zone) {
1404                 vfsp = vfslist = rootvfs;
1405         } else {
1406                 vfsp = vfslist = zone->zone_vfslist;
1407                 /*
1408                  * If the zone has a root entry, it will be the first in
1409                  * the list.  If it doesn't, we conjure one up.
1410                  */
1411                 if (vfslist == NULL ||
1412                     strcmp(refstr_value(vfsp->vfs_mntpt),
1413                     zone->zone_rootpath) != 0) {
1414                         struct vfs *tvfsp;
1415                         /*
1416                          * The root of the zone is not a mount point.  The vfs
1417                          * we want to report is that of the zone's root vnode.
1418                          */
1419                         tvfsp = zone->zone_rootvp->v_vfsp;
1420 
1421                         lxpr_uiobuf_printf(uiobuf,
1422                             "/ / %s %s 0 0\n",
1423                             vfssw[tvfsp->vfs_fstype].vsw_name,
1424                             tvfsp->vfs_flag & VFS_RDONLY ? "ro" : "rw");
1425 
1426                 }
1427                 if (vfslist == NULL) {
1428                         vfs_list_unlock();
1429                         return;
1430                 }
1431         }
1432 
1433         /*
1434          * Later on we have to do a lookupname, which can end up causing
1435          * another vfs_list_read_lock() to be called. Which can lead to a
1436          * deadlock. To avoid this, we extract the data we need into a local
1437          * list, then we can run this list without holding vfs_list_read_lock()
1438          * We keep the list in the same order as the vfs_list
1439          */
1440         do {
1441                 /* Skip mounts we shouldn't show */
1442                 if (vfsp->vfs_flag & VFS_NOMNTTAB) {
1443                         goto nextfs;
1444                 }
1445 
1446                 printp = kmem_alloc(sizeof (*printp), KM_SLEEP);
1447                 refstr_hold(vfsp->vfs_mntpt);
1448                 printp->vfs_mntpt = vfsp->vfs_mntpt;
1449                 refstr_hold(vfsp->vfs_resource);
1450                 printp->vfs_resource = vfsp->vfs_resource;
1451                 printp->vfs_flag = vfsp->vfs_flag;
1452                 printp->vfs_fstype = vfsp->vfs_fstype;
1453                 printp->next = NULL;
1454 
1455                 *print_tail = printp;
1456                 print_tail = &printp->next;
1457 
1458 nextfs:
1459                 vfsp = (zone == global_zone) ?
1460                     vfsp->vfs_next : vfsp->vfs_zone_next;
1461 
1462         } while (vfsp != vfslist);
1463 
1464         vfs_list_unlock();
1465 
1466         /*
1467          * now we can run through what we've extracted without holding
1468          * vfs_list_read_lock()
1469          */
1470         printp = print_head;
1471         while (printp != NULL) {
1472                 struct print_data *printp_next;
1473                 const char *resource;
1474                 char *mntpt;
1475                 struct vnode *vp;
1476                 int error;
1477 
1478                 mntpt = (char *)refstr_value(printp->vfs_mntpt);
1479                 resource = refstr_value(printp->vfs_resource);
1480 
1481                 if (mntpt != NULL && mntpt[0] != '\0')
1482                         mntpt = ZONE_PATH_TRANSLATE(mntpt, zone);
1483                 else
1484                         mntpt = "-";
1485 
1486                 error = lookupname(mntpt, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp);
1487 
1488                 if (error != 0)
1489                         goto nextp;
1490 
1491                 if (!(vp->v_flag & VROOT)) {
1492                         VN_RELE(vp);
1493                         goto nextp;
1494                 }
1495                 VN_RELE(vp);
1496 
1497                 if (resource != NULL && resource[0] != '\0') {
1498                         if (resource[0] == '/') {
1499                                 resource = ZONE_PATH_VISIBLE(resource, zone) ?
1500                                     ZONE_PATH_TRANSLATE(resource, zone) :
1501                                     mntpt;
1502                         }
1503                 } else {
1504                         resource = "-";
1505                 }
1506 
1507                 lxpr_uiobuf_printf(uiobuf,
1508                     "%s %s %s %s 0 0\n",
1509                     resource, mntpt, vfssw[printp->vfs_fstype].vsw_name,
1510                     printp->vfs_flag & VFS_RDONLY ? "ro" : "rw");
1511 
1512 nextp:
1513                 printp_next = printp->next;
1514                 refstr_rele(printp->vfs_mntpt);
1515                 refstr_rele(printp->vfs_resource);
1516                 kmem_free(printp, sizeof (*printp));
1517                 printp = printp_next;
1518 
1519         }
1520 }
1521 
1522 /*
1523  * lxpr_read_partitions():
1524  *
1525  * We don't support partitions in a local zone because it requires access to
1526  * physical devices.  But we need to fake up enough of the file to show that we
1527  * have no partitions.
1528  */
1529 /* ARGSUSED */
1530 static void
1531 lxpr_read_partitions(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1532 {
1533         lxpr_uiobuf_printf(uiobuf,
1534             "major minor  #blocks  name     rio rmerge rsect ruse "
1535             "wio wmerge wsect wuse running use aveq\n\n");
1536 }
1537 
1538 /*
1539  * lxpr_read_version(): read the contents of the "version" file.
1540  */
1541 /* ARGSUSED */
1542 static void
1543 lxpr_read_version(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1544 {
1545         char *vers;
1546         if (lx_get_zone_kern_version(LXPTOZ(lxpnp)) <= LX_KERN_2_4)
1547                 vers = LX_UNAME_RELEASE_2_4;
1548         else
1549                 vers = LX_UNAME_RELEASE_2_6;
1550 
1551         lxpr_uiobuf_printf(uiobuf,
1552             "%s version %s (%s version %d.%d.%d) "
1553             "#%s SMP %s\n",
1554             LX_UNAME_SYSNAME, vers,
1555 #if defined(__GNUC__)
1556             "gcc",
1557             __GNUC__,
1558             __GNUC_MINOR__,
1559             __GNUC_PATCHLEVEL__,
1560 #else
1561             "Sun C",
1562             __SUNPRO_C / 0x100,
1563             (__SUNPRO_C & 0xff) / 0x10,
1564             __SUNPRO_C & 0xf,
1565 #endif
1566             LX_UNAME_VERSION,
1567             "00:00:00 00/00/00");
1568 }
1569 
1570 
1571 /*
1572  * lxpr_read_stat(): read the contents of the "stat" file.
1573  *
1574  */
1575 /* ARGSUSED */
1576 
1577 static void
1578 lxpr_read_stat(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1579 {
1580         cpu_t *cp, *cpstart;
1581         int pools_enabled;
1582         ulong_t idle_cum = 0;
1583         ulong_t sys_cum  = 0;
1584         ulong_t user_cum = 0;
1585         ulong_t irq_cum = 0;
1586         uint_t cpu_nrunnable_cum = 0;
1587         uint_t w_io_cum = 0;
1588 
1589         ulong_t pgpgin_cum    = 0;
1590         ulong_t pgpgout_cum   = 0;
1591         ulong_t pgswapout_cum = 0;
1592         ulong_t pgswapin_cum  = 0;
1593         ulong_t intr_cum = 0;
1594         ulong_t pswitch_cum = 0;
1595         ulong_t forks_cum = 0;
1596         hrtime_t msnsecs[NCMSTATES];
1597         int lx_kern_version = lx_get_zone_kern_version(LXPTOZ(lxpnp));
1598         /* temporary variable since scalehrtime modifies data in place */
1599         hrtime_t tmptime;
1600 
1601         ASSERT(lxpnp->lxpr_type == LXPR_STAT);
1602 
1603         mutex_enter(&cpu_lock);
1604         pools_enabled = pool_pset_enabled();
1605 
1606         /* Calculate cumulative stats */
1607         cp = cpstart = CPU;
1608         do {
1609                 int i;
1610 
1611                 /*
1612                  * Don't count CPUs that aren't even in the system
1613                  * or aren't up yet.
1614                  */
1615                 if ((cp->cpu_flags & CPU_EXISTS) == 0) {
1616                         continue;
1617                 }
1618 
1619                 get_cpu_mstate(cp, msnsecs);
1620 
1621                 idle_cum += NSEC_TO_TICK(msnsecs[CMS_IDLE]);
1622                 sys_cum  += NSEC_TO_TICK(msnsecs[CMS_SYSTEM]);
1623                 user_cum += NSEC_TO_TICK(msnsecs[CMS_USER]);
1624 
1625                 pgpgin_cum += CPU_STATS(cp, vm.pgpgin);
1626                 pgpgout_cum += CPU_STATS(cp, vm.pgpgout);
1627                 pgswapin_cum += CPU_STATS(cp, vm.pgswapin);
1628                 pgswapout_cum += CPU_STATS(cp, vm.pgswapout);
1629 
1630                 if (lx_kern_version >= LX_KERN_2_6) {
1631                         cpu_nrunnable_cum += cp->cpu_disp->disp_nrunnable;
1632                         w_io_cum += CPU_STATS(cp, sys.iowait);
1633                         for (i = 0; i < NCMSTATES; i++) {
1634                                 tmptime = cp->cpu_intracct[i];
1635                                 scalehrtime(&tmptime);
1636                                 irq_cum += NSEC_TO_TICK(tmptime);
1637                         }
1638                 }
1639 
1640                 for (i = 0; i < PIL_MAX; i++)
1641                         intr_cum += CPU_STATS(cp, sys.intr[i]);
1642 
1643                 pswitch_cum += CPU_STATS(cp, sys.pswitch);
1644                 forks_cum += CPU_STATS(cp, sys.sysfork);
1645                 forks_cum += CPU_STATS(cp, sys.sysvfork);
1646 
1647                 if (pools_enabled)
1648                         cp = cp->cpu_next_part;
1649                 else
1650                         cp = cp->cpu_next;
1651         } while (cp != cpstart);
1652 
1653         if (lx_kern_version >= LX_KERN_2_6) {
1654                 lxpr_uiobuf_printf(uiobuf,
1655                     "cpu %ld %ld %ld %ld %ld %ld %ld\n",
1656                     user_cum, 0, sys_cum, idle_cum, 0, irq_cum, 0);
1657         } else {
1658                 lxpr_uiobuf_printf(uiobuf,
1659                     "cpu %ld %ld %ld %ld\n",
1660                     user_cum, 0, sys_cum, idle_cum);
1661         }
1662 
1663         /* Do per processor stats */
1664         do {
1665                 int i;
1666 
1667                 ulong_t idle_ticks;
1668                 ulong_t sys_ticks;
1669                 ulong_t user_ticks;
1670                 ulong_t irq_ticks = 0;
1671 
1672                 /*
1673                  * Don't count CPUs that aren't even in the system
1674                  * or aren't up yet.
1675                  */
1676                 if ((cp->cpu_flags & CPU_EXISTS) == 0) {
1677                         continue;
1678                 }
1679 
1680                 get_cpu_mstate(cp, msnsecs);
1681 
1682                 idle_ticks = NSEC_TO_TICK(msnsecs[CMS_IDLE]);
1683                 sys_ticks  = NSEC_TO_TICK(msnsecs[CMS_SYSTEM]);
1684                 user_ticks = NSEC_TO_TICK(msnsecs[CMS_USER]);
1685 
1686                 if (lx_kern_version >= LX_KERN_2_6) {
1687                         for (i = 0; i < NCMSTATES; i++) {
1688                                 tmptime = cp->cpu_intracct[i];
1689                                 scalehrtime(&tmptime);
1690                                 irq_ticks += NSEC_TO_TICK(tmptime);
1691                         }
1692 
1693                         lxpr_uiobuf_printf(uiobuf,
1694                             "cpu%d %ld %ld %ld %ld %ld %ld %ld\n",
1695                             cp->cpu_id, user_ticks, 0, sys_ticks, idle_ticks,
1696                             0, irq_ticks, 0);
1697                 } else {
1698                         lxpr_uiobuf_printf(uiobuf,
1699                             "cpu%d %ld %ld %ld %ld\n",
1700                             cp->cpu_id,
1701                             user_ticks, 0, sys_ticks, idle_ticks);
1702                 }
1703 
1704                 if (pools_enabled)
1705                         cp = cp->cpu_next_part;
1706                 else
1707                         cp = cp->cpu_next;
1708         } while (cp != cpstart);
1709 
1710         mutex_exit(&cpu_lock);
1711 
1712         if (lx_kern_version >= LX_KERN_2_6) {
1713                 lxpr_uiobuf_printf(uiobuf,
1714                     "page %lu %lu\n"
1715                     "swap %lu %lu\n"
1716                     "intr %lu\n"
1717                     "ctxt %lu\n"
1718                     "btime %lu\n"
1719                     "processes %lu\n"
1720                     "procs_running %lu\n"
1721                     "procs_blocked %lu\n",
1722                     pgpgin_cum, pgpgout_cum,
1723                     pgswapin_cum, pgswapout_cum,
1724                     intr_cum,
1725                     pswitch_cum,
1726                     boot_time,
1727                     forks_cum,
1728                     cpu_nrunnable_cum,
1729                     w_io_cum);
1730         } else {
1731                 lxpr_uiobuf_printf(uiobuf,
1732                     "page %lu %lu\n"
1733                     "swap %lu %lu\n"
1734                     "intr %lu\n"
1735                     "ctxt %lu\n"
1736                     "btime %lu\n"
1737                     "processes %lu\n",
1738                     pgpgin_cum, pgpgout_cum,
1739                     pgswapin_cum, pgswapout_cum,
1740                     intr_cum,
1741                     pswitch_cum,
1742                     boot_time,
1743                     forks_cum);
1744         }
1745 }
1746 
1747 
1748 /*
1749  * lxpr_read_uptime(): read the contents of the "uptime" file.
1750  *
1751  * format is: "%.2lf, %.2lf",uptime_secs, idle_secs
1752  * Use fixed point arithmetic to get 2 decimal places
1753  */
1754 /* ARGSUSED */
1755 static void
1756 lxpr_read_uptime(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1757 {
1758         cpu_t *cp, *cpstart;
1759         int pools_enabled;
1760         ulong_t idle_cum = 0;
1761         ulong_t cpu_count = 0;
1762         ulong_t idle_s;
1763         ulong_t idle_cs;
1764         ulong_t up_s;
1765         ulong_t up_cs;
1766         hrtime_t birthtime;
1767         hrtime_t centi_sec = 10000000;  /* 10^7 */
1768 
1769         ASSERT(lxpnp->lxpr_type == LXPR_UPTIME);
1770 
1771         /* Calculate cumulative stats */
1772         mutex_enter(&cpu_lock);
1773         pools_enabled = pool_pset_enabled();
1774 
1775         cp = cpstart = CPU;
1776         do {
1777                 /*
1778                  * Don't count CPUs that aren't even in the system
1779                  * or aren't up yet.
1780                  */
1781                 if ((cp->cpu_flags & CPU_EXISTS) == 0) {
1782                         continue;
1783                 }
1784 
1785                 idle_cum += CPU_STATS(cp, sys.cpu_ticks_idle);
1786                 idle_cum += CPU_STATS(cp, sys.cpu_ticks_wait);
1787                 cpu_count += 1;
1788 
1789                 if (pools_enabled)
1790                         cp = cp->cpu_next_part;
1791                 else
1792                         cp = cp->cpu_next;
1793         } while (cp != cpstart);
1794         mutex_exit(&cpu_lock);
1795 
1796         /* Getting the Zone zsched process startup time */
1797         birthtime = LXPTOZ(lxpnp)->zone_zsched->p_mstart;
1798         up_cs = (gethrtime() - birthtime) / centi_sec;
1799         up_s = up_cs / 100;
1800         up_cs %= 100;
1801 
1802         ASSERT(cpu_count > 0);
1803         idle_cum /= cpu_count;
1804         idle_s = idle_cum / hz;
1805         idle_cs = idle_cum % hz;
1806         idle_cs *= 100;
1807         idle_cs /= hz;
1808 
1809         lxpr_uiobuf_printf(uiobuf,
1810             "%ld.%02d %ld.%02d\n", up_s, up_cs, idle_s, idle_cs);
1811 }
1812 
1813 static const char *amd_x_edx[] = {
1814         NULL,   NULL,   NULL,   NULL,
1815         NULL,   NULL,   NULL,   NULL,
1816         NULL,   NULL,   NULL,   "syscall",
1817         NULL,   NULL,   NULL,   NULL,
1818         NULL,   NULL,   NULL,   "mp",
1819         "nx",   NULL,   "mmxext", NULL,
1820         NULL,   NULL,   NULL,   NULL,
1821         NULL,   "lm",   "3dnowext", "3dnow"
1822 };
1823 
1824 static const char *amd_x_ecx[] = {
1825         "lahf_lm", NULL, "svm", NULL,
1826         "altmovcr8"
1827 };
1828 
1829 static const char *tm_x_edx[] = {
1830         "recovery", "longrun", NULL, "lrti"
1831 };
1832 
1833 /*
1834  * Intel calls no-execute "xd" in its docs, but Linux still reports it as "nx."
1835  */
1836 static const char *intc_x_edx[] = {
1837         NULL,   NULL,   NULL,   NULL,
1838         NULL,   NULL,   NULL,   NULL,
1839         NULL,   NULL,   NULL,   "syscall",
1840         NULL,   NULL,   NULL,   NULL,
1841         NULL,   NULL,   NULL,   NULL,
1842         "nx",   NULL,   NULL,   NULL,
1843         NULL,   NULL,   NULL,   NULL,
1844         NULL,   "lm",   NULL,   NULL
1845 };
1846 
1847 static const char *intc_edx[] = {
1848         "fpu",  "vme",  "de",   "pse",
1849         "tsc",  "msr",  "pae",  "mce",
1850         "cx8",  "apic",  NULL,  "sep",
1851         "mtrr", "pge",  "mca",  "cmov",
1852         "pat",  "pse36", "pn",  "clflush",
1853         NULL,   "dts",  "acpi", "mmx",
1854         "fxsr", "sse",  "sse2", "ss",
1855         "ht",   "tm",   "ia64", "pbe"
1856 };
1857 
1858 /*
1859  * "sse3" on linux is called "pni" (Prescott New Instructions).
1860  */
1861 static const char *intc_ecx[] = {
1862         "pni",  NULL,   NULL, "monitor",
1863         "ds_cpl", NULL, NULL, "est",
1864         "tm2",  NULL,   "cid", NULL,
1865         NULL,   "cx16", "xtpr"
1866 };
1867 
1868 static void
1869 lxpr_read_cpuinfo(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
1870 {
1871         int i;
1872         uint32_t bits;
1873         cpu_t *cp, *cpstart;
1874         int pools_enabled;
1875         const char **fp;
1876         char brandstr[CPU_IDSTRLEN];
1877         struct cpuid_regs cpr;
1878         int maxeax;
1879         int std_ecx, std_edx, ext_ecx, ext_edx;
1880 
1881         ASSERT(lxpnp->lxpr_type == LXPR_CPUINFO);
1882 
1883         mutex_enter(&cpu_lock);
1884         pools_enabled = pool_pset_enabled();
1885 
1886         cp = cpstart = CPU;
1887         do {
1888                 /*
1889                  * This returns the maximum eax value for standard cpuid
1890                  * functions in eax.
1891                  */
1892                 cpr.cp_eax = 0;
1893                 (void) cpuid_insn(cp, &cpr);
1894                 maxeax = cpr.cp_eax;
1895 
1896                 /*
1897                  * Get standard x86 feature flags.
1898                  */
1899                 cpr.cp_eax = 1;
1900                 (void) cpuid_insn(cp, &cpr);
1901                 std_ecx = cpr.cp_ecx;
1902                 std_edx = cpr.cp_edx;
1903 
1904                 /*
1905                  * Now get extended feature flags.
1906                  */
1907                 cpr.cp_eax = 0x80000001;
1908                 (void) cpuid_insn(cp, &cpr);
1909                 ext_ecx = cpr.cp_ecx;
1910                 ext_edx = cpr.cp_edx;
1911 
1912                 (void) cpuid_getbrandstr(cp, brandstr, CPU_IDSTRLEN);
1913 
1914                 lxpr_uiobuf_printf(uiobuf,
1915                     "processor\t: %d\n"
1916                     "vendor_id\t: %s\n"
1917                     "cpu family\t: %d\n"
1918                     "model\t\t: %d\n"
1919                     "model name\t: %s\n"
1920                     "stepping\t: %d\n"
1921                     "cpu MHz\t\t: %u.%03u\n",
1922                     cp->cpu_id, cpuid_getvendorstr(cp), cpuid_getfamily(cp),
1923                     cpuid_getmodel(cp), brandstr, cpuid_getstep(cp),
1924                     (uint32_t)(cpu_freq_hz / 1000000),
1925                     ((uint32_t)(cpu_freq_hz / 1000)) % 1000);
1926 
1927                 lxpr_uiobuf_printf(uiobuf, "cache size\t: %u KB\n",
1928                     getl2cacheinfo(cp, NULL, NULL, NULL) / 1024);
1929 
1930                 if (x86_feature & X86_HTT) {
1931                         /*
1932                          * 'siblings' is used for HT-style threads
1933                          */
1934                         lxpr_uiobuf_printf(uiobuf,
1935                             "physical id\t: %lu\n"
1936                             "siblings\t: %u\n",
1937                             pg_plat_hw_instance_id(cp, PGHW_CHIP),
1938                             cpuid_get_ncpu_per_chip(cp));
1939                 }
1940 
1941                 /*
1942                  * Since we're relatively picky about running on older hardware,
1943                  * we can be somewhat cavalier about the answers to these ones.
1944                  *
1945                  * In fact, given the hardware we support, we just say:
1946                  *
1947                  *      fdiv_bug        : no    (if we're on a 64-bit kernel)
1948                  *      hlt_bug         : no
1949                  *      f00f_bug        : no
1950                  *      coma_bug        : no
1951                  *      wp              : yes   (write protect in supervsr mode)
1952                  */
1953                 lxpr_uiobuf_printf(uiobuf,
1954                     "fdiv_bug\t: %s\n"
1955                     "hlt_bug \t: no\n"
1956                     "f00f_bug\t: no\n"
1957                     "coma_bug\t: no\n"
1958                     "fpu\t\t: %s\n"
1959                     "fpu_exception\t: %s\n"
1960                     "cpuid level\t: %d\n"
1961                     "flags\t\t:",
1962 #if defined(__i386)
1963                     fpu_pentium_fdivbug ? "yes" : "no",
1964 #else
1965                     "no",
1966 #endif /* __i386 */
1967                     fpu_exists ? "yes" : "no", fpu_exists ? "yes" : "no",
1968                     maxeax);
1969 
1970                 for (bits = std_edx, fp = intc_edx, i = 0;
1971                     i < sizeof (intc_edx) / sizeof (intc_edx[0]); fp++, i++)
1972                         if ((bits & (1 << i)) != 0 && *fp)
1973                                 lxpr_uiobuf_printf(uiobuf, " %s", *fp);
1974 
1975                 /*
1976                  * name additional features where appropriate
1977                  */
1978                 switch (x86_vendor) {
1979                 case X86_VENDOR_Intel:
1980                         for (bits = ext_edx, fp = intc_x_edx, i = 0;
1981                             i < sizeof (intc_x_edx) / sizeof (intc_x_edx[0]);
1982                             fp++, i++)
1983                                 if ((bits & (1 << i)) != 0 && *fp)
1984                                         lxpr_uiobuf_printf(uiobuf, " %s", *fp);
1985                         break;
1986 
1987                 case X86_VENDOR_AMD:
1988                         for (bits = ext_edx, fp = amd_x_edx, i = 0;
1989                             i < sizeof (amd_x_edx) / sizeof (amd_x_edx[0]);
1990                             fp++, i++)
1991                                 if ((bits & (1 << i)) != 0 && *fp)
1992                                         lxpr_uiobuf_printf(uiobuf, " %s", *fp);
1993 
1994                         for (bits = ext_ecx, fp = amd_x_ecx, i = 0;
1995                             i < sizeof (amd_x_ecx) / sizeof (amd_x_ecx[0]);
1996                             fp++, i++)
1997                                 if ((bits & (1 << i)) != 0 && *fp)
1998                                         lxpr_uiobuf_printf(uiobuf, " %s", *fp);
1999                         break;
2000 
2001                 case X86_VENDOR_TM:
2002                         for (bits = ext_edx, fp = tm_x_edx, i = 0;
2003                             i < sizeof (tm_x_edx) / sizeof (tm_x_edx[0]);
2004                             fp++, i++)
2005                                 if ((bits & (1 << i)) != 0 && *fp)
2006                                         lxpr_uiobuf_printf(uiobuf, " %s", *fp);
2007                         break;
2008                 default:
2009                         break;
2010                 }
2011 
2012                 for (bits = std_ecx, fp = intc_ecx, i = 0;
2013                     i < sizeof (intc_ecx) / sizeof (intc_ecx[0]); fp++, i++)
2014                         if ((bits & (1 << i)) != 0 && *fp)
2015                                 lxpr_uiobuf_printf(uiobuf, " %s", *fp);
2016 
2017                 lxpr_uiobuf_printf(uiobuf, "\n\n");
2018 
2019                 if (pools_enabled)
2020                         cp = cp->cpu_next_part;
2021                 else
2022                         cp = cp->cpu_next;
2023         } while (cp != cpstart);
2024 
2025         mutex_exit(&cpu_lock);
2026 }
2027 
2028 /* ARGSUSED */
2029 static void
2030 lxpr_read_fd(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
2031 {
2032         ASSERT(lxpnp->lxpr_type == LXPR_PID_FD_FD);
2033         lxpr_uiobuf_seterr(uiobuf, EFAULT);
2034 }
2035 
2036 
2037 
2038 /*
2039  * lxpr_getattr(): Vnode operation for VOP_GETATTR()
2040  */
2041 static int
2042 lxpr_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
2043     caller_context_t *ct)
2044 {
2045         register lxpr_node_t *lxpnp = VTOLXP(vp);
2046         lxpr_nodetype_t type = lxpnp->lxpr_type;
2047         extern uint_t nproc;
2048         int error;
2049 
2050         /*
2051          * Return attributes of underlying vnode if ATTR_REAL
2052          *
2053          * but keep fd files with the symlink permissions
2054          */
2055         if (lxpnp->lxpr_realvp != NULL && (flags & ATTR_REAL)) {
2056                 vnode_t *rvp = lxpnp->lxpr_realvp;
2057 
2058                 /*
2059                  * withold attribute information to owner or root
2060                  */
2061                 if ((error = VOP_ACCESS(rvp, 0, 0, cr, ct)) != 0) {
2062                         return (error);
2063                 }
2064 
2065                 /*
2066                  * now its attributes
2067                  */
2068                 if ((error = VOP_GETATTR(rvp, vap, flags, cr, ct)) != 0) {
2069                         return (error);
2070                 }
2071 
2072                 /*
2073                  * if it's a file in lx /proc/pid/fd/xx then set its
2074                  * mode and keep it looking like a symlink
2075                  */
2076                 if (type == LXPR_PID_FD_FD) {
2077                         vap->va_mode = lxpnp->lxpr_mode;
2078                         vap->va_type = vp->v_type;
2079                         vap->va_size = 0;
2080                         vap->va_nlink = 1;
2081                 }
2082                 return (0);
2083         }
2084 
2085         /* Default attributes, that may be overridden below */
2086         bzero(vap, sizeof (*vap));
2087         vap->va_atime = vap->va_mtime = vap->va_ctime = lxpnp->lxpr_time;
2088         vap->va_nlink = 1;
2089         vap->va_type = vp->v_type;
2090         vap->va_mode = lxpnp->lxpr_mode;
2091         vap->va_fsid = vp->v_vfsp->vfs_dev;
2092         vap->va_blksize = DEV_BSIZE;
2093         vap->va_uid = lxpnp->lxpr_uid;
2094         vap->va_gid = lxpnp->lxpr_gid;
2095         vap->va_nodeid = lxpnp->lxpr_ino;
2096 
2097         switch (type) {
2098         case LXPR_PROCDIR:
2099                 vap->va_nlink = nproc + 2 + PROCDIRFILES;
2100                 vap->va_size = (nproc + 2 + PROCDIRFILES) * LXPR_SDSIZE;
2101                 break;
2102         case LXPR_PIDDIR:
2103                 vap->va_nlink = PIDDIRFILES;
2104                 vap->va_size = PIDDIRFILES * LXPR_SDSIZE;
2105                 break;
2106         case LXPR_SELF:
2107                 vap->va_uid = crgetruid(curproc->p_cred);
2108                 vap->va_gid = crgetrgid(curproc->p_cred);
2109                 break;
2110         default:
2111                 break;
2112         }
2113 
2114         vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
2115         return (0);
2116 }
2117 
2118 
2119 /*
2120  * lxpr_access(): Vnode operation for VOP_ACCESS()
2121  */
2122 static int
2123 lxpr_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
2124 {
2125         lxpr_node_t *lxpnp = VTOLXP(vp);
2126         int shift = 0;
2127         proc_t *tp;
2128 
2129         /* lx /proc is a read only file system */
2130         if (mode & VWRITE)
2131                 return (EROFS);
2132 
2133         /*
2134          * If this is a restricted file, check access permissions.
2135          */
2136         switch (lxpnp->lxpr_type) {
2137         case LXPR_PIDDIR:
2138                 return (0);
2139         case LXPR_PID_CURDIR:
2140         case LXPR_PID_ENV:
2141         case LXPR_PID_EXE:
2142         case LXPR_PID_MAPS:
2143         case LXPR_PID_MEM:
2144         case LXPR_PID_ROOTDIR:
2145         case LXPR_PID_FDDIR:
2146         case LXPR_PID_FD_FD:
2147                 if ((tp = lxpr_lock(lxpnp->lxpr_pid)) == NULL)
2148                         return (ENOENT);
2149                 if (tp != curproc && secpolicy_proc_access(cr) != 0 &&
2150                     priv_proc_cred_perm(cr, tp, NULL, mode) != 0) {
2151                         lxpr_unlock(tp);
2152                         return (EACCES);
2153                 }
2154                 lxpr_unlock(tp);
2155         default:
2156                 break;
2157         }
2158 
2159         if (lxpnp->lxpr_realvp != NULL) {
2160                 /*
2161                  * For these we use the underlying vnode's accessibility.
2162                  */
2163                 return (VOP_ACCESS(lxpnp->lxpr_realvp, mode, flags, cr, ct));
2164         }
2165 
2166         /* If user is root allow access regardless of permission bits */
2167         if (secpolicy_proc_access(cr) == 0)
2168                 return (0);
2169 
2170         /*
2171          * Access check is based on only
2172          * one of owner, group, public.
2173          * If not owner, then check group.
2174          * If not a member of the group, then
2175          * check public access.
2176          */
2177         if (crgetuid(cr) != lxpnp->lxpr_uid) {
2178                 shift += 3;
2179                 if (!groupmember((uid_t)lxpnp->lxpr_gid, cr))
2180                         shift += 3;
2181         }
2182 
2183         mode &= ~(lxpnp->lxpr_mode << shift);
2184 
2185         if (mode == 0)
2186                 return (0);
2187 
2188         return (EACCES);
2189 }
2190 
2191 
2192 
2193 
2194 /* ARGSUSED */
2195 static vnode_t *
2196 lxpr_lookup_not_a_dir(vnode_t *dp, char *comp)
2197 {
2198         return (NULL);
2199 }
2200 
2201 
2202 /*
2203  * lxpr_lookup(): Vnode operation for VOP_LOOKUP()
2204  */
2205 /* ARGSUSED */
2206 static int
2207 lxpr_lookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
2208         int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
2209         int *direntflags, pathname_t *realpnp)
2210 {
2211         lxpr_node_t *lxpnp = VTOLXP(dp);
2212         lxpr_nodetype_t type = lxpnp->lxpr_type;
2213         int error;
2214 
2215         ASSERT(dp->v_type == VDIR);
2216         ASSERT(type >= 0 && type < LXPR_NFILES);
2217 
2218         /*
2219          * we should never get here because the lookup
2220          * is done on the realvp for these nodes
2221          */
2222         ASSERT(type != LXPR_PID_FD_FD &&
2223             type != LXPR_PID_CURDIR &&
2224             type != LXPR_PID_ROOTDIR);
2225 
2226         /*
2227          * restrict lookup permission to owner or root
2228          */
2229         if ((error = lxpr_access(dp, VEXEC, 0, cr, ct)) != 0) {
2230                 return (error);
2231         }
2232 
2233         /*
2234          * Just return the parent vnode
2235          * if thats where we are trying to go
2236          */
2237         if (strcmp(comp, "..") == 0) {
2238                 VN_HOLD(lxpnp->lxpr_parent);
2239                 *vpp = lxpnp->lxpr_parent;
2240                 return (0);
2241         }
2242 
2243         /*
2244          * Special handling for directory searches
2245          * Note: null component name is synonym for
2246          * current directory being searched.
2247          */
2248         if ((dp->v_type == VDIR) && (*comp == '\0' || strcmp(comp, ".") == 0)) {
2249                 VN_HOLD(dp);
2250                 *vpp = dp;
2251                 return (0);
2252         }
2253 
2254         *vpp = (lxpr_lookup_function[type](dp, comp));
2255         return ((*vpp == NULL) ? ENOENT : 0);
2256 }
2257 
2258 /*
2259  * Do a sequential search on the given directory table
2260  */
2261 static vnode_t *
2262 lxpr_lookup_common(vnode_t *dp, char *comp, proc_t *p,
2263     lxpr_dirent_t *dirtab, int dirtablen)
2264 {
2265         lxpr_node_t *lxpnp;
2266         int count;
2267 
2268         for (count = 0; count < dirtablen; count++) {
2269                 if (strcmp(dirtab[count].d_name, comp) == 0) {
2270                         lxpnp = lxpr_getnode(dp, dirtab[count].d_type, p, 0);
2271                         dp = LXPTOV(lxpnp);
2272                         ASSERT(dp != NULL);
2273                         return (dp);
2274                 }
2275         }
2276         return (NULL);
2277 }
2278 
2279 
2280 static vnode_t *
2281 lxpr_lookup_piddir(vnode_t *dp, char *comp)
2282 {
2283         proc_t *p;
2284 
2285         ASSERT(VTOLXP(dp)->lxpr_type == LXPR_PIDDIR);
2286 
2287         p = lxpr_lock(VTOLXP(dp)->lxpr_pid);
2288         if (p == NULL)
2289                 return (NULL);
2290 
2291         dp = lxpr_lookup_common(dp, comp, p, piddir, PIDDIRFILES);
2292 
2293         lxpr_unlock(p);
2294 
2295         return (dp);
2296 }
2297 
2298 
2299 /*
2300  * Lookup one of the process's open files.
2301  */
2302 static vnode_t *
2303 lxpr_lookup_fddir(vnode_t *dp, char *comp)
2304 {
2305         lxpr_node_t *dlxpnp = VTOLXP(dp);
2306         lxpr_node_t *lxpnp;
2307         vnode_t *vp = NULL;
2308         proc_t *p;
2309         file_t *fp;
2310         uint_t fd;
2311         int c;
2312         uf_entry_t *ufp;
2313         uf_info_t *fip;
2314 
2315         ASSERT(dlxpnp->lxpr_type == LXPR_PID_FDDIR);
2316 
2317         /*
2318          * convert the string rendition of the filename
2319          * to a file descriptor
2320          */
2321         fd = 0;
2322         while ((c = *comp++) != '\0') {
2323                 int ofd;
2324                 if (c < '0' || c > '9')
2325                         return (NULL);
2326 
2327                 ofd = fd;
2328                 fd = 10*fd + c - '0';
2329                 /* integer overflow */
2330                 if (fd / 10 != ofd)
2331                         return (NULL);
2332         }
2333 
2334         /*
2335          * get the proc to work with and lock it
2336          */
2337         p = lxpr_lock(dlxpnp->lxpr_pid);
2338         if ((p == NULL))
2339                 return (NULL);
2340 
2341         /*
2342          * If the process is a zombie or system process
2343          * it can't have any open files.
2344          */
2345         if ((p->p_stat == SZOMB) || (p->p_flag & SSYS) || (p->p_as == &kas)) {
2346                 lxpr_unlock(p);
2347                 return (NULL);
2348         }
2349 
2350         /*
2351          * get us a fresh node/vnode
2352          */
2353         lxpnp = lxpr_getnode(dp, LXPR_PID_FD_FD, p, fd);
2354 
2355         /*
2356          * get open file info
2357          */
2358         fip = (&(p)->p_user.u_finfo);
2359         mutex_enter(&fip->fi_lock);
2360 
2361         /*
2362          * got the fd data so now done with this proc
2363          */
2364         lxpr_unlock(p);
2365 
2366         if (fd < fip->fi_nfiles) {
2367                 UF_ENTER(ufp, fip, fd);
2368                 /*
2369                  * ensure the fd is still kosher.
2370                  * it may have gone between the readdir and
2371                  * the lookup
2372                  */
2373                 if (fip->fi_list[fd].uf_file == NULL) {
2374                         mutex_exit(&fip->fi_lock);
2375                         UF_EXIT(ufp);
2376                         lxpr_freenode(lxpnp);
2377                         return (NULL);
2378                 }
2379 
2380                 if ((fp = ufp->uf_file) != NULL)
2381                         vp = fp->f_vnode;
2382                 UF_EXIT(ufp);
2383         }
2384         mutex_exit(&fip->fi_lock);
2385 
2386         if (vp == NULL) {
2387                 lxpr_freenode(lxpnp);
2388                 return (NULL);
2389         } else {
2390                 /*
2391                  * Fill in the lxpr_node so future references will
2392                  * be able to find the underlying vnode.
2393                  * The vnode is held on the realvp.
2394                  */
2395                 lxpnp->lxpr_realvp = vp;
2396                 VN_HOLD(lxpnp->lxpr_realvp);
2397         }
2398 
2399         dp = LXPTOV(lxpnp);
2400         ASSERT(dp != NULL);
2401 
2402         return (dp);
2403 }
2404 
2405 
2406 static vnode_t *
2407 lxpr_lookup_netdir(vnode_t *dp, char *comp)
2408 {
2409         ASSERT(VTOLXP(dp)->lxpr_type == LXPR_NETDIR);
2410 
2411         dp = lxpr_lookup_common(dp, comp, NULL, netdir, NETDIRFILES);
2412 
2413         return (dp);
2414 }
2415 
2416 
2417 static vnode_t *
2418 lxpr_lookup_procdir(vnode_t *dp, char *comp)
2419 {
2420         ASSERT(VTOLXP(dp)->lxpr_type == LXPR_PROCDIR);
2421 
2422         /*
2423          * We know all the names of files & dirs in our
2424          * file system structure except those that are pid names.
2425          * These change as pids are created/deleted etc.
2426          * So just look for a number as the first char to see if we
2427          * are we doing pid lookups?
2428          *
2429          * Don't need to check for "self" as it is implemented as a symlink
2430          */
2431         if (*comp >= '0' && *comp <= '9') {
2432                 pid_t pid = 0;
2433                 lxpr_node_t *lxpnp = NULL;
2434                 proc_t *p;
2435                 int c;
2436 
2437                 while ((c = *comp++) != '\0')
2438                         pid = 10*pid + c - '0';
2439 
2440                 /*
2441                  * Can't continue if the process is still loading
2442                  * or it doesn't really exist yet (or maybe it just died!)
2443                  */
2444                 p = lxpr_lock(pid);
2445                 if (p == NULL)
2446                         return (NULL);
2447 
2448                 if (secpolicy_basic_procinfo(CRED(), p, curproc) != 0) {
2449                         lxpr_unlock(p);
2450                         return (NULL);
2451                 }
2452 
2453                 /*
2454                  * allocate and fill in a new lx /proc node
2455                  */
2456                 lxpnp = lxpr_getnode(dp, LXPR_PIDDIR, p, 0);
2457 
2458                 lxpr_unlock(p);
2459 
2460                 dp = LXPTOV(lxpnp);
2461                 ASSERT(dp != NULL);
2462 
2463                 return (dp);
2464 
2465         }
2466 
2467         /* Lookup fixed names */
2468         return (lxpr_lookup_common(dp, comp, NULL, lx_procdir, PROCDIRFILES));
2469 }
2470 
2471 
2472 
2473 
2474 /*
2475  * lxpr_readdir(): Vnode operation for VOP_READDIR()
2476  */
2477 /* ARGSUSED */
2478 static int
2479 lxpr_readdir(vnode_t *dp, uio_t *uiop, cred_t *cr, int *eofp,
2480         caller_context_t *ct, int flags)
2481 {
2482         lxpr_node_t *lxpnp = VTOLXP(dp);
2483         lxpr_nodetype_t type = lxpnp->lxpr_type;
2484         ssize_t uresid;
2485         off_t uoffset;
2486         int error;
2487 
2488         ASSERT(dp->v_type == VDIR);
2489         ASSERT(type >= 0 && type < LXPR_NFILES);
2490 
2491         /*
2492          * we should never get here because the readdir
2493          * is done on the realvp for these nodes
2494          */
2495         ASSERT(type != LXPR_PID_FD_FD &&
2496             type != LXPR_PID_CURDIR &&
2497             type != LXPR_PID_ROOTDIR);
2498 
2499         /*
2500          * restrict readdir permission to owner or root
2501          */
2502         if ((error = lxpr_access(dp, VREAD, 0, cr, ct)) != 0)
2503                 return (error);
2504 
2505         uoffset = uiop->uio_offset;
2506         uresid = uiop->uio_resid;
2507 
2508         /* can't do negative reads */
2509         if (uoffset < 0 || uresid <= 0)
2510                 return (EINVAL);
2511 
2512         /* can't read directory entries that don't exist! */
2513         if (uoffset % LXPR_SDSIZE)
2514                 return (ENOENT);
2515 
2516         return (lxpr_readdir_function[lxpnp->lxpr_type](lxpnp, uiop, eofp));
2517 }
2518 
2519 
2520 /* ARGSUSED */
2521 static int
2522 lxpr_readdir_not_a_dir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
2523 {
2524         return (ENOTDIR);
2525 }
2526 
2527 /*
2528  * This has the common logic for returning directory entries
2529  */
2530 static int
2531 lxpr_readdir_common(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp,
2532     lxpr_dirent_t *dirtab, int dirtablen)
2533 {
2534         /* bp holds one dirent64 structure */
2535         longlong_t bp[DIRENT64_RECLEN(LXPNSIZ) / sizeof (longlong_t)];
2536         dirent64_t *dirent = (dirent64_t *)bp;
2537         ssize_t oresid; /* save a copy for testing later */
2538         ssize_t uresid;
2539 
2540         oresid = uiop->uio_resid;
2541 
2542         /* clear out the dirent buffer */
2543         bzero(bp, sizeof (bp));
2544 
2545         /*
2546          * Satisfy user request
2547          */
2548         while ((uresid = uiop->uio_resid) > 0) {
2549                 int dirindex;
2550                 off_t uoffset;
2551                 int reclen;
2552                 int error;
2553 
2554                 uoffset = uiop->uio_offset;
2555                 dirindex  = (uoffset / LXPR_SDSIZE) - 2;
2556 
2557                 if (uoffset == 0) {
2558 
2559                         dirent->d_ino = lxpnp->lxpr_ino;
2560                         dirent->d_name[0] = '.';
2561                         dirent->d_name[1] = '\0';
2562                         reclen = DIRENT64_RECLEN(1);
2563 
2564                 } else if (uoffset == LXPR_SDSIZE) {
2565 
2566                         dirent->d_ino = lxpr_parentinode(lxpnp);
2567                         dirent->d_name[0] = '.';
2568                         dirent->d_name[1] = '.';
2569                         dirent->d_name[2] = '\0';
2570                         reclen = DIRENT64_RECLEN(2);
2571 
2572                 } else if (dirindex < dirtablen) {
2573                         int slen = strlen(dirtab[dirindex].d_name);
2574 
2575                         dirent->d_ino = lxpr_inode(dirtab[dirindex].d_type,
2576                             lxpnp->lxpr_pid, 0);
2577 
2578                         ASSERT(slen < LXPNSIZ);
2579                         (void) strcpy(dirent->d_name, dirtab[dirindex].d_name);
2580                         reclen = DIRENT64_RECLEN(slen);
2581 
2582                 } else {
2583                         /* Run out of table entries */
2584                         if (eofp) {
2585                                 *eofp = 1;
2586                         }
2587                         return (0);
2588                 }
2589 
2590                 dirent->d_off = (off64_t)(uoffset + LXPR_SDSIZE);
2591                 dirent->d_reclen = (ushort_t)reclen;
2592 
2593                 /*
2594                  * if the size of the data to transfer is greater
2595                  * that that requested then we can't do it this transfer.
2596                  */
2597                 if (reclen > uresid) {
2598                         /*
2599                          * Error if no entries have been returned yet.
2600                          */
2601                         if (uresid == oresid) {
2602                                 return (EINVAL);
2603                         }
2604                         break;
2605                 }
2606 
2607                 /*
2608                  * uiomove() updates both uiop->uio_resid and
2609                  * uiop->uio_offset by the same amount.  But we want
2610                  * uiop->uio_offset to change in increments
2611                  * of LXPR_SDSIZE, which is different from the number of bytes
2612                  * being returned to the user.
2613                  * So we set uiop->uio_offset separately, ignoring what
2614                  * uiomove() does.
2615                  */
2616                 if (error = uiomove((caddr_t)dirent, reclen, UIO_READ, uiop)) {
2617                         return (error);
2618                 }
2619 
2620                 uiop->uio_offset = uoffset + LXPR_SDSIZE;
2621         }
2622 
2623         /* Have run out of space, but could have just done last table entry */
2624         if (eofp) {
2625                 *eofp =
2626                     (uiop->uio_offset >= ((dirtablen+2) * LXPR_SDSIZE)) ? 1 : 0;
2627         }
2628         return (0);
2629 }
2630 
2631 
2632 static int
2633 lxpr_readdir_procdir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
2634 {
2635         /* bp holds one dirent64 structure */
2636         longlong_t bp[DIRENT64_RECLEN(LXPNSIZ) / sizeof (longlong_t)];
2637         dirent64_t *dirent = (dirent64_t *)bp;
2638         ssize_t oresid; /* save a copy for testing later */
2639         ssize_t uresid;
2640         off_t uoffset;
2641         zoneid_t zoneid;
2642         pid_t pid;
2643         int error;
2644         int ceof;
2645 
2646         ASSERT(lxpnp->lxpr_type == LXPR_PROCDIR);
2647 
2648         oresid = uiop->uio_resid;
2649         zoneid = LXPTOZ(lxpnp)->zone_id;
2650 
2651         /*
2652          * We return directory entries in the order:
2653          * "." and ".." then the unique lx procfs files, then the
2654          * directories corresponding to the running processes.
2655          *
2656          * This is a good order because it allows us to more easily
2657          * keep track of where we are betwen calls to getdents().
2658          * If the number of processes changes between calls then we
2659          * can't lose track of where we are in the lx procfs files.
2660          */
2661 
2662         /* Do the fixed entries */
2663         error = lxpr_readdir_common(lxpnp, uiop, &ceof, lx_procdir,
2664             PROCDIRFILES);
2665 
2666         /* Finished if we got an error or if we couldn't do all the table */
2667         if (error != 0 || ceof == 0)
2668                 return (error);
2669 
2670         /* clear out the dirent buffer */
2671         bzero(bp, sizeof (bp));
2672 
2673         /* Do the process entries */
2674         while ((uresid = uiop->uio_resid) > 0) {
2675                 proc_t *p;
2676                 int len;
2677                 int reclen;
2678                 int i;
2679 
2680                 uoffset = uiop->uio_offset;
2681 
2682                 /*
2683                  * Stop when entire proc table has been examined.
2684                  */
2685                 i = (uoffset / LXPR_SDSIZE) - 2 - PROCDIRFILES;
2686                 if (i >= v.v_proc) {
2687                         /* Run out of table entries */
2688                         if (eofp) {
2689                                 *eofp = 1;
2690                         }
2691                         return (0);
2692                 }
2693                 mutex_enter(&pidlock);
2694 
2695                 /*
2696                  * Skip indices for which there is no pid_entry, PIDs for
2697                  * which there is no corresponding process, a PID of 0,
2698                  * and anything the security policy doesn't allow
2699                  * us to look at.
2700                  */
2701                 if ((p = pid_entry(i)) == NULL || p->p_stat == SIDL ||
2702                     p->p_pid == 0 ||
2703                     secpolicy_basic_procinfo(CRED(), p, curproc) != 0) {
2704                         mutex_exit(&pidlock);
2705                         goto next;
2706                 }
2707                 mutex_exit(&pidlock);
2708 
2709                 /*
2710                  * Convert pid to the Linux default of 1 if we're the zone's
2711                  * init process, otherwise use the value from the proc
2712                  * structure
2713                  */
2714                 pid = ((p->p_pid != curproc->p_zone->zone_proc_initpid) ?
2715                     p->p_pid : 1);
2716 
2717                 /*
2718                  * If this /proc was mounted in the global zone, view
2719                  * all procs; otherwise, only view zone member procs.
2720                  */
2721                 if (zoneid != GLOBAL_ZONEID && p->p_zone->zone_id != zoneid) {
2722                         goto next;
2723                 }
2724 
2725                 ASSERT(p->p_stat != 0);
2726 
2727                 dirent->d_ino = lxpr_inode(LXPR_PIDDIR, pid, 0);
2728                 len = snprintf(dirent->d_name, LXPNSIZ, "%d", pid);
2729                 ASSERT(len < LXPNSIZ);
2730                 reclen = DIRENT64_RECLEN(len);
2731 
2732                 dirent->d_off = (off64_t)(uoffset + LXPR_SDSIZE);
2733                 dirent->d_reclen = (ushort_t)reclen;
2734 
2735                 /*
2736                  * if the size of the data to transfer is greater
2737                  * that that requested then we can't do it this transfer.
2738                  */
2739                 if (reclen > uresid) {
2740                         /*
2741                          * Error if no entries have been returned yet.
2742                          */
2743                         if (uresid == oresid)
2744                                 return (EINVAL);
2745                         break;
2746                 }
2747 
2748                 /*
2749                  * uiomove() updates both uiop->uio_resid and
2750                  * uiop->uio_offset by the same amount.  But we want
2751                  * uiop->uio_offset to change in increments
2752                  * of LXPR_SDSIZE, which is different from the number of bytes
2753                  * being returned to the user.
2754                  * So we set uiop->uio_offset separately, in the
2755                  * increment of this for loop, ignoring what uiomove() does.
2756                  */
2757                 if (error = uiomove((caddr_t)dirent, reclen, UIO_READ, uiop))
2758                         return (error);
2759 
2760 next:
2761                 uiop->uio_offset = uoffset + LXPR_SDSIZE;
2762         }
2763 
2764         if (eofp)
2765                 *eofp =
2766                     (uiop->uio_offset >=
2767                     ((v.v_proc + PROCDIRFILES + 2) * LXPR_SDSIZE)) ? 1 : 0;
2768 
2769         return (0);
2770 }
2771 
2772 
2773 static int
2774 lxpr_readdir_piddir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
2775 {
2776         proc_t *p;
2777 
2778         ASSERT(lxpnp->lxpr_type == LXPR_PIDDIR);
2779 
2780         /* can't read its contents if it died */
2781         mutex_enter(&pidlock);
2782 
2783         p = prfind((lxpnp->lxpr_pid == 1) ?
2784             curproc->p_zone->zone_proc_initpid : lxpnp->lxpr_pid);
2785 
2786         if (p == NULL || p->p_stat == SIDL) {
2787                 mutex_exit(&pidlock);
2788                 return (ENOENT);
2789         }
2790         mutex_exit(&pidlock);
2791 
2792         return (lxpr_readdir_common(lxpnp, uiop, eofp, piddir, PIDDIRFILES));
2793 }
2794 
2795 
2796 static int
2797 lxpr_readdir_netdir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
2798 {
2799         ASSERT(lxpnp->lxpr_type == LXPR_NETDIR);
2800         return (lxpr_readdir_common(lxpnp, uiop, eofp, netdir, NETDIRFILES));
2801 }
2802 
2803 
2804 static int
2805 lxpr_readdir_fddir(lxpr_node_t *lxpnp, uio_t *uiop, int *eofp)
2806 {
2807         /* bp holds one dirent64 structure */
2808         longlong_t bp[DIRENT64_RECLEN(LXPNSIZ) / sizeof (longlong_t)];
2809         dirent64_t *dirent = (dirent64_t *)bp;
2810         ssize_t oresid; /* save a copy for testing later */
2811         ssize_t uresid;
2812         off_t uoffset;
2813         int error;
2814         int ceof;
2815         proc_t *p;
2816         int fddirsize;
2817         uf_info_t *fip;
2818 
2819 
2820         ASSERT(lxpnp->lxpr_type == LXPR_PID_FDDIR);
2821 
2822         oresid = uiop->uio_resid;
2823 
2824         /* can't read its contents if it died */
2825         p = lxpr_lock(lxpnp->lxpr_pid);
2826         if (p == NULL)
2827                 return (ENOENT);
2828 
2829         /* Get open file info */
2830         fip = (&(p)->p_user.u_finfo);
2831 
2832         if ((p->p_stat == SZOMB) || (p->p_flag & SSYS) || (p->p_as == &kas))
2833                 fddirsize = 0;
2834         else
2835                 fddirsize = fip->fi_nfiles;
2836 
2837         mutex_enter(&fip->fi_lock);
2838         lxpr_unlock(p);
2839 
2840         /* Do the fixed entries (in this case just "." & "..") */
2841         error = lxpr_readdir_common(lxpnp, uiop, &ceof, 0, 0);
2842 
2843         /* Finished if we got an error or if we couldn't do all the table */
2844         if (error != 0 || ceof == 0)
2845                 return (error);
2846 
2847         /* clear out the dirent buffer */
2848         bzero(bp, sizeof (bp));
2849 
2850         /*
2851          * Loop until user's request is satisfied or until
2852          * all file descriptors have been examined.
2853          */
2854         for (; (uresid = uiop->uio_resid) > 0;
2855             uiop->uio_offset = uoffset + LXPR_SDSIZE) {
2856                 int reclen;
2857                 int fd;
2858                 int len;
2859 
2860                 uoffset = uiop->uio_offset;
2861 
2862                 /*
2863                  * Stop at the end of the fd list
2864                  */
2865                 fd = (uoffset / LXPR_SDSIZE) - 2;
2866                 if (fd >= fddirsize) {
2867                         if (eofp) {
2868                                 *eofp = 1;
2869                         }
2870                         goto out;
2871                 }
2872 
2873                 if (fip->fi_list[fd].uf_file == NULL)
2874                         continue;
2875 
2876                 dirent->d_ino = lxpr_inode(LXPR_PID_FD_FD, lxpnp->lxpr_pid, fd);
2877                 len = snprintf(dirent->d_name, LXPNSIZ, "%d", fd);
2878                 ASSERT(len < LXPNSIZ);
2879                 reclen = DIRENT64_RECLEN(len);
2880 
2881                 dirent->d_off = (off64_t)(uoffset + LXPR_SDSIZE);
2882                 dirent->d_reclen = (ushort_t)reclen;
2883 
2884                 if (reclen > uresid) {
2885                         /*
2886                          * Error if no entries have been returned yet.
2887                          */
2888                         if (uresid == oresid)
2889                                 error = EINVAL;
2890                         goto out;
2891                 }
2892 
2893                 if (error = uiomove((caddr_t)dirent, reclen, UIO_READ, uiop))
2894                         goto out;
2895         }
2896 
2897         if (eofp)
2898                 *eofp =
2899                     (uiop->uio_offset >= ((fddirsize+2) * LXPR_SDSIZE)) ? 1 : 0;
2900 
2901 out:
2902         mutex_exit(&fip->fi_lock);
2903         return (error);
2904 }
2905 
2906 
2907 /*
2908  * lxpr_readlink(): Vnode operation for VOP_READLINK()
2909  */
2910 /* ARGSUSED */
2911 static int
2912 lxpr_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
2913 {
2914         char bp[MAXPATHLEN + 1];
2915         size_t buflen = sizeof (bp);
2916         lxpr_node_t *lxpnp = VTOLXP(vp);
2917         vnode_t *rvp = lxpnp->lxpr_realvp;
2918         pid_t pid;
2919         int error = 0;
2920 
2921         /* must be a symbolic link file */
2922         if (vp->v_type != VLNK)
2923                 return (EINVAL);
2924 
2925         /* Try to produce a symlink name for anything that has a realvp */
2926         if (rvp != NULL) {
2927                 if ((error = lxpr_access(vp, VREAD, 0, CRED(), ct)) != 0)
2928                         return (error);
2929                 if ((error = vnodetopath(NULL, rvp, bp, buflen, CRED())) != 0)
2930                         return (error);
2931         } else {
2932                 switch (lxpnp->lxpr_type) {
2933                 case LXPR_SELF:
2934                         /*
2935                          * Don't need to check result as every possible int
2936                          * will fit within MAXPATHLEN bytes
2937                          */
2938 
2939                         /*
2940                          * Convert pid to the Linux default of 1 if we're the
2941                          * zone's init process
2942                          */
2943                         pid = ((curproc->p_pid !=
2944                             curproc->p_zone->zone_proc_initpid)
2945                             ? curproc->p_pid : 1);
2946 
2947                         (void) snprintf(bp, buflen, "%d", pid);
2948                         break;
2949                 case LXPR_PID_CURDIR:
2950                 case LXPR_PID_ROOTDIR:
2951                 case LXPR_PID_EXE:
2952                         return (EACCES);
2953                 default:
2954                         /*
2955                          * Need to return error so that nothing thinks
2956                          * that the symlink is empty and hence "."
2957                          */
2958                         return (EINVAL);
2959                 }
2960         }
2961 
2962         /* copy the link data to user space */
2963         return (uiomove(bp, strlen(bp), UIO_READ, uiop));
2964 }
2965 
2966 
2967 /*
2968  * lxpr_inactive(): Vnode operation for VOP_INACTIVE()
2969  * Vnode is no longer referenced, deallocate the file
2970  * and all its resources.
2971  */
2972 /* ARGSUSED */
2973 static void
2974 lxpr_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
2975 {
2976         lxpr_freenode(VTOLXP(vp));
2977 }
2978 
2979 
2980 /*
2981  * lxpr_sync(): Vnode operation for VOP_SYNC()
2982  */
2983 static int
2984 lxpr_sync()
2985 {
2986         /*
2987          * nothing to sync but this
2988          * function must never fail
2989          */
2990         return (0);
2991 }
2992 
2993 
2994 /*
2995  * lxpr_cmp(): Vnode operation for VOP_CMP()
2996  */
2997 static int
2998 lxpr_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
2999 {
3000         vnode_t *rvp;
3001 
3002         while (vn_matchops(vp1, lxpr_vnodeops) &&
3003             (rvp = VTOLXP(vp1)->lxpr_realvp) != NULL)
3004                 vp1 = rvp;
3005         while (vn_matchops(vp2, lxpr_vnodeops) &&
3006             (rvp = VTOLXP(vp2)->lxpr_realvp) != NULL)
3007                 vp2 = rvp;
3008         if (vn_matchops(vp1, lxpr_vnodeops) || vn_matchops(vp2, lxpr_vnodeops))
3009                 return (vp1 == vp2);
3010         return (VOP_CMP(vp1, vp2, ct));
3011 }
3012 
3013 
3014 /*
3015  * lxpr_realvp(): Vnode operation for VOP_REALVP()
3016  */
3017 static int
3018 lxpr_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
3019 {
3020         vnode_t *rvp;
3021 
3022         if ((rvp = VTOLXP(vp)->lxpr_realvp) != NULL) {
3023                 vp = rvp;
3024                 if (VOP_REALVP(vp, &rvp, ct) == 0)
3025                         vp = rvp;
3026         }
3027 
3028         *vpp = vp;
3029         return (0);
3030 }