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
54436Sstephh * Common Development and Distribution License (the "License").
64436Sstephh * 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*11416SStephen.Hanson@Sun.COM * Copyright 2010 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 #include <stdio.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include "alloc.h"
340Sstevel@tonic-gate #include "out.h"
350Sstevel@tonic-gate #include "lut.h"
360Sstevel@tonic-gate #include "tree.h"
370Sstevel@tonic-gate #include "ptree.h"
380Sstevel@tonic-gate #include "itree.h"
390Sstevel@tonic-gate #include "ipath.h"
405433Saf #include "ipath_impl.h"
410Sstevel@tonic-gate #include "stats.h"
420Sstevel@tonic-gate #include "eval.h"
430Sstevel@tonic-gate #include "config.h"
440Sstevel@tonic-gate
450Sstevel@tonic-gate static struct stats *Nipath;
460Sstevel@tonic-gate static struct stats *Nbytes;
470Sstevel@tonic-gate
480Sstevel@tonic-gate static struct lut *Ipaths; /* the ipath cache itself */
490Sstevel@tonic-gate
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate * ipath_init -- initialize the ipath module
520Sstevel@tonic-gate */
530Sstevel@tonic-gate void
ipath_init(void)540Sstevel@tonic-gate ipath_init(void)
550Sstevel@tonic-gate {
560Sstevel@tonic-gate Nipath = stats_new_counter("ievent.nipath", "ipath cache entries", 1);
570Sstevel@tonic-gate Nbytes = stats_new_counter("ievent.nbytes", "total cache size", 1);
580Sstevel@tonic-gate }
590Sstevel@tonic-gate
600Sstevel@tonic-gate /*
610Sstevel@tonic-gate * ipath_cmp -- compare two ipath entries
620Sstevel@tonic-gate *
630Sstevel@tonic-gate * since two ipaths containing the same components and instance
640Sstevel@tonic-gate * numbers always point to the same cache entry, they are equal
650Sstevel@tonic-gate * if their pointers are equal, so this function is not necessary
660Sstevel@tonic-gate * to test if two ipaths are same. but when inserting a new ipath
670Sstevel@tonic-gate * into the cache, we must use the same lut comparison logic as when
680Sstevel@tonic-gate * we're searching for it, so this function must always match the
690Sstevel@tonic-gate * itree_epnamecmp() function's logic (see below) for searching the lut.
700Sstevel@tonic-gate */
710Sstevel@tonic-gate static int
ipath_cmp(struct ipath * ipp1,struct ipath * ipp2)720Sstevel@tonic-gate ipath_cmp(struct ipath *ipp1, struct ipath *ipp2)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate int i;
750Sstevel@tonic-gate
760Sstevel@tonic-gate ASSERT(ipp1 != NULL);
770Sstevel@tonic-gate ASSERT(ipp2 != NULL);
780Sstevel@tonic-gate
790Sstevel@tonic-gate for (i = 0; ipp1[i].s != NULL && ipp2[i].s != NULL; i++)
800Sstevel@tonic-gate if (ipp1[i].s != ipp2[i].s)
810Sstevel@tonic-gate return (ipp2[i].s - ipp1[i].s);
820Sstevel@tonic-gate else if (ipp1[i].i != ipp2[i].i)
830Sstevel@tonic-gate return (ipp2[i].i - ipp1[i].i);
840Sstevel@tonic-gate
850Sstevel@tonic-gate if (ipp1[i].s == NULL && ipp2[i].s == NULL)
860Sstevel@tonic-gate return (0);
870Sstevel@tonic-gate else if (ipp1[i].s == NULL)
880Sstevel@tonic-gate return (1);
890Sstevel@tonic-gate else
900Sstevel@tonic-gate return (-1);
910Sstevel@tonic-gate }
920Sstevel@tonic-gate
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate * ipath_epnamecmp -- compare an ipath with a struct node *epname list
950Sstevel@tonic-gate *
960Sstevel@tonic-gate * this function is used when searching the cache, allowing us to search
970Sstevel@tonic-gate * a lut full of ipaths by looking directly at a struct node *epname
980Sstevel@tonic-gate * (without having to convert it first). the comparison logic here must
990Sstevel@tonic-gate * exactly match itree_cmp()'s logic (see above) so lut lookups use find
1000Sstevel@tonic-gate * the same node as lut inserts.
1010Sstevel@tonic-gate */
1020Sstevel@tonic-gate static int
ipath_epnamecmp(struct ipath * ipp,struct node * np)1030Sstevel@tonic-gate ipath_epnamecmp(struct ipath *ipp, struct node *np)
1040Sstevel@tonic-gate {
1050Sstevel@tonic-gate int i;
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate ASSERT(np != NULL);
1080Sstevel@tonic-gate ASSERT(ipp != NULL);
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate for (i = 0; ipp[i].s != NULL && np != NULL; i++, np = np->u.name.next) {
1110Sstevel@tonic-gate ASSERTinfo(np->t == T_NAME, ptree_nodetype2str(np->t));
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate if (ipp[i].s != np->u.name.s)
1140Sstevel@tonic-gate return (np->u.name.s - ipp[i].s);
1150Sstevel@tonic-gate else {
1160Sstevel@tonic-gate int inum;
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate if (np->u.name.child != NULL &&
1190Sstevel@tonic-gate np->u.name.child->t == T_NUM)
1200Sstevel@tonic-gate inum = (int)np->u.name.child->u.ull;
1210Sstevel@tonic-gate else
1220Sstevel@tonic-gate config_getcompname(np->u.name.cp, NULL, &inum);
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate if (ipp[i].i != inum)
1250Sstevel@tonic-gate return (inum - ipp[i].i);
1260Sstevel@tonic-gate }
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate if (ipp[i].s == NULL && np == NULL)
1300Sstevel@tonic-gate return (0);
1310Sstevel@tonic-gate else if (ipp[i].s == NULL)
1320Sstevel@tonic-gate return (1);
1330Sstevel@tonic-gate else
1340Sstevel@tonic-gate return (-1);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate
1379874SStephen.Hanson@Sun.COM /*
1389874SStephen.Hanson@Sun.COM * The following functions are only used in the "itree_create_dummy()" first
1399874SStephen.Hanson@Sun.COM * pass at itree creation. ipath_dummy() creates paths used in the itree (see
1409874SStephen.Hanson@Sun.COM * comment above add_event_dummy() for details). ipath_for_usednames() creates
1419874SStephen.Hanson@Sun.COM * a different set of paths using the full names from the propagations. These
1429874SStephen.Hanson@Sun.COM * are only used by ipath_dummy_lut() in order to set up the Usednames lut
1439874SStephen.Hanson@Sun.COM * correctly, which in turn allows conf propteries on any alement in those
1449874SStephen.Hanson@Sun.COM * names to be used in constraints.
1459874SStephen.Hanson@Sun.COM */
1464436Sstephh struct lut *Usednames;
1474436Sstephh
1484436Sstephh void
ipath_dummy_lut(struct arrow * arrowp)1494436Sstephh ipath_dummy_lut(struct arrow *arrowp)
1504436Sstephh {
1514436Sstephh const struct ipath *ipp;
1524436Sstephh
1539874SStephen.Hanson@Sun.COM ipp = arrowp->head->myevent->ipp_un;
1544436Sstephh while (ipp->s != NULL) {
1554436Sstephh Usednames = lut_add(Usednames, (void *)ipp->s,
1564436Sstephh (void *)ipp->s, NULL);
1574436Sstephh ipp++;
1584436Sstephh }
1599874SStephen.Hanson@Sun.COM ipp = arrowp->tail->myevent->ipp_un;
1604436Sstephh while (ipp->s != NULL) {
1614436Sstephh Usednames = lut_add(Usednames, (void *)ipp->s,
1624436Sstephh (void *)ipp->s, NULL);
1634436Sstephh ipp++;
1644436Sstephh }
1654436Sstephh }
1664436Sstephh
1674436Sstephh struct ipath *
ipath_dummy(struct node * np,struct ipath * ipp)1684436Sstephh ipath_dummy(struct node *np, struct ipath *ipp)
1694436Sstephh {
1704436Sstephh struct ipath *ret;
1714436Sstephh
1724436Sstephh ret = ipp;
1734436Sstephh while (ipp[1].s != NULL)
1744436Sstephh ipp++;
1754436Sstephh if (strcmp(ipp[0].s, np->u.name.last->u.name.s) == 0)
1764436Sstephh return (ret);
1774436Sstephh
1784436Sstephh ret = MALLOC(sizeof (*ret) * 2);
1794436Sstephh ret[0].s = np->u.name.last->u.name.s;
1804436Sstephh ret[0].i = 0;
1814436Sstephh ret[1].s = NULL;
1824436Sstephh if ((ipp = lut_lookup(Ipaths, (void *)ret,
1834436Sstephh (lut_cmp)ipath_cmp)) != NULL) {
1844436Sstephh FREE(ret);
1854436Sstephh return (ipp);
1864436Sstephh }
1874436Sstephh Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret, (lut_cmp)ipath_cmp);
1884436Sstephh stats_counter_bump(Nipath);
1894436Sstephh stats_counter_add(Nbytes, 2 * sizeof (struct ipath));
1904436Sstephh return (ret);
1914436Sstephh }
1924436Sstephh
1939874SStephen.Hanson@Sun.COM struct ipath *
ipath_for_usednames(struct node * np)1949874SStephen.Hanson@Sun.COM ipath_for_usednames(struct node *np)
1959874SStephen.Hanson@Sun.COM {
1969874SStephen.Hanson@Sun.COM struct ipath *ret, *ipp;
1979874SStephen.Hanson@Sun.COM int i = 0;
1989874SStephen.Hanson@Sun.COM struct node *np2;
1999874SStephen.Hanson@Sun.COM
2009874SStephen.Hanson@Sun.COM for (np2 = np; np2 != NULL; np2 = np2->u.name.next)
2019874SStephen.Hanson@Sun.COM i++;
2029874SStephen.Hanson@Sun.COM ret = MALLOC(sizeof (*ret) * (i + 1));
2039874SStephen.Hanson@Sun.COM for (i = 0, np2 = np; np2 != NULL; np2 = np2->u.name.next) {
2049874SStephen.Hanson@Sun.COM ret[i].s = np2->u.name.s;
2059874SStephen.Hanson@Sun.COM ret[i++].i = 0;
2069874SStephen.Hanson@Sun.COM }
2079874SStephen.Hanson@Sun.COM ret[i].s = NULL;
2089874SStephen.Hanson@Sun.COM if ((ipp = lut_lookup(Ipaths, (void *)ret,
2099874SStephen.Hanson@Sun.COM (lut_cmp)ipath_cmp)) != NULL) {
2109874SStephen.Hanson@Sun.COM FREE(ret);
2119874SStephen.Hanson@Sun.COM return (ipp);
2129874SStephen.Hanson@Sun.COM }
2139874SStephen.Hanson@Sun.COM Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret, (lut_cmp)ipath_cmp);
2149874SStephen.Hanson@Sun.COM stats_counter_bump(Nipath);
2159874SStephen.Hanson@Sun.COM stats_counter_add(Nbytes, (i + 1) * sizeof (struct ipath));
2169874SStephen.Hanson@Sun.COM return (ret);
2179874SStephen.Hanson@Sun.COM }
2189874SStephen.Hanson@Sun.COM
2190Sstevel@tonic-gate /*
2200Sstevel@tonic-gate * ipath -- find instanced path in cache, or add it if necessary
2210Sstevel@tonic-gate */
2220Sstevel@tonic-gate const struct ipath *
ipath(struct node * np)2230Sstevel@tonic-gate ipath(struct node *np)
2240Sstevel@tonic-gate {
2250Sstevel@tonic-gate struct ipath *ret;
2260Sstevel@tonic-gate int count;
2270Sstevel@tonic-gate struct node *namep;
2280Sstevel@tonic-gate int i;
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate if ((ret = lut_lookup(Ipaths, (void *)np,
2310Sstevel@tonic-gate (lut_cmp)ipath_epnamecmp)) != NULL)
2320Sstevel@tonic-gate return (ret); /* already in cache */
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate * not in cache, make new cache entry.
2360Sstevel@tonic-gate * start by counting the length of the name.
2370Sstevel@tonic-gate */
2380Sstevel@tonic-gate count = 0;
2390Sstevel@tonic-gate namep = np;
2400Sstevel@tonic-gate while (namep != NULL) {
2410Sstevel@tonic-gate ASSERTinfo(namep->t == T_NAME, ptree_nodetype2str(namep->t));
2420Sstevel@tonic-gate count++;
2430Sstevel@tonic-gate namep = namep->u.name.next;
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate ASSERT(count > 0);
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate /* allocate array for name and last NULL entry */
2490Sstevel@tonic-gate ret = MALLOC(sizeof (*ret) * (count + 1));
2500Sstevel@tonic-gate ret[count].s = NULL;
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate /* fill in ipath entry */
2530Sstevel@tonic-gate namep = np;
2540Sstevel@tonic-gate i = 0;
2550Sstevel@tonic-gate while (namep != NULL) {
2560Sstevel@tonic-gate ASSERT(i < count);
2570Sstevel@tonic-gate ret[i].s = namep->u.name.s;
2580Sstevel@tonic-gate if (namep->u.name.child != NULL &&
2590Sstevel@tonic-gate namep->u.name.child->t == T_NUM)
2600Sstevel@tonic-gate ret[i].i = (int)namep->u.name.child->u.ull;
2610Sstevel@tonic-gate else
2620Sstevel@tonic-gate config_getcompname(namep->u.name.cp, NULL, &ret[i].i);
2630Sstevel@tonic-gate i++;
2640Sstevel@tonic-gate namep = namep->u.name.next;
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate /* add it to the cache */
2680Sstevel@tonic-gate Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret,
2690Sstevel@tonic-gate (lut_cmp)ipath_cmp);
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate stats_counter_bump(Nipath);
2720Sstevel@tonic-gate stats_counter_add(Nbytes, (count + 1) * sizeof (struct ipath));
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate return (ret);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate /*
2780Sstevel@tonic-gate * ipath2str -- convert ename and ipath to class@path string
2790Sstevel@tonic-gate *
2800Sstevel@tonic-gate * if both ename and ipp are provided (non-NULL), the resulting string
2810Sstevel@tonic-gate * will be "class@path". otherwise, the string will just contain the
2820Sstevel@tonic-gate * event class name (e.g. "ereport.io.pci.device") or just the path
2830Sstevel@tonic-gate * name (e.g. "mothboard0/hostbridge0/pcibus1/pcidev0/pcifn1"), depending
2840Sstevel@tonic-gate * on which argument is non-NULL.
2850Sstevel@tonic-gate */
2860Sstevel@tonic-gate char *
ipath2str(const char * ename,const struct ipath * ipp)2870Sstevel@tonic-gate ipath2str(const char *ename, const struct ipath *ipp)
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate int i;
2900Sstevel@tonic-gate size_t len = 0;
2910Sstevel@tonic-gate char *ret;
2920Sstevel@tonic-gate char *cp;
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate /* count up length of class string */
2950Sstevel@tonic-gate if (ename != NULL)
2960Sstevel@tonic-gate len += strlen(ename);
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate /* count up length of path string, including slash separators */
2990Sstevel@tonic-gate if (ipp != NULL) {
3000Sstevel@tonic-gate for (i = 0; ipp[i].s != NULL; i++) {
3010Sstevel@tonic-gate /* add slash separator, but no leading slash */
3020Sstevel@tonic-gate if (i != 0)
3030Sstevel@tonic-gate len++;
3040Sstevel@tonic-gate len += snprintf(NULL, 0, "%s%d", ipp[i].s, ipp[i].i);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate
3080Sstevel@tonic-gate if (ename != NULL && ipp != NULL)
3090Sstevel@tonic-gate len++; /* room for '@' */
3100Sstevel@tonic-gate
3110Sstevel@tonic-gate len++; /* room for final '\0' */
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate cp = ret = MALLOC(len);
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate if (ename != NULL) {
3160Sstevel@tonic-gate /* construct class string */
3170Sstevel@tonic-gate (void) strcpy(cp, ename);
3180Sstevel@tonic-gate cp += strlen(cp);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate /* if doing both strings, put '@' between them */
3220Sstevel@tonic-gate if (ename != NULL && ipp != NULL)
3230Sstevel@tonic-gate *cp++ = '@';
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate if (ipp != NULL) {
3260Sstevel@tonic-gate /* construct path string */
3270Sstevel@tonic-gate for (i = 0; ipp[i].s != NULL; i++) {
3280Sstevel@tonic-gate if (i != 0)
3290Sstevel@tonic-gate *cp++ = '/';
3300Sstevel@tonic-gate (void) snprintf(cp, &ret[len] - cp, "%s%d",
3310Sstevel@tonic-gate ipp[i].s, ipp[i].i);
3320Sstevel@tonic-gate cp += strlen(cp);
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate *cp++ = '\0';
3370Sstevel@tonic-gate
3380Sstevel@tonic-gate return (ret);
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate
341*11416SStephen.Hanson@Sun.COM void
ipathlastcomp(const struct ipath * ipp)342*11416SStephen.Hanson@Sun.COM ipathlastcomp(const struct ipath *ipp)
343*11416SStephen.Hanson@Sun.COM {
344*11416SStephen.Hanson@Sun.COM int i;
345*11416SStephen.Hanson@Sun.COM
346*11416SStephen.Hanson@Sun.COM for (i = 0; ipp[i].s != NULL; i++)
347*11416SStephen.Hanson@Sun.COM ;
348*11416SStephen.Hanson@Sun.COM
349*11416SStephen.Hanson@Sun.COM out(O_ALTFP, "newfme: add %s to Usednames", ipp[i - 1].s);
350*11416SStephen.Hanson@Sun.COM Usednames = lut_add(Usednames, (void *)ipp[i - 1].s,
351*11416SStephen.Hanson@Sun.COM (void *)ipp[i - 1].s, NULL);
352*11416SStephen.Hanson@Sun.COM }
353*11416SStephen.Hanson@Sun.COM
3540Sstevel@tonic-gate /*
3551414Scindi * ipath2strlen -- calculate the len of what ipath2str() would return
3561414Scindi */
3571414Scindi size_t
ipath2strlen(const char * ename,const struct ipath * ipp)3581414Scindi ipath2strlen(const char *ename, const struct ipath *ipp)
3591414Scindi {
3601414Scindi int i;
3611414Scindi size_t len = 0;
3621414Scindi
3631414Scindi /* count up length of class string */
3641414Scindi if (ename != NULL)
3651414Scindi len += strlen(ename);
3661414Scindi
3671414Scindi /* count up length of path string, including slash separators */
3681414Scindi if (ipp != NULL) {
3691414Scindi for (i = 0; ipp[i].s != NULL; i++) {
3701414Scindi /* add slash separator, but no leading slash */
3711414Scindi if (i != 0)
3721414Scindi len++;
3731414Scindi len += snprintf(NULL, 0, "%s%d", ipp[i].s, ipp[i].i);
3741414Scindi }
3751414Scindi }
3761414Scindi
3771414Scindi if (ename != NULL && ipp != NULL)
3781414Scindi len++; /* room for '@' */
3791414Scindi
3801414Scindi return (len);
3811414Scindi }
3821414Scindi
3831414Scindi /*
3840Sstevel@tonic-gate * ipath_print -- print out an ename, ipath, or both with '@' between them
3850Sstevel@tonic-gate */
3860Sstevel@tonic-gate void
ipath_print(int flags,const char * ename,const struct ipath * ipp)3870Sstevel@tonic-gate ipath_print(int flags, const char *ename, const struct ipath *ipp)
3880Sstevel@tonic-gate {
3890Sstevel@tonic-gate if (ename != NULL) {
3900Sstevel@tonic-gate out(flags|O_NONL, ename);
3910Sstevel@tonic-gate if (ipp != NULL)
3920Sstevel@tonic-gate out(flags|O_NONL, "@");
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate if (ipp != NULL) {
3950Sstevel@tonic-gate char *sep = "";
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate while (ipp->s != NULL) {
3980Sstevel@tonic-gate out(flags|O_NONL, "%s%s%d", sep, ipp->s, ipp->i);
3990Sstevel@tonic-gate ipp++;
4000Sstevel@tonic-gate sep = "/";
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate
4050Sstevel@tonic-gate /*ARGSUSED*/
4060Sstevel@tonic-gate static void
ipath_destructor(void * left,void * right,void * arg)4070Sstevel@tonic-gate ipath_destructor(void *left, void *right, void *arg)
4080Sstevel@tonic-gate {
4090Sstevel@tonic-gate struct ipath *ipp = (struct ipath *)right;
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate FREE(ipp);
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate /*
4150Sstevel@tonic-gate * ipath_fini -- free the ipath cache
4160Sstevel@tonic-gate */
4170Sstevel@tonic-gate void
ipath_fini(void)4180Sstevel@tonic-gate ipath_fini(void)
4190Sstevel@tonic-gate {
4200Sstevel@tonic-gate lut_free(Ipaths, ipath_destructor, NULL);
4210Sstevel@tonic-gate Ipaths = NULL;
4225947Sstephh lut_free(Usednames, NULL, NULL);
4235947Sstephh Usednames = NULL;
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate if (Nipath) {
4260Sstevel@tonic-gate stats_delete(Nipath);
4270Sstevel@tonic-gate Nipath = NULL;
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate if (Nbytes) {
4310Sstevel@tonic-gate stats_delete(Nbytes);
4320Sstevel@tonic-gate Nbytes = NULL;
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate }
435