ipath.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik/*
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * CDDL HEADER START
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik *
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * The contents of this file are subject to the terms of the
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * Common Development and Distribution License, Version 1.0 only
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * (the "License"). You may not use this file except in compliance
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * with the License.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik *
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * or http://www.opensolaris.org/os/licensing.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * See the License for the specific language governing permissions
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * and limitations under the License.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik *
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * When distributing Covered Code, include this CDDL HEADER in each
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * If applicable, add the following below this CDDL HEADER, with the
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * fields enclosed by brackets "[]" replaced with your own identifying
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * information: Portions Copyright [yyyy] [name of copyright owner]
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik *
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * CDDL HEADER END
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik */
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik/*
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * Use is subject to license terms.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik *
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * ipath.c -- instanced pathname module
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik *
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * this module provides a cache of fully instantized component paths,
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * stored in a fairly compact format.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik */
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#pragma ident "%Z%%M% %I% %E% SMI"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include <stdio.h>
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include <string.h>
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "alloc.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "out.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "lut.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "tree.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "ptree.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "itree.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "ipath.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "stats.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "eval.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "config.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikstatic struct stats *Nipath;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikstatic struct stats *Nbytes;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik/* an ipath cache entry is an array of these, with s==NULL at the end */
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikstruct ipath {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik const char *s; /* component name (in stable) */
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik int i; /* instance number */
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik};
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikstatic struct lut *Ipaths; /* the ipath cache itself */
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik/*
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * ipath_init -- initialize the ipath module
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik */
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikvoid
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikipath_init(void)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik{
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik Nipath = stats_new_counter("ievent.nipath", "ipath cache entries", 1);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik Nbytes = stats_new_counter("ievent.nbytes", "total cache size", 1);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik}
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik/*
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * ipath_cmp -- compare two ipath entries
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik *
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * since two ipaths containing the same components and instance
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * numbers always point to the same cache entry, they are equal
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * if their pointers are equal, so this function is not necessary
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * to test if two ipaths are same. but when inserting a new ipath
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * into the cache, we must use the same lut comparison logic as when
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * we're searching for it, so this function must always match the
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * itree_epnamecmp() function's logic (see below) for searching the lut.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik */
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikstatic int
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikipath_cmp(struct ipath *ipp1, struct ipath *ipp2)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik{
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik int i;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik ASSERT(ipp1 != NULL);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik ASSERT(ipp2 != NULL);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik for (i = 0; ipp1[i].s != NULL && ipp2[i].s != NULL; i++)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (ipp1[i].s != ipp2[i].s)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return (ipp2[i].s - ipp1[i].s);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik else if (ipp1[i].i != ipp2[i].i)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return (ipp2[i].i - ipp1[i].i);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (ipp1[i].s == NULL && ipp2[i].s == NULL)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return (0);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik else if (ipp1[i].s == NULL)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return (1);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik else
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return (-1);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik}
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik/*
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * ipath_epnamecmp -- compare an ipath with a struct node *epname list
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik *
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * this function is used when searching the cache, allowing us to search
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * a lut full of ipaths by looking directly at a struct node *epname
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * (without having to convert it first). the comparison logic here must
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * exactly match itree_cmp()'s logic (see above) so lut lookups use find
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik * the same node as lut inserts.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik */
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikstatic int
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikipath_epnamecmp(struct ipath *ipp, struct node *np)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik{
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik int i;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik ASSERT(np != NULL);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik ASSERT(ipp != NULL);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik for (i = 0; ipp[i].s != NULL && np != NULL; i++, np = np->u.name.next) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik ASSERTinfo(np->t == T_NAME, ptree_nodetype2str(np->t));
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (ipp[i].s != np->u.name.s)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return (np->u.name.s - ipp[i].s);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik else {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik int inum;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (np->u.name.child != NULL &&
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik np->u.name.child->t == T_NUM)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik inum = (int)np->u.name.child->u.ull;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik else
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik config_getcompname(np->u.name.cp, NULL, &inum);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (ipp[i].i != inum)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return (inum - ipp[i].i);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik }
}
if (ipp[i].s == NULL && np == NULL)
return (0);
else if (ipp[i].s == NULL)
return (1);
else
return (-1);
}
/*
* ipath -- find instanced path in cache, or add it if necessary
*/
const struct ipath *
ipath(struct node *np)
{
struct ipath *ret;
int count;
struct node *namep;
int i;
if ((ret = lut_lookup(Ipaths, (void *)np,
(lut_cmp)ipath_epnamecmp)) != NULL)
return (ret); /* already in cache */
/*
* not in cache, make new cache entry.
* start by counting the length of the name.
*/
count = 0;
namep = np;
while (namep != NULL) {
ASSERTinfo(namep->t == T_NAME, ptree_nodetype2str(namep->t));
count++;
namep = namep->u.name.next;
}
ASSERT(count > 0);
/* allocate array for name and last NULL entry */
ret = MALLOC(sizeof (*ret) * (count + 1));
ret[count].s = NULL;
/* fill in ipath entry */
namep = np;
i = 0;
while (namep != NULL) {
ASSERT(i < count);
ret[i].s = namep->u.name.s;
if (namep->u.name.child != NULL &&
namep->u.name.child->t == T_NUM)
ret[i].i = (int)namep->u.name.child->u.ull;
else
config_getcompname(namep->u.name.cp, NULL, &ret[i].i);
i++;
namep = namep->u.name.next;
}
/* add it to the cache */
Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret,
(lut_cmp)ipath_cmp);
stats_counter_bump(Nipath);
stats_counter_add(Nbytes, (count + 1) * sizeof (struct ipath));
return (ret);
}
/*
* ipath2str -- convert ename and ipath to class@path string
*
* if both ename and ipp are provided (non-NULL), the resulting string
* will be "class@path". otherwise, the string will just contain the
* event class name (e.g. "ereport.io.pci.device") or just the path
* name (e.g. "mothboard0/hostbridge0/pcibus1/pcidev0/pcifn1"), depending
* on which argument is non-NULL.
*/
char *
ipath2str(const char *ename, const struct ipath *ipp)
{
int i;
size_t len = 0;
char *ret;
char *cp;
/* count up length of class string */
if (ename != NULL)
len += strlen(ename);
/* count up length of path string, including slash separators */
if (ipp != NULL) {
for (i = 0; ipp[i].s != NULL; i++) {
/* add slash separator, but no leading slash */
if (i != 0)
len++;
len += snprintf(NULL, 0, "%s%d", ipp[i].s, ipp[i].i);
}
}
if (ename != NULL && ipp != NULL)
len++; /* room for '@' */
len++; /* room for final '\0' */
cp = ret = MALLOC(len);
if (ename != NULL) {
/* construct class string */
(void) strcpy(cp, ename);
cp += strlen(cp);
}
/* if doing both strings, put '@' between them */
if (ename != NULL && ipp != NULL)
*cp++ = '@';
if (ipp != NULL) {
/* construct path string */
for (i = 0; ipp[i].s != NULL; i++) {
if (i != 0)
*cp++ = '/';
(void) snprintf(cp, &ret[len] - cp, "%s%d",
ipp[i].s, ipp[i].i);
cp += strlen(cp);
}
}
*cp++ = '\0';
return (ret);
}
/*
* ipath_print -- print out an ename, ipath, or both with '@' between them
*/
void
ipath_print(int flags, const char *ename, const struct ipath *ipp)
{
if (ename != NULL) {
out(flags|O_NONL, ename);
if (ipp != NULL)
out(flags|O_NONL, "@");
}
if (ipp != NULL) {
char *sep = "";
while (ipp->s != NULL) {
out(flags|O_NONL, "%s%s%d", sep, ipp->s, ipp->i);
ipp++;
sep = "/";
}
}
}
/*ARGSUSED*/
static void
ipath_destructor(void *left, void *right, void *arg)
{
struct ipath *ipp = (struct ipath *)right;
FREE(ipp);
}
/*
* ipath_fini -- free the ipath cache
*/
void
ipath_fini(void)
{
lut_free(Ipaths, ipath_destructor, NULL);
Ipaths = NULL;
if (Nipath) {
stats_delete(Nipath);
Nipath = NULL;
}
if (Nbytes) {
stats_delete(Nbytes);
Nbytes = NULL;
}
}