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 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 /*
  28  * tnf driver - provides probe control and kernel trace buffer access
  29  * to the user programs prex and tnfxtract.
  30  */
  31 
  32 #include <sys/types.h>
  33 #include <sys/param.h>
  34 #include <sys/sysmacros.h>
  35 #include <sys/file.h>
  36 #include <sys/cmn_err.h>
  37 #include <sys/fcntl.h>
  38 #include <sys/uio.h>
  39 #include <sys/kmem.h>
  40 #include <sys/cred.h>
  41 #include <sys/mman.h>
  42 #include <sys/errno.h>
  43 #include <sys/stat.h>
  44 #include <sys/conf.h>
  45 #include <sys/ddi.h>
  46 #include <sys/sunddi.h>
  47 #include <sys/modctl.h>
  48 #include <sys/tnf.h>
  49 #include <sys/debug.h>
  50 #include <sys/devops.h>
  51 #include <vm/as.h>
  52 #include <vm/seg_kp.h>
  53 #include <sys/tnf_probe.h>
  54 #include <sys/kobj.h>
  55 
  56 #include "tnf_buf.h"
  57 #include "tnf_types.h"
  58 #include "tnf_trace.h"
  59 
  60 #ifndef NPROBE
  61 
  62 /*
  63  * Each probe is independently put in the kernel, prex uses
  64  * __tnf_probe_list_head and __tnf_tag_list_head as pointers to linked list
  65  * for probes and static tnf_tag_data_t, respectively.
  66  * tnf used the elf relocation record to build a separate linked list for
  67  * the probes and tnf_tag_data_t. We will describe how the linked list for
  68  * __tnf_tag_list_head is made, the probe list is very similar.
  69  * During the dynamic relocation(in uts/sparc/krtld/kobj_reloc.c),
  70  * the &__tnf_tag_version_1(the first member in tnf_tag_data_t data struct)
  71  * (and since it is a global variable which was never defined) will be filled
  72  * with 0. The following code in kobj_reloc.c will get the address of current
  73  * __tnf_tag_list_head and put it in value_p:
  74  *   #define TAG_MARKER_SYMBOL       "__tnf_tag_version_1"
  75  *   if (strcmp(symname, TAG_MARKER_SYMBOL) == 0) {
  76  *       *addend_p = 0;
  77  *       *value_p = (Addr) __tnf_tag_list_head; (value_p points to list head)
  78  *       __tnf_tag_list_head = (void *)*offset_p;(list head is the next record)
  79  *       return (0);
  80  *   }
  81  *
  82  * the function do_reloc(in the kobj_reloc.c) will put vlaue_p into
  83  * &__tnf_tag_version_1
  84  * Now the &__tnf_tag_version_1 points to the last list head
  85  * and __tnf_tag_list_head points to the new list head.
  86  * This is equivalent to attatch a node at the beginning of the list.
  87  *
  88  */
  89 extern tnf_probe_control_t *__tnf_probe_list_head;
  90 extern tnf_tag_data_t *__tnf_tag_list_head;
  91 extern int tnf_changed_probe_list;
  92 
  93 static int tnf_attach(dev_info_t *, ddi_attach_cmd_t);
  94 static int tnf_detach(dev_info_t *, ddi_detach_cmd_t);
  95 static int tnf_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
  96 static int tnf_open(dev_t *, int, int, struct cred *);
  97 static int tnf_close(dev_t, int, int, struct cred *);
  98 #ifdef UNUSED
  99 static int tnf_mmap(dev_t, off_t, int);
 100 #endif
 101 static int tnf_ioctl(dev_t, int, intptr_t, int, struct cred *, int *);
 102 #ifdef UNUSED
 103 static int tnf_prop_op(dev_t, dev_info_t *, ddi_prop_op_t,
 104     int, char *, caddr_t, int *);
 105 #endif
 106 static dev_info_t *tnf_devi;
 107 
 108 static struct {
 109         int             tnf_probe_count;
 110         boolean_t       tnf_pidfilter_mode;
 111         boolean_t       ctldev_is_open;
 112         int             mapdev_open_count;
 113         kmutex_t        tnf_mtx;
 114 } tnf_drv_state = { 0, B_FALSE, B_FALSE, 0 };
 115 
 116 static int tnf_getmaxprobe(caddr_t, int);
 117 static int tnf_getprobevals(caddr_t, int);
 118 static int tnf_getprobestring(caddr_t, int);
 119 static int tnf_setprobevals(caddr_t, int);
 120 static int tnf_getstate(caddr_t, int);
 121 static int tnf_allocbuf(intptr_t);
 122 static int tnf_deallocbuf(void);
 123 static int tnf_settracing(int);
 124 static int tnf_pidfilterset(int);
 125 static int tnf_pidfilterget(caddr_t, int);
 126 static int tnf_getpidstate(caddr_t, int);
 127 static int tnf_setpidstate(int, pid_t, int);
 128 static int tnf_getheader(caddr_t, int);
 129 static int tnf_getblock(caddr_t, int);
 130 static int tnf_getfwzone(caddr_t, int);
 131 
 132 static void *tnf_test_1(void *, tnf_probe_control_t *, tnf_probe_setup_t *);
 133 static void *tnf_test_2(void *, tnf_probe_control_t *, tnf_probe_setup_t *);
 134 
 135 #define TNFCTL_MINOR 0
 136 #define TNFMAP_MINOR 1
 137 
 138 struct cb_ops   tnf_cb_ops = {
 139         tnf_open,               /* open */
 140         tnf_close,              /* close */
 141         nodev,                  /* strategy */
 142         nodev,                  /* print */
 143         nodev,                  /* dump */
 144         nodev,                  /* read */
 145         nodev,                  /* write */
 146         tnf_ioctl,              /* ioctl */
 147         nodev,                  /* devmap */
 148         nodev,                  /* mmap */
 149         nodev,                  /* segmap */
 150         nochpoll,               /* poll */
 151         ddi_prop_op,            /* prop_op */
 152         0,                      /* streamtab  */
 153         D_NEW | D_MP            /* Driver compatibility flag */
 154 };
 155 
 156 struct dev_ops  tnf_ops = {
 157         DEVO_REV,               /* devo_rev, */
 158         0,                      /* refcnt  */
 159         tnf_info,               /* info */
 160         nulldev,                /* identify */
 161         nulldev,                /* probe */
 162         tnf_attach,             /* attach */
 163         tnf_detach,             /* detach */
 164         nodev,                  /* reset */
 165         &tnf_cb_ops,                /* driver operations */
 166         (struct bus_ops *)0,    /* no bus operations */
 167         NULL,                   /* power */
 168         ddi_quiesce_not_needed,         /* quiesce */
 169 };
 170 
 171 extern struct mod_ops mod_driverops;
 172 
 173 static struct modldrv modldrv = {
 174         &mod_driverops,
 175         "kernel probes driver",
 176         &tnf_ops,
 177 };
 178 
 179 static struct modlinkage modlinkage = {
 180         MODREV_1,
 181         (void *)&modldrv,
 182         NULL
 183 };
 184 
 185 int
 186 _init()
 187 {
 188         register int error;
 189 
 190         mutex_init(&tnf_drv_state.tnf_mtx, NULL, MUTEX_DEFAULT, NULL);
 191 
 192         if ((error = mod_install(&modlinkage)) != 0) {
 193                 mutex_destroy(&tnf_drv_state.tnf_mtx);
 194                 return (error);
 195         }
 196 
 197         /* Give t0 a tpdp */
 198         if (!t0.t_tnf_tpdp)
 199                 t0.t_tnf_tpdp = kmem_zalloc(sizeof (tnf_ops_t), KM_SLEEP);
 200         /* Initialize tag system */
 201         tnf_tag_core_init();
 202         tnf_tag_trace_init();
 203         tnf_changed_probe_list = 1;
 204         return (0);
 205 }
 206 
 207 int
 208 _fini()
 209 {
 210         /* Not safe to unload this module, currently */
 211         return (EBUSY);
 212 }
 213 
 214 int
 215 _info(struct modinfo *modinfop)
 216 {
 217         return (mod_info(&modlinkage, modinfop));
 218 }
 219 
 220 /* ARGSUSED */
 221 static int
 222 tnf_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
 223 {
 224         register int error;
 225 
 226         switch (infocmd) {
 227         case DDI_INFO_DEVT2DEVINFO:
 228                 *result = (void *)tnf_devi;
 229                 error = DDI_SUCCESS;
 230                 break;
 231         case DDI_INFO_DEVT2INSTANCE:
 232                 *result = (void *)0;
 233                 error = DDI_SUCCESS;
 234                 break;
 235         default:
 236                 error = DDI_FAILURE;
 237         }
 238         return (error);
 239 }
 240 
 241 static int
 242 tnf_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 243 {
 244         if (cmd != DDI_ATTACH)
 245                 return (DDI_FAILURE);
 246         if ((ddi_create_minor_node(devi, "tnfctl", S_IFCHR, TNFCTL_MINOR,
 247             DDI_PSEUDO, NULL) == DDI_FAILURE) ||
 248             (ddi_create_minor_node(devi, "tnfmap", S_IFCHR, TNFMAP_MINOR,
 249             DDI_PSEUDO, NULL) == DDI_FAILURE)) {
 250                 ddi_remove_minor_node(devi, NULL);
 251                 return (DDI_FAILURE);
 252         }
 253         tnf_devi = devi;
 254         return (DDI_SUCCESS);
 255 }
 256 
 257 static int
 258 tnf_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 259 {
 260         if (cmd != DDI_DETACH)
 261                 return (DDI_FAILURE);
 262         ddi_remove_minor_node(devi, NULL);
 263         return (DDI_SUCCESS);
 264 }
 265 
 266 /*
 267  * property operations. Return the size of the kernel trace buffer.  We
 268  * only handle size property requests.  Others are passed on.
 269  */
 270 #ifdef UNUSED
 271 static int
 272 tnf_prop_op(dev_t dev, dev_info_t *di, ddi_prop_op_t prop,
 273     int m, char *name, caddr_t valuep, int *lengthp)
 274 {
 275         int length, *retbuf, size;
 276 
 277         if (strcmp(name, "size") == 0) {
 278 
 279                 /* Don't need tnf_mtx, since mapdev_open_count > 0 */
 280                 size = tnf_trace_file_size;
 281 
 282                 length = *lengthp;              /* get caller's length */
 283                 *lengthp = sizeof (int);        /* set caller's length */
 284 
 285                 switch (prop) {
 286 
 287                 case PROP_LEN:
 288                         return (DDI_PROP_SUCCESS);
 289 
 290                 case PROP_LEN_AND_VAL_ALLOC:
 291                         retbuf = kmem_alloc(sizeof (int),
 292                             (m & DDI_PROP_CANSLEEP) ? KM_SLEEP : KM_NOSLEEP);
 293                         if (retbuf == NULL)
 294                                 return (DDI_PROP_NO_MEMORY);
 295                         *(int **)valuep = retbuf;       /* set caller's buf */
 296                         *retbuf = size;
 297                         return (DDI_PROP_SUCCESS);
 298 
 299                 case PROP_LEN_AND_VAL_BUF:
 300                         if (length < sizeof (int))
 301                                 return (DDI_PROP_BUF_TOO_SMALL);
 302                         *(int *)valuep = size;
 303                         return (DDI_PROP_SUCCESS);
 304                 }
 305         }
 306         return (ddi_prop_op(dev, dip, prop, m, name, valuep, lengthp));
 307 }
 308 #endif
 309 
 310 /* ARGSUSED */
 311 static int
 312 tnf_open(dev_t *devp, int flag, int otyp, struct cred *cred)
 313 {
 314         int err = 0;
 315         mutex_enter(&tnf_drv_state.tnf_mtx);
 316         if (getminor(*devp) == TNFCTL_MINOR) {
 317                 if (tnf_drv_state.ctldev_is_open)
 318                         err = EBUSY;
 319                 else {
 320                         tnf_drv_state.ctldev_is_open = B_TRUE;
 321                         /* stop autounloading -- XXX temporary */
 322                         modunload_disable();
 323                 }
 324         } else {
 325                 /* ASSERT(getminor(*devp) == TNFMAP_MINOR) */
 326                 ++tnf_drv_state.mapdev_open_count;
 327         }
 328         mutex_exit(&tnf_drv_state.tnf_mtx);
 329         return (err);
 330 }
 331 
 332 /* ARGSUSED */
 333 static int
 334 tnf_close(dev_t dev, int flag, int otyp, struct cred *cred)
 335 {
 336         if (getminor(dev) == TNFCTL_MINOR) {
 337                 /*
 338                  * Request the reenablement of autounloading
 339                  */
 340                 modunload_enable();
 341                 tnf_drv_state.ctldev_is_open = B_FALSE;
 342         } else {
 343                 /* ASSERT(getminor(dev) == TNFMAP_MINOR) */
 344                 /*
 345                  * Unconditionally zero the open count since close()
 346                  * is called when last client closes the device.
 347                  */
 348                 tnf_drv_state.mapdev_open_count = 0;
 349         }
 350         return (0);
 351 }
 352 
 353 /*
 354  * return the address of the image referenced by dev.
 355  *
 356  * 1191344: aliasing problem on VAC machines.  It could be made to
 357  * work by ensuring that tnf_buf is allocated on a vac_size boundary.
 358  */
 359 #ifdef UNUSED
 360 /*ARGSUSED*/
 361 static int
 362 tnf_mmap(dev_t dev, off_t off, int prot)
 363 {
 364         register caddr_t addr;
 365         register caddr_t pg_offset;
 366 
 367         if (getminor(dev) != TNFMAP_MINOR)
 368                 return (-1);
 369         if (tnf_buf == 0 || off >= tnf_trace_file_size) {
 370                 return (-1);
 371         }
 372 
 373         addr = tnf_buf;
 374         pg_offset = (caddr_t)((ulong_t)addr + (ulong_t)off);
 375         return ((int)hat_getpfnum(kas.a_hat, pg_offset));
 376 }
 377 #endif
 378 
 379 /*ARGSUSED4*/
 380 static int
 381 tnf_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
 382         cred_t *credp, int *rvalp)
 383 {
 384         int filterval = 1;
 385 
 386         if ((mode & FMODELS) != FNATIVE)
 387                 return (ENOTSUP);
 388 
 389         if (getminor(dev) != TNFCTL_MINOR &&
 390             cmd != TIFIOCGSTATE &&
 391             cmd != TIFIOCGHEADER &&
 392             cmd != TIFIOCGBLOCK &&
 393             cmd != TIFIOCGFWZONE)
 394                 return (EINVAL);
 395 
 396         switch (cmd) {
 397         case TIFIOCGMAXPROBE:
 398                 return (tnf_getmaxprobe((caddr_t)arg, mode));
 399         case TIFIOCGPROBEVALS:
 400                 return (tnf_getprobevals((caddr_t)arg, mode));
 401         case TIFIOCGPROBESTRING:
 402                 return (tnf_getprobestring((caddr_t)arg, mode));
 403         case TIFIOCSPROBEVALS:
 404                 return (tnf_setprobevals((caddr_t)arg, mode));
 405         case TIFIOCGSTATE:
 406                 return (tnf_getstate((caddr_t)arg, mode));
 407         case TIFIOCALLOCBUF:
 408                 return (tnf_allocbuf(arg));
 409         case TIFIOCDEALLOCBUF:
 410                 return (tnf_deallocbuf());
 411         case TIFIOCSTRACING:
 412                 /* LINTED cast from 64-bit integer to 32-bit integer */
 413                 return (tnf_settracing((int)arg));
 414         case TIFIOCSPIDFILTER:
 415                 /* LINTED cast from 64-bit integer to 32-bit integer */
 416                 return (tnf_pidfilterset((int)arg));
 417         case TIFIOCGPIDSTATE:
 418                 return (tnf_getpidstate((caddr_t)arg, mode));
 419         case TIFIOCSPIDOFF:
 420                 filterval = 0;
 421                 /*FALLTHROUGH*/
 422         case TIFIOCSPIDON:
 423                 /* LINTED cast from 64-bit integer to 32-bit integer */
 424                 return (tnf_setpidstate(filterval, (pid_t)arg, mode));
 425         case TIFIOCPIDFILTERGET:
 426                 return (tnf_pidfilterget((caddr_t)arg, mode));
 427         case TIFIOCGHEADER:
 428                 return (tnf_getheader((caddr_t)arg, mode));
 429         case TIFIOCGBLOCK:
 430                 return (tnf_getblock((caddr_t)arg, mode));
 431         case TIFIOCGFWZONE:
 432                 return (tnf_getfwzone((caddr_t)arg, mode));
 433         default:
 434                 return (EINVAL);
 435         }
 436 }
 437 
 438 /*
 439  * ioctls
 440  */
 441 
 442 static int
 443 tnf_getmaxprobe(caddr_t arg, int mode)
 444 {
 445         tnf_probe_control_t *p;
 446         /*
 447          * XXX Still not right for module unload -- just counting
 448          * the probes is not enough
 449          */
 450         if (tnf_changed_probe_list) {
 451                 mutex_enter(&mod_lock);
 452                 tnf_changed_probe_list = 0;
 453                 tnf_drv_state.tnf_probe_count = 0;
 454                 for (p = (tnf_probe_control_t *)__tnf_probe_list_head;
 455                     p != 0; p = p->next)
 456                         ++tnf_drv_state.tnf_probe_count;
 457                 mutex_exit(&mod_lock);
 458         }
 459         if (ddi_copyout((caddr_t)&tnf_drv_state.tnf_probe_count,
 460             arg, sizeof (tnf_drv_state.tnf_probe_count), mode))
 461                 return (EFAULT);
 462         return (0);
 463 }
 464 
 465 static int
 466 tnf_getprobevals(caddr_t arg, int mode)
 467 {
 468         tnf_probevals_t probebuf;
 469         tnf_probe_control_t *p;
 470         int i, retval = 0;
 471 
 472         if (ddi_copyin(arg, (caddr_t)&probebuf, sizeof (probebuf), mode))
 473                 return (EFAULT);
 474 
 475         mutex_enter(&mod_lock);
 476         for (i = 1, p = (tnf_probe_control_t *)__tnf_probe_list_head;
 477             p != NULL && i != probebuf.probenum;
 478             ++i, p = p->next)
 479                 ;
 480         if (p == NULL)
 481                 retval = ENOENT;
 482         else {
 483                 probebuf.enabled = (p->test_func != NULL);
 484                 probebuf.traced = (p->probe_func == tnf_trace_commit);
 485                 /* LINTED assignment of 64-bit integer to 32-bit integer */
 486                 probebuf.attrsize = strlen(p->attrs) + 1;
 487                 if (ddi_copyout((caddr_t)&probebuf,
 488                     arg, sizeof (probebuf), mode))
 489                         retval = EFAULT;
 490         }
 491         mutex_exit(&mod_lock);
 492         return (retval);
 493 }
 494 
 495 static int
 496 tnf_getprobestring(caddr_t arg, int mode)
 497 {
 498         tnf_probevals_t probebuf;
 499         tnf_probe_control_t *p;
 500         int i, retval = 0;
 501 
 502         if (ddi_copyin(arg, (caddr_t)&probebuf, sizeof (probebuf), mode))
 503                 return (EFAULT);
 504 
 505         mutex_enter(&mod_lock);
 506         for (i = 1, p = (tnf_probe_control_t *)__tnf_probe_list_head;
 507             p != NULL && i != probebuf.probenum;
 508             ++i, p = p->next)
 509                 ;
 510         if (p == NULL)
 511                 retval = ENOENT;
 512         else if (ddi_copyout((caddr_t)p->attrs,
 513             arg, strlen(p->attrs) + 1, mode))
 514                 retval = EFAULT;
 515         mutex_exit(&mod_lock);
 516         return (retval);
 517 }
 518 
 519 static int
 520 tnf_setprobevals(caddr_t arg, int mode)
 521 {
 522         tnf_probevals_t probebuf;
 523         tnf_probe_control_t *p;
 524         int i, retval = 0;
 525 
 526         if (ddi_copyin(arg, (caddr_t)&probebuf, sizeof (probebuf), mode))
 527                 return (EFAULT);
 528 
 529         mutex_enter(&mod_lock);
 530         for (i = 1, p = (tnf_probe_control_t *)__tnf_probe_list_head;
 531             p != NULL && i != probebuf.probenum;
 532             ++i, p = p->next)
 533                 ;
 534         if (p == NULL)
 535                 retval = ENOENT;
 536         else {
 537                 /*
 538                  * First do trace, then enable.
 539                  * Set test_func last.
 540                  */
 541                 if (probebuf.traced)
 542                         p->probe_func = tnf_trace_commit;
 543                 else
 544                         p->probe_func = tnf_trace_rollback;
 545                 if (probebuf.enabled) {
 546                         p->alloc_func = tnf_trace_alloc;
 547                         /* this must be set last */
 548                         if (tnf_drv_state.tnf_pidfilter_mode)
 549                                 p->test_func = tnf_test_2;
 550                         else
 551                                 p->test_func = tnf_test_1;
 552                 } else
 553                         p->test_func = NULL;
 554         }
 555         mutex_exit(&mod_lock);
 556         return (retval);
 557 }
 558 
 559 static int
 560 tnf_getstate(caddr_t arg, int mode)
 561 {
 562         tifiocstate_t   tstate;
 563         proc_t          *procp;
 564 
 565         if (tnf_buf == NULL) {
 566                 tstate.buffer_state = TIFIOCBUF_NONE;
 567                 tstate.buffer_size = 0;
 568         } else {
 569                 switch (tnfw_b_state & ~TNFW_B_STOPPED) {
 570                 case TNFW_B_RUNNING:
 571                         tstate.buffer_state = TIFIOCBUF_OK;
 572                         break;
 573                 case TNFW_B_NOBUFFER:
 574                         tstate.buffer_state = TIFIOCBUF_UNINIT;
 575                         break;
 576                 case TNFW_B_BROKEN:
 577                         tstate.buffer_state = TIFIOCBUF_BROKEN;
 578                         break;
 579                 }
 580                 /* LINTED assignment of 64-bit integer to 32-bit integer */
 581                 tstate.buffer_size = tnf_trace_file_size;
 582         }
 583         tstate.trace_stopped = tnfw_b_state & TNFW_B_STOPPED;
 584         tstate.pidfilter_mode = tnf_drv_state.tnf_pidfilter_mode;
 585         tstate.pidfilter_size = 0;
 586 
 587         mutex_enter(&pidlock);
 588         for (procp = practive; procp != NULL; procp = procp->p_next)
 589                 if (PROC_IS_FILTER(procp))
 590                         tstate.pidfilter_size++;
 591         mutex_exit(&pidlock);
 592 
 593         if (ddi_copyout((caddr_t)&tstate, arg, sizeof (tstate), mode))
 594                 return (EFAULT);
 595         return (0);
 596 }
 597 
 598 static int
 599 tnf_allocbuf(intptr_t arg)
 600 {
 601         size_t bufsz;
 602 
 603         if (tnf_buf != NULL)
 604                 return (EBUSY);
 605 
 606         bufsz = roundup((size_t)arg, PAGESIZE);
 607         /*
 608          * Validate size
 609          * XXX Take kernel VM into consideration as well
 610          */
 611         /* bug fix #4057599 if (bufsz > (physmem << PAGESHIFT) / 2) */
 612         if (btop(bufsz) > (physmem / 2))
 613                 return (ENOMEM);
 614         if (bufsz < TNF_TRACE_FILE_MIN)
 615                 bufsz = TNF_TRACE_FILE_MIN;
 616 
 617 #if TNF_USE_KMA
 618         tnf_buf = kmem_zalloc(bufsz, KM_SLEEP);
 619 #else
 620         /* LINTED cast from 64-bit integer to 32-bit intege */
 621         tnf_buf = segkp_get(segkp, (int)bufsz,
 622             KPD_ZERO | KPD_LOCKED | KPD_NO_ANON);
 623 #endif
 624         if (tnf_buf == NULL)
 625                 return (ENOMEM);
 626 
 627         tnf_trace_file_size = bufsz;
 628         tnf_trace_init();
 629         return (0);
 630 }
 631 
 632 /*
 633  * Process a "deallocate buffer" ioctl request.  Tracing must be turned
 634  * off.  We must clear references to the buffer from the tag sites;
 635  * invalidate all threads' notions of block ownership; make sure nobody
 636  * is executing a probe (they might have started before tracing was
 637  * turned off); and free the buffer.
 638  */
 639 static int
 640 tnf_deallocbuf(void)
 641 {
 642         tnf_ops_t *tpdp;
 643         kthread_t *t;
 644         tnf_probe_control_t *probep;
 645         tnf_tag_data_t *tagp;
 646 
 647         if (tnf_drv_state.mapdev_open_count > 0 || tnf_tracing_active)
 648                 return (EBUSY);
 649         if (tnf_buf == NULL)
 650                 return (ENOMEM);
 651 
 652         /*
 653          * Make sure nobody is executing a probe.
 654          * (They could be if they got started while
 655          * tnf_tracing_active was still on.)  Grab
 656          * pidlock, and check the busy flag in all
 657          * TPDP's.
 658          */
 659         mutex_enter(&pidlock);
 660         t = curthread;
 661         do {
 662                 if (t->t_tnf_tpdp != NULL) {
 663                 /* LINTED pointer cast may result in improper alignment */
 664                         tpdp = (tnf_ops_t *)t->t_tnf_tpdp;
 665                         if (LOCK_HELD(&tpdp->busy)) {
 666                                 mutex_exit(&pidlock);
 667                                 return (EBUSY);
 668                         }
 669                         tpdp->wcb.tnfw_w_pos.tnfw_w_block = NULL;
 670                         tpdp->wcb.tnfw_w_tag_pos.tnfw_w_block = NULL;
 671                         tpdp->schedule.record_p = NULL;
 672                 }
 673                 t = t->t_next;
 674         } while (t != curthread);
 675         mutex_exit(&pidlock);
 676 
 677         /*
 678          * Zap all references to the buffer we're freeing.
 679          * Grab mod_lock while walking list to keep it
 680          * consistent.
 681          */
 682         mutex_enter(&mod_lock);
 683         tagp = (tnf_tag_data_t *)__tnf_tag_list_head;
 684         while (tagp != NULL) {
 685                 tagp->tag_index = 0;
 686                 tagp = (tnf_tag_data_t *)tagp->tag_version;
 687         }
 688         probep = (tnf_probe_control_t *)__tnf_probe_list_head;
 689         while (probep != NULL) {
 690                 probep->index = 0;
 691                 probep = probep->next;
 692         }
 693         mutex_exit(&mod_lock);
 694 
 695         tnfw_b_state = TNFW_B_NOBUFFER | TNFW_B_STOPPED;
 696 #if TNF_USE_KMA
 697         kmem_free(tnf_buf, tnf_trace_file_size);
 698 #else
 699         segkp_release(segkp, tnf_buf);
 700 #endif
 701         tnf_buf = NULL;
 702 
 703         return (0);
 704 }
 705 
 706 static int
 707 tnf_settracing(int arg)
 708 {
 709         if (arg)
 710                 if (tnf_buf == NULL)
 711                         return (ENOMEM);
 712                 else
 713                         tnf_trace_on();
 714         else
 715                 tnf_trace_off();
 716 
 717 #ifdef _TNF_SPEED_TEST
 718 #define NITER   255
 719         {
 720                 int i;
 721 
 722                 for (i = 0; i < NITER; i++)
 723                         TNF_PROBE_0(tnf_speed_0, "tnf", /* CSTYLED */);
 724                 for (i = 0; i < NITER; i++)
 725                         TNF_PROBE_1(tnf_speed_1, "tnf", /* CSTYLED */,
 726                             tnf_long,   long,   i);
 727                 for (i = 0; i < NITER; i++)
 728                         TNF_PROBE_2(tnf_speed_2, "tnf", /* CSTYLED */,
 729                             tnf_long,   long1,  i,
 730                             tnf_long,   long2,  i);
 731         }
 732 #endif /* _TNF_SPEED_TEST */
 733 
 734         return (0);
 735 }
 736 
 737 static int
 738 tnf_getpidstate(caddr_t arg, int mode)
 739 {
 740         int     err = 0;
 741         pid_t   pid;
 742         proc_t  *procp;
 743         int     result;
 744 
 745         if (ddi_copyin(arg, (caddr_t)&pid, sizeof (pid), mode))
 746                 return (EFAULT);
 747 
 748         mutex_enter(&pidlock);
 749         if ((procp = prfind(pid)) != NULL)
 750                 result = PROC_IS_FILTER(procp);
 751         else
 752                 err = ESRCH;
 753         mutex_exit(&pidlock);
 754 
 755         if (!err)
 756                 if (ddi_copyout((caddr_t)&result, (caddr_t)arg,
 757                     sizeof (result), mode))
 758                         return (EFAULT);
 759         return (err);
 760 }
 761 
 762 /*ARGSUSED*/
 763 static int
 764 tnf_setpidstate(int filterval, pid_t pid, int mode)
 765 {
 766         int     err = 0;
 767         proc_t  *procp;
 768 
 769         mutex_enter(&pidlock);
 770         if ((procp = prfind(pid)) != NULL)
 771                 if (filterval)
 772                         PROC_FILTER_SET(procp);
 773                 else
 774                         PROC_FILTER_CLR(procp);
 775         else
 776                 err = ESRCH;
 777         mutex_exit(&pidlock);
 778 
 779         return (err);
 780 }
 781 
 782 static int
 783 tnf_pidfilterset(int mode)
 784 {
 785         tnf_probe_control_t     *p;
 786         tnf_probe_test_func_t   func;
 787 
 788         tnf_drv_state.tnf_pidfilter_mode = mode;
 789 
 790         /* Establish correct test func for each probe */
 791         if (mode)
 792                 func = tnf_test_2;
 793         else
 794                 func = tnf_test_1;
 795 
 796         mutex_enter(&mod_lock);
 797         p = (tnf_probe_control_t *)__tnf_probe_list_head;
 798         while (p != NULL) {
 799                 if (p->test_func != NULL)
 800                         p->test_func = func;
 801                 p = p->next;
 802         }
 803         mutex_exit(&mod_lock);
 804 
 805         return (0);
 806 }
 807 
 808 static int
 809 tnf_pidfilterget(caddr_t dest, int mode)
 810 {
 811         int err = 0;
 812         int filtercount = 0;
 813         size_t  sz;
 814         pid_t   *filterbuf, *bufp;
 815         proc_t  *procp;
 816 
 817         /* Count how many processes in filter set (upper bound) */
 818         mutex_enter(&pidlock);
 819         for (procp = practive; procp != NULL; procp = procp->p_next)
 820                 if (PROC_IS_FILTER(procp))
 821                         filtercount++;
 822         mutex_exit(&pidlock);
 823 
 824         /* Allocate temp space to hold filter set (upper bound) */
 825         sz = sizeof (pid_t) * (filtercount + 1);
 826         filterbuf = kmem_zalloc(sz, KM_SLEEP);
 827 
 828         /*
 829          * NOTE: The filter set cannot grow between the first and
 830          * second acquisitions of pidlock.  This is currently true
 831          * because:
 832          *      1. /dev/tnfctl is exclusive open, so all driver
 833          *         control operations, including changing the filter
 834          *         set and this code, are effectively single-threaded.
 835          *      2. There is no in-kernel API to manipulate the filter
 836          *         set (i.e. toggle the on/off bit in a proc struct).
 837          *      3. The proc filter bit is not inherited across a fork()
 838          *         operation; the child starts with the bit off.
 839          * If any of these assumptions is invalidated, a possible
 840          * solution is to check whether we're overflowing the allocated
 841          * filterbuf below, and back out and restart from the beginning
 842          * if so.
 843          *
 844          * The code below handles the case when the filter set shrinks
 845          * due to processes exiting.
 846          */
 847 
 848         /* Fill in filter set */
 849         bufp = filterbuf + 1;   /* first word is for count */
 850         filtercount = 0;        /* recomputed below */
 851         mutex_enter(&pidlock);
 852         for (procp = practive; procp != NULL; procp = procp->p_next) {
 853                 if (PROC_IS_FILTER(procp)) {
 854                         filtercount++;
 855                         *bufp++ = procp->p_pid;
 856                 }
 857         }
 858         mutex_exit(&pidlock);
 859 
 860         /* Set filtercount */
 861         *filterbuf = (pid_t)filtercount;
 862 
 863         /* Copy out result */
 864         if (ddi_copyout((caddr_t)filterbuf, dest, sz, mode))
 865                 err = EFAULT;
 866 
 867         /* Free temp space */
 868         kmem_free(filterbuf, sz);
 869 
 870         return (err);
 871 }
 872 
 873 static int
 874 tnf_getheader(caddr_t arg, int mode)
 875 {
 876         if (tnf_buf == NULL)
 877                 return (ENOMEM);
 878         if (ddi_copyout(tnf_buf, arg, TNF_BLOCK_SIZE, mode))
 879                 return (EFAULT);
 880         return (0);
 881 }
 882 
 883 static int
 884 tnf_getblock(caddr_t arg, int mode)
 885 {
 886         int             err = 0;
 887         tifiocgblock_t  parms;
 888         caddr_t         area;
 889         tnf_block_header_t      *blk;
 890 
 891         if (tnf_buf == NULL)
 892                 return (ENOMEM);
 893         if (ddi_copyin(arg, (caddr_t)&parms, sizeof (parms), mode))
 894                 return (EFAULT);
 895         area = tnf_buf + TNF_DIRECTORY_SIZE +
 896             parms.block_num * TNF_BLOCK_SIZE;
 897         if (area < tnf_buf + TNF_DIRECTORY_SIZE ||
 898             area >= tnf_buf + tnf_trace_file_size)
 899                 return (EFAULT);
 900         /* LINTED pointer cast */
 901         blk = (tnf_block_header_t *)area;
 902         /*
 903          * B-lock the block while we're reading
 904          */
 905         if (!lock_try(&blk->B_lock))
 906                 return (EBUSY);
 907         if (ddi_copyout(area, parms.dst_addr, TNF_BLOCK_SIZE, mode))
 908                 err = EFAULT;
 909         lock_clear(&blk->B_lock);
 910         return (err);
 911 }
 912 
 913 static int
 914 tnf_getfwzone(caddr_t arg, int mode)
 915 {
 916         tifiocgfw_t parms;
 917 
 918         if (tnf_buf == NULL)
 919                 return (ENOMEM);
 920         if (ddi_copyin(arg, (caddr_t)&parms, sizeof (parms), mode))
 921                 return (EFAULT);
 922         if (ddi_copyout(tnf_buf + TNF_BLOCK_SIZE + parms.start *
 923             sizeof (tnf_ref32_t), (caddr_t)parms.dst_addr,
 924             parms.slots * (int)(sizeof (tnf_ref32_t)), mode))
 925                 return (EFAULT);
 926         return (0);
 927 }
 928 
 929 /*ARGSUSED*/
 930 static void *
 931 tnf_test_1(void *tpdp, tnf_probe_control_t *probe_p, tnf_probe_setup_t *sp)
 932 {
 933         tpdp = (void *)curthread->t_tnf_tpdp;
 934         if (tpdp != NULL)
 935                 return (tnf_trace_alloc((tnf_ops_t *)tpdp, probe_p, sp));
 936         return (NULL);
 937 }
 938 
 939 /*ARGSUSED*/
 940 static void *
 941 tnf_test_2(void *tpdp, tnf_probe_control_t *probe_p, tnf_probe_setup_t *sp)
 942 {
 943         tpdp = (void *)curthread->t_tnf_tpdp;
 944         if (tpdp != NULL && PROC_IS_FILTER(curproc))
 945                 return (tnf_trace_alloc((tnf_ops_t *)tpdp, probe_p, sp));
 946         return (NULL);
 947 }
 948 
 949 #endif /* !NPROBE */