Home | History | Annotate | Download | only in tnf
      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, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"@(#)tnf.c	1.53	05/06/08 SMI"
     28 
     29 /*
     30  * tnf driver - provides probe control and kernel trace buffer access
     31  * to the user programs prex and tnfxtract.
     32  */
     33 
     34 #include <sys/types.h>
     35 #include <sys/param.h>
     36 #include <sys/sysmacros.h>
     37 #include <sys/file.h>
     38 #include <sys/cmn_err.h>
     39 #include <sys/fcntl.h>
     40 #include <sys/uio.h>
     41 #include <sys/kmem.h>
     42 #include <sys/cred.h>
     43 #include <sys/mman.h>
     44 #include <sys/errno.h>
     45 #include <sys/stat.h>
     46 #include <sys/conf.h>
     47 #include <sys/ddi.h>
     48 #include <sys/sunddi.h>
     49 #include <sys/modctl.h>
     50 #include <sys/tnf.h>
     51 #include <sys/debug.h>
     52 #include <sys/devops.h>
     53 #include <vm/as.h>
     54 #include <vm/seg_kp.h>
     55 #include <sys/tnf_probe.h>
     56 #include <sys/kobj.h>
     57 
     58 #include "tnf_buf.h"
     59 #include "tnf_types.h"
     60 #include "tnf_trace.h"
     61 
     62 #ifndef NPROBE
     63 
     64 /*
     65  * Each probe is independently put in the kernel, prex uses
     66  * __tnf_probe_list_head and __tnf_tag_list_head as pointers to linked list
     67  * for probes and static tnf_tag_data_t, respectively.
     68  * tnf used the elf relocation record to build a separate linked list for
     69  * the probes and tnf_tag_data_t. We will describe how the linked list for
     70  * __tnf_tag_list_head is made, the probe list is very similar.
     71  * During the dynamic relocation(in uts/sparc/krtld/kobj_reloc.c),
     72  * the &__tnf_tag_version_1(the first member in tnf_tag_data_t data struct)
     73  * (and since it is a global variable which was never defined) will be filled
     74  * with 0. The following code in kobj_reloc.c will get the address of current
     75  * __tnf_tag_list_head and put it in value_p:
     76  *   #define TAG_MARKER_SYMBOL       "__tnf_tag_version_1"
     77  *   if (strcmp(symname, TAG_MARKER_SYMBOL) == 0) {
     78  *       *addend_p = 0;
     79  *       *value_p = (Addr) __tnf_tag_list_head; (value_p points to list head)
     80  *       __tnf_tag_list_head = (void *)*offset_p;(list head is the next record)
     81  *       return (0);
     82  *   }
     83  *
     84  * the function do_reloc(in the kobj_reloc.c) will put vlaue_p into
     85  * &__tnf_tag_version_1
     86  * Now the &__tnf_tag_version_1 points to the last list head
     87  * and __tnf_tag_list_head points to the new list head.
     88  * This is equivalent to attatch a node at the beginning of the list.
     89  *
     90  */
     91 extern tnf_probe_control_t *__tnf_probe_list_head;
     92 extern tnf_tag_data_t *__tnf_tag_list_head;
     93 extern int tnf_changed_probe_list;
     94 
     95 static int tnf_attach(dev_info_t *, ddi_attach_cmd_t);
     96 static int tnf_detach(dev_info_t *, ddi_detach_cmd_t);
     97 static int tnf_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
     98 static int tnf_open(dev_t *, int, int, struct cred *);
     99 static int tnf_close(dev_t, int, int, struct cred *);
    100 #ifdef UNUSED
    101 static int tnf_mmap(dev_t, off_t, int);
    102 #endif
    103 static int tnf_ioctl(dev_t, int, intptr_t, int, struct cred *, int *);
    104 #ifdef UNUSED
    105 static int tnf_prop_op(dev_t, dev_info_t *, ddi_prop_op_t,
    106     int, char *, caddr_t, int *);
    107 #endif
    108 static dev_info_t *tnf_devi;
    109 
    110 static struct {
    111 	int		tnf_probe_count;
    112 	boolean_t	tnf_pidfilter_mode;
    113 	boolean_t	ctldev_is_open;
    114 	int		mapdev_open_count;
    115 	kmutex_t 	tnf_mtx;
    116 } tnf_drv_state = { 0, B_FALSE, B_FALSE, 0 };
    117 
    118 static int tnf_getmaxprobe(caddr_t, int);
    119 static int tnf_getprobevals(caddr_t, int);
    120 static int tnf_getprobestring(caddr_t, int);
    121 static int tnf_setprobevals(caddr_t, int);
    122 static int tnf_getstate(caddr_t, int);
    123 static int tnf_allocbuf(intptr_t);
    124 static int tnf_deallocbuf(void);
    125 static int tnf_settracing(int);
    126 static int tnf_pidfilterset(int);
    127 static int tnf_pidfilterget(caddr_t, int);
    128 static int tnf_getpidstate(caddr_t, int);
    129 static int tnf_setpidstate(int, pid_t, int);
    130 static int tnf_getheader(caddr_t, int);
    131 static int tnf_getblock(caddr_t, int);
    132 static int tnf_getfwzone(caddr_t, int);
    133 
    134 static void *tnf_test_1(void *, tnf_probe_control_t *, tnf_probe_setup_t *);
    135 static void *tnf_test_2(void *, tnf_probe_control_t *, tnf_probe_setup_t *);
    136 
    137 #define	TNFCTL_MINOR 0
    138 #define	TNFMAP_MINOR 1
    139 
    140 struct cb_ops	tnf_cb_ops = {
    141 	tnf_open,		/* open */
    142 	tnf_close,		/* close */
    143 	nodev,			/* strategy */
    144 	nodev,			/* print */
    145 	nodev,			/* dump */
    146 	nodev,			/* read */
    147 	nodev,			/* write */
    148 	tnf_ioctl,		/* ioctl */
    149 	nodev,			/* devmap */
    150 	nodev,			/* mmap */
    151 	nodev,			/* segmap */
    152 	nochpoll,		/* poll */
    153 	ddi_prop_op,		/* prop_op */
    154 	0,			/* streamtab  */
    155 	D_NEW | D_MP		/* Driver compatibility flag */
    156 };
    157 
    158 struct dev_ops	tnf_ops = {
    159 	DEVO_REV,		/* devo_rev, */
    160 	0,			/* refcnt  */
    161 	tnf_info,		/* info */
    162 	nulldev,		/* identify */
    163 	nulldev,		/* probe */
    164 	tnf_attach,		/* attach */
    165 	tnf_detach,		/* detach */
    166 	nodev,			/* reset */
    167 	&tnf_cb_ops,		/* driver operations */
    168 	(struct bus_ops *)0	/* no bus operations */
    169 };
    170 
    171 extern struct mod_ops mod_driverops;
    172 
    173 static struct modldrv modldrv = {
    174 	&mod_driverops,
    175 	"kernel probes driver 1.53",
    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 */
    950