10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*4436Sstephh * Common Development and Distribution License (the "License"). 6*4436Sstephh * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*4436Sstephh * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate * 250Sstevel@tonic-gate * ipath.c -- instanced pathname module 260Sstevel@tonic-gate * 270Sstevel@tonic-gate * this module provides a cache of fully instantized component paths, 280Sstevel@tonic-gate * stored in a fairly compact format. 290Sstevel@tonic-gate */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <stdio.h> 340Sstevel@tonic-gate #include <string.h> 350Sstevel@tonic-gate #include "alloc.h" 360Sstevel@tonic-gate #include "out.h" 370Sstevel@tonic-gate #include "lut.h" 380Sstevel@tonic-gate #include "tree.h" 390Sstevel@tonic-gate #include "ptree.h" 400Sstevel@tonic-gate #include "itree.h" 410Sstevel@tonic-gate #include "ipath.h" 420Sstevel@tonic-gate #include "stats.h" 430Sstevel@tonic-gate #include "eval.h" 440Sstevel@tonic-gate #include "config.h" 450Sstevel@tonic-gate 460Sstevel@tonic-gate static struct stats *Nipath; 470Sstevel@tonic-gate static struct stats *Nbytes; 480Sstevel@tonic-gate 490Sstevel@tonic-gate /* an ipath cache entry is an array of these, with s==NULL at the end */ 500Sstevel@tonic-gate struct ipath { 510Sstevel@tonic-gate const char *s; /* component name (in stable) */ 520Sstevel@tonic-gate int i; /* instance number */ 530Sstevel@tonic-gate }; 540Sstevel@tonic-gate 550Sstevel@tonic-gate static struct lut *Ipaths; /* the ipath cache itself */ 560Sstevel@tonic-gate 570Sstevel@tonic-gate /* 580Sstevel@tonic-gate * ipath_init -- initialize the ipath module 590Sstevel@tonic-gate */ 600Sstevel@tonic-gate void 610Sstevel@tonic-gate ipath_init(void) 620Sstevel@tonic-gate { 630Sstevel@tonic-gate Nipath = stats_new_counter("ievent.nipath", "ipath cache entries", 1); 640Sstevel@tonic-gate Nbytes = stats_new_counter("ievent.nbytes", "total cache size", 1); 650Sstevel@tonic-gate } 660Sstevel@tonic-gate 670Sstevel@tonic-gate /* 680Sstevel@tonic-gate * ipath_cmp -- compare two ipath entries 690Sstevel@tonic-gate * 700Sstevel@tonic-gate * since two ipaths containing the same components and instance 710Sstevel@tonic-gate * numbers always point to the same cache entry, they are equal 720Sstevel@tonic-gate * if their pointers are equal, so this function is not necessary 730Sstevel@tonic-gate * to test if two ipaths are same. but when inserting a new ipath 740Sstevel@tonic-gate * into the cache, we must use the same lut comparison logic as when 750Sstevel@tonic-gate * we're searching for it, so this function must always match the 760Sstevel@tonic-gate * itree_epnamecmp() function's logic (see below) for searching the lut. 770Sstevel@tonic-gate */ 780Sstevel@tonic-gate static int 790Sstevel@tonic-gate ipath_cmp(struct ipath *ipp1, struct ipath *ipp2) 800Sstevel@tonic-gate { 810Sstevel@tonic-gate int i; 820Sstevel@tonic-gate 830Sstevel@tonic-gate ASSERT(ipp1 != NULL); 840Sstevel@tonic-gate ASSERT(ipp2 != NULL); 850Sstevel@tonic-gate 860Sstevel@tonic-gate for (i = 0; ipp1[i].s != NULL && ipp2[i].s != NULL; i++) 870Sstevel@tonic-gate if (ipp1[i].s != ipp2[i].s) 880Sstevel@tonic-gate return (ipp2[i].s - ipp1[i].s); 890Sstevel@tonic-gate else if (ipp1[i].i != ipp2[i].i) 900Sstevel@tonic-gate return (ipp2[i].i - ipp1[i].i); 910Sstevel@tonic-gate 920Sstevel@tonic-gate if (ipp1[i].s == NULL && ipp2[i].s == NULL) 930Sstevel@tonic-gate return (0); 940Sstevel@tonic-gate else if (ipp1[i].s == NULL) 950Sstevel@tonic-gate return (1); 960Sstevel@tonic-gate else 970Sstevel@tonic-gate return (-1); 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* 1010Sstevel@tonic-gate * ipath_epnamecmp -- compare an ipath with a struct node *epname list 1020Sstevel@tonic-gate * 1030Sstevel@tonic-gate * this function is used when searching the cache, allowing us to search 1040Sstevel@tonic-gate * a lut full of ipaths by looking directly at a struct node *epname 1050Sstevel@tonic-gate * (without having to convert it first). the comparison logic here must 1060Sstevel@tonic-gate * exactly match itree_cmp()'s logic (see above) so lut lookups use find 1070Sstevel@tonic-gate * the same node as lut inserts. 1080Sstevel@tonic-gate */ 1090Sstevel@tonic-gate static int 1100Sstevel@tonic-gate ipath_epnamecmp(struct ipath *ipp, struct node *np) 1110Sstevel@tonic-gate { 1120Sstevel@tonic-gate int i; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate ASSERT(np != NULL); 1150Sstevel@tonic-gate ASSERT(ipp != NULL); 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate for (i = 0; ipp[i].s != NULL && np != NULL; i++, np = np->u.name.next) { 1180Sstevel@tonic-gate ASSERTinfo(np->t == T_NAME, ptree_nodetype2str(np->t)); 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate if (ipp[i].s != np->u.name.s) 1210Sstevel@tonic-gate return (np->u.name.s - ipp[i].s); 1220Sstevel@tonic-gate else { 1230Sstevel@tonic-gate int inum; 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate if (np->u.name.child != NULL && 1260Sstevel@tonic-gate np->u.name.child->t == T_NUM) 1270Sstevel@tonic-gate inum = (int)np->u.name.child->u.ull; 1280Sstevel@tonic-gate else 1290Sstevel@tonic-gate config_getcompname(np->u.name.cp, NULL, &inum); 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate if (ipp[i].i != inum) 1320Sstevel@tonic-gate return (inum - ipp[i].i); 1330Sstevel@tonic-gate } 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate if (ipp[i].s == NULL && np == NULL) 1370Sstevel@tonic-gate return (0); 1380Sstevel@tonic-gate else if (ipp[i].s == NULL) 1390Sstevel@tonic-gate return (1); 1400Sstevel@tonic-gate else 1410Sstevel@tonic-gate return (-1); 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate 144*4436Sstephh struct lut *Usednames; 145*4436Sstephh 146*4436Sstephh void 147*4436Sstephh ipath_dummy_lut(struct arrow *arrowp) 148*4436Sstephh { 149*4436Sstephh const struct ipath *ipp; 150*4436Sstephh 151*4436Sstephh ipp = arrowp->head->myevent->ipp; 152*4436Sstephh while (ipp->s != NULL) { 153*4436Sstephh Usednames = lut_add(Usednames, (void *)ipp->s, 154*4436Sstephh (void *)ipp->s, NULL); 155*4436Sstephh ipp++; 156*4436Sstephh } 157*4436Sstephh ipp = arrowp->tail->myevent->ipp; 158*4436Sstephh while (ipp->s != NULL) { 159*4436Sstephh Usednames = lut_add(Usednames, (void *)ipp->s, 160*4436Sstephh (void *)ipp->s, NULL); 161*4436Sstephh ipp++; 162*4436Sstephh } 163*4436Sstephh } 164*4436Sstephh 165*4436Sstephh struct ipath * 166*4436Sstephh ipath_dummy(struct node *np, struct ipath *ipp) 167*4436Sstephh { 168*4436Sstephh struct ipath *ret; 169*4436Sstephh 170*4436Sstephh ret = ipp; 171*4436Sstephh while (ipp[1].s != NULL) 172*4436Sstephh ipp++; 173*4436Sstephh if (strcmp(ipp[0].s, np->u.name.last->u.name.s) == 0) 174*4436Sstephh return (ret); 175*4436Sstephh 176*4436Sstephh ret = MALLOC(sizeof (*ret) * 2); 177*4436Sstephh ret[0].s = np->u.name.last->u.name.s; 178*4436Sstephh ret[0].i = 0; 179*4436Sstephh ret[1].s = NULL; 180*4436Sstephh if ((ipp = lut_lookup(Ipaths, (void *)ret, 181*4436Sstephh (lut_cmp)ipath_cmp)) != NULL) { 182*4436Sstephh FREE(ret); 183*4436Sstephh return (ipp); 184*4436Sstephh } 185*4436Sstephh Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret, (lut_cmp)ipath_cmp); 186*4436Sstephh stats_counter_bump(Nipath); 187*4436Sstephh stats_counter_add(Nbytes, 2 * sizeof (struct ipath)); 188*4436Sstephh return (ret); 189*4436Sstephh } 190*4436Sstephh 1910Sstevel@tonic-gate /* 1920Sstevel@tonic-gate * ipath -- find instanced path in cache, or add it if necessary 1930Sstevel@tonic-gate */ 1940Sstevel@tonic-gate const struct ipath * 1950Sstevel@tonic-gate ipath(struct node *np) 1960Sstevel@tonic-gate { 1970Sstevel@tonic-gate struct ipath *ret; 1980Sstevel@tonic-gate int count; 1990Sstevel@tonic-gate struct node *namep; 2000Sstevel@tonic-gate int i; 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate if ((ret = lut_lookup(Ipaths, (void *)np, 2030Sstevel@tonic-gate (lut_cmp)ipath_epnamecmp)) != NULL) 2040Sstevel@tonic-gate return (ret); /* already in cache */ 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate /* 2070Sstevel@tonic-gate * not in cache, make new cache entry. 2080Sstevel@tonic-gate * start by counting the length of the name. 2090Sstevel@tonic-gate */ 2100Sstevel@tonic-gate count = 0; 2110Sstevel@tonic-gate namep = np; 2120Sstevel@tonic-gate while (namep != NULL) { 2130Sstevel@tonic-gate ASSERTinfo(namep->t == T_NAME, ptree_nodetype2str(namep->t)); 2140Sstevel@tonic-gate count++; 2150Sstevel@tonic-gate namep = namep->u.name.next; 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate ASSERT(count > 0); 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate /* allocate array for name and last NULL entry */ 2210Sstevel@tonic-gate ret = MALLOC(sizeof (*ret) * (count + 1)); 2220Sstevel@tonic-gate ret[count].s = NULL; 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate /* fill in ipath entry */ 2250Sstevel@tonic-gate namep = np; 2260Sstevel@tonic-gate i = 0; 2270Sstevel@tonic-gate while (namep != NULL) { 2280Sstevel@tonic-gate ASSERT(i < count); 2290Sstevel@tonic-gate ret[i].s = namep->u.name.s; 2300Sstevel@tonic-gate if (namep->u.name.child != NULL && 2310Sstevel@tonic-gate namep->u.name.child->t == T_NUM) 2320Sstevel@tonic-gate ret[i].i = (int)namep->u.name.child->u.ull; 2330Sstevel@tonic-gate else 2340Sstevel@tonic-gate config_getcompname(namep->u.name.cp, NULL, &ret[i].i); 2350Sstevel@tonic-gate i++; 2360Sstevel@tonic-gate namep = namep->u.name.next; 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate /* add it to the cache */ 2400Sstevel@tonic-gate Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret, 2410Sstevel@tonic-gate (lut_cmp)ipath_cmp); 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate stats_counter_bump(Nipath); 2440Sstevel@tonic-gate stats_counter_add(Nbytes, (count + 1) * sizeof (struct ipath)); 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate return (ret); 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate /* 2500Sstevel@tonic-gate * ipath2str -- convert ename and ipath to class@path string 2510Sstevel@tonic-gate * 2520Sstevel@tonic-gate * if both ename and ipp are provided (non-NULL), the resulting string 2530Sstevel@tonic-gate * will be "class@path". otherwise, the string will just contain the 2540Sstevel@tonic-gate * event class name (e.g. "ereport.io.pci.device") or just the path 2550Sstevel@tonic-gate * name (e.g. "mothboard0/hostbridge0/pcibus1/pcidev0/pcifn1"), depending 2560Sstevel@tonic-gate * on which argument is non-NULL. 2570Sstevel@tonic-gate */ 2580Sstevel@tonic-gate char * 2590Sstevel@tonic-gate ipath2str(const char *ename, const struct ipath *ipp) 2600Sstevel@tonic-gate { 2610Sstevel@tonic-gate int i; 2620Sstevel@tonic-gate size_t len = 0; 2630Sstevel@tonic-gate char *ret; 2640Sstevel@tonic-gate char *cp; 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate /* count up length of class string */ 2670Sstevel@tonic-gate if (ename != NULL) 2680Sstevel@tonic-gate len += strlen(ename); 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate /* count up length of path string, including slash separators */ 2710Sstevel@tonic-gate if (ipp != NULL) { 2720Sstevel@tonic-gate for (i = 0; ipp[i].s != NULL; i++) { 2730Sstevel@tonic-gate /* add slash separator, but no leading slash */ 2740Sstevel@tonic-gate if (i != 0) 2750Sstevel@tonic-gate len++; 2760Sstevel@tonic-gate len += snprintf(NULL, 0, "%s%d", ipp[i].s, ipp[i].i); 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate if (ename != NULL && ipp != NULL) 2810Sstevel@tonic-gate len++; /* room for '@' */ 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate len++; /* room for final '\0' */ 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate cp = ret = MALLOC(len); 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate if (ename != NULL) { 2880Sstevel@tonic-gate /* construct class string */ 2890Sstevel@tonic-gate (void) strcpy(cp, ename); 2900Sstevel@tonic-gate cp += strlen(cp); 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate /* if doing both strings, put '@' between them */ 2940Sstevel@tonic-gate if (ename != NULL && ipp != NULL) 2950Sstevel@tonic-gate *cp++ = '@'; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate if (ipp != NULL) { 2980Sstevel@tonic-gate /* construct path string */ 2990Sstevel@tonic-gate for (i = 0; ipp[i].s != NULL; i++) { 3000Sstevel@tonic-gate if (i != 0) 3010Sstevel@tonic-gate *cp++ = '/'; 3020Sstevel@tonic-gate (void) snprintf(cp, &ret[len] - cp, "%s%d", 3030Sstevel@tonic-gate ipp[i].s, ipp[i].i); 3040Sstevel@tonic-gate cp += strlen(cp); 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate *cp++ = '\0'; 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate return (ret); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate /* 3141414Scindi * ipath2strlen -- calculate the len of what ipath2str() would return 3151414Scindi */ 3161414Scindi size_t 3171414Scindi ipath2strlen(const char *ename, const struct ipath *ipp) 3181414Scindi { 3191414Scindi int i; 3201414Scindi size_t len = 0; 3211414Scindi 3221414Scindi /* count up length of class string */ 3231414Scindi if (ename != NULL) 3241414Scindi len += strlen(ename); 3251414Scindi 3261414Scindi /* count up length of path string, including slash separators */ 3271414Scindi if (ipp != NULL) { 3281414Scindi for (i = 0; ipp[i].s != NULL; i++) { 3291414Scindi /* add slash separator, but no leading slash */ 3301414Scindi if (i != 0) 3311414Scindi len++; 3321414Scindi len += snprintf(NULL, 0, "%s%d", ipp[i].s, ipp[i].i); 3331414Scindi } 3341414Scindi } 3351414Scindi 3361414Scindi if (ename != NULL && ipp != NULL) 3371414Scindi len++; /* room for '@' */ 3381414Scindi 3391414Scindi return (len); 3401414Scindi } 3411414Scindi 3421414Scindi /* 3430Sstevel@tonic-gate * ipath_print -- print out an ename, ipath, or both with '@' between them 3440Sstevel@tonic-gate */ 3450Sstevel@tonic-gate void 3460Sstevel@tonic-gate ipath_print(int flags, const char *ename, const struct ipath *ipp) 3470Sstevel@tonic-gate { 3480Sstevel@tonic-gate if (ename != NULL) { 3490Sstevel@tonic-gate out(flags|O_NONL, ename); 3500Sstevel@tonic-gate if (ipp != NULL) 3510Sstevel@tonic-gate out(flags|O_NONL, "@"); 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate if (ipp != NULL) { 3540Sstevel@tonic-gate char *sep = ""; 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate while (ipp->s != NULL) { 3570Sstevel@tonic-gate out(flags|O_NONL, "%s%s%d", sep, ipp->s, ipp->i); 3580Sstevel@tonic-gate ipp++; 3590Sstevel@tonic-gate sep = "/"; 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate /*ARGSUSED*/ 3650Sstevel@tonic-gate static void 3660Sstevel@tonic-gate ipath_destructor(void *left, void *right, void *arg) 3670Sstevel@tonic-gate { 3680Sstevel@tonic-gate struct ipath *ipp = (struct ipath *)right; 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate FREE(ipp); 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate /* 3740Sstevel@tonic-gate * ipath_fini -- free the ipath cache 3750Sstevel@tonic-gate */ 3760Sstevel@tonic-gate void 3770Sstevel@tonic-gate ipath_fini(void) 3780Sstevel@tonic-gate { 3790Sstevel@tonic-gate lut_free(Ipaths, ipath_destructor, NULL); 3800Sstevel@tonic-gate Ipaths = NULL; 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate if (Nipath) { 3830Sstevel@tonic-gate stats_delete(Nipath); 3840Sstevel@tonic-gate Nipath = NULL; 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate if (Nbytes) { 3880Sstevel@tonic-gate stats_delete(Nbytes); 3890Sstevel@tonic-gate Nbytes = NULL; 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate } 392