17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 525c6ff4bSstephh * Common Development and Distribution License (the "License"). 625c6ff4bSstephh * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21dde64cd7Smws 227c478bd9Sstevel@tonic-gate /* 23*cbf75e67SStephen Hanson * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h> 28d9638e54Smws #include <sys/bitmap.h> 29d9638e54Smws 307c478bd9Sstevel@tonic-gate #include <strings.h> 31d9638e54Smws #include <limits.h> 327c478bd9Sstevel@tonic-gate #include <alloca.h> 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <fmd_alloc.h> 357c478bd9Sstevel@tonic-gate #include <fmd_string.h> 36d9638e54Smws #include <fmd_module.h> 377c478bd9Sstevel@tonic-gate #include <fmd_dispq.h> 387c478bd9Sstevel@tonic-gate #include <fmd_subr.h> 39d9638e54Smws 407c478bd9Sstevel@tonic-gate #include <fmd.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate static fmd_dispqelem_t * 437c478bd9Sstevel@tonic-gate fmd_dispqelem_create(const char *name) 447c478bd9Sstevel@tonic-gate { 457c478bd9Sstevel@tonic-gate fmd_dispqelem_t *dep = fmd_alloc(sizeof (fmd_dispqelem_t), FMD_SLEEP); 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate dep->dq_name = fmd_strdup(name, FMD_SLEEP); 487c478bd9Sstevel@tonic-gate dep->dq_link = NULL; 497c478bd9Sstevel@tonic-gate dep->dq_hashlen = fmd.d_str_buckets; 507c478bd9Sstevel@tonic-gate dep->dq_hash = fmd_zalloc(sizeof (void *) * dep->dq_hashlen, FMD_SLEEP); 517c478bd9Sstevel@tonic-gate dep->dq_list = NULL; 527c478bd9Sstevel@tonic-gate dep->dq_refs = 0; 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate return (dep); 557c478bd9Sstevel@tonic-gate } 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate static void 587c478bd9Sstevel@tonic-gate fmd_dispqelem_destroy(fmd_dispqelem_t *dep) 597c478bd9Sstevel@tonic-gate { 607c478bd9Sstevel@tonic-gate fmd_dispqlist_t *dlp, *nlp; 617c478bd9Sstevel@tonic-gate fmd_dispqelem_t *p, *q; 627c478bd9Sstevel@tonic-gate uint_t i; 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate for (dlp = dep->dq_list; dlp != NULL; dlp = nlp) { 657c478bd9Sstevel@tonic-gate nlp = dlp->dq_next; 667c478bd9Sstevel@tonic-gate fmd_free(dlp, sizeof (fmd_dispqlist_t)); 677c478bd9Sstevel@tonic-gate } 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate for (i = 0; i < dep->dq_hashlen; i++) { 707c478bd9Sstevel@tonic-gate for (p = dep->dq_hash[i]; p != NULL; p = q) { 717c478bd9Sstevel@tonic-gate q = p->dq_link; 727c478bd9Sstevel@tonic-gate fmd_dispqelem_destroy(p); 737c478bd9Sstevel@tonic-gate } 747c478bd9Sstevel@tonic-gate } 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate fmd_free(dep->dq_hash, sizeof (void *) * dep->dq_hashlen); 777c478bd9Sstevel@tonic-gate fmd_strfree(dep->dq_name); 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate fmd_free(dep, sizeof (fmd_dispqelem_t)); 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate static fmd_dispqelem_t * 837c478bd9Sstevel@tonic-gate fmd_dispqelem_lookup(fmd_dispqelem_t *dep, const char *name) 847c478bd9Sstevel@tonic-gate { 857c478bd9Sstevel@tonic-gate uint_t h = fmd_strhash(name) % dep->dq_hashlen; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate for (dep = dep->dq_hash[h]; dep != NULL; dep = dep->dq_link) { 887c478bd9Sstevel@tonic-gate if (strcmp(dep->dq_name, name) == 0) 897c478bd9Sstevel@tonic-gate break; 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate return (dep); 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate fmd_dispq_t * 967c478bd9Sstevel@tonic-gate fmd_dispq_create(void) 977c478bd9Sstevel@tonic-gate { 987c478bd9Sstevel@tonic-gate fmd_dispq_t *dqp = fmd_alloc(sizeof (fmd_dispq_t), FMD_SLEEP); 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate (void) pthread_rwlock_init(&dqp->dq_lock, NULL); 1017c478bd9Sstevel@tonic-gate dqp->dq_root = fmd_dispqelem_create(NULL); 102d9638e54Smws dqp->dq_gids = fmd_idspace_create("dispq_gids", 1, INT_MAX); 103d9638e54Smws dqp->dq_gmax = 0; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate return (dqp); 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate void 1097c478bd9Sstevel@tonic-gate fmd_dispq_destroy(fmd_dispq_t *dqp) 1107c478bd9Sstevel@tonic-gate { 1117c478bd9Sstevel@tonic-gate fmd_dispqelem_destroy(dqp->dq_root); 112d9638e54Smws fmd_idspace_destroy(dqp->dq_gids); 1137c478bd9Sstevel@tonic-gate fmd_free(dqp, sizeof (fmd_dispq_t)); 1147c478bd9Sstevel@tonic-gate } 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate static fmd_dispqelem_t * 1177c478bd9Sstevel@tonic-gate fmd_dispq_insert_one(fmd_dispqelem_t *dep, const char *name) 1187c478bd9Sstevel@tonic-gate { 1197c478bd9Sstevel@tonic-gate uint_t h = fmd_strhash(name) % dep->dq_hashlen; 1207c478bd9Sstevel@tonic-gate fmd_dispqelem_t *ep; 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate for (ep = dep->dq_hash[h]; ep != NULL; ep = ep->dq_link) { 1237c478bd9Sstevel@tonic-gate if (strcmp(ep->dq_name, name) == 0) 1247c478bd9Sstevel@tonic-gate break; 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate if (ep == NULL) { 1287c478bd9Sstevel@tonic-gate ep = fmd_dispqelem_create(name); 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate ep->dq_link = dep->dq_hash[h]; 1317c478bd9Sstevel@tonic-gate dep->dq_hash[h] = ep; 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate dep->dq_refs++; 1347c478bd9Sstevel@tonic-gate ASSERT(dep->dq_refs != 0); 1357c478bd9Sstevel@tonic-gate } 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate return (ep); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate void 141d9638e54Smws fmd_dispq_insert(fmd_dispq_t *dqp, fmd_eventq_t *eqp, const char *pattern) 1427c478bd9Sstevel@tonic-gate { 1437c478bd9Sstevel@tonic-gate char *p, *q, *s = fmd_strdup(pattern, FMD_SLEEP); 1447c478bd9Sstevel@tonic-gate size_t len = strlen(s); 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate fmd_dispqlist_t *dlp = fmd_alloc(sizeof (fmd_dispqlist_t), FMD_SLEEP); 1477c478bd9Sstevel@tonic-gate fmd_dispqelem_t *dep; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate (void) pthread_rwlock_wrlock(&dqp->dq_lock); 1507c478bd9Sstevel@tonic-gate dep = dqp->dq_root; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate for (p = strtok_r(s, ".", &q); p != NULL; p = strtok_r(NULL, ".", &q)) 1537c478bd9Sstevel@tonic-gate dep = fmd_dispq_insert_one(dep, p); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate dlp->dq_next = dep->dq_list; 156d9638e54Smws dlp->dq_eventq = eqp; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate dep->dq_list = dlp; 1597c478bd9Sstevel@tonic-gate dep->dq_refs++; 1607c478bd9Sstevel@tonic-gate ASSERT(dep->dq_refs != 0); 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&dqp->dq_lock); 1637c478bd9Sstevel@tonic-gate fmd_free(s, len + 1); 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate static void 1677c478bd9Sstevel@tonic-gate fmd_dispq_delete_one(fmd_dispqelem_t *dep, 168d9638e54Smws fmd_eventq_t *eqp, int patc, char *patv[]) 1697c478bd9Sstevel@tonic-gate { 1707c478bd9Sstevel@tonic-gate fmd_dispqlist_t *lp, **lpp; 1717c478bd9Sstevel@tonic-gate fmd_dispqelem_t *ep, **epp; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate uint_t h = fmd_strhash(patv[0]) % dep->dq_hashlen; 1747c478bd9Sstevel@tonic-gate epp = &dep->dq_hash[h]; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate for (ep = *epp; ep != NULL; ep = ep->dq_link) { 1777c478bd9Sstevel@tonic-gate if (strcmp(ep->dq_name, patv[0]) != 0) 1787c478bd9Sstevel@tonic-gate epp = &ep->dq_link; 1797c478bd9Sstevel@tonic-gate else 1807c478bd9Sstevel@tonic-gate break; 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate ASSERT(ep != NULL); 1847c478bd9Sstevel@tonic-gate lpp = &ep->dq_list; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate if (patc > 1) { 187d9638e54Smws fmd_dispq_delete_one(ep, eqp, patc - 1, patv + 1); 1887c478bd9Sstevel@tonic-gate } else { 1897c478bd9Sstevel@tonic-gate for (lp = *lpp; lp != NULL; lp = lp->dq_next) { 190d9638e54Smws if (lp->dq_eventq != eqp) 1917c478bd9Sstevel@tonic-gate lpp = &lp->dq_next; 1927c478bd9Sstevel@tonic-gate else 1937c478bd9Sstevel@tonic-gate break; 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 196d9638e54Smws if (lp != NULL) { 1977c478bd9Sstevel@tonic-gate *lpp = lp->dq_next; 1987c478bd9Sstevel@tonic-gate fmd_free(lp, sizeof (fmd_dispqlist_t)); 1997c478bd9Sstevel@tonic-gate ASSERT(ep->dq_refs != 0); 2007c478bd9Sstevel@tonic-gate ep->dq_refs--; 2017c478bd9Sstevel@tonic-gate } 202d9638e54Smws } 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate if (ep->dq_refs == 0) { 2057c478bd9Sstevel@tonic-gate *epp = ep->dq_link; 2067c478bd9Sstevel@tonic-gate fmd_dispqelem_destroy(ep); 2077c478bd9Sstevel@tonic-gate ASSERT(dep->dq_refs != 0); 2087c478bd9Sstevel@tonic-gate dep->dq_refs--; 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate void 213d9638e54Smws fmd_dispq_delete(fmd_dispq_t *dqp, fmd_eventq_t *eqp, const char *pattern) 2147c478bd9Sstevel@tonic-gate { 2157c478bd9Sstevel@tonic-gate char *p, *q, *s = fmd_strdup(pattern, FMD_SLEEP); 2167c478bd9Sstevel@tonic-gate size_t len = strlen(s); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate char **patv = fmd_zalloc(sizeof (char *) * (len / 2 + 1), FMD_SLEEP); 2197c478bd9Sstevel@tonic-gate int patc = 0; 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate for (p = strtok_r(s, ".", &q); p != NULL; p = strtok_r(NULL, ".", &q)) 2227c478bd9Sstevel@tonic-gate patv[patc++] = p; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate if (patc != 0) { 2257c478bd9Sstevel@tonic-gate (void) pthread_rwlock_wrlock(&dqp->dq_lock); 226d9638e54Smws fmd_dispq_delete_one(dqp->dq_root, eqp, patc, patv); 2277c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&dqp->dq_lock); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate fmd_free(patv, sizeof (char *) * (len / 2 + 1)); 2317c478bd9Sstevel@tonic-gate fmd_free(s, len + 1); 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate static uint_t 235d9638e54Smws fmd_dispq_dispatch_one(fmd_dispqelem_t *dep, ulong_t *gids, 236d9638e54Smws fmd_event_t *ep, const char *class) 2377c478bd9Sstevel@tonic-gate { 2387c478bd9Sstevel@tonic-gate fmd_dispqlist_t *dlp; 2397c478bd9Sstevel@tonic-gate uint_t n = 0; 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate for (dlp = dep->dq_list; dlp != NULL; dlp = dlp->dq_next, n++) { 242d9638e54Smws id_t gid = dlp->dq_eventq->eq_sgid; 2437c478bd9Sstevel@tonic-gate 244d9638e54Smws if (BT_TEST(gids, gid) != 0) 245d9638e54Smws continue; /* event already queued for this group ID */ 246d9638e54Smws 247d9638e54Smws TRACE((FMD_DBG_DISP, "queue %p (%s) for %s (%d)", (void *)ep, 248d9638e54Smws class, dlp->dq_eventq->eq_mod->mod_name, (int)gid)); 249d9638e54Smws 250d9638e54Smws fmd_eventq_insert_at_time(dlp->dq_eventq, ep); 251d9638e54Smws BT_SET(gids, gid); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate return (n); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * This function handles the descent of the dispatch queue hash tree on behalf 2597c478bd9Sstevel@tonic-gate * of fmd_dispq_dispatch(). We recursively descend the tree along two paths: 2607c478bd9Sstevel@tonic-gate * one using the next component of the split class string (stored in cv[0]) and 2617c478bd9Sstevel@tonic-gate * one using the wildcard "*" in place of cv[0]. If we can't find either one, 2627c478bd9Sstevel@tonic-gate * our descent stops. If we descend far enough to consume cv[] (i.e. cc == 0), 2637c478bd9Sstevel@tonic-gate * then we have a match and we dispatch the event to all modules at that level. 2647c478bd9Sstevel@tonic-gate * We also dispatch the event to modules found at any interior "*" element, 2657c478bd9Sstevel@tonic-gate * allowing a subscription to "a.*" to match "a.b", "a.b.c", and so on. 2667c478bd9Sstevel@tonic-gate */ 2677c478bd9Sstevel@tonic-gate static uint_t 268d9638e54Smws fmd_dispq_dispatchv(fmd_dispqelem_t *root, ulong_t *gids, 2697c478bd9Sstevel@tonic-gate fmd_event_t *ep, const char *class, uint_t cc, char *cv[]) 2707c478bd9Sstevel@tonic-gate { 2717c478bd9Sstevel@tonic-gate fmd_dispqelem_t *dep; 2727c478bd9Sstevel@tonic-gate uint_t n = 0; 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate if (cc == 0) 275d9638e54Smws return (fmd_dispq_dispatch_one(root, gids, ep, class)); 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if ((dep = fmd_dispqelem_lookup(root, cv[0])) != NULL) 278d9638e54Smws n += fmd_dispq_dispatchv(dep, gids, ep, class, cc - 1, cv + 1); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate if ((dep = fmd_dispqelem_lookup(root, "*")) != NULL) 281d9638e54Smws n += fmd_dispq_dispatchv(dep, gids, ep, class, cc - 1, cv + 1); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate if (dep != NULL && cc > 1) 284d9638e54Smws n += fmd_dispq_dispatch_one(dep, gids, ep, class); 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate return (n); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 289d9638e54Smws static uint_t 290d9638e54Smws fmd_dispq_tokenize(const char *class, 291d9638e54Smws char *buf, size_t buflen, char **cv, uint_t cvlen) 2927c478bd9Sstevel@tonic-gate { 293d9638e54Smws uint_t cc = 0; 294d9638e54Smws char *p, *q; 2957c478bd9Sstevel@tonic-gate 296d9638e54Smws (void) strlcpy(buf, class, buflen); 297d9638e54Smws 298d9638e54Smws for (p = strtok_r(buf, ".", &q); p != NULL; p = strtok_r(NULL, ".", &q)) 299d9638e54Smws cv[cc++] = p; 300d9638e54Smws 301d9638e54Smws if (cc > cvlen) 302d9638e54Smws fmd_panic("fmd_dispq_tokenize() cc=%u > cv[%u]\n", cc, cvlen); 303d9638e54Smws 304d9638e54Smws return (cc); 305d9638e54Smws } 306d9638e54Smws 307d9638e54Smws void 308d9638e54Smws fmd_dispq_dispatch_gid(fmd_dispq_t *dqp, 309d9638e54Smws fmd_event_t *ep, const char *class, id_t gid) 310d9638e54Smws { 311dde64cd7Smws size_t cvbuflen = strlen(class) + 1; 312d9638e54Smws uint_t cc, cvlen, n = 0; 313d9638e54Smws char *c, *cvbuf, **cv; 314d9638e54Smws 315d9638e54Smws ulong_t *gids; 316d9638e54Smws uint_t glen, i; 317d9638e54Smws 318d9638e54Smws nvlist_t **nva; 319d9638e54Smws uint_t nvi, nvc = 0; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate fmd_event_hold(ep); 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate /* 3247c478bd9Sstevel@tonic-gate * If the event is a protocol list.suspect event with one or more 325d9638e54Smws * events contained inside of it, determine the maximum length of all 326d9638e54Smws * class strings that will be used in this dispatch operation. 3277c478bd9Sstevel@tonic-gate */ 32825c6ff4bSstephh if (FMD_EVENT_TYPE(ep) == FMD_EVT_PROTOCOL && 32925c6ff4bSstephh (strcmp(class, FM_LIST_SUSPECT_CLASS) == 0 || 33025c6ff4bSstephh strcmp(class, FM_LIST_REPAIRED_CLASS) == 0 || 331*cbf75e67SStephen Hanson strcmp(class, FM_LIST_RESOLVED_CLASS) == 0 || 33225c6ff4bSstephh strcmp(class, FM_LIST_UPDATED_CLASS) == 0) && 33325c6ff4bSstephh nvlist_lookup_nvlist_array(FMD_EVENT_NVL(ep), FM_SUSPECT_FAULT_LIST, 33425c6ff4bSstephh &nva, &nvc) == 0) { 335d9638e54Smws for (nvi = 0; nvi < nvc; nvi++) { 336d9638e54Smws if (nvlist_lookup_string(nva[nvi], FM_CLASS, &c) == 0) { 337dde64cd7Smws size_t len = strlen(c) + 1; 338d9638e54Smws cvbuflen = MAX(cvbuflen, len); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate } 341d9638e54Smws } 342d9638e54Smws 343dde64cd7Smws cvbuf = alloca(cvbuflen); 344d9638e54Smws cvlen = cvbuflen / 2 + 1; 345d9638e54Smws cv = alloca(sizeof (char *) * cvlen); 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* 348d9638e54Smws * With dq_lock held as reader, allocate a bitmap on the stack for 349d9638e54Smws * group IDs for this dispatch, zero it, and then do the dispatch. 3507c478bd9Sstevel@tonic-gate */ 3517c478bd9Sstevel@tonic-gate (void) pthread_rwlock_rdlock(&dqp->dq_lock); 352d9638e54Smws 353d9638e54Smws glen = BT_BITOUL(dqp->dq_gmax); 354d9638e54Smws gids = alloca(sizeof (ulong_t) * glen); 355d9638e54Smws bzero(gids, sizeof (ulong_t) * glen); 356d9638e54Smws 357d9638e54Smws /* 358d9638e54Smws * If we are dispatching to only a single gid, set all bits in the 359d9638e54Smws * group IDs mask and then clear only the bit for the specified gid. 360d9638e54Smws */ 361d9638e54Smws if (gid >= 0) { 362d9638e54Smws for (i = 0; i < glen; i++) 363d9638e54Smws gids[i] = BT_ULMAXMASK; 364d9638e54Smws BT_CLEAR(gids, gid); 365d9638e54Smws } 366d9638e54Smws 367d9638e54Smws for (nvi = 0; nvi < nvc; nvi++) { 368d9638e54Smws if (nvlist_lookup_string(nva[nvi], FM_CLASS, &c) == 0) { 369d9638e54Smws cc = fmd_dispq_tokenize(c, cvbuf, cvbuflen, cv, cvlen); 370d9638e54Smws n += fmd_dispq_dispatchv(dqp->dq_root, 371d9638e54Smws gids, ep, c, cc, cv); 372d9638e54Smws } 373d9638e54Smws } 374d9638e54Smws 375d9638e54Smws cc = fmd_dispq_tokenize(class, cvbuf, cvbuflen, cv, cvlen); 376d9638e54Smws n += fmd_dispq_dispatchv(dqp->dq_root, gids, ep, class, cc, cv); 377d9638e54Smws 3787c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&dqp->dq_lock); 379d9638e54Smws fmd_dprintf(FMD_DBG_DISP, "%s dispatched to %u queues\n", class, n); 3807c478bd9Sstevel@tonic-gate 381d9638e54Smws /* 382d9638e54Smws * If the total subscriptions matched (n) was zero and we're not being 383d9638e54Smws * called for a single gid, send the event to the self-diagnosis module. 384d9638e54Smws */ 385d9638e54Smws if (n == 0 && gid < 0 && fmd.d_self != NULL) 3867c478bd9Sstevel@tonic-gate fmd_eventq_insert_at_time(fmd.d_self->mod_queue, ep); 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate fmd_event_rele(ep); 3897c478bd9Sstevel@tonic-gate } 390d9638e54Smws 391d9638e54Smws void 392d9638e54Smws fmd_dispq_dispatch(fmd_dispq_t *dqp, fmd_event_t *ep, const char *class) 393d9638e54Smws { 394d9638e54Smws fmd_dispq_dispatch_gid(dqp, ep, class, -1); 395d9638e54Smws } 396d9638e54Smws 397d9638e54Smws id_t 398d9638e54Smws fmd_dispq_getgid(fmd_dispq_t *dqp, void *cookie) 399d9638e54Smws { 400d9638e54Smws id_t gid; 401d9638e54Smws 402d9638e54Smws (void) pthread_rwlock_wrlock(&dqp->dq_lock); 403d9638e54Smws 404d9638e54Smws gid = fmd_idspace_alloc_min(dqp->dq_gids, cookie); 405d9638e54Smws dqp->dq_gmax = MAX(dqp->dq_gmax, gid); 406d9638e54Smws 407d9638e54Smws (void) pthread_rwlock_unlock(&dqp->dq_lock); 408d9638e54Smws 409d9638e54Smws return (gid); 410d9638e54Smws } 411d9638e54Smws 412d9638e54Smws void 413d9638e54Smws fmd_dispq_delgid(fmd_dispq_t *dqp, id_t gid) 414d9638e54Smws { 415d9638e54Smws (void) pthread_rwlock_wrlock(&dqp->dq_lock); 416d9638e54Smws 417d9638e54Smws ASSERT(fmd_idspace_contains(dqp->dq_gids, gid)); 418d9638e54Smws (void) fmd_idspace_free(dqp->dq_gids, gid); 419d9638e54Smws 420d9638e54Smws (void) pthread_rwlock_unlock(&dqp->dq_lock); 421d9638e54Smws } 422