17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*19397407SSherry Moore * Common Development and Distribution License (the "License"). 6*19397407SSherry Moore * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * tnf driver - provides probe control and kernel trace buffer access 297c478bd9Sstevel@tonic-gate * to the user programs prex and tnfxtract. 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/param.h> 347c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 357c478bd9Sstevel@tonic-gate #include <sys/file.h> 367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 377c478bd9Sstevel@tonic-gate #include <sys/fcntl.h> 387c478bd9Sstevel@tonic-gate #include <sys/uio.h> 397c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 407c478bd9Sstevel@tonic-gate #include <sys/cred.h> 417c478bd9Sstevel@tonic-gate #include <sys/mman.h> 427c478bd9Sstevel@tonic-gate #include <sys/errno.h> 437c478bd9Sstevel@tonic-gate #include <sys/stat.h> 447c478bd9Sstevel@tonic-gate #include <sys/conf.h> 457c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 467c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 477c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 487c478bd9Sstevel@tonic-gate #include <sys/tnf.h> 497c478bd9Sstevel@tonic-gate #include <sys/debug.h> 507c478bd9Sstevel@tonic-gate #include <sys/devops.h> 517c478bd9Sstevel@tonic-gate #include <vm/as.h> 527c478bd9Sstevel@tonic-gate #include <vm/seg_kp.h> 537c478bd9Sstevel@tonic-gate #include <sys/tnf_probe.h> 547c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate #include "tnf_buf.h" 577c478bd9Sstevel@tonic-gate #include "tnf_types.h" 587c478bd9Sstevel@tonic-gate #include "tnf_trace.h" 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate #ifndef NPROBE 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate /* 637c478bd9Sstevel@tonic-gate * Each probe is independently put in the kernel, prex uses 647c478bd9Sstevel@tonic-gate * __tnf_probe_list_head and __tnf_tag_list_head as pointers to linked list 657c478bd9Sstevel@tonic-gate * for probes and static tnf_tag_data_t, respectively. 667c478bd9Sstevel@tonic-gate * tnf used the elf relocation record to build a separate linked list for 677c478bd9Sstevel@tonic-gate * the probes and tnf_tag_data_t. We will describe how the linked list for 687c478bd9Sstevel@tonic-gate * __tnf_tag_list_head is made, the probe list is very similar. 697c478bd9Sstevel@tonic-gate * During the dynamic relocation(in uts/sparc/krtld/kobj_reloc.c), 707c478bd9Sstevel@tonic-gate * the &__tnf_tag_version_1(the first member in tnf_tag_data_t data struct) 717c478bd9Sstevel@tonic-gate * (and since it is a global variable which was never defined) will be filled 727c478bd9Sstevel@tonic-gate * with 0. The following code in kobj_reloc.c will get the address of current 737c478bd9Sstevel@tonic-gate * __tnf_tag_list_head and put it in value_p: 747c478bd9Sstevel@tonic-gate * #define TAG_MARKER_SYMBOL "__tnf_tag_version_1" 757c478bd9Sstevel@tonic-gate * if (strcmp(symname, TAG_MARKER_SYMBOL) == 0) { 767c478bd9Sstevel@tonic-gate * *addend_p = 0; 777c478bd9Sstevel@tonic-gate * *value_p = (Addr) __tnf_tag_list_head; (value_p points to list head) 787c478bd9Sstevel@tonic-gate * __tnf_tag_list_head = (void *)*offset_p;(list head is the next record) 797c478bd9Sstevel@tonic-gate * return (0); 807c478bd9Sstevel@tonic-gate * } 817c478bd9Sstevel@tonic-gate * 827c478bd9Sstevel@tonic-gate * the function do_reloc(in the kobj_reloc.c) will put vlaue_p into 837c478bd9Sstevel@tonic-gate * &__tnf_tag_version_1 847c478bd9Sstevel@tonic-gate * Now the &__tnf_tag_version_1 points to the last list head 857c478bd9Sstevel@tonic-gate * and __tnf_tag_list_head points to the new list head. 867c478bd9Sstevel@tonic-gate * This is equivalent to attatch a node at the beginning of the list. 877c478bd9Sstevel@tonic-gate * 887c478bd9Sstevel@tonic-gate */ 897c478bd9Sstevel@tonic-gate extern tnf_probe_control_t *__tnf_probe_list_head; 907c478bd9Sstevel@tonic-gate extern tnf_tag_data_t *__tnf_tag_list_head; 917c478bd9Sstevel@tonic-gate extern int tnf_changed_probe_list; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate static int tnf_attach(dev_info_t *, ddi_attach_cmd_t); 947c478bd9Sstevel@tonic-gate static int tnf_detach(dev_info_t *, ddi_detach_cmd_t); 957c478bd9Sstevel@tonic-gate static int tnf_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 967c478bd9Sstevel@tonic-gate static int tnf_open(dev_t *, int, int, struct cred *); 977c478bd9Sstevel@tonic-gate static int tnf_close(dev_t, int, int, struct cred *); 987c478bd9Sstevel@tonic-gate #ifdef UNUSED 997c478bd9Sstevel@tonic-gate static int tnf_mmap(dev_t, off_t, int); 1007c478bd9Sstevel@tonic-gate #endif 1017c478bd9Sstevel@tonic-gate static int tnf_ioctl(dev_t, int, intptr_t, int, struct cred *, int *); 1027c478bd9Sstevel@tonic-gate #ifdef UNUSED 1037c478bd9Sstevel@tonic-gate static int tnf_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, 1047c478bd9Sstevel@tonic-gate int, char *, caddr_t, int *); 1057c478bd9Sstevel@tonic-gate #endif 1067c478bd9Sstevel@tonic-gate static dev_info_t *tnf_devi; 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate static struct { 1097c478bd9Sstevel@tonic-gate int tnf_probe_count; 1107c478bd9Sstevel@tonic-gate boolean_t tnf_pidfilter_mode; 1117c478bd9Sstevel@tonic-gate boolean_t ctldev_is_open; 1127c478bd9Sstevel@tonic-gate int mapdev_open_count; 1137c478bd9Sstevel@tonic-gate kmutex_t tnf_mtx; 1147c478bd9Sstevel@tonic-gate } tnf_drv_state = { 0, B_FALSE, B_FALSE, 0 }; 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate static int tnf_getmaxprobe(caddr_t, int); 1177c478bd9Sstevel@tonic-gate static int tnf_getprobevals(caddr_t, int); 1187c478bd9Sstevel@tonic-gate static int tnf_getprobestring(caddr_t, int); 1197c478bd9Sstevel@tonic-gate static int tnf_setprobevals(caddr_t, int); 1207c478bd9Sstevel@tonic-gate static int tnf_getstate(caddr_t, int); 1217c478bd9Sstevel@tonic-gate static int tnf_allocbuf(intptr_t); 1227c478bd9Sstevel@tonic-gate static int tnf_deallocbuf(void); 1237c478bd9Sstevel@tonic-gate static int tnf_settracing(int); 1247c478bd9Sstevel@tonic-gate static int tnf_pidfilterset(int); 1257c478bd9Sstevel@tonic-gate static int tnf_pidfilterget(caddr_t, int); 1267c478bd9Sstevel@tonic-gate static int tnf_getpidstate(caddr_t, int); 1277c478bd9Sstevel@tonic-gate static int tnf_setpidstate(int, pid_t, int); 1287c478bd9Sstevel@tonic-gate static int tnf_getheader(caddr_t, int); 1297c478bd9Sstevel@tonic-gate static int tnf_getblock(caddr_t, int); 1307c478bd9Sstevel@tonic-gate static int tnf_getfwzone(caddr_t, int); 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate static void *tnf_test_1(void *, tnf_probe_control_t *, tnf_probe_setup_t *); 1337c478bd9Sstevel@tonic-gate static void *tnf_test_2(void *, tnf_probe_control_t *, tnf_probe_setup_t *); 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate #define TNFCTL_MINOR 0 1367c478bd9Sstevel@tonic-gate #define TNFMAP_MINOR 1 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate struct cb_ops tnf_cb_ops = { 1397c478bd9Sstevel@tonic-gate tnf_open, /* open */ 1407c478bd9Sstevel@tonic-gate tnf_close, /* close */ 1417c478bd9Sstevel@tonic-gate nodev, /* strategy */ 1427c478bd9Sstevel@tonic-gate nodev, /* print */ 1437c478bd9Sstevel@tonic-gate nodev, /* dump */ 1447c478bd9Sstevel@tonic-gate nodev, /* read */ 1457c478bd9Sstevel@tonic-gate nodev, /* write */ 1467c478bd9Sstevel@tonic-gate tnf_ioctl, /* ioctl */ 1477c478bd9Sstevel@tonic-gate nodev, /* devmap */ 1487c478bd9Sstevel@tonic-gate nodev, /* mmap */ 1497c478bd9Sstevel@tonic-gate nodev, /* segmap */ 1507c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 1517c478bd9Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 1527c478bd9Sstevel@tonic-gate 0, /* streamtab */ 1537c478bd9Sstevel@tonic-gate D_NEW | D_MP /* Driver compatibility flag */ 1547c478bd9Sstevel@tonic-gate }; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate struct dev_ops tnf_ops = { 1577c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 1587c478bd9Sstevel@tonic-gate 0, /* refcnt */ 1597c478bd9Sstevel@tonic-gate tnf_info, /* info */ 1607c478bd9Sstevel@tonic-gate nulldev, /* identify */ 1617c478bd9Sstevel@tonic-gate nulldev, /* probe */ 1627c478bd9Sstevel@tonic-gate tnf_attach, /* attach */ 1637c478bd9Sstevel@tonic-gate tnf_detach, /* detach */ 1647c478bd9Sstevel@tonic-gate nodev, /* reset */ 1657c478bd9Sstevel@tonic-gate &tnf_cb_ops, /* driver operations */ 166*19397407SSherry Moore (struct bus_ops *)0, /* no bus operations */ 167*19397407SSherry Moore NULL, /* power */ 168*19397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 1697c478bd9Sstevel@tonic-gate }; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1747c478bd9Sstevel@tonic-gate &mod_driverops, 175*19397407SSherry Moore "kernel probes driver", 1767c478bd9Sstevel@tonic-gate &tnf_ops, 1777c478bd9Sstevel@tonic-gate }; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1807c478bd9Sstevel@tonic-gate MODREV_1, 1817c478bd9Sstevel@tonic-gate (void *)&modldrv, 1827c478bd9Sstevel@tonic-gate NULL 1837c478bd9Sstevel@tonic-gate }; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate int 1867c478bd9Sstevel@tonic-gate _init() 1877c478bd9Sstevel@tonic-gate { 1887c478bd9Sstevel@tonic-gate register int error; 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate mutex_init(&tnf_drv_state.tnf_mtx, NULL, MUTEX_DEFAULT, NULL); 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate if ((error = mod_install(&modlinkage)) != 0) { 1937c478bd9Sstevel@tonic-gate mutex_destroy(&tnf_drv_state.tnf_mtx); 1947c478bd9Sstevel@tonic-gate return (error); 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* Give t0 a tpdp */ 1987c478bd9Sstevel@tonic-gate if (!t0.t_tnf_tpdp) 1997c478bd9Sstevel@tonic-gate t0.t_tnf_tpdp = kmem_zalloc(sizeof (tnf_ops_t), KM_SLEEP); 2007c478bd9Sstevel@tonic-gate /* Initialize tag system */ 2017c478bd9Sstevel@tonic-gate tnf_tag_core_init(); 2027c478bd9Sstevel@tonic-gate tnf_tag_trace_init(); 2037c478bd9Sstevel@tonic-gate tnf_changed_probe_list = 1; 2047c478bd9Sstevel@tonic-gate return (0); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate int 2087c478bd9Sstevel@tonic-gate _fini() 2097c478bd9Sstevel@tonic-gate { 2107c478bd9Sstevel@tonic-gate /* Not safe to unload this module, currently */ 2117c478bd9Sstevel@tonic-gate return (EBUSY); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate int 2157c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2167c478bd9Sstevel@tonic-gate { 2177c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2217c478bd9Sstevel@tonic-gate static int 2227c478bd9Sstevel@tonic-gate tnf_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2237c478bd9Sstevel@tonic-gate { 2247c478bd9Sstevel@tonic-gate register int error; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate switch (infocmd) { 2277c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2287c478bd9Sstevel@tonic-gate *result = (void *)tnf_devi; 2297c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 2307c478bd9Sstevel@tonic-gate break; 2317c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2327c478bd9Sstevel@tonic-gate *result = (void *)0; 2337c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 2347c478bd9Sstevel@tonic-gate break; 2357c478bd9Sstevel@tonic-gate default: 2367c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate return (error); 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate static int 2427c478bd9Sstevel@tonic-gate tnf_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 2437c478bd9Sstevel@tonic-gate { 2447c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) 2457c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2467c478bd9Sstevel@tonic-gate if ((ddi_create_minor_node(devi, "tnfctl", S_IFCHR, TNFCTL_MINOR, 2477c478bd9Sstevel@tonic-gate DDI_PSEUDO, NULL) == DDI_FAILURE) || 2487c478bd9Sstevel@tonic-gate (ddi_create_minor_node(devi, "tnfmap", S_IFCHR, TNFMAP_MINOR, 2497c478bd9Sstevel@tonic-gate DDI_PSEUDO, NULL) == DDI_FAILURE)) { 2507c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 2517c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate tnf_devi = devi; 2547c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate static int 2587c478bd9Sstevel@tonic-gate tnf_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 2597c478bd9Sstevel@tonic-gate { 2607c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH) 2617c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2627c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 2637c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate /* 2677c478bd9Sstevel@tonic-gate * property operations. Return the size of the kernel trace buffer. We 2687c478bd9Sstevel@tonic-gate * only handle size property requests. Others are passed on. 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate #ifdef UNUSED 2717c478bd9Sstevel@tonic-gate static int 2727c478bd9Sstevel@tonic-gate tnf_prop_op(dev_t dev, dev_info_t *di, ddi_prop_op_t prop, 2737c478bd9Sstevel@tonic-gate int m, char *name, caddr_t valuep, int *lengthp) 2747c478bd9Sstevel@tonic-gate { 2757c478bd9Sstevel@tonic-gate int length, *retbuf, size; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if (strcmp(name, "size") == 0) { 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* Don't need tnf_mtx, since mapdev_open_count > 0 */ 2807c478bd9Sstevel@tonic-gate size = tnf_trace_file_size; 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate length = *lengthp; /* get caller's length */ 2837c478bd9Sstevel@tonic-gate *lengthp = sizeof (int); /* set caller's length */ 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate switch (prop) { 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate case PROP_LEN: 2887c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate case PROP_LEN_AND_VAL_ALLOC: 2917c478bd9Sstevel@tonic-gate retbuf = kmem_alloc(sizeof (int), 2927c478bd9Sstevel@tonic-gate (m & DDI_PROP_CANSLEEP) ? KM_SLEEP : KM_NOSLEEP); 2937c478bd9Sstevel@tonic-gate if (retbuf == NULL) 2947c478bd9Sstevel@tonic-gate return (DDI_PROP_NO_MEMORY); 2957c478bd9Sstevel@tonic-gate *(int **)valuep = retbuf; /* set caller's buf */ 2967c478bd9Sstevel@tonic-gate *retbuf = size; 2977c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate case PROP_LEN_AND_VAL_BUF: 3007c478bd9Sstevel@tonic-gate if (length < sizeof (int)) 3017c478bd9Sstevel@tonic-gate return (DDI_PROP_BUF_TOO_SMALL); 3027c478bd9Sstevel@tonic-gate *(int *)valuep = size; 3037c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate return (ddi_prop_op(dev, dip, prop, m, name, valuep, lengthp)); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate #endif 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3117c478bd9Sstevel@tonic-gate static int 3127c478bd9Sstevel@tonic-gate tnf_open(dev_t *devp, int flag, int otyp, struct cred *cred) 3137c478bd9Sstevel@tonic-gate { 3147c478bd9Sstevel@tonic-gate int err = 0; 3157c478bd9Sstevel@tonic-gate mutex_enter(&tnf_drv_state.tnf_mtx); 3167c478bd9Sstevel@tonic-gate if (getminor(*devp) == TNFCTL_MINOR) { 3177c478bd9Sstevel@tonic-gate if (tnf_drv_state.ctldev_is_open) 3187c478bd9Sstevel@tonic-gate err = EBUSY; 3197c478bd9Sstevel@tonic-gate else { 3207c478bd9Sstevel@tonic-gate tnf_drv_state.ctldev_is_open = B_TRUE; 3217c478bd9Sstevel@tonic-gate /* stop autounloading -- XXX temporary */ 3227c478bd9Sstevel@tonic-gate modunload_disable(); 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate } else { 3257c478bd9Sstevel@tonic-gate /* ASSERT(getminor(*devp) == TNFMAP_MINOR) */ 3267c478bd9Sstevel@tonic-gate ++tnf_drv_state.mapdev_open_count; 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate mutex_exit(&tnf_drv_state.tnf_mtx); 3297c478bd9Sstevel@tonic-gate return (err); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3337c478bd9Sstevel@tonic-gate static int 3347c478bd9Sstevel@tonic-gate tnf_close(dev_t dev, int flag, int otyp, struct cred *cred) 3357c478bd9Sstevel@tonic-gate { 3367c478bd9Sstevel@tonic-gate if (getminor(dev) == TNFCTL_MINOR) { 3377c478bd9Sstevel@tonic-gate /* 3387c478bd9Sstevel@tonic-gate * Request the reenablement of autounloading 3397c478bd9Sstevel@tonic-gate */ 3407c478bd9Sstevel@tonic-gate modunload_enable(); 3417c478bd9Sstevel@tonic-gate tnf_drv_state.ctldev_is_open = B_FALSE; 3427c478bd9Sstevel@tonic-gate } else { 3437c478bd9Sstevel@tonic-gate /* ASSERT(getminor(dev) == TNFMAP_MINOR) */ 3447c478bd9Sstevel@tonic-gate /* 3457c478bd9Sstevel@tonic-gate * Unconditionally zero the open count since close() 3467c478bd9Sstevel@tonic-gate * is called when last client closes the device. 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate tnf_drv_state.mapdev_open_count = 0; 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate return (0); 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* 3547c478bd9Sstevel@tonic-gate * return the address of the image referenced by dev. 3557c478bd9Sstevel@tonic-gate * 3567c478bd9Sstevel@tonic-gate * 1191344: aliasing problem on VAC machines. It could be made to 3577c478bd9Sstevel@tonic-gate * work by ensuring that tnf_buf is allocated on a vac_size boundary. 3587c478bd9Sstevel@tonic-gate */ 3597c478bd9Sstevel@tonic-gate #ifdef UNUSED 3607c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3617c478bd9Sstevel@tonic-gate static int 3627c478bd9Sstevel@tonic-gate tnf_mmap(dev_t dev, off_t off, int prot) 3637c478bd9Sstevel@tonic-gate { 3647c478bd9Sstevel@tonic-gate register caddr_t addr; 3657c478bd9Sstevel@tonic-gate register caddr_t pg_offset; 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate if (getminor(dev) != TNFMAP_MINOR) 3687c478bd9Sstevel@tonic-gate return (-1); 3697c478bd9Sstevel@tonic-gate if (tnf_buf == 0 || off >= tnf_trace_file_size) { 3707c478bd9Sstevel@tonic-gate return (-1); 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate addr = tnf_buf; 3747c478bd9Sstevel@tonic-gate pg_offset = (caddr_t)((ulong_t)addr + (ulong_t)off); 3757c478bd9Sstevel@tonic-gate return ((int)hat_getpfnum(kas.a_hat, pg_offset)); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate #endif 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /*ARGSUSED4*/ 3807c478bd9Sstevel@tonic-gate static int 3817c478bd9Sstevel@tonic-gate tnf_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 3827c478bd9Sstevel@tonic-gate cred_t *credp, int *rvalp) 3837c478bd9Sstevel@tonic-gate { 3847c478bd9Sstevel@tonic-gate int filterval = 1; 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate if ((mode & FMODELS) != FNATIVE) 3877c478bd9Sstevel@tonic-gate return (ENOTSUP); 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate if (getminor(dev) != TNFCTL_MINOR && 3907c478bd9Sstevel@tonic-gate cmd != TIFIOCGSTATE && 3917c478bd9Sstevel@tonic-gate cmd != TIFIOCGHEADER && 3927c478bd9Sstevel@tonic-gate cmd != TIFIOCGBLOCK && 3937c478bd9Sstevel@tonic-gate cmd != TIFIOCGFWZONE) 3947c478bd9Sstevel@tonic-gate return (EINVAL); 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate switch (cmd) { 3977c478bd9Sstevel@tonic-gate case TIFIOCGMAXPROBE: 3987c478bd9Sstevel@tonic-gate return (tnf_getmaxprobe((caddr_t)arg, mode)); 3997c478bd9Sstevel@tonic-gate case TIFIOCGPROBEVALS: 4007c478bd9Sstevel@tonic-gate return (tnf_getprobevals((caddr_t)arg, mode)); 4017c478bd9Sstevel@tonic-gate case TIFIOCGPROBESTRING: 4027c478bd9Sstevel@tonic-gate return (tnf_getprobestring((caddr_t)arg, mode)); 4037c478bd9Sstevel@tonic-gate case TIFIOCSPROBEVALS: 4047c478bd9Sstevel@tonic-gate return (tnf_setprobevals((caddr_t)arg, mode)); 4057c478bd9Sstevel@tonic-gate case TIFIOCGSTATE: 4067c478bd9Sstevel@tonic-gate return (tnf_getstate((caddr_t)arg, mode)); 4077c478bd9Sstevel@tonic-gate case TIFIOCALLOCBUF: 4087c478bd9Sstevel@tonic-gate return (tnf_allocbuf(arg)); 4097c478bd9Sstevel@tonic-gate case TIFIOCDEALLOCBUF: 4107c478bd9Sstevel@tonic-gate return (tnf_deallocbuf()); 4117c478bd9Sstevel@tonic-gate case TIFIOCSTRACING: 4127c478bd9Sstevel@tonic-gate /* LINTED cast from 64-bit integer to 32-bit integer */ 4137c478bd9Sstevel@tonic-gate return (tnf_settracing((int)arg)); 4147c478bd9Sstevel@tonic-gate case TIFIOCSPIDFILTER: 4157c478bd9Sstevel@tonic-gate /* LINTED cast from 64-bit integer to 32-bit integer */ 4167c478bd9Sstevel@tonic-gate return (tnf_pidfilterset((int)arg)); 4177c478bd9Sstevel@tonic-gate case TIFIOCGPIDSTATE: 4187c478bd9Sstevel@tonic-gate return (tnf_getpidstate((caddr_t)arg, mode)); 4197c478bd9Sstevel@tonic-gate case TIFIOCSPIDOFF: 4207c478bd9Sstevel@tonic-gate filterval = 0; 4217c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 4227c478bd9Sstevel@tonic-gate case TIFIOCSPIDON: 4237c478bd9Sstevel@tonic-gate /* LINTED cast from 64-bit integer to 32-bit integer */ 4247c478bd9Sstevel@tonic-gate return (tnf_setpidstate(filterval, (pid_t)arg, mode)); 4257c478bd9Sstevel@tonic-gate case TIFIOCPIDFILTERGET: 4267c478bd9Sstevel@tonic-gate return (tnf_pidfilterget((caddr_t)arg, mode)); 4277c478bd9Sstevel@tonic-gate case TIFIOCGHEADER: 4287c478bd9Sstevel@tonic-gate return (tnf_getheader((caddr_t)arg, mode)); 4297c478bd9Sstevel@tonic-gate case TIFIOCGBLOCK: 4307c478bd9Sstevel@tonic-gate return (tnf_getblock((caddr_t)arg, mode)); 4317c478bd9Sstevel@tonic-gate case TIFIOCGFWZONE: 4327c478bd9Sstevel@tonic-gate return (tnf_getfwzone((caddr_t)arg, mode)); 4337c478bd9Sstevel@tonic-gate default: 4347c478bd9Sstevel@tonic-gate return (EINVAL); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * ioctls 4407c478bd9Sstevel@tonic-gate */ 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate static int 4437c478bd9Sstevel@tonic-gate tnf_getmaxprobe(caddr_t arg, int mode) 4447c478bd9Sstevel@tonic-gate { 4457c478bd9Sstevel@tonic-gate tnf_probe_control_t *p; 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * XXX Still not right for module unload -- just counting 4487c478bd9Sstevel@tonic-gate * the probes is not enough 4497c478bd9Sstevel@tonic-gate */ 4507c478bd9Sstevel@tonic-gate if (tnf_changed_probe_list) { 4517c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 4527c478bd9Sstevel@tonic-gate tnf_changed_probe_list = 0; 4537c478bd9Sstevel@tonic-gate tnf_drv_state.tnf_probe_count = 0; 4547c478bd9Sstevel@tonic-gate for (p = (tnf_probe_control_t *)__tnf_probe_list_head; 4557c478bd9Sstevel@tonic-gate p != 0; p = p->next) 4567c478bd9Sstevel@tonic-gate ++tnf_drv_state.tnf_probe_count; 4577c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)&tnf_drv_state.tnf_probe_count, 4607c478bd9Sstevel@tonic-gate arg, sizeof (tnf_drv_state.tnf_probe_count), mode)) 4617c478bd9Sstevel@tonic-gate return (EFAULT); 4627c478bd9Sstevel@tonic-gate return (0); 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate static int 4667c478bd9Sstevel@tonic-gate tnf_getprobevals(caddr_t arg, int mode) 4677c478bd9Sstevel@tonic-gate { 4687c478bd9Sstevel@tonic-gate tnf_probevals_t probebuf; 4697c478bd9Sstevel@tonic-gate tnf_probe_control_t *p; 4707c478bd9Sstevel@tonic-gate int i, retval = 0; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate if (ddi_copyin(arg, (caddr_t)&probebuf, sizeof (probebuf), mode)) 4737c478bd9Sstevel@tonic-gate return (EFAULT); 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 4767c478bd9Sstevel@tonic-gate for (i = 1, p = (tnf_probe_control_t *)__tnf_probe_list_head; 4777c478bd9Sstevel@tonic-gate p != NULL && i != probebuf.probenum; 4787c478bd9Sstevel@tonic-gate ++i, p = p->next) 4797c478bd9Sstevel@tonic-gate ; 4807c478bd9Sstevel@tonic-gate if (p == NULL) 4817c478bd9Sstevel@tonic-gate retval = ENOENT; 4827c478bd9Sstevel@tonic-gate else { 4837c478bd9Sstevel@tonic-gate probebuf.enabled = (p->test_func != NULL); 4847c478bd9Sstevel@tonic-gate probebuf.traced = (p->probe_func == tnf_trace_commit); 4857c478bd9Sstevel@tonic-gate /* LINTED assignment of 64-bit integer to 32-bit integer */ 4867c478bd9Sstevel@tonic-gate probebuf.attrsize = strlen(p->attrs) + 1; 4877c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)&probebuf, 4887c478bd9Sstevel@tonic-gate arg, sizeof (probebuf), mode)) 4897c478bd9Sstevel@tonic-gate retval = EFAULT; 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 4927c478bd9Sstevel@tonic-gate return (retval); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate static int 4967c478bd9Sstevel@tonic-gate tnf_getprobestring(caddr_t arg, int mode) 4977c478bd9Sstevel@tonic-gate { 4987c478bd9Sstevel@tonic-gate tnf_probevals_t probebuf; 4997c478bd9Sstevel@tonic-gate tnf_probe_control_t *p; 5007c478bd9Sstevel@tonic-gate int i, retval = 0; 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate if (ddi_copyin(arg, (caddr_t)&probebuf, sizeof (probebuf), mode)) 5037c478bd9Sstevel@tonic-gate return (EFAULT); 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 5067c478bd9Sstevel@tonic-gate for (i = 1, p = (tnf_probe_control_t *)__tnf_probe_list_head; 5077c478bd9Sstevel@tonic-gate p != NULL && i != probebuf.probenum; 5087c478bd9Sstevel@tonic-gate ++i, p = p->next) 5097c478bd9Sstevel@tonic-gate ; 5107c478bd9Sstevel@tonic-gate if (p == NULL) 5117c478bd9Sstevel@tonic-gate retval = ENOENT; 5127c478bd9Sstevel@tonic-gate else if (ddi_copyout((caddr_t)p->attrs, 5137c478bd9Sstevel@tonic-gate arg, strlen(p->attrs) + 1, mode)) 5147c478bd9Sstevel@tonic-gate retval = EFAULT; 5157c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 5167c478bd9Sstevel@tonic-gate return (retval); 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate static int 5207c478bd9Sstevel@tonic-gate tnf_setprobevals(caddr_t arg, int mode) 5217c478bd9Sstevel@tonic-gate { 5227c478bd9Sstevel@tonic-gate tnf_probevals_t probebuf; 5237c478bd9Sstevel@tonic-gate tnf_probe_control_t *p; 5247c478bd9Sstevel@tonic-gate int i, retval = 0; 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate if (ddi_copyin(arg, (caddr_t)&probebuf, sizeof (probebuf), mode)) 5277c478bd9Sstevel@tonic-gate return (EFAULT); 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 5307c478bd9Sstevel@tonic-gate for (i = 1, p = (tnf_probe_control_t *)__tnf_probe_list_head; 5317c478bd9Sstevel@tonic-gate p != NULL && i != probebuf.probenum; 5327c478bd9Sstevel@tonic-gate ++i, p = p->next) 5337c478bd9Sstevel@tonic-gate ; 5347c478bd9Sstevel@tonic-gate if (p == NULL) 5357c478bd9Sstevel@tonic-gate retval = ENOENT; 5367c478bd9Sstevel@tonic-gate else { 5377c478bd9Sstevel@tonic-gate /* 5387c478bd9Sstevel@tonic-gate * First do trace, then enable. 5397c478bd9Sstevel@tonic-gate * Set test_func last. 5407c478bd9Sstevel@tonic-gate */ 5417c478bd9Sstevel@tonic-gate if (probebuf.traced) 5427c478bd9Sstevel@tonic-gate p->probe_func = tnf_trace_commit; 5437c478bd9Sstevel@tonic-gate else 5447c478bd9Sstevel@tonic-gate p->probe_func = tnf_trace_rollback; 5457c478bd9Sstevel@tonic-gate if (probebuf.enabled) { 5467c478bd9Sstevel@tonic-gate p->alloc_func = tnf_trace_alloc; 5477c478bd9Sstevel@tonic-gate /* this must be set last */ 5487c478bd9Sstevel@tonic-gate if (tnf_drv_state.tnf_pidfilter_mode) 5497c478bd9Sstevel@tonic-gate p->test_func = tnf_test_2; 5507c478bd9Sstevel@tonic-gate else 5517c478bd9Sstevel@tonic-gate p->test_func = tnf_test_1; 5527c478bd9Sstevel@tonic-gate } else 5537c478bd9Sstevel@tonic-gate p->test_func = NULL; 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 5567c478bd9Sstevel@tonic-gate return (retval); 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate static int 5607c478bd9Sstevel@tonic-gate tnf_getstate(caddr_t arg, int mode) 5617c478bd9Sstevel@tonic-gate { 5627c478bd9Sstevel@tonic-gate tifiocstate_t tstate; 5637c478bd9Sstevel@tonic-gate proc_t *procp; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate if (tnf_buf == NULL) { 5667c478bd9Sstevel@tonic-gate tstate.buffer_state = TIFIOCBUF_NONE; 5677c478bd9Sstevel@tonic-gate tstate.buffer_size = 0; 5687c478bd9Sstevel@tonic-gate } else { 5697c478bd9Sstevel@tonic-gate switch (tnfw_b_state & ~TNFW_B_STOPPED) { 5707c478bd9Sstevel@tonic-gate case TNFW_B_RUNNING: 5717c478bd9Sstevel@tonic-gate tstate.buffer_state = TIFIOCBUF_OK; 5727c478bd9Sstevel@tonic-gate break; 5737c478bd9Sstevel@tonic-gate case TNFW_B_NOBUFFER: 5747c478bd9Sstevel@tonic-gate tstate.buffer_state = TIFIOCBUF_UNINIT; 5757c478bd9Sstevel@tonic-gate break; 5767c478bd9Sstevel@tonic-gate case TNFW_B_BROKEN: 5777c478bd9Sstevel@tonic-gate tstate.buffer_state = TIFIOCBUF_BROKEN; 5787c478bd9Sstevel@tonic-gate break; 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate /* LINTED assignment of 64-bit integer to 32-bit integer */ 5817c478bd9Sstevel@tonic-gate tstate.buffer_size = tnf_trace_file_size; 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate tstate.trace_stopped = tnfw_b_state & TNFW_B_STOPPED; 5847c478bd9Sstevel@tonic-gate tstate.pidfilter_mode = tnf_drv_state.tnf_pidfilter_mode; 5857c478bd9Sstevel@tonic-gate tstate.pidfilter_size = 0; 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 5887c478bd9Sstevel@tonic-gate for (procp = practive; procp != NULL; procp = procp->p_next) 5897c478bd9Sstevel@tonic-gate if (PROC_IS_FILTER(procp)) 5907c478bd9Sstevel@tonic-gate tstate.pidfilter_size++; 5917c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)&tstate, arg, sizeof (tstate), mode)) 5947c478bd9Sstevel@tonic-gate return (EFAULT); 5957c478bd9Sstevel@tonic-gate return (0); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate static int 5997c478bd9Sstevel@tonic-gate tnf_allocbuf(intptr_t arg) 6007c478bd9Sstevel@tonic-gate { 6017c478bd9Sstevel@tonic-gate size_t bufsz; 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate if (tnf_buf != NULL) 6047c478bd9Sstevel@tonic-gate return (EBUSY); 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate bufsz = roundup((size_t)arg, PAGESIZE); 6077c478bd9Sstevel@tonic-gate /* 6087c478bd9Sstevel@tonic-gate * Validate size 6097c478bd9Sstevel@tonic-gate * XXX Take kernel VM into consideration as well 6107c478bd9Sstevel@tonic-gate */ 6117c478bd9Sstevel@tonic-gate /* bug fix #4057599 if (bufsz > (physmem << PAGESHIFT) / 2) */ 6127c478bd9Sstevel@tonic-gate if (btop(bufsz) > (physmem / 2)) 6137c478bd9Sstevel@tonic-gate return (ENOMEM); 6147c478bd9Sstevel@tonic-gate if (bufsz < TNF_TRACE_FILE_MIN) 6157c478bd9Sstevel@tonic-gate bufsz = TNF_TRACE_FILE_MIN; 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate #if TNF_USE_KMA 6187c478bd9Sstevel@tonic-gate tnf_buf = kmem_zalloc(bufsz, KM_SLEEP); 6197c478bd9Sstevel@tonic-gate #else 6207c478bd9Sstevel@tonic-gate /* LINTED cast from 64-bit integer to 32-bit intege */ 6217c478bd9Sstevel@tonic-gate tnf_buf = segkp_get(segkp, (int)bufsz, 6227c478bd9Sstevel@tonic-gate KPD_ZERO | KPD_LOCKED | KPD_NO_ANON); 6237c478bd9Sstevel@tonic-gate #endif 6247c478bd9Sstevel@tonic-gate if (tnf_buf == NULL) 6257c478bd9Sstevel@tonic-gate return (ENOMEM); 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate tnf_trace_file_size = bufsz; 6287c478bd9Sstevel@tonic-gate tnf_trace_init(); 6297c478bd9Sstevel@tonic-gate return (0); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /* 6337c478bd9Sstevel@tonic-gate * Process a "deallocate buffer" ioctl request. Tracing must be turned 6347c478bd9Sstevel@tonic-gate * off. We must clear references to the buffer from the tag sites; 6357c478bd9Sstevel@tonic-gate * invalidate all threads' notions of block ownership; make sure nobody 6367c478bd9Sstevel@tonic-gate * is executing a probe (they might have started before tracing was 6377c478bd9Sstevel@tonic-gate * turned off); and free the buffer. 6387c478bd9Sstevel@tonic-gate */ 6397c478bd9Sstevel@tonic-gate static int 6407c478bd9Sstevel@tonic-gate tnf_deallocbuf(void) 6417c478bd9Sstevel@tonic-gate { 6427c478bd9Sstevel@tonic-gate tnf_ops_t *tpdp; 6437c478bd9Sstevel@tonic-gate kthread_t *t; 6447c478bd9Sstevel@tonic-gate tnf_probe_control_t *probep; 6457c478bd9Sstevel@tonic-gate tnf_tag_data_t *tagp; 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate if (tnf_drv_state.mapdev_open_count > 0 || tnf_tracing_active) 6487c478bd9Sstevel@tonic-gate return (EBUSY); 6497c478bd9Sstevel@tonic-gate if (tnf_buf == NULL) 6507c478bd9Sstevel@tonic-gate return (ENOMEM); 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate /* 6537c478bd9Sstevel@tonic-gate * Make sure nobody is executing a probe. 6547c478bd9Sstevel@tonic-gate * (They could be if they got started while 6557c478bd9Sstevel@tonic-gate * tnf_tracing_active was still on.) Grab 6567c478bd9Sstevel@tonic-gate * pidlock, and check the busy flag in all 6577c478bd9Sstevel@tonic-gate * TPDP's. 6587c478bd9Sstevel@tonic-gate */ 6597c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 6607c478bd9Sstevel@tonic-gate t = curthread; 6617c478bd9Sstevel@tonic-gate do { 6627c478bd9Sstevel@tonic-gate if (t->t_tnf_tpdp != NULL) { 6637c478bd9Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */ 6647c478bd9Sstevel@tonic-gate tpdp = (tnf_ops_t *)t->t_tnf_tpdp; 6657c478bd9Sstevel@tonic-gate if (LOCK_HELD(&tpdp->busy)) { 6667c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 6677c478bd9Sstevel@tonic-gate return (EBUSY); 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate tpdp->wcb.tnfw_w_pos.tnfw_w_block = NULL; 6707c478bd9Sstevel@tonic-gate tpdp->wcb.tnfw_w_tag_pos.tnfw_w_block = NULL; 6717c478bd9Sstevel@tonic-gate tpdp->schedule.record_p = NULL; 6727c478bd9Sstevel@tonic-gate } 6737c478bd9Sstevel@tonic-gate t = t->t_next; 6747c478bd9Sstevel@tonic-gate } while (t != curthread); 6757c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate /* 6787c478bd9Sstevel@tonic-gate * Zap all references to the buffer we're freeing. 6797c478bd9Sstevel@tonic-gate * Grab mod_lock while walking list to keep it 6807c478bd9Sstevel@tonic-gate * consistent. 6817c478bd9Sstevel@tonic-gate */ 6827c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 6837c478bd9Sstevel@tonic-gate tagp = (tnf_tag_data_t *)__tnf_tag_list_head; 6847c478bd9Sstevel@tonic-gate while (tagp != NULL) { 6857c478bd9Sstevel@tonic-gate tagp->tag_index = 0; 6867c478bd9Sstevel@tonic-gate tagp = (tnf_tag_data_t *)tagp->tag_version; 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate probep = (tnf_probe_control_t *)__tnf_probe_list_head; 6897c478bd9Sstevel@tonic-gate while (probep != NULL) { 6907c478bd9Sstevel@tonic-gate probep->index = 0; 6917c478bd9Sstevel@tonic-gate probep = probep->next; 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate tnfw_b_state = TNFW_B_NOBUFFER | TNFW_B_STOPPED; 6967c478bd9Sstevel@tonic-gate #if TNF_USE_KMA 6977c478bd9Sstevel@tonic-gate kmem_free(tnf_buf, tnf_trace_file_size); 6987c478bd9Sstevel@tonic-gate #else 6997c478bd9Sstevel@tonic-gate segkp_release(segkp, tnf_buf); 7007c478bd9Sstevel@tonic-gate #endif 7017c478bd9Sstevel@tonic-gate tnf_buf = NULL; 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate return (0); 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate static int 7077c478bd9Sstevel@tonic-gate tnf_settracing(int arg) 7087c478bd9Sstevel@tonic-gate { 7097c478bd9Sstevel@tonic-gate if (arg) 7107c478bd9Sstevel@tonic-gate if (tnf_buf == NULL) 7117c478bd9Sstevel@tonic-gate return (ENOMEM); 7127c478bd9Sstevel@tonic-gate else 7137c478bd9Sstevel@tonic-gate tnf_trace_on(); 7147c478bd9Sstevel@tonic-gate else 7157c478bd9Sstevel@tonic-gate tnf_trace_off(); 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate #ifdef _TNF_SPEED_TEST 7187c478bd9Sstevel@tonic-gate #define NITER 255 7197c478bd9Sstevel@tonic-gate { 7207c478bd9Sstevel@tonic-gate int i; 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate for (i = 0; i < NITER; i++) 7237c478bd9Sstevel@tonic-gate TNF_PROBE_0(tnf_speed_0, "tnf", /* CSTYLED */); 7247c478bd9Sstevel@tonic-gate for (i = 0; i < NITER; i++) 7257c478bd9Sstevel@tonic-gate TNF_PROBE_1(tnf_speed_1, "tnf", /* CSTYLED */, 7267c478bd9Sstevel@tonic-gate tnf_long, long, i); 7277c478bd9Sstevel@tonic-gate for (i = 0; i < NITER; i++) 7287c478bd9Sstevel@tonic-gate TNF_PROBE_2(tnf_speed_2, "tnf", /* CSTYLED */, 7297c478bd9Sstevel@tonic-gate tnf_long, long1, i, 7307c478bd9Sstevel@tonic-gate tnf_long, long2, i); 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate #endif /* _TNF_SPEED_TEST */ 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate return (0); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate static int 7387c478bd9Sstevel@tonic-gate tnf_getpidstate(caddr_t arg, int mode) 7397c478bd9Sstevel@tonic-gate { 7407c478bd9Sstevel@tonic-gate int err = 0; 7417c478bd9Sstevel@tonic-gate pid_t pid; 7427c478bd9Sstevel@tonic-gate proc_t *procp; 7437c478bd9Sstevel@tonic-gate int result; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate if (ddi_copyin(arg, (caddr_t)&pid, sizeof (pid), mode)) 7467c478bd9Sstevel@tonic-gate return (EFAULT); 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 7497c478bd9Sstevel@tonic-gate if ((procp = prfind(pid)) != NULL) 7507c478bd9Sstevel@tonic-gate result = PROC_IS_FILTER(procp); 7517c478bd9Sstevel@tonic-gate else 7527c478bd9Sstevel@tonic-gate err = ESRCH; 7537c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate if (!err) 7567c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)&result, (caddr_t)arg, 7577c478bd9Sstevel@tonic-gate sizeof (result), mode)) 7587c478bd9Sstevel@tonic-gate return (EFAULT); 7597c478bd9Sstevel@tonic-gate return (err); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7637c478bd9Sstevel@tonic-gate static int 7647c478bd9Sstevel@tonic-gate tnf_setpidstate(int filterval, pid_t pid, int mode) 7657c478bd9Sstevel@tonic-gate { 7667c478bd9Sstevel@tonic-gate int err = 0; 7677c478bd9Sstevel@tonic-gate proc_t *procp; 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 7707c478bd9Sstevel@tonic-gate if ((procp = prfind(pid)) != NULL) 7717c478bd9Sstevel@tonic-gate if (filterval) 7727c478bd9Sstevel@tonic-gate PROC_FILTER_SET(procp); 7737c478bd9Sstevel@tonic-gate else 7747c478bd9Sstevel@tonic-gate PROC_FILTER_CLR(procp); 7757c478bd9Sstevel@tonic-gate else 7767c478bd9Sstevel@tonic-gate err = ESRCH; 7777c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate return (err); 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate static int 7837c478bd9Sstevel@tonic-gate tnf_pidfilterset(int mode) 7847c478bd9Sstevel@tonic-gate { 7857c478bd9Sstevel@tonic-gate tnf_probe_control_t *p; 7867c478bd9Sstevel@tonic-gate tnf_probe_test_func_t func; 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate tnf_drv_state.tnf_pidfilter_mode = mode; 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate /* Establish correct test func for each probe */ 7917c478bd9Sstevel@tonic-gate if (mode) 7927c478bd9Sstevel@tonic-gate func = tnf_test_2; 7937c478bd9Sstevel@tonic-gate else 7947c478bd9Sstevel@tonic-gate func = tnf_test_1; 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 7977c478bd9Sstevel@tonic-gate p = (tnf_probe_control_t *)__tnf_probe_list_head; 7987c478bd9Sstevel@tonic-gate while (p != NULL) { 7997c478bd9Sstevel@tonic-gate if (p->test_func != NULL) 8007c478bd9Sstevel@tonic-gate p->test_func = func; 8017c478bd9Sstevel@tonic-gate p = p->next; 8027c478bd9Sstevel@tonic-gate } 8037c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate return (0); 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate static int 8097c478bd9Sstevel@tonic-gate tnf_pidfilterget(caddr_t dest, int mode) 8107c478bd9Sstevel@tonic-gate { 8117c478bd9Sstevel@tonic-gate int err = 0; 8127c478bd9Sstevel@tonic-gate int filtercount = 0; 8137c478bd9Sstevel@tonic-gate size_t sz; 8147c478bd9Sstevel@tonic-gate pid_t *filterbuf, *bufp; 8157c478bd9Sstevel@tonic-gate proc_t *procp; 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate /* Count how many processes in filter set (upper bound) */ 8187c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 8197c478bd9Sstevel@tonic-gate for (procp = practive; procp != NULL; procp = procp->p_next) 8207c478bd9Sstevel@tonic-gate if (PROC_IS_FILTER(procp)) 8217c478bd9Sstevel@tonic-gate filtercount++; 8227c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate /* Allocate temp space to hold filter set (upper bound) */ 8257c478bd9Sstevel@tonic-gate sz = sizeof (pid_t) * (filtercount + 1); 8267c478bd9Sstevel@tonic-gate filterbuf = kmem_zalloc(sz, KM_SLEEP); 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate /* 8297c478bd9Sstevel@tonic-gate * NOTE: The filter set cannot grow between the first and 8307c478bd9Sstevel@tonic-gate * second acquisitions of pidlock. This is currently true 8317c478bd9Sstevel@tonic-gate * because: 8327c478bd9Sstevel@tonic-gate * 1. /dev/tnfctl is exclusive open, so all driver 8337c478bd9Sstevel@tonic-gate * control operations, including changing the filter 8347c478bd9Sstevel@tonic-gate * set and this code, are effectively single-threaded. 8357c478bd9Sstevel@tonic-gate * 2. There is no in-kernel API to manipulate the filter 8367c478bd9Sstevel@tonic-gate * set (i.e. toggle the on/off bit in a proc struct). 8377c478bd9Sstevel@tonic-gate * 3. The proc filter bit is not inherited across a fork() 8387c478bd9Sstevel@tonic-gate * operation; the child starts with the bit off. 8397c478bd9Sstevel@tonic-gate * If any of these assumptions is invalidated, a possible 8407c478bd9Sstevel@tonic-gate * solution is to check whether we're overflowing the allocated 8417c478bd9Sstevel@tonic-gate * filterbuf below, and back out and restart from the beginning 8427c478bd9Sstevel@tonic-gate * if so. 8437c478bd9Sstevel@tonic-gate * 8447c478bd9Sstevel@tonic-gate * The code below handles the case when the filter set shrinks 8457c478bd9Sstevel@tonic-gate * due to processes exiting. 8467c478bd9Sstevel@tonic-gate */ 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate /* Fill in filter set */ 8497c478bd9Sstevel@tonic-gate bufp = filterbuf + 1; /* first word is for count */ 8507c478bd9Sstevel@tonic-gate filtercount = 0; /* recomputed below */ 8517c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 8527c478bd9Sstevel@tonic-gate for (procp = practive; procp != NULL; procp = procp->p_next) { 8537c478bd9Sstevel@tonic-gate if (PROC_IS_FILTER(procp)) { 8547c478bd9Sstevel@tonic-gate filtercount++; 8557c478bd9Sstevel@tonic-gate *bufp++ = procp->p_pid; 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate /* Set filtercount */ 8617c478bd9Sstevel@tonic-gate *filterbuf = (pid_t)filtercount; 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate /* Copy out result */ 8647c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)filterbuf, dest, sz, mode)) 8657c478bd9Sstevel@tonic-gate err = EFAULT; 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate /* Free temp space */ 8687c478bd9Sstevel@tonic-gate kmem_free(filterbuf, sz); 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate return (err); 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate static int 8747c478bd9Sstevel@tonic-gate tnf_getheader(caddr_t arg, int mode) 8757c478bd9Sstevel@tonic-gate { 8767c478bd9Sstevel@tonic-gate if (tnf_buf == NULL) 8777c478bd9Sstevel@tonic-gate return (ENOMEM); 8787c478bd9Sstevel@tonic-gate if (ddi_copyout(tnf_buf, arg, TNF_BLOCK_SIZE, mode)) 8797c478bd9Sstevel@tonic-gate return (EFAULT); 8807c478bd9Sstevel@tonic-gate return (0); 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate static int 8847c478bd9Sstevel@tonic-gate tnf_getblock(caddr_t arg, int mode) 8857c478bd9Sstevel@tonic-gate { 8867c478bd9Sstevel@tonic-gate int err = 0; 8877c478bd9Sstevel@tonic-gate tifiocgblock_t parms; 8887c478bd9Sstevel@tonic-gate caddr_t area; 8897c478bd9Sstevel@tonic-gate tnf_block_header_t *blk; 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate if (tnf_buf == NULL) 8927c478bd9Sstevel@tonic-gate return (ENOMEM); 8937c478bd9Sstevel@tonic-gate if (ddi_copyin(arg, (caddr_t)&parms, sizeof (parms), mode)) 8947c478bd9Sstevel@tonic-gate return (EFAULT); 8957c478bd9Sstevel@tonic-gate area = tnf_buf + TNF_DIRECTORY_SIZE + 8967c478bd9Sstevel@tonic-gate parms.block_num * TNF_BLOCK_SIZE; 8977c478bd9Sstevel@tonic-gate if (area < tnf_buf + TNF_DIRECTORY_SIZE || 8987c478bd9Sstevel@tonic-gate area >= tnf_buf + tnf_trace_file_size) 8997c478bd9Sstevel@tonic-gate return (EFAULT); 9007c478bd9Sstevel@tonic-gate /* LINTED pointer cast */ 9017c478bd9Sstevel@tonic-gate blk = (tnf_block_header_t *)area; 9027c478bd9Sstevel@tonic-gate /* 9037c478bd9Sstevel@tonic-gate * B-lock the block while we're reading 9047c478bd9Sstevel@tonic-gate */ 9057c478bd9Sstevel@tonic-gate if (!lock_try(&blk->B_lock)) 9067c478bd9Sstevel@tonic-gate return (EBUSY); 9077c478bd9Sstevel@tonic-gate if (ddi_copyout(area, parms.dst_addr, TNF_BLOCK_SIZE, mode)) 9087c478bd9Sstevel@tonic-gate err = EFAULT; 9097c478bd9Sstevel@tonic-gate lock_clear(&blk->B_lock); 9107c478bd9Sstevel@tonic-gate return (err); 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate static int 9147c478bd9Sstevel@tonic-gate tnf_getfwzone(caddr_t arg, int mode) 9157c478bd9Sstevel@tonic-gate { 9167c478bd9Sstevel@tonic-gate tifiocgfw_t parms; 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate if (tnf_buf == NULL) 9197c478bd9Sstevel@tonic-gate return (ENOMEM); 9207c478bd9Sstevel@tonic-gate if (ddi_copyin(arg, (caddr_t)&parms, sizeof (parms), mode)) 9217c478bd9Sstevel@tonic-gate return (EFAULT); 9227c478bd9Sstevel@tonic-gate if (ddi_copyout(tnf_buf + TNF_BLOCK_SIZE + parms.start * 9237c478bd9Sstevel@tonic-gate sizeof (tnf_ref32_t), (caddr_t)parms.dst_addr, 9247c478bd9Sstevel@tonic-gate parms.slots * (int)(sizeof (tnf_ref32_t)), mode)) 9257c478bd9Sstevel@tonic-gate return (EFAULT); 9267c478bd9Sstevel@tonic-gate return (0); 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9307c478bd9Sstevel@tonic-gate static void * 9317c478bd9Sstevel@tonic-gate tnf_test_1(void *tpdp, tnf_probe_control_t *probe_p, tnf_probe_setup_t *sp) 9327c478bd9Sstevel@tonic-gate { 9337c478bd9Sstevel@tonic-gate tpdp = (void *)curthread->t_tnf_tpdp; 9347c478bd9Sstevel@tonic-gate if (tpdp != NULL) 9357c478bd9Sstevel@tonic-gate return (tnf_trace_alloc((tnf_ops_t *)tpdp, probe_p, sp)); 9367c478bd9Sstevel@tonic-gate return (NULL); 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9407c478bd9Sstevel@tonic-gate static void * 9417c478bd9Sstevel@tonic-gate tnf_test_2(void *tpdp, tnf_probe_control_t *probe_p, tnf_probe_setup_t *sp) 9427c478bd9Sstevel@tonic-gate { 9437c478bd9Sstevel@tonic-gate tpdp = (void *)curthread->t_tnf_tpdp; 9447c478bd9Sstevel@tonic-gate if (tpdp != NULL && PROC_IS_FILTER(curproc)) 9457c478bd9Sstevel@tonic-gate return (tnf_trace_alloc((tnf_ops_t *)tpdp, probe_p, sp)); 9467c478bd9Sstevel@tonic-gate return (NULL); 9477c478bd9Sstevel@tonic-gate } 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate #endif /* !NPROBE */ 950