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 * ipath.c -- instanced pathname module 27 * 28 * this module provides a cache of fully instantized component paths, 29 * stored in a fairly compact format. 30 */ 31 32 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 #include <stdio.h> 35 #include <string.h> 36 #include "alloc.h" 37 #include "out.h" 38 #include "lut.h" 39 #include "tree.h" 40 #include "ptree.h" 41 #include "itree.h" 42 #include "ipath.h" 43 #include "stats.h" 44 #include "eval.h" 45 #include "config.h" 46 47 static struct stats *Nipath; 48 static struct stats *Nbytes; 49 50 /* an ipath cache entry is an array of these, with s==NULL at the end */ 51 struct ipath { 52 const char *s; /* component name (in stable) */ 53 int i; /* instance number */ 54 }; 55 56 static struct lut *Ipaths; /* the ipath cache itself */ 57 58 /* 59 * ipath_init -- initialize the ipath module 60 */ 61 void 62 ipath_init(void) 63 { 64 Nipath = stats_new_counter("ievent.nipath", "ipath cache entries", 1); 65 Nbytes = stats_new_counter("ievent.nbytes", "total cache size", 1); 66 } 67 68 /* 69 * ipath_cmp -- compare two ipath entries 70 * 71 * since two ipaths containing the same components and instance 72 * numbers always point to the same cache entry, they are equal 73 * if their pointers are equal, so this function is not necessary 74 * to test if two ipaths are same. but when inserting a new ipath 75 * into the cache, we must use the same lut comparison logic as when 76 * we're searching for it, so this function must always match the 77 * itree_epnamecmp() function's logic (see below) for searching the lut. 78 */ 79 static int 80 ipath_cmp(struct ipath *ipp1, struct ipath *ipp2) 81 { 82 int i; 83 84 ASSERT(ipp1 != NULL); 85 ASSERT(ipp2 != NULL); 86 87 for (i = 0; ipp1[i].s != NULL && ipp2[i].s != NULL; i++) 88 if (ipp1[i].s != ipp2[i].s) 89 return (ipp2[i].s - ipp1[i].s); 90 else if (ipp1[i].i != ipp2[i].i) 91 return (ipp2[i].i - ipp1[i].i); 92 93 if (ipp1[i].s == NULL && ipp2[i].s == NULL) 94 return (0); 95 else if (ipp1[i].s == NULL) 96 return (1); 97 else 98 return (-1); 99 } 100 101 /* 102 * ipath_epnamecmp -- compare an ipath with a struct node *epname list 103 * 104 * this function is used when searching the cache, allowing us to search 105 * a lut full of ipaths by looking directly at a struct node *epname 106 * (without having to convert it first). the comparison logic here must 107 * exactly match itree_cmp()'s logic (see above) so lut lookups use find 108 * the same node as lut inserts. 109 */ 110 static int 111 ipath_epnamecmp(struct ipath *ipp, struct node *np) 112 { 113 int i; 114 115 ASSERT(np != NULL); 116 ASSERT(ipp != NULL); 117 118 for (i = 0; ipp[i].s != NULL && np != NULL; i++, np = np->u.name.next) { 119 ASSERTinfo(np->t == T_NAME, ptree_nodetype2str(np->t)); 120 121 if (ipp[i].s != np->u.name.s) 122 return (np->u.name.s - ipp[i].s); 123 else { 124 int inum; 125 126 if (np->u.name.child != NULL && 127 np->u.name.child->t == T_NUM) 128 inum = (int)np->u.name.child->u.ull; 129 else 130 config_getcompname(np->u.name.cp, NULL, &inum); 131 132 if (ipp[i].i != inum) 133 return (inum - ipp[i].i); 134 } 135 } 136 137 if (ipp[i].s == NULL && np == NULL) 138 return (0); 139 else if (ipp[i].s == NULL) 140 return (1); 141 else 142 return (-1); 143 } 144 145 /* 146 * ipath -- find instanced path in cache, or add it if necessary 147 */ 148 const struct ipath * 149 ipath(struct node *np) 150 { 151 struct ipath *ret; 152 int count; 153 struct node *namep; 154 int i; 155 156 if ((ret = lut_lookup(Ipaths, (void *)np, 157 (lut_cmp)ipath_epnamecmp)) != NULL) 158 return (ret); /* already in cache */ 159 160 /* 161 * not in cache, make new cache entry. 162 * start by counting the length of the name. 163 */ 164 count = 0; 165 namep = np; 166 while (namep != NULL) { 167 ASSERTinfo(namep->t == T_NAME, ptree_nodetype2str(namep->t)); 168 count++; 169 namep = namep->u.name.next; 170 } 171 172 ASSERT(count > 0); 173 174 /* allocate array for name and last NULL entry */ 175 ret = MALLOC(sizeof (*ret) * (count + 1)); 176 ret[count].s = NULL; 177 178 /* fill in ipath entry */ 179 namep = np; 180 i = 0; 181 while (namep != NULL) { 182 ASSERT(i < count); 183 ret[i].s = namep->u.name.s; 184 if (namep->u.name.child != NULL && 185 namep->u.name.child->t == T_NUM) 186 ret[i].i = (int)namep->u.name.child->u.ull; 187 else 188 config_getcompname(namep->u.name.cp, NULL, &ret[i].i); 189 i++; 190 namep = namep->u.name.next; 191 } 192 193 /* add it to the cache */ 194 Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret, 195 (lut_cmp)ipath_cmp); 196 197 stats_counter_bump(Nipath); 198 stats_counter_add(Nbytes, (count + 1) * sizeof (struct ipath)); 199 200 return (ret); 201 } 202 203 /* 204 * ipath2str -- convert ename and ipath to class@path string 205 * 206 * if both ename and ipp are provided (non-NULL), the resulting string 207 * will be "class@path". otherwise, the string will just contain the 208 * event class name (e.g. "ereport.io.pci.device") or just the path 209 * name (e.g. "mothboard0/hostbridge0/pcibus1/pcidev0/pcifn1"), depending 210 * on which argument is non-NULL. 211 */ 212 char * 213 ipath2str(const char *ename, const struct ipath *ipp) 214 { 215 int i; 216 size_t len = 0; 217 char *ret; 218 char *cp; 219 220 /* count up length of class string */ 221 if (ename != NULL) 222 len += strlen(ename); 223 224 /* count up length of path string, including slash separators */ 225 if (ipp != NULL) { 226 for (i = 0; ipp[i].s != NULL; i++) { 227 /* add slash separator, but no leading slash */ 228 if (i != 0) 229 len++; 230 len += snprintf(NULL, 0, "%s%d", ipp[i].s, ipp[i].i); 231 } 232 } 233 234 if (ename != NULL && ipp != NULL) 235 len++; /* room for '@' */ 236 237 len++; /* room for final '\0' */ 238 239 cp = ret = MALLOC(len); 240 241 if (ename != NULL) { 242 /* construct class string */ 243 (void) strcpy(cp, ename); 244 cp += strlen(cp); 245 } 246 247 /* if doing both strings, put '@' between them */ 248 if (ename != NULL && ipp != NULL) 249 *cp++ = '@'; 250 251 if (ipp != NULL) { 252 /* construct path string */ 253 for (i = 0; ipp[i].s != NULL; i++) { 254 if (i != 0) 255 *cp++ = '/'; 256 (void) snprintf(cp, &ret[len] - cp, "%s%d", 257 ipp[i].s, ipp[i].i); 258 cp += strlen(cp); 259 } 260 } 261 262 *cp++ = '\0'; 263 264 return (ret); 265 } 266 267 /* 268 * ipath_print -- print out an ename, ipath, or both with '@' between them 269 */ 270 void 271 ipath_print(int flags, const char *ename, const struct ipath *ipp) 272 { 273 if (ename != NULL) { 274 out(flags|O_NONL, ename); 275 if (ipp != NULL) 276 out(flags|O_NONL, "@"); 277 } 278 if (ipp != NULL) { 279 char *sep = ""; 280 281 while (ipp->s != NULL) { 282 out(flags|O_NONL, "%s%s%d", sep, ipp->s, ipp->i); 283 ipp++; 284 sep = "/"; 285 } 286 } 287 } 288 289 /*ARGSUSED*/ 290 static void 291 ipath_destructor(void *left, void *right, void *arg) 292 { 293 struct ipath *ipp = (struct ipath *)right; 294 295 FREE(ipp); 296 } 297 298 /* 299 * ipath_fini -- free the ipath cache 300 */ 301 void 302 ipath_fini(void) 303 { 304 lut_free(Ipaths, ipath_destructor, NULL); 305 Ipaths = NULL; 306 307 if (Nipath) { 308 stats_delete(Nipath); 309 Nipath = NULL; 310 } 311 312 if (Nbytes) { 313 stats_delete(Nbytes); 314 Nbytes = NULL; 315 } 316 } 317