4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * ipath.c -- instanced pathname module
27 * this module provides a cache of fully instantized component paths,
28 * stored in a fairly compact format.
40 #include "ipath_impl.h"
45 static struct stats
*Nipath
;
46 static struct stats
*Nbytes
;
48 static struct lut
*Ipaths
; /* the ipath cache itself */
51 * ipath_init -- initialize the ipath module
56 Nipath
= stats_new_counter("ievent.nipath", "ipath cache entries", 1);
57 Nbytes
= stats_new_counter("ievent.nbytes", "total cache size", 1);
61 * ipath_cmp -- compare two ipath entries
63 * since two ipaths containing the same components and instance
64 * numbers always point to the same cache entry, they are equal
65 * if their pointers are equal, so this function is not necessary
66 * to test if two ipaths are same. but when inserting a new ipath
67 * into the cache, we must use the same lut comparison logic as when
68 * we're searching for it, so this function must always match the
69 * itree_epnamecmp() function's logic (see below) for searching the lut.
72 ipath_cmp(struct ipath
*ipp1
, struct ipath
*ipp2
)
79 for (i
= 0; ipp1
[i
].s
!= NULL
&& ipp2
[i
].s
!= NULL
; i
++)
80 if (ipp1
[i
].s
!= ipp2
[i
].s
)
81 return (ipp2
[i
].s
- ipp1
[i
].s
);
82 else if (ipp1
[i
].i
!= ipp2
[i
].i
)
83 return (ipp2
[i
].i
- ipp1
[i
].i
);
85 if (ipp1
[i
].s
== NULL
&& ipp2
[i
].s
== NULL
)
87 else if (ipp1
[i
].s
== NULL
)
94 * ipath_epnamecmp -- compare an ipath with a struct node *epname list
96 * this function is used when searching the cache, allowing us to search
97 * a lut full of ipaths by looking directly at a struct node *epname
98 * (without having to convert it first). the comparison logic here must
99 * exactly match itree_cmp()'s logic (see above) so lut lookups use find
100 * the same node as lut inserts.
103 ipath_epnamecmp(struct ipath
*ipp
, struct node
*np
)
110 for (i
= 0; ipp
[i
].s
!= NULL
&& np
!= NULL
; i
++, np
= np
->u
.name
.next
) {
111 ASSERTinfo(np
->t
== T_NAME
, ptree_nodetype2str(np
->t
));
113 if (ipp
[i
].s
!= np
->u
.name
.s
)
114 return (np
->u
.name
.s
- ipp
[i
].s
);
118 if (np
->u
.name
.child
!= NULL
&&
119 np
->u
.name
.child
->t
== T_NUM
)
120 inum
= (int)np
->u
.name
.child
->u
.ull
;
122 config_getcompname(np
->u
.name
.cp
, NULL
, &inum
);
124 if (ipp
[i
].i
!= inum
)
125 return (inum
- ipp
[i
].i
);
129 if (ipp
[i
].s
== NULL
&& np
== NULL
)
131 else if (ipp
[i
].s
== NULL
)
138 * The following functions are only used in the "itree_create_dummy()" first
139 * pass at itree creation. ipath_dummy() creates paths used in the itree (see
140 * comment above add_event_dummy() for details). ipath_for_usednames() creates
141 * a different set of paths using the full names from the propagations. These
142 * are only used by ipath_dummy_lut() in order to set up the Usednames lut
143 * correctly, which in turn allows conf propteries on any alement in those
144 * names to be used in constraints.
146 struct lut
*Usednames
;
149 ipath_dummy_lut(struct arrow
*arrowp
)
151 const struct ipath
*ipp
;
153 ipp
= arrowp
->head
->myevent
->ipp_un
;
154 while (ipp
->s
!= NULL
) {
155 Usednames
= lut_add(Usednames
, (void *)ipp
->s
,
156 (void *)ipp
->s
, NULL
);
159 ipp
= arrowp
->tail
->myevent
->ipp_un
;
160 while (ipp
->s
!= NULL
) {
161 Usednames
= lut_add(Usednames
, (void *)ipp
->s
,
162 (void *)ipp
->s
, NULL
);
168 ipath_dummy(struct node
*np
, struct ipath
*ipp
)
173 while (ipp
[1].s
!= NULL
)
175 if (strcmp(ipp
[0].s
, np
->u
.name
.last
->u
.name
.s
) == 0)
178 ret
= MALLOC(sizeof (*ret
) * 2);
179 ret
[0].s
= np
->u
.name
.last
->u
.name
.s
;
182 if ((ipp
= lut_lookup(Ipaths
, (void *)ret
,
183 (lut_cmp
)ipath_cmp
)) != NULL
) {
187 Ipaths
= lut_add(Ipaths
, (void *)ret
, (void *)ret
, (lut_cmp
)ipath_cmp
);
188 stats_counter_bump(Nipath
);
189 stats_counter_add(Nbytes
, 2 * sizeof (struct ipath
));
194 ipath_for_usednames(struct node
*np
)
196 struct ipath
*ret
, *ipp
;
200 for (np2
= np
; np2
!= NULL
; np2
= np2
->u
.name
.next
)
202 ret
= MALLOC(sizeof (*ret
) * (i
+ 1));
203 for (i
= 0, np2
= np
; np2
!= NULL
; np2
= np2
->u
.name
.next
) {
204 ret
[i
].s
= np2
->u
.name
.s
;
208 if ((ipp
= lut_lookup(Ipaths
, (void *)ret
,
209 (lut_cmp
)ipath_cmp
)) != NULL
) {
213 Ipaths
= lut_add(Ipaths
, (void *)ret
, (void *)ret
, (lut_cmp
)ipath_cmp
);
214 stats_counter_bump(Nipath
);
215 stats_counter_add(Nbytes
, (i
+ 1) * sizeof (struct ipath
));
220 * ipath -- find instanced path in cache, or add it if necessary
223 ipath(struct node
*np
)
230 if ((ret
= lut_lookup(Ipaths
, (void *)np
,
231 (lut_cmp
)ipath_epnamecmp
)) != NULL
)
232 return (ret
); /* already in cache */
235 * not in cache, make new cache entry.
236 * start by counting the length of the name.
240 while (namep
!= NULL
) {
241 ASSERTinfo(namep
->t
== T_NAME
, ptree_nodetype2str(namep
->t
));
243 namep
= namep
->u
.name
.next
;
248 /* allocate array for name and last NULL entry */
249 ret
= MALLOC(sizeof (*ret
) * (count
+ 1));
252 /* fill in ipath entry */
255 while (namep
!= NULL
) {
257 ret
[i
].s
= namep
->u
.name
.s
;
258 if (namep
->u
.name
.child
!= NULL
&&
259 namep
->u
.name
.child
->t
== T_NUM
)
260 ret
[i
].i
= (int)namep
->u
.name
.child
->u
.ull
;
262 config_getcompname(namep
->u
.name
.cp
, NULL
, &ret
[i
].i
);
264 namep
= namep
->u
.name
.next
;
267 /* add it to the cache */
268 Ipaths
= lut_add(Ipaths
, (void *)ret
, (void *)ret
,
271 stats_counter_bump(Nipath
);
272 stats_counter_add(Nbytes
, (count
+ 1) * sizeof (struct ipath
));
278 * ipath2str -- convert ename and ipath to class@path string
280 * if both ename and ipp are provided (non-NULL), the resulting string
281 * will be "class@path". otherwise, the string will just contain the
282 * event class name (e.g. "ereport.io.pci.device") or just the path
283 * name (e.g. "mothboard0/hostbridge0/pcibus1/pcidev0/pcifn1"), depending
284 * on which argument is non-NULL.
287 ipath2str(const char *ename
, const struct ipath
*ipp
)
294 /* count up length of class string */
296 len
+= strlen(ename
);
298 /* count up length of path string, including slash separators */
300 for (i
= 0; ipp
[i
].s
!= NULL
; i
++) {
301 /* add slash separator, but no leading slash */
304 len
+= snprintf(NULL
, 0, "%s%d", ipp
[i
].s
, ipp
[i
].i
);
308 if (ename
!= NULL
&& ipp
!= NULL
)
309 len
++; /* room for '@' */
311 len
++; /* room for final '\0' */
313 cp
= ret
= MALLOC(len
);
316 /* construct class string */
317 (void) strcpy(cp
, ename
);
321 /* if doing both strings, put '@' between them */
322 if (ename
!= NULL
&& ipp
!= NULL
)
326 /* construct path string */
327 for (i
= 0; ipp
[i
].s
!= NULL
; i
++) {
330 (void) snprintf(cp
, &ret
[len
] - cp
, "%s%d",
342 ipathlastcomp(const struct ipath
*ipp
)
346 for (i
= 0; ipp
[i
].s
!= NULL
; i
++)
349 out(O_ALTFP
, "newfme: add %s to Usednames", ipp
[i
- 1].s
);
350 Usednames
= lut_add(Usednames
, (void *)ipp
[i
- 1].s
,
351 (void *)ipp
[i
- 1].s
, NULL
);
355 * ipath2strlen -- calculate the len of what ipath2str() would return
358 ipath2strlen(const char *ename
, const struct ipath
*ipp
)
363 /* count up length of class string */
365 len
+= strlen(ename
);
367 /* count up length of path string, including slash separators */
369 for (i
= 0; ipp
[i
].s
!= NULL
; i
++) {
370 /* add slash separator, but no leading slash */
373 len
+= snprintf(NULL
, 0, "%s%d", ipp
[i
].s
, ipp
[i
].i
);
377 if (ename
!= NULL
&& ipp
!= NULL
)
378 len
++; /* room for '@' */
384 * ipath_print -- print out an ename, ipath, or both with '@' between them
387 ipath_print(int flags
, const char *ename
, const struct ipath
*ipp
)
390 out(flags
|O_NONL
, ename
);
392 out(flags
|O_NONL
, "@");
397 while (ipp
->s
!= NULL
) {
398 out(flags
|O_NONL
, "%s%s%d", sep
, ipp
->s
, ipp
->i
);
407 ipath_destructor(void *left
, void *right
, void *arg
)
409 struct ipath
*ipp
= (struct ipath
*)right
;
415 * ipath_fini -- free the ipath cache
420 lut_free(Ipaths
, ipath_destructor
, NULL
);
422 lut_free(Usednames
, NULL
, NULL
);
426 stats_delete(Nipath
);
431 stats_delete(Nbytes
);