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 55f25dc2aSgavinm * Common Development and Distribution License (the "License"). 65f25dc2aSgavinm * 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 */ 215f25dc2aSgavinm 227c478bd9Sstevel@tonic-gate /* 23*b5016cbbSstephh * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate * 267c478bd9Sstevel@tonic-gate * fme.c -- fault management exercise module 277c478bd9Sstevel@tonic-gate * 287c478bd9Sstevel@tonic-gate * this module provides the simulated fault management exercise. 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <stdio.h> 347c478bd9Sstevel@tonic-gate #include <stdlib.h> 357c478bd9Sstevel@tonic-gate #include <string.h> 367c478bd9Sstevel@tonic-gate #include <strings.h> 377c478bd9Sstevel@tonic-gate #include <ctype.h> 387c478bd9Sstevel@tonic-gate #include <alloca.h> 397c478bd9Sstevel@tonic-gate #include <libnvpair.h> 407c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h> 417c478bd9Sstevel@tonic-gate #include <fm/fmd_api.h> 427c478bd9Sstevel@tonic-gate #include "alloc.h" 437c478bd9Sstevel@tonic-gate #include "out.h" 447c478bd9Sstevel@tonic-gate #include "stats.h" 457c478bd9Sstevel@tonic-gate #include "stable.h" 467c478bd9Sstevel@tonic-gate #include "literals.h" 477c478bd9Sstevel@tonic-gate #include "lut.h" 487c478bd9Sstevel@tonic-gate #include "tree.h" 497c478bd9Sstevel@tonic-gate #include "ptree.h" 507c478bd9Sstevel@tonic-gate #include "itree.h" 517c478bd9Sstevel@tonic-gate #include "ipath.h" 527c478bd9Sstevel@tonic-gate #include "fme.h" 537c478bd9Sstevel@tonic-gate #include "evnv.h" 547c478bd9Sstevel@tonic-gate #include "eval.h" 557c478bd9Sstevel@tonic-gate #include "config.h" 567c478bd9Sstevel@tonic-gate #include "platform.h" 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* imported from eft.c... */ 597c478bd9Sstevel@tonic-gate extern char *Autoclose; 607aec1d6eScindi extern int Dupclose; 617c478bd9Sstevel@tonic-gate extern hrtime_t Hesitate; 627c478bd9Sstevel@tonic-gate extern nv_alloc_t Eft_nv_hdl; 630cc1f05eSjrutt extern int Max_fme; 647aec1d6eScindi extern fmd_hdl_t *Hdl; 657aec1d6eScindi 667aec1d6eScindi static int Istat_need_save; 67*b5016cbbSstephh static int Serd_need_save; 6808f6c065Sgavinm void istat_save(void); 69*b5016cbbSstephh void serd_save(void); 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* fme under construction is global so we can free it on module abort */ 727c478bd9Sstevel@tonic-gate static struct fme *Nfmep; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate static const char *Undiag_reason; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate static int Nextid = 0; 777c478bd9Sstevel@tonic-gate 780cc1f05eSjrutt static int Open_fme_count = 0; /* Count of open FMEs */ 790cc1f05eSjrutt 807c478bd9Sstevel@tonic-gate /* list of fault management exercises underway */ 817c478bd9Sstevel@tonic-gate static struct fme { 827c478bd9Sstevel@tonic-gate struct fme *next; /* next exercise */ 837c478bd9Sstevel@tonic-gate unsigned long long ull; /* time when fme was created */ 847c478bd9Sstevel@tonic-gate int id; /* FME id */ 857c478bd9Sstevel@tonic-gate struct cfgdata *cfgdata; /* full configuration data */ 867c478bd9Sstevel@tonic-gate struct lut *eventtree; /* propagation tree for this FME */ 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * The initial error report that created this FME is kept in 897c478bd9Sstevel@tonic-gate * two forms. e0 points to the instance tree node and is used 907c478bd9Sstevel@tonic-gate * by fme_eval() as the starting point for the inference 917c478bd9Sstevel@tonic-gate * algorithm. e0r is the event handle FMD passed to us when 927c478bd9Sstevel@tonic-gate * the ereport first arrived and is used when setting timers, 937c478bd9Sstevel@tonic-gate * which are always relative to the time of this initial 947c478bd9Sstevel@tonic-gate * report. 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate struct event *e0; 977c478bd9Sstevel@tonic-gate fmd_event_t *e0r; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate id_t timer; /* for setting an fmd time-out */ 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate struct event *ecurrent; /* ereport under consideration */ 1027c478bd9Sstevel@tonic-gate struct event *suspects; /* current suspect list */ 1037c478bd9Sstevel@tonic-gate struct event *psuspects; /* previous suspect list */ 1047c478bd9Sstevel@tonic-gate int nsuspects; /* count of suspects */ 1057c478bd9Sstevel@tonic-gate int nonfault; /* zero if all suspects T_FAULT */ 1067c478bd9Sstevel@tonic-gate int posted_suspects; /* true if we've posted a diagnosis */ 1077c478bd9Sstevel@tonic-gate int uniqobs; /* number of unique events observed */ 1087c478bd9Sstevel@tonic-gate int peek; /* just peeking, don't track suspects */ 1090cc1f05eSjrutt int overflow; /* true if overflow FME */ 1107c478bd9Sstevel@tonic-gate enum fme_state { 1117c478bd9Sstevel@tonic-gate FME_NOTHING = 5000, /* not evaluated yet */ 1127c478bd9Sstevel@tonic-gate FME_WAIT, /* need to wait for more info */ 1137c478bd9Sstevel@tonic-gate FME_CREDIBLE, /* suspect list is credible */ 1147aec1d6eScindi FME_DISPROVED, /* no valid suspects found */ 1157aec1d6eScindi FME_DEFERRED /* don't know yet (k-count not met) */ 1167c478bd9Sstevel@tonic-gate } state; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate unsigned long long pull; /* time passed since created */ 1197c478bd9Sstevel@tonic-gate unsigned long long wull; /* wait until this time for re-eval */ 1207c478bd9Sstevel@tonic-gate struct event *observations; /* observation list */ 1217c478bd9Sstevel@tonic-gate struct lut *globals; /* values of global variables */ 1227c478bd9Sstevel@tonic-gate /* fmd interfacing */ 1237c478bd9Sstevel@tonic-gate fmd_hdl_t *hdl; /* handle for talking with fmd */ 1247c478bd9Sstevel@tonic-gate fmd_case_t *fmcase; /* what fmd 'case' we associate with */ 1257c478bd9Sstevel@tonic-gate /* stats */ 1267c478bd9Sstevel@tonic-gate struct stats *Rcount; 1277c478bd9Sstevel@tonic-gate struct stats *Hcallcount; 1287c478bd9Sstevel@tonic-gate struct stats *Rcallcount; 1297c478bd9Sstevel@tonic-gate struct stats *Ccallcount; 1307c478bd9Sstevel@tonic-gate struct stats *Ecallcount; 1317c478bd9Sstevel@tonic-gate struct stats *Tcallcount; 1327c478bd9Sstevel@tonic-gate struct stats *Marrowcount; 1337c478bd9Sstevel@tonic-gate struct stats *diags; 1347c478bd9Sstevel@tonic-gate } *FMElist, *EFMElist, *ClosedFMEs; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate static struct case_list { 1377c478bd9Sstevel@tonic-gate fmd_case_t *fmcase; 1387c478bd9Sstevel@tonic-gate struct case_list *next; 1397c478bd9Sstevel@tonic-gate } *Undiagablecaselist; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate static void fme_eval(struct fme *fmep, fmd_event_t *ffep); 1427c478bd9Sstevel@tonic-gate static enum fme_state hypothesise(struct fme *fmep, struct event *ep, 1437aec1d6eScindi unsigned long long at_latest_by, unsigned long long *pdelay); 1447c478bd9Sstevel@tonic-gate static struct node *eventprop_lookup(struct event *ep, const char *propname); 1457c478bd9Sstevel@tonic-gate static struct node *pathstring2epnamenp(char *path); 146*b5016cbbSstephh static void publish_undiagnosable(fmd_hdl_t *hdl, fmd_event_t *ffep, 147*b5016cbbSstephh fmd_case_t *fmcase); 1487c478bd9Sstevel@tonic-gate static void restore_suspects(struct fme *fmep); 1497c478bd9Sstevel@tonic-gate static void save_suspects(struct fme *fmep); 1507c478bd9Sstevel@tonic-gate static void destroy_fme(struct fme *f); 1517c478bd9Sstevel@tonic-gate static void fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep, 1527c478bd9Sstevel@tonic-gate const char *eventstring, const struct ipath *ipp, nvlist_t *nvl); 15308f6c065Sgavinm static void istat_counter_reset_cb(struct istat_entry *entp, 15408f6c065Sgavinm struct stats *statp, const struct ipath *ipp); 155*b5016cbbSstephh static void serd_reset_cb(struct serd_entry *entp, void *unused, 156*b5016cbbSstephh const struct ipath *ipp); 157*b5016cbbSstephh static void destroy_fme_bufs(struct fme *fp); 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate static struct fme * 1607c478bd9Sstevel@tonic-gate alloc_fme(void) 1617c478bd9Sstevel@tonic-gate { 1627c478bd9Sstevel@tonic-gate struct fme *fmep; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate fmep = MALLOC(sizeof (*fmep)); 1657c478bd9Sstevel@tonic-gate bzero(fmep, sizeof (*fmep)); 1667c478bd9Sstevel@tonic-gate return (fmep); 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * fme_ready -- called when all initialization of the FME (except for 1717c478bd9Sstevel@tonic-gate * stats) has completed successfully. Adds the fme to global lists 1727c478bd9Sstevel@tonic-gate * and establishes its stats. 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate static struct fme * 1757c478bd9Sstevel@tonic-gate fme_ready(struct fme *fmep) 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate char nbuf[100]; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate Nfmep = NULL; /* don't need to free this on module abort now */ 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate if (EFMElist) { 1827c478bd9Sstevel@tonic-gate EFMElist->next = fmep; 1837c478bd9Sstevel@tonic-gate EFMElist = fmep; 1847c478bd9Sstevel@tonic-gate } else 1857c478bd9Sstevel@tonic-gate FMElist = EFMElist = fmep; 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate (void) sprintf(nbuf, "fme%d.Rcount", fmep->id); 1887c478bd9Sstevel@tonic-gate fmep->Rcount = stats_new_counter(nbuf, "ereports received", 0); 1897c478bd9Sstevel@tonic-gate (void) sprintf(nbuf, "fme%d.Hcall", fmep->id); 1907c478bd9Sstevel@tonic-gate fmep->Hcallcount = stats_new_counter(nbuf, "calls to hypothesise()", 1); 1917c478bd9Sstevel@tonic-gate (void) sprintf(nbuf, "fme%d.Rcall", fmep->id); 1927c478bd9Sstevel@tonic-gate fmep->Rcallcount = stats_new_counter(nbuf, 1937c478bd9Sstevel@tonic-gate "calls to requirements_test()", 1); 1947c478bd9Sstevel@tonic-gate (void) sprintf(nbuf, "fme%d.Ccall", fmep->id); 1957c478bd9Sstevel@tonic-gate fmep->Ccallcount = stats_new_counter(nbuf, "calls to causes_test()", 1); 1967c478bd9Sstevel@tonic-gate (void) sprintf(nbuf, "fme%d.Ecall", fmep->id); 1977c478bd9Sstevel@tonic-gate fmep->Ecallcount = 1987c478bd9Sstevel@tonic-gate stats_new_counter(nbuf, "calls to effects_test()", 1); 1997c478bd9Sstevel@tonic-gate (void) sprintf(nbuf, "fme%d.Tcall", fmep->id); 2007c478bd9Sstevel@tonic-gate fmep->Tcallcount = stats_new_counter(nbuf, "calls to triggered()", 1); 2017c478bd9Sstevel@tonic-gate (void) sprintf(nbuf, "fme%d.Marrow", fmep->id); 2027c478bd9Sstevel@tonic-gate fmep->Marrowcount = stats_new_counter(nbuf, 2037c478bd9Sstevel@tonic-gate "arrows marked by mark_arrows()", 1); 2047c478bd9Sstevel@tonic-gate (void) sprintf(nbuf, "fme%d.diags", fmep->id); 2057c478bd9Sstevel@tonic-gate fmep->diags = stats_new_counter(nbuf, "suspect lists diagnosed", 0); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB2, "newfme: config snapshot contains..."); 2087c478bd9Sstevel@tonic-gate config_print(O_ALTFP|O_VERB2, fmep->cfgdata->cooked); 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate return (fmep); 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 213*b5016cbbSstephh extern void ipath_dummy_lut(struct arrow *); 214*b5016cbbSstephh extern struct lut *itree_create_dummy(const char *, const struct ipath *); 215*b5016cbbSstephh 216*b5016cbbSstephh /* ARGSUSED */ 217*b5016cbbSstephh static void 218*b5016cbbSstephh set_needed_arrows(struct event *ep, struct event *ep2, struct fme *fmep) 219*b5016cbbSstephh { 220*b5016cbbSstephh struct bubble *bp; 221*b5016cbbSstephh struct arrowlist *ap; 222*b5016cbbSstephh 223*b5016cbbSstephh for (bp = itree_next_bubble(ep, NULL); bp; 224*b5016cbbSstephh bp = itree_next_bubble(ep, bp)) { 225*b5016cbbSstephh if (bp->t != B_FROM) 226*b5016cbbSstephh continue; 227*b5016cbbSstephh for (ap = itree_next_arrow(bp, NULL); ap; 228*b5016cbbSstephh ap = itree_next_arrow(bp, ap)) { 229*b5016cbbSstephh ap->arrowp->pnode->u.arrow.needed = 1; 230*b5016cbbSstephh ipath_dummy_lut(ap->arrowp); 231*b5016cbbSstephh } 232*b5016cbbSstephh } 233*b5016cbbSstephh } 234*b5016cbbSstephh 235*b5016cbbSstephh /* ARGSUSED */ 236*b5016cbbSstephh static void 237*b5016cbbSstephh unset_needed_arrows(struct event *ep, struct event *ep2, struct fme *fmep) 238*b5016cbbSstephh { 239*b5016cbbSstephh struct bubble *bp; 240*b5016cbbSstephh struct arrowlist *ap; 241*b5016cbbSstephh 242*b5016cbbSstephh for (bp = itree_next_bubble(ep, NULL); bp; 243*b5016cbbSstephh bp = itree_next_bubble(ep, bp)) { 244*b5016cbbSstephh if (bp->t != B_FROM) 245*b5016cbbSstephh continue; 246*b5016cbbSstephh for (ap = itree_next_arrow(bp, NULL); ap; 247*b5016cbbSstephh ap = itree_next_arrow(bp, ap)) 248*b5016cbbSstephh ap->arrowp->pnode->u.arrow.needed = 0; 249*b5016cbbSstephh } 250*b5016cbbSstephh } 251*b5016cbbSstephh 252*b5016cbbSstephh static void globals_destructor(void *left, void *right, void *arg); 253*b5016cbbSstephh static void clear_arrows(struct event *ep, struct event *ep2, struct fme *fmep); 254*b5016cbbSstephh 255*b5016cbbSstephh static void 256*b5016cbbSstephh prune_propagations(const char *e0class, const struct ipath *e0ipp) 257*b5016cbbSstephh { 258*b5016cbbSstephh char nbuf[100]; 259*b5016cbbSstephh unsigned long long my_delay = TIMEVAL_EVENTUALLY; 260*b5016cbbSstephh extern struct lut *Usednames; 261*b5016cbbSstephh 262*b5016cbbSstephh Nfmep = alloc_fme(); 263*b5016cbbSstephh Nfmep->id = Nextid; 264*b5016cbbSstephh Nfmep->state = FME_NOTHING; 265*b5016cbbSstephh Nfmep->eventtree = itree_create_dummy(e0class, e0ipp); 266*b5016cbbSstephh if ((Nfmep->e0 = 267*b5016cbbSstephh itree_lookup(Nfmep->eventtree, e0class, e0ipp)) == NULL) { 268*b5016cbbSstephh out(O_ALTFP, "prune_propagations: e0 not in instance tree"); 269*b5016cbbSstephh itree_free(Nfmep->eventtree); 270*b5016cbbSstephh FREE(Nfmep); 271*b5016cbbSstephh Nfmep = NULL; 272*b5016cbbSstephh return; 273*b5016cbbSstephh } 274*b5016cbbSstephh Nfmep->ecurrent = Nfmep->observations = Nfmep->e0; 275*b5016cbbSstephh Nfmep->e0->count++; 276*b5016cbbSstephh 277*b5016cbbSstephh (void) sprintf(nbuf, "fme%d.Rcount", Nfmep->id); 278*b5016cbbSstephh Nfmep->Rcount = stats_new_counter(nbuf, "ereports received", 0); 279*b5016cbbSstephh (void) sprintf(nbuf, "fme%d.Hcall", Nfmep->id); 280*b5016cbbSstephh Nfmep->Hcallcount = 281*b5016cbbSstephh stats_new_counter(nbuf, "calls to hypothesise()", 1); 282*b5016cbbSstephh (void) sprintf(nbuf, "fme%d.Rcall", Nfmep->id); 283*b5016cbbSstephh Nfmep->Rcallcount = stats_new_counter(nbuf, 284*b5016cbbSstephh "calls to requirements_test()", 1); 285*b5016cbbSstephh (void) sprintf(nbuf, "fme%d.Ccall", Nfmep->id); 286*b5016cbbSstephh Nfmep->Ccallcount = 287*b5016cbbSstephh stats_new_counter(nbuf, "calls to causes_test()", 1); 288*b5016cbbSstephh (void) sprintf(nbuf, "fme%d.Ecall", Nfmep->id); 289*b5016cbbSstephh Nfmep->Ecallcount = 290*b5016cbbSstephh stats_new_counter(nbuf, "calls to effects_test()", 1); 291*b5016cbbSstephh (void) sprintf(nbuf, "fme%d.Tcall", Nfmep->id); 292*b5016cbbSstephh Nfmep->Tcallcount = stats_new_counter(nbuf, "calls to triggered()", 1); 293*b5016cbbSstephh (void) sprintf(nbuf, "fme%d.Marrow", Nfmep->id); 294*b5016cbbSstephh Nfmep->Marrowcount = stats_new_counter(nbuf, 295*b5016cbbSstephh "arrows marked by mark_arrows()", 1); 296*b5016cbbSstephh (void) sprintf(nbuf, "fme%d.diags", Nfmep->id); 297*b5016cbbSstephh Nfmep->diags = stats_new_counter(nbuf, "suspect lists diagnosed", 0); 298*b5016cbbSstephh 299*b5016cbbSstephh Nfmep->peek = 1; 300*b5016cbbSstephh lut_walk(Nfmep->eventtree, (lut_cb)unset_needed_arrows, (void *)Nfmep); 301*b5016cbbSstephh lut_free(Usednames, NULL, NULL); 302*b5016cbbSstephh Usednames = NULL; 303*b5016cbbSstephh lut_walk(Nfmep->eventtree, (lut_cb)clear_arrows, (void *)Nfmep); 304*b5016cbbSstephh (void) hypothesise(Nfmep, Nfmep->e0, Nfmep->ull, &my_delay); 305*b5016cbbSstephh itree_prune(Nfmep->eventtree); 306*b5016cbbSstephh lut_walk(Nfmep->eventtree, (lut_cb)set_needed_arrows, (void *)Nfmep); 307*b5016cbbSstephh 308*b5016cbbSstephh stats_delete(Nfmep->Rcount); 309*b5016cbbSstephh stats_delete(Nfmep->Hcallcount); 310*b5016cbbSstephh stats_delete(Nfmep->Rcallcount); 311*b5016cbbSstephh stats_delete(Nfmep->Ccallcount); 312*b5016cbbSstephh stats_delete(Nfmep->Ecallcount); 313*b5016cbbSstephh stats_delete(Nfmep->Tcallcount); 314*b5016cbbSstephh stats_delete(Nfmep->Marrowcount); 315*b5016cbbSstephh stats_delete(Nfmep->diags); 316*b5016cbbSstephh itree_free(Nfmep->eventtree); 317*b5016cbbSstephh lut_free(Nfmep->globals, globals_destructor, NULL); 318*b5016cbbSstephh FREE(Nfmep); 319*b5016cbbSstephh } 320*b5016cbbSstephh 3217c478bd9Sstevel@tonic-gate static struct fme * 322*b5016cbbSstephh newfme(const char *e0class, const struct ipath *e0ipp, fmd_hdl_t *hdl, 323*b5016cbbSstephh fmd_case_t *fmcase) 3247c478bd9Sstevel@tonic-gate { 3257c478bd9Sstevel@tonic-gate struct cfgdata *cfgdata; 326*b5016cbbSstephh int init_size; 327*b5016cbbSstephh extern int alloc_total(); 3287c478bd9Sstevel@tonic-gate 329*b5016cbbSstephh init_size = alloc_total(); 330*b5016cbbSstephh out(O_ALTFP|O_STAMP, "start config_snapshot using %d bytes", init_size); 3317c478bd9Sstevel@tonic-gate if ((cfgdata = config_snapshot()) == NULL) { 3327c478bd9Sstevel@tonic-gate out(O_ALTFP, "newfme: NULL configuration"); 3337c478bd9Sstevel@tonic-gate Undiag_reason = UD_NOCONF; 3347c478bd9Sstevel@tonic-gate return (NULL); 3357c478bd9Sstevel@tonic-gate } 336*b5016cbbSstephh platform_save_config(hdl, fmcase); 337*b5016cbbSstephh out(O_ALTFP|O_STAMP, "config_snapshot added %d bytes", 338*b5016cbbSstephh alloc_total() - init_size); 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate Nfmep = alloc_fme(); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate Nfmep->id = Nextid++; 3437c478bd9Sstevel@tonic-gate Nfmep->cfgdata = cfgdata; 3447c478bd9Sstevel@tonic-gate Nfmep->posted_suspects = 0; 3457c478bd9Sstevel@tonic-gate Nfmep->uniqobs = 0; 3467c478bd9Sstevel@tonic-gate Nfmep->state = FME_NOTHING; 3477c478bd9Sstevel@tonic-gate Nfmep->pull = 0ULL; 3480cc1f05eSjrutt Nfmep->overflow = 0; 3497c478bd9Sstevel@tonic-gate 350*b5016cbbSstephh Nfmep->fmcase = fmcase; 351*b5016cbbSstephh Nfmep->hdl = hdl; 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate if ((Nfmep->eventtree = itree_create(cfgdata->cooked)) == NULL) { 3547c478bd9Sstevel@tonic-gate out(O_ALTFP, "newfme: NULL instance tree"); 3557c478bd9Sstevel@tonic-gate Undiag_reason = UD_INSTFAIL; 3567c478bd9Sstevel@tonic-gate config_free(cfgdata); 357*b5016cbbSstephh destroy_fme_bufs(Nfmep); 3587c478bd9Sstevel@tonic-gate FREE(Nfmep); 3597c478bd9Sstevel@tonic-gate Nfmep = NULL; 3607c478bd9Sstevel@tonic-gate return (NULL); 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate itree_ptree(O_ALTFP|O_VERB2, Nfmep->eventtree); 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate if ((Nfmep->e0 = 3667c478bd9Sstevel@tonic-gate itree_lookup(Nfmep->eventtree, e0class, e0ipp)) == NULL) { 3677c478bd9Sstevel@tonic-gate out(O_ALTFP, "newfme: e0 not in instance tree"); 3687c478bd9Sstevel@tonic-gate Undiag_reason = UD_BADEVENTI; 3697c478bd9Sstevel@tonic-gate itree_free(Nfmep->eventtree); 3707c478bd9Sstevel@tonic-gate config_free(cfgdata); 371*b5016cbbSstephh destroy_fme_bufs(Nfmep); 3727c478bd9Sstevel@tonic-gate FREE(Nfmep); 3737c478bd9Sstevel@tonic-gate Nfmep = NULL; 3747c478bd9Sstevel@tonic-gate return (NULL); 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate return (fme_ready(Nfmep)); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate void 3817c478bd9Sstevel@tonic-gate fme_fini(void) 3827c478bd9Sstevel@tonic-gate { 3837c478bd9Sstevel@tonic-gate struct fme *sfp, *fp; 3847c478bd9Sstevel@tonic-gate struct case_list *ucasep, *nextcasep; 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate ucasep = Undiagablecaselist; 3877c478bd9Sstevel@tonic-gate while (ucasep != NULL) { 3887c478bd9Sstevel@tonic-gate nextcasep = ucasep->next; 3897c478bd9Sstevel@tonic-gate FREE(ucasep); 3907c478bd9Sstevel@tonic-gate ucasep = nextcasep; 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate Undiagablecaselist = NULL; 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* clean up closed fmes */ 3957c478bd9Sstevel@tonic-gate fp = ClosedFMEs; 3967c478bd9Sstevel@tonic-gate while (fp != NULL) { 3977c478bd9Sstevel@tonic-gate sfp = fp->next; 3987c478bd9Sstevel@tonic-gate destroy_fme(fp); 3997c478bd9Sstevel@tonic-gate fp = sfp; 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate ClosedFMEs = NULL; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate fp = FMElist; 4047c478bd9Sstevel@tonic-gate while (fp != NULL) { 4057c478bd9Sstevel@tonic-gate sfp = fp->next; 4067c478bd9Sstevel@tonic-gate destroy_fme(fp); 4077c478bd9Sstevel@tonic-gate fp = sfp; 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate FMElist = EFMElist = NULL; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* if we were in the middle of creating an fme, free it now */ 4127c478bd9Sstevel@tonic-gate if (Nfmep) { 4137c478bd9Sstevel@tonic-gate destroy_fme(Nfmep); 4147c478bd9Sstevel@tonic-gate Nfmep = NULL; 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * Allocated space for a buffer name. 20 bytes allows for 4207c478bd9Sstevel@tonic-gate * a ridiculous 9,999,999 unique observations. 4217c478bd9Sstevel@tonic-gate */ 4227c478bd9Sstevel@tonic-gate #define OBBUFNMSZ 20 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate /* 4257c478bd9Sstevel@tonic-gate * serialize_observation 4267c478bd9Sstevel@tonic-gate * 4277c478bd9Sstevel@tonic-gate * Create a recoverable version of the current observation 4287c478bd9Sstevel@tonic-gate * (f->ecurrent). We keep a serialized version of each unique 4297c478bd9Sstevel@tonic-gate * observation in order that we may resume correctly the fme in the 4307c478bd9Sstevel@tonic-gate * correct state if eft or fmd crashes and we're restarted. 4317c478bd9Sstevel@tonic-gate */ 4327c478bd9Sstevel@tonic-gate static void 4337c478bd9Sstevel@tonic-gate serialize_observation(struct fme *fp, const char *cls, const struct ipath *ipp) 4347c478bd9Sstevel@tonic-gate { 4357c478bd9Sstevel@tonic-gate size_t pkdlen; 4367c478bd9Sstevel@tonic-gate char tmpbuf[OBBUFNMSZ]; 4377c478bd9Sstevel@tonic-gate char *pkd = NULL; 4387c478bd9Sstevel@tonic-gate char *estr; 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate (void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", fp->uniqobs); 4417c478bd9Sstevel@tonic-gate estr = ipath2str(cls, ipp); 4427c478bd9Sstevel@tonic-gate fmd_buf_create(fp->hdl, fp->fmcase, tmpbuf, strlen(estr) + 1); 4437c478bd9Sstevel@tonic-gate fmd_buf_write(fp->hdl, fp->fmcase, tmpbuf, (void *)estr, 4447c478bd9Sstevel@tonic-gate strlen(estr) + 1); 4457c478bd9Sstevel@tonic-gate FREE(estr); 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate if (fp->ecurrent != NULL && fp->ecurrent->nvp != NULL) { 4487c478bd9Sstevel@tonic-gate (void) snprintf(tmpbuf, 4497c478bd9Sstevel@tonic-gate OBBUFNMSZ, "observed%d.nvp", fp->uniqobs); 4507c478bd9Sstevel@tonic-gate if (nvlist_xpack(fp->ecurrent->nvp, 4517c478bd9Sstevel@tonic-gate &pkd, &pkdlen, NV_ENCODE_XDR, &Eft_nv_hdl) != 0) 4527c478bd9Sstevel@tonic-gate out(O_DIE|O_SYS, "pack of observed nvl failed"); 4537c478bd9Sstevel@tonic-gate fmd_buf_create(fp->hdl, fp->fmcase, tmpbuf, pkdlen); 4547c478bd9Sstevel@tonic-gate fmd_buf_write(fp->hdl, fp->fmcase, tmpbuf, (void *)pkd, pkdlen); 4557c478bd9Sstevel@tonic-gate FREE(pkd); 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate fp->uniqobs++; 4597c478bd9Sstevel@tonic-gate fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_NOBS, (void *)&fp->uniqobs, 4607c478bd9Sstevel@tonic-gate sizeof (fp->uniqobs)); 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate /* 4647c478bd9Sstevel@tonic-gate * init_fme_bufs -- We keep several bits of state about an fme for 4657c478bd9Sstevel@tonic-gate * use if eft or fmd crashes and we're restarted. 4667c478bd9Sstevel@tonic-gate */ 4677c478bd9Sstevel@tonic-gate static void 4687c478bd9Sstevel@tonic-gate init_fme_bufs(struct fme *fp) 4697c478bd9Sstevel@tonic-gate { 4707c478bd9Sstevel@tonic-gate fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_PULL, sizeof (fp->pull)); 4717c478bd9Sstevel@tonic-gate fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_PULL, (void *)&fp->pull, 4727c478bd9Sstevel@tonic-gate sizeof (fp->pull)); 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_ID, sizeof (fp->id)); 4757c478bd9Sstevel@tonic-gate fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_ID, (void *)&fp->id, 4767c478bd9Sstevel@tonic-gate sizeof (fp->id)); 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_NOBS, sizeof (fp->uniqobs)); 4797c478bd9Sstevel@tonic-gate fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_NOBS, (void *)&fp->uniqobs, 4807c478bd9Sstevel@tonic-gate sizeof (fp->uniqobs)); 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_POSTD, 4837c478bd9Sstevel@tonic-gate sizeof (fp->posted_suspects)); 4847c478bd9Sstevel@tonic-gate fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_POSTD, 4857c478bd9Sstevel@tonic-gate (void *)&fp->posted_suspects, sizeof (fp->posted_suspects)); 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate static void 4897c478bd9Sstevel@tonic-gate destroy_fme_bufs(struct fme *fp) 4907c478bd9Sstevel@tonic-gate { 4917c478bd9Sstevel@tonic-gate char tmpbuf[OBBUFNMSZ]; 4927c478bd9Sstevel@tonic-gate int o; 4937c478bd9Sstevel@tonic-gate 494*b5016cbbSstephh platform_restore_config(fp->hdl, fp->fmcase); 4957c478bd9Sstevel@tonic-gate fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_CFGLEN); 4967c478bd9Sstevel@tonic-gate fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_CFG); 4977c478bd9Sstevel@tonic-gate fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_PULL); 4987c478bd9Sstevel@tonic-gate fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_ID); 4997c478bd9Sstevel@tonic-gate fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_POSTD); 5007c478bd9Sstevel@tonic-gate fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_NOBS); 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate for (o = 0; o < fp->uniqobs; o++) { 5037c478bd9Sstevel@tonic-gate (void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", o); 5047c478bd9Sstevel@tonic-gate fmd_buf_destroy(fp->hdl, fp->fmcase, tmpbuf); 5057c478bd9Sstevel@tonic-gate (void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d.nvp", o); 5067c478bd9Sstevel@tonic-gate fmd_buf_destroy(fp->hdl, fp->fmcase, tmpbuf); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate * reconstitute_observations -- convert a case's serialized observations 5127c478bd9Sstevel@tonic-gate * back into struct events. Returns zero if all observations are 5137c478bd9Sstevel@tonic-gate * successfully reconstituted. 5147c478bd9Sstevel@tonic-gate */ 5157c478bd9Sstevel@tonic-gate static int 5167c478bd9Sstevel@tonic-gate reconstitute_observations(struct fme *fmep) 5177c478bd9Sstevel@tonic-gate { 5187c478bd9Sstevel@tonic-gate struct event *ep; 5197c478bd9Sstevel@tonic-gate struct node *epnamenp = NULL; 5207c478bd9Sstevel@tonic-gate size_t pkdlen; 5217c478bd9Sstevel@tonic-gate char *pkd = NULL; 5227c478bd9Sstevel@tonic-gate char *tmpbuf = alloca(OBBUFNMSZ); 5237c478bd9Sstevel@tonic-gate char *sepptr; 5247c478bd9Sstevel@tonic-gate char *estr; 5257c478bd9Sstevel@tonic-gate int ocnt; 5267c478bd9Sstevel@tonic-gate int elen; 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate for (ocnt = 0; ocnt < fmep->uniqobs; ocnt++) { 5297c478bd9Sstevel@tonic-gate (void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", ocnt); 5307c478bd9Sstevel@tonic-gate elen = fmd_buf_size(fmep->hdl, fmep->fmcase, tmpbuf); 5317c478bd9Sstevel@tonic-gate if (elen == 0) { 5327c478bd9Sstevel@tonic-gate out(O_ALTFP, 5337c478bd9Sstevel@tonic-gate "reconstitute_observation: no %s buffer found.", 5347c478bd9Sstevel@tonic-gate tmpbuf); 5357c478bd9Sstevel@tonic-gate Undiag_reason = UD_MISSINGOBS; 5367c478bd9Sstevel@tonic-gate break; 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate estr = MALLOC(elen); 5407c478bd9Sstevel@tonic-gate fmd_buf_read(fmep->hdl, fmep->fmcase, tmpbuf, estr, elen); 5417c478bd9Sstevel@tonic-gate sepptr = strchr(estr, '@'); 5427c478bd9Sstevel@tonic-gate if (sepptr == NULL) { 5437c478bd9Sstevel@tonic-gate out(O_ALTFP, 5447c478bd9Sstevel@tonic-gate "reconstitute_observation: %s: " 5457c478bd9Sstevel@tonic-gate "missing @ separator in %s.", 5467c478bd9Sstevel@tonic-gate tmpbuf, estr); 5477c478bd9Sstevel@tonic-gate Undiag_reason = UD_MISSINGPATH; 5487c478bd9Sstevel@tonic-gate FREE(estr); 5497c478bd9Sstevel@tonic-gate break; 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate *sepptr = '\0'; 5537c478bd9Sstevel@tonic-gate if ((epnamenp = pathstring2epnamenp(sepptr + 1)) == NULL) { 5547c478bd9Sstevel@tonic-gate out(O_ALTFP, 5557c478bd9Sstevel@tonic-gate "reconstitute_observation: %s: " 5567c478bd9Sstevel@tonic-gate "trouble converting path string \"%s\" " 5577c478bd9Sstevel@tonic-gate "to internal representation.", 5587c478bd9Sstevel@tonic-gate tmpbuf, sepptr + 1); 5597c478bd9Sstevel@tonic-gate Undiag_reason = UD_MISSINGPATH; 5607c478bd9Sstevel@tonic-gate FREE(estr); 5617c478bd9Sstevel@tonic-gate break; 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate /* construct the event */ 5657c478bd9Sstevel@tonic-gate ep = itree_lookup(fmep->eventtree, 5667c478bd9Sstevel@tonic-gate stable(estr), ipath(epnamenp)); 5677c478bd9Sstevel@tonic-gate if (ep == NULL) { 5687c478bd9Sstevel@tonic-gate out(O_ALTFP, 5697c478bd9Sstevel@tonic-gate "reconstitute_observation: %s: " 5707c478bd9Sstevel@tonic-gate "lookup of \"%s\" in itree failed.", 5717c478bd9Sstevel@tonic-gate tmpbuf, ipath2str(estr, ipath(epnamenp))); 5727c478bd9Sstevel@tonic-gate Undiag_reason = UD_BADOBS; 5737c478bd9Sstevel@tonic-gate tree_free(epnamenp); 5747c478bd9Sstevel@tonic-gate FREE(estr); 5757c478bd9Sstevel@tonic-gate break; 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate tree_free(epnamenp); 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate /* 5807c478bd9Sstevel@tonic-gate * We may or may not have a saved nvlist for the observation 5817c478bd9Sstevel@tonic-gate */ 5827c478bd9Sstevel@tonic-gate (void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d.nvp", ocnt); 5837c478bd9Sstevel@tonic-gate pkdlen = fmd_buf_size(fmep->hdl, fmep->fmcase, tmpbuf); 5847c478bd9Sstevel@tonic-gate if (pkdlen != 0) { 5857c478bd9Sstevel@tonic-gate pkd = MALLOC(pkdlen); 5867c478bd9Sstevel@tonic-gate fmd_buf_read(fmep->hdl, 5877c478bd9Sstevel@tonic-gate fmep->fmcase, tmpbuf, pkd, pkdlen); 5887aec1d6eScindi ASSERT(ep->nvp == NULL); 5897c478bd9Sstevel@tonic-gate if (nvlist_xunpack(pkd, 5907c478bd9Sstevel@tonic-gate pkdlen, &ep->nvp, &Eft_nv_hdl) != 0) 5917c478bd9Sstevel@tonic-gate out(O_DIE|O_SYS, "pack of observed nvl failed"); 5927c478bd9Sstevel@tonic-gate FREE(pkd); 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate if (ocnt == 0) 5967c478bd9Sstevel@tonic-gate fmep->e0 = ep; 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate FREE(estr); 5997c478bd9Sstevel@tonic-gate fmep->ecurrent = ep; 6007c478bd9Sstevel@tonic-gate ep->count++; 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate /* link it into list of observations seen */ 6037c478bd9Sstevel@tonic-gate ep->observations = fmep->observations; 6047c478bd9Sstevel@tonic-gate fmep->observations = ep; 6057c478bd9Sstevel@tonic-gate } 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate if (ocnt == fmep->uniqobs) { 6087c478bd9Sstevel@tonic-gate (void) fme_ready(fmep); 6097c478bd9Sstevel@tonic-gate return (0); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate return (1); 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate /* 6167c478bd9Sstevel@tonic-gate * restart_fme -- called during eft initialization. Reconstitutes 6177c478bd9Sstevel@tonic-gate * an in-progress fme. 6187c478bd9Sstevel@tonic-gate */ 6197c478bd9Sstevel@tonic-gate void 6207c478bd9Sstevel@tonic-gate fme_restart(fmd_hdl_t *hdl, fmd_case_t *inprogress) 6217c478bd9Sstevel@tonic-gate { 6227c478bd9Sstevel@tonic-gate nvlist_t *defect; 6237c478bd9Sstevel@tonic-gate struct case_list *bad; 6247c478bd9Sstevel@tonic-gate struct fme *fmep; 6257c478bd9Sstevel@tonic-gate struct cfgdata *cfgdata = NULL; 6267c478bd9Sstevel@tonic-gate size_t rawsz; 627*b5016cbbSstephh struct event *ep; 628*b5016cbbSstephh char *tmpbuf = alloca(OBBUFNMSZ); 629*b5016cbbSstephh char *sepptr; 630*b5016cbbSstephh char *estr; 631*b5016cbbSstephh int elen; 632*b5016cbbSstephh struct node *epnamenp = NULL; 633*b5016cbbSstephh int init_size; 634*b5016cbbSstephh extern int alloc_total(); 635*b5016cbbSstephh 636*b5016cbbSstephh /* 637*b5016cbbSstephh * ignore solved or closed cases 638*b5016cbbSstephh */ 639*b5016cbbSstephh if (fmd_case_solved(hdl, inprogress) || 640*b5016cbbSstephh fmd_case_closed(hdl, inprogress)) 641*b5016cbbSstephh return; 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate fmep = alloc_fme(); 6447c478bd9Sstevel@tonic-gate fmep->fmcase = inprogress; 6457c478bd9Sstevel@tonic-gate fmep->hdl = hdl; 6467c478bd9Sstevel@tonic-gate 6479f8ca725Sstephh if (fmd_buf_size(hdl, inprogress, WOBUF_POSTD) == 0) { 6489f8ca725Sstephh out(O_ALTFP, "restart_fme: no saved posted status"); 6499f8ca725Sstephh Undiag_reason = UD_MISSINGINFO; 6509f8ca725Sstephh goto badcase; 6519f8ca725Sstephh } else { 6529f8ca725Sstephh fmd_buf_read(hdl, inprogress, WOBUF_POSTD, 6539f8ca725Sstephh (void *)&fmep->posted_suspects, 6549f8ca725Sstephh sizeof (fmep->posted_suspects)); 6559f8ca725Sstephh } 6569f8ca725Sstephh 657*b5016cbbSstephh if (fmd_buf_size(hdl, inprogress, WOBUF_ID) == 0) { 658*b5016cbbSstephh out(O_ALTFP, "restart_fme: no saved id"); 659*b5016cbbSstephh Undiag_reason = UD_MISSINGINFO; 6609f8ca725Sstephh goto badcase; 661*b5016cbbSstephh } else { 662*b5016cbbSstephh fmd_buf_read(hdl, inprogress, WOBUF_ID, (void *)&fmep->id, 663*b5016cbbSstephh sizeof (fmep->id)); 664*b5016cbbSstephh } 665*b5016cbbSstephh if (Nextid <= fmep->id) 666*b5016cbbSstephh Nextid = fmep->id + 1; 667*b5016cbbSstephh 668*b5016cbbSstephh out(O_ALTFP, "Replay FME %d", fmep->id); 6699f8ca725Sstephh 6707c478bd9Sstevel@tonic-gate if (fmd_buf_size(hdl, inprogress, WOBUF_CFGLEN) != sizeof (size_t)) { 6717c478bd9Sstevel@tonic-gate out(O_ALTFP, "restart_fme: No config data"); 6727c478bd9Sstevel@tonic-gate Undiag_reason = UD_MISSINGINFO; 6737c478bd9Sstevel@tonic-gate goto badcase; 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate fmd_buf_read(hdl, inprogress, WOBUF_CFGLEN, (void *)&rawsz, 6767c478bd9Sstevel@tonic-gate sizeof (size_t)); 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate if ((fmep->e0r = fmd_case_getprincipal(hdl, inprogress)) == NULL) { 6797c478bd9Sstevel@tonic-gate out(O_ALTFP, "restart_fme: No event zero"); 6807c478bd9Sstevel@tonic-gate Undiag_reason = UD_MISSINGZERO; 6817c478bd9Sstevel@tonic-gate goto badcase; 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate 684*b5016cbbSstephh if (fmd_buf_size(hdl, inprogress, WOBUF_PULL) == 0) { 685*b5016cbbSstephh out(O_ALTFP, "restart_fme: no saved wait time"); 686*b5016cbbSstephh Undiag_reason = UD_MISSINGINFO; 687*b5016cbbSstephh goto badcase; 688*b5016cbbSstephh } else { 689*b5016cbbSstephh fmd_buf_read(hdl, inprogress, WOBUF_PULL, (void *)&fmep->pull, 690*b5016cbbSstephh sizeof (fmep->pull)); 691*b5016cbbSstephh } 692*b5016cbbSstephh 693*b5016cbbSstephh if (fmd_buf_size(hdl, inprogress, WOBUF_NOBS) == 0) { 694*b5016cbbSstephh out(O_ALTFP, "restart_fme: no count of observations"); 695*b5016cbbSstephh Undiag_reason = UD_MISSINGINFO; 696*b5016cbbSstephh goto badcase; 697*b5016cbbSstephh } else { 698*b5016cbbSstephh fmd_buf_read(hdl, inprogress, WOBUF_NOBS, 699*b5016cbbSstephh (void *)&fmep->uniqobs, sizeof (fmep->uniqobs)); 700*b5016cbbSstephh } 701*b5016cbbSstephh 702*b5016cbbSstephh (void) snprintf(tmpbuf, OBBUFNMSZ, "observed0"); 703*b5016cbbSstephh elen = fmd_buf_size(fmep->hdl, fmep->fmcase, tmpbuf); 704*b5016cbbSstephh if (elen == 0) { 705*b5016cbbSstephh out(O_ALTFP, "reconstitute_observation: no %s buffer found.", 706*b5016cbbSstephh tmpbuf); 707*b5016cbbSstephh Undiag_reason = UD_MISSINGOBS; 708*b5016cbbSstephh goto badcase; 709*b5016cbbSstephh } 710*b5016cbbSstephh estr = MALLOC(elen); 711*b5016cbbSstephh fmd_buf_read(fmep->hdl, fmep->fmcase, tmpbuf, estr, elen); 712*b5016cbbSstephh sepptr = strchr(estr, '@'); 713*b5016cbbSstephh if (sepptr == NULL) { 714*b5016cbbSstephh out(O_ALTFP, "reconstitute_observation: %s: " 715*b5016cbbSstephh "missing @ separator in %s.", 716*b5016cbbSstephh tmpbuf, estr); 717*b5016cbbSstephh Undiag_reason = UD_MISSINGPATH; 718*b5016cbbSstephh FREE(estr); 719*b5016cbbSstephh goto badcase; 720*b5016cbbSstephh } 721*b5016cbbSstephh *sepptr = '\0'; 722*b5016cbbSstephh if ((epnamenp = pathstring2epnamenp(sepptr + 1)) == NULL) { 723*b5016cbbSstephh out(O_ALTFP, "reconstitute_observation: %s: " 724*b5016cbbSstephh "trouble converting path string \"%s\" " 725*b5016cbbSstephh "to internal representation.", tmpbuf, sepptr + 1); 726*b5016cbbSstephh Undiag_reason = UD_MISSINGPATH; 727*b5016cbbSstephh FREE(estr); 728*b5016cbbSstephh goto badcase; 729*b5016cbbSstephh } 730*b5016cbbSstephh prune_propagations(stable(estr), ipath(epnamenp)); 731*b5016cbbSstephh tree_free(epnamenp); 732*b5016cbbSstephh FREE(estr); 733*b5016cbbSstephh 734*b5016cbbSstephh init_size = alloc_total(); 735*b5016cbbSstephh out(O_ALTFP|O_STAMP, "start config_restore using %d bytes", init_size); 7367c478bd9Sstevel@tonic-gate cfgdata = MALLOC(sizeof (struct cfgdata)); 7377c478bd9Sstevel@tonic-gate cfgdata->cooked = NULL; 7387c478bd9Sstevel@tonic-gate cfgdata->devcache = NULL; 7397c478bd9Sstevel@tonic-gate cfgdata->cpucache = NULL; 740*b5016cbbSstephh cfgdata->cooked_refcnt = 0; 741*b5016cbbSstephh cfgdata->raw_refcnt = 1; 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate if (rawsz > 0) { 7447c478bd9Sstevel@tonic-gate if (fmd_buf_size(hdl, inprogress, WOBUF_CFG) != rawsz) { 7457c478bd9Sstevel@tonic-gate out(O_ALTFP, "restart_fme: Config data size mismatch"); 7467c478bd9Sstevel@tonic-gate Undiag_reason = UD_CFGMISMATCH; 7477c478bd9Sstevel@tonic-gate goto badcase; 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate cfgdata->begin = MALLOC(rawsz); 7507c478bd9Sstevel@tonic-gate cfgdata->end = cfgdata->nextfree = cfgdata->begin + rawsz; 7517c478bd9Sstevel@tonic-gate fmd_buf_read(hdl, 7527c478bd9Sstevel@tonic-gate inprogress, WOBUF_CFG, cfgdata->begin, rawsz); 7537c478bd9Sstevel@tonic-gate } else { 7547c478bd9Sstevel@tonic-gate cfgdata->begin = cfgdata->end = cfgdata->nextfree = NULL; 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate fmep->cfgdata = cfgdata; 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate config_cook(cfgdata); 759*b5016cbbSstephh if (cfgdata->begin) 760*b5016cbbSstephh FREE(cfgdata->begin); 761*b5016cbbSstephh cfgdata->begin = NULL; 762*b5016cbbSstephh cfgdata->end = NULL; 763*b5016cbbSstephh cfgdata->nextfree = NULL; 764*b5016cbbSstephh out(O_ALTFP|O_STAMP, "config_restore added %d bytes", 765*b5016cbbSstephh alloc_total() - init_size); 766*b5016cbbSstephh 7677c478bd9Sstevel@tonic-gate if ((fmep->eventtree = itree_create(cfgdata->cooked)) == NULL) { 7687c478bd9Sstevel@tonic-gate /* case not properly saved or irretrievable */ 7697c478bd9Sstevel@tonic-gate out(O_ALTFP, "restart_fme: NULL instance tree"); 7707c478bd9Sstevel@tonic-gate Undiag_reason = UD_INSTFAIL; 7717c478bd9Sstevel@tonic-gate goto badcase; 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate itree_ptree(O_ALTFP|O_VERB2, fmep->eventtree); 7757c478bd9Sstevel@tonic-gate 776*b5016cbbSstephh if (reconstitute_observations(fmep) != 0) 7777c478bd9Sstevel@tonic-gate goto badcase; 7787c478bd9Sstevel@tonic-gate 779*b5016cbbSstephh out(O_ALTFP|O_NONL, "FME %d replay observations: ", fmep->id); 780*b5016cbbSstephh for (ep = fmep->observations; ep; ep = ep->observations) { 781*b5016cbbSstephh out(O_ALTFP|O_NONL, " "); 782*b5016cbbSstephh itree_pevent_brief(O_ALTFP|O_NONL, ep); 7837c478bd9Sstevel@tonic-gate } 784*b5016cbbSstephh out(O_ALTFP, NULL); 7857c478bd9Sstevel@tonic-gate 7860cc1f05eSjrutt Open_fme_count++; 7870cc1f05eSjrutt 7887c478bd9Sstevel@tonic-gate /* give the diagnosis algorithm a shot at the new FME state */ 7899f8ca725Sstephh fme_eval(fmep, fmep->e0r); 7907c478bd9Sstevel@tonic-gate return; 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate badcase: 7937c478bd9Sstevel@tonic-gate if (fmep->eventtree != NULL) 7947c478bd9Sstevel@tonic-gate itree_free(fmep->eventtree); 7957c478bd9Sstevel@tonic-gate config_free(cfgdata); 7967c478bd9Sstevel@tonic-gate destroy_fme_bufs(fmep); 7977c478bd9Sstevel@tonic-gate FREE(fmep); 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate /* 8007c478bd9Sstevel@tonic-gate * Since we're unable to restart the case, add it to the undiagable 8017c478bd9Sstevel@tonic-gate * list and solve and close it as appropriate. 8027c478bd9Sstevel@tonic-gate */ 8037c478bd9Sstevel@tonic-gate bad = MALLOC(sizeof (struct case_list)); 8047c478bd9Sstevel@tonic-gate bad->next = NULL; 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate if (Undiagablecaselist != NULL) 8077c478bd9Sstevel@tonic-gate bad->next = Undiagablecaselist; 8087c478bd9Sstevel@tonic-gate Undiagablecaselist = bad; 8097c478bd9Sstevel@tonic-gate bad->fmcase = inprogress; 8107c478bd9Sstevel@tonic-gate 8119f8ca725Sstephh out(O_ALTFP|O_NONL, "[case %s (unable to restart), ", 8127c478bd9Sstevel@tonic-gate fmd_case_uuid(hdl, bad->fmcase)); 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate if (fmd_case_solved(hdl, bad->fmcase)) { 8159f8ca725Sstephh out(O_ALTFP|O_NONL, "already solved, "); 8167c478bd9Sstevel@tonic-gate } else { 8179f8ca725Sstephh out(O_ALTFP|O_NONL, "solving, "); 8187c478bd9Sstevel@tonic-gate defect = fmd_nvl_create_fault(hdl, UNDIAGNOSABLE_DEFECT, 100, 8197c478bd9Sstevel@tonic-gate NULL, NULL, NULL); 8207c478bd9Sstevel@tonic-gate if (Undiag_reason != NULL) 8217c478bd9Sstevel@tonic-gate (void) nvlist_add_string(defect, 8227c478bd9Sstevel@tonic-gate UNDIAG_REASON, Undiag_reason); 8237c478bd9Sstevel@tonic-gate fmd_case_add_suspect(hdl, bad->fmcase, defect); 8247c478bd9Sstevel@tonic-gate fmd_case_solve(hdl, bad->fmcase); 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate if (fmd_case_closed(hdl, bad->fmcase)) { 8287c478bd9Sstevel@tonic-gate out(O_ALTFP, "already closed ]"); 8297c478bd9Sstevel@tonic-gate } else { 8307c478bd9Sstevel@tonic-gate out(O_ALTFP, "closing ]"); 8317c478bd9Sstevel@tonic-gate fmd_case_close(hdl, bad->fmcase); 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate 8357aec1d6eScindi /*ARGSUSED*/ 8367aec1d6eScindi static void 8377aec1d6eScindi globals_destructor(void *left, void *right, void *arg) 8387aec1d6eScindi { 8397aec1d6eScindi struct evalue *evp = (struct evalue *)right; 8407aec1d6eScindi if (evp->t == NODEPTR) 84180ab886dSwesolows tree_free((struct node *)(uintptr_t)evp->v); 8427aec1d6eScindi evp->v = NULL; 8437aec1d6eScindi FREE(evp); 8447aec1d6eScindi } 8457aec1d6eScindi 8467c478bd9Sstevel@tonic-gate void 8477c478bd9Sstevel@tonic-gate destroy_fme(struct fme *f) 8487c478bd9Sstevel@tonic-gate { 8497c478bd9Sstevel@tonic-gate stats_delete(f->Rcount); 8507c478bd9Sstevel@tonic-gate stats_delete(f->Hcallcount); 8517c478bd9Sstevel@tonic-gate stats_delete(f->Rcallcount); 8527c478bd9Sstevel@tonic-gate stats_delete(f->Ccallcount); 8537c478bd9Sstevel@tonic-gate stats_delete(f->Ecallcount); 8547c478bd9Sstevel@tonic-gate stats_delete(f->Tcallcount); 8557c478bd9Sstevel@tonic-gate stats_delete(f->Marrowcount); 8567c478bd9Sstevel@tonic-gate stats_delete(f->diags); 8577c478bd9Sstevel@tonic-gate 8589f8ca725Sstephh if (f->eventtree != NULL) 8599f8ca725Sstephh itree_free(f->eventtree); 8609f8ca725Sstephh if (f->cfgdata != NULL) 8619f8ca725Sstephh config_free(f->cfgdata); 8627aec1d6eScindi lut_free(f->globals, globals_destructor, NULL); 8637c478bd9Sstevel@tonic-gate FREE(f); 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate static const char * 8677c478bd9Sstevel@tonic-gate fme_state2str(enum fme_state s) 8687c478bd9Sstevel@tonic-gate { 8697c478bd9Sstevel@tonic-gate switch (s) { 8707c478bd9Sstevel@tonic-gate case FME_NOTHING: return ("NOTHING"); 8717c478bd9Sstevel@tonic-gate case FME_WAIT: return ("WAIT"); 8727c478bd9Sstevel@tonic-gate case FME_CREDIBLE: return ("CREDIBLE"); 8737c478bd9Sstevel@tonic-gate case FME_DISPROVED: return ("DISPROVED"); 8747aec1d6eScindi case FME_DEFERRED: return ("DEFERRED"); 8757c478bd9Sstevel@tonic-gate default: return ("UNKNOWN"); 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate static int 8807c478bd9Sstevel@tonic-gate is_problem(enum nametype t) 8817c478bd9Sstevel@tonic-gate { 8827c478bd9Sstevel@tonic-gate return (t == N_FAULT || t == N_DEFECT || t == N_UPSET); 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate static int 8867c478bd9Sstevel@tonic-gate is_fault(enum nametype t) 8877c478bd9Sstevel@tonic-gate { 8887c478bd9Sstevel@tonic-gate return (t == N_FAULT); 8897c478bd9Sstevel@tonic-gate } 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate static int 8927c478bd9Sstevel@tonic-gate is_defect(enum nametype t) 8937c478bd9Sstevel@tonic-gate { 8947c478bd9Sstevel@tonic-gate return (t == N_DEFECT); 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate static int 8987c478bd9Sstevel@tonic-gate is_upset(enum nametype t) 8997c478bd9Sstevel@tonic-gate { 9007c478bd9Sstevel@tonic-gate return (t == N_UPSET); 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate static void 9047c478bd9Sstevel@tonic-gate fme_print(int flags, struct fme *fmep) 9057c478bd9Sstevel@tonic-gate { 9067c478bd9Sstevel@tonic-gate struct event *ep; 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate out(flags, "Fault Management Exercise %d", fmep->id); 9097c478bd9Sstevel@tonic-gate out(flags, "\t State: %s", fme_state2str(fmep->state)); 9107c478bd9Sstevel@tonic-gate out(flags|O_NONL, "\t Start time: "); 9117c478bd9Sstevel@tonic-gate ptree_timeval(flags|O_NONL, &fmep->ull); 9127c478bd9Sstevel@tonic-gate out(flags, NULL); 9137c478bd9Sstevel@tonic-gate if (fmep->wull) { 9147c478bd9Sstevel@tonic-gate out(flags|O_NONL, "\t Wait time: "); 9157c478bd9Sstevel@tonic-gate ptree_timeval(flags|O_NONL, &fmep->wull); 9167c478bd9Sstevel@tonic-gate out(flags, NULL); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate out(flags|O_NONL, "\t E0: "); 9197c478bd9Sstevel@tonic-gate if (fmep->e0) 9207c478bd9Sstevel@tonic-gate itree_pevent_brief(flags|O_NONL, fmep->e0); 9217c478bd9Sstevel@tonic-gate else 9227c478bd9Sstevel@tonic-gate out(flags|O_NONL, "NULL"); 9237c478bd9Sstevel@tonic-gate out(flags, NULL); 9247c478bd9Sstevel@tonic-gate out(flags|O_NONL, "\tObservations:"); 9257c478bd9Sstevel@tonic-gate for (ep = fmep->observations; ep; ep = ep->observations) { 9267c478bd9Sstevel@tonic-gate out(flags|O_NONL, " "); 9277c478bd9Sstevel@tonic-gate itree_pevent_brief(flags|O_NONL, ep); 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate out(flags, NULL); 9307c478bd9Sstevel@tonic-gate out(flags|O_NONL, "\tSuspect list:"); 9317c478bd9Sstevel@tonic-gate for (ep = fmep->suspects; ep; ep = ep->suspects) { 9327c478bd9Sstevel@tonic-gate out(flags|O_NONL, " "); 9337c478bd9Sstevel@tonic-gate itree_pevent_brief(flags|O_NONL, ep); 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate out(flags, NULL); 9369f8ca725Sstephh if (fmep->eventtree != NULL) { 9379f8ca725Sstephh out(flags|O_VERB2, "\t Tree:"); 9389f8ca725Sstephh itree_ptree(flags|O_VERB2, fmep->eventtree); 9399f8ca725Sstephh } 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate static struct node * 9437c478bd9Sstevel@tonic-gate pathstring2epnamenp(char *path) 9447c478bd9Sstevel@tonic-gate { 9457c478bd9Sstevel@tonic-gate char *sep = "/"; 9467c478bd9Sstevel@tonic-gate struct node *ret; 9477c478bd9Sstevel@tonic-gate char *ptr; 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate if ((ptr = strtok(path, sep)) == NULL) 9507c478bd9Sstevel@tonic-gate out(O_DIE, "pathstring2epnamenp: invalid empty class"); 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate ret = tree_iname(stable(ptr), NULL, 0); 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate while ((ptr = strtok(NULL, sep)) != NULL) 9557c478bd9Sstevel@tonic-gate ret = tree_name_append(ret, 9567c478bd9Sstevel@tonic-gate tree_iname(stable(ptr), NULL, 0)); 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate return (ret); 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate /* 9627c478bd9Sstevel@tonic-gate * for a given upset sp, increment the corresponding SERD engine. if the 9637c478bd9Sstevel@tonic-gate * SERD engine trips, return the ename and ipp of the resulting ereport. 9647c478bd9Sstevel@tonic-gate * returns true if engine tripped and *enamep and *ippp were filled in. 9657c478bd9Sstevel@tonic-gate */ 9667c478bd9Sstevel@tonic-gate static int 9677aec1d6eScindi serd_eval(struct fme *fmep, fmd_hdl_t *hdl, fmd_event_t *ffep, 9687aec1d6eScindi fmd_case_t *fmcase, struct event *sp, const char **enamep, 9697aec1d6eScindi const struct ipath **ippp) 9707c478bd9Sstevel@tonic-gate { 9717c478bd9Sstevel@tonic-gate struct node *serdinst; 9727c478bd9Sstevel@tonic-gate char *serdname; 9737aec1d6eScindi struct node *nid; 974*b5016cbbSstephh struct serd_entry *newentp; 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate ASSERT(sp->t == N_UPSET); 9777c478bd9Sstevel@tonic-gate ASSERT(ffep != NULL); 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate /* 9807c478bd9Sstevel@tonic-gate * obtain instanced SERD engine from the upset sp. from this 9817c478bd9Sstevel@tonic-gate * derive serdname, the string used to identify the SERD engine. 9827c478bd9Sstevel@tonic-gate */ 9837c478bd9Sstevel@tonic-gate serdinst = eventprop_lookup(sp, L_engine); 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate if (serdinst == NULL) 9867c478bd9Sstevel@tonic-gate return (NULL); 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate serdname = ipath2str(serdinst->u.stmt.np->u.event.ename->u.name.s, 9897c478bd9Sstevel@tonic-gate ipath(serdinst->u.stmt.np->u.event.epname)); 9907c478bd9Sstevel@tonic-gate 9917aec1d6eScindi /* handle serd engine "id" property, if there is one */ 9927aec1d6eScindi if ((nid = 9937aec1d6eScindi lut_lookup(serdinst->u.stmt.lutp, (void *)L_id, NULL)) != NULL) { 9947aec1d6eScindi struct evalue *gval; 9957aec1d6eScindi char suffixbuf[200]; 9967aec1d6eScindi char *suffix; 9977aec1d6eScindi char *nserdname; 9987aec1d6eScindi size_t nname; 9997aec1d6eScindi 10007aec1d6eScindi out(O_ALTFP|O_NONL, "serd \"%s\" id: ", serdname); 10017aec1d6eScindi ptree_name_iter(O_ALTFP|O_NONL, nid); 10027aec1d6eScindi 10037aec1d6eScindi ASSERTinfo(nid->t == T_GLOBID, ptree_nodetype2str(nid->t)); 10047aec1d6eScindi 10057aec1d6eScindi if ((gval = lut_lookup(fmep->globals, 10067aec1d6eScindi (void *)nid->u.globid.s, NULL)) == NULL) { 10077aec1d6eScindi out(O_ALTFP, " undefined"); 10087aec1d6eScindi } else if (gval->t == UINT64) { 10097aec1d6eScindi out(O_ALTFP, " %llu", gval->v); 10107aec1d6eScindi (void) sprintf(suffixbuf, "%llu", gval->v); 10117aec1d6eScindi suffix = suffixbuf; 10127aec1d6eScindi } else { 101380ab886dSwesolows out(O_ALTFP, " \"%s\"", (char *)(uintptr_t)gval->v); 101480ab886dSwesolows suffix = (char *)(uintptr_t)gval->v; 10157aec1d6eScindi } 10167aec1d6eScindi 10177aec1d6eScindi nname = strlen(serdname) + strlen(suffix) + 2; 10187aec1d6eScindi nserdname = MALLOC(nname); 10197aec1d6eScindi (void) snprintf(nserdname, nname, "%s:%s", serdname, suffix); 10207aec1d6eScindi FREE(serdname); 10217aec1d6eScindi serdname = nserdname; 10227aec1d6eScindi } 10237aec1d6eScindi 10247c478bd9Sstevel@tonic-gate if (!fmd_serd_exists(hdl, serdname)) { 10257c478bd9Sstevel@tonic-gate struct node *nN, *nT; 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate /* no SERD engine yet, so create it */ 10287c478bd9Sstevel@tonic-gate nN = lut_lookup(serdinst->u.stmt.lutp, (void *)L_N, NULL); 10297c478bd9Sstevel@tonic-gate nT = lut_lookup(serdinst->u.stmt.lutp, (void *)L_T, NULL); 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate ASSERT(nN->t == T_NUM); 10327c478bd9Sstevel@tonic-gate ASSERT(nT->t == T_TIMEVAL); 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate fmd_serd_create(hdl, serdname, (uint_t)nN->u.ull, 10357c478bd9Sstevel@tonic-gate (hrtime_t)nT->u.ull); 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate 1038*b5016cbbSstephh newentp = MALLOC(sizeof (*newentp)); 1039*b5016cbbSstephh newentp->ename = serdinst->u.stmt.np->u.event.ename->u.name.s; 1040*b5016cbbSstephh newentp->ipath = ipath(serdinst->u.stmt.np->u.event.epname); 1041*b5016cbbSstephh newentp->hdl = hdl; 1042*b5016cbbSstephh if (lut_lookup(SerdEngines, newentp, (lut_cmp)serd_cmp) == NULL) { 1043*b5016cbbSstephh SerdEngines = lut_add(SerdEngines, (void *)newentp, 1044*b5016cbbSstephh (void *)NULL, (lut_cmp)serd_cmp); 1045*b5016cbbSstephh Serd_need_save = 1; 1046*b5016cbbSstephh serd_save(); 1047*b5016cbbSstephh } else { 1048*b5016cbbSstephh FREE(newentp); 1049*b5016cbbSstephh } 1050*b5016cbbSstephh 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate /* 10537c478bd9Sstevel@tonic-gate * increment SERD engine. if engine fires, reset serd 10547c478bd9Sstevel@tonic-gate * engine and return trip_strcode 10557c478bd9Sstevel@tonic-gate */ 10567c478bd9Sstevel@tonic-gate if (fmd_serd_record(hdl, serdname, ffep)) { 10577c478bd9Sstevel@tonic-gate struct node *tripinst = lut_lookup(serdinst->u.stmt.lutp, 10587c478bd9Sstevel@tonic-gate (void *)L_trip, NULL); 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate ASSERT(tripinst != NULL); 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate *enamep = tripinst->u.event.ename->u.name.s; 10637c478bd9Sstevel@tonic-gate *ippp = ipath(tripinst->u.event.epname); 10647c478bd9Sstevel@tonic-gate 10653e8d8e18Sdb fmd_case_add_serd(hdl, fmcase, serdname); 10667c478bd9Sstevel@tonic-gate fmd_serd_reset(hdl, serdname); 10677c478bd9Sstevel@tonic-gate out(O_ALTFP|O_NONL, "[engine fired: %s, sending: ", serdname); 10687c478bd9Sstevel@tonic-gate ipath_print(O_ALTFP|O_NONL, *enamep, *ippp); 10697c478bd9Sstevel@tonic-gate out(O_ALTFP, "]"); 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate FREE(serdname); 10727c478bd9Sstevel@tonic-gate return (1); 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate FREE(serdname); 10767c478bd9Sstevel@tonic-gate return (0); 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate /* 10807c478bd9Sstevel@tonic-gate * search a suspect list for upsets. feed each upset to serd_eval() and 10817c478bd9Sstevel@tonic-gate * build up tripped[], an array of ereports produced by the firing of 10827c478bd9Sstevel@tonic-gate * any SERD engines. then feed each ereport back into 10837c478bd9Sstevel@tonic-gate * fme_receive_report(). 10847c478bd9Sstevel@tonic-gate * 10857c478bd9Sstevel@tonic-gate * returns ntrip, the number of these ereports produced. 10867c478bd9Sstevel@tonic-gate */ 10877c478bd9Sstevel@tonic-gate static int 10887c478bd9Sstevel@tonic-gate upsets_eval(struct fme *fmep, fmd_event_t *ffep) 10897c478bd9Sstevel@tonic-gate { 10907c478bd9Sstevel@tonic-gate /* we build an array of tripped ereports that we send ourselves */ 10917c478bd9Sstevel@tonic-gate struct { 10927c478bd9Sstevel@tonic-gate const char *ename; 10937c478bd9Sstevel@tonic-gate const struct ipath *ipp; 10947c478bd9Sstevel@tonic-gate } *tripped; 10957c478bd9Sstevel@tonic-gate struct event *sp; 10967c478bd9Sstevel@tonic-gate int ntrip, nupset, i; 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate /* 10997c478bd9Sstevel@tonic-gate * count the number of upsets to determine the upper limit on 11007c478bd9Sstevel@tonic-gate * expected trip ereport strings. remember that one upset can 11017c478bd9Sstevel@tonic-gate * lead to at most one ereport. 11027c478bd9Sstevel@tonic-gate */ 11037c478bd9Sstevel@tonic-gate nupset = 0; 11047c478bd9Sstevel@tonic-gate for (sp = fmep->suspects; sp; sp = sp->suspects) { 11057c478bd9Sstevel@tonic-gate if (sp->t == N_UPSET) 11067c478bd9Sstevel@tonic-gate nupset++; 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate if (nupset == 0) 11107c478bd9Sstevel@tonic-gate return (0); 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate /* 11137c478bd9Sstevel@tonic-gate * get to this point if we have upsets and expect some trip 11147c478bd9Sstevel@tonic-gate * ereports 11157c478bd9Sstevel@tonic-gate */ 11167c478bd9Sstevel@tonic-gate tripped = alloca(sizeof (*tripped) * nupset); 11177c478bd9Sstevel@tonic-gate bzero((void *)tripped, sizeof (*tripped) * nupset); 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate ntrip = 0; 11207c478bd9Sstevel@tonic-gate for (sp = fmep->suspects; sp; sp = sp->suspects) 11213e8d8e18Sdb if (sp->t == N_UPSET && 11227aec1d6eScindi serd_eval(fmep, fmep->hdl, ffep, fmep->fmcase, sp, 1123*b5016cbbSstephh &tripped[ntrip].ename, &tripped[ntrip].ipp)) 11247c478bd9Sstevel@tonic-gate ntrip++; 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate for (i = 0; i < ntrip; i++) 11277aec1d6eScindi fme_receive_report(fmep->hdl, ffep, 11287c478bd9Sstevel@tonic-gate tripped[i].ename, tripped[i].ipp, NULL); 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate return (ntrip); 11317c478bd9Sstevel@tonic-gate } 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate /* 11347c478bd9Sstevel@tonic-gate * fme_receive_external_report -- call when an external ereport comes in 11357c478bd9Sstevel@tonic-gate * 11367c478bd9Sstevel@tonic-gate * this routine just converts the relevant information from the ereport 11377c478bd9Sstevel@tonic-gate * into a format used internally and passes it on to fme_receive_report(). 11387c478bd9Sstevel@tonic-gate */ 11397c478bd9Sstevel@tonic-gate void 11407c478bd9Sstevel@tonic-gate fme_receive_external_report(fmd_hdl_t *hdl, fmd_event_t *ffep, nvlist_t *nvl, 11417c478bd9Sstevel@tonic-gate const char *eventstring) 11427c478bd9Sstevel@tonic-gate { 11437c478bd9Sstevel@tonic-gate struct node *epnamenp = platform_getpath(nvl); 11447c478bd9Sstevel@tonic-gate const struct ipath *ipp; 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate /* 11477c478bd9Sstevel@tonic-gate * XFILE: If we ended up without a path, it's an X-file. 11487c478bd9Sstevel@tonic-gate * For now, use our undiagnosable interface. 11497c478bd9Sstevel@tonic-gate */ 11507c478bd9Sstevel@tonic-gate if (epnamenp == NULL) { 1151*b5016cbbSstephh fmd_case_t *fmcase; 1152*b5016cbbSstephh 11537c478bd9Sstevel@tonic-gate out(O_ALTFP, "XFILE: Unable to get path from ereport"); 11547c478bd9Sstevel@tonic-gate Undiag_reason = UD_NOPATH; 1155*b5016cbbSstephh fmcase = fmd_case_open(hdl, NULL); 1156*b5016cbbSstephh publish_undiagnosable(hdl, ffep, fmcase); 11577c478bd9Sstevel@tonic-gate return; 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate ipp = ipath(epnamenp); 11617c478bd9Sstevel@tonic-gate tree_free(epnamenp); 11627c478bd9Sstevel@tonic-gate fme_receive_report(hdl, ffep, stable(eventstring), ipp, nvl); 11637c478bd9Sstevel@tonic-gate } 11647c478bd9Sstevel@tonic-gate 116508f6c065Sgavinm /*ARGSUSED*/ 116608f6c065Sgavinm void 116708f6c065Sgavinm fme_receive_repair_list(fmd_hdl_t *hdl, fmd_event_t *ffep, nvlist_t *nvl, 116808f6c065Sgavinm const char *eventstring) 116908f6c065Sgavinm { 117008f6c065Sgavinm char *uuid; 117108f6c065Sgavinm nvlist_t **nva; 117208f6c065Sgavinm uint_t nvc; 117308f6c065Sgavinm const struct ipath *ipp; 117408f6c065Sgavinm 117508f6c065Sgavinm if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) != 0 || 117608f6c065Sgavinm nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST, 117708f6c065Sgavinm &nva, &nvc) != 0) { 117808f6c065Sgavinm out(O_ALTFP, "No uuid or fault list for list.repaired event"); 117908f6c065Sgavinm return; 118008f6c065Sgavinm } 118108f6c065Sgavinm 118208f6c065Sgavinm out(O_ALTFP, "Processing list.repaired from case %s", uuid); 118308f6c065Sgavinm 118408f6c065Sgavinm while (nvc-- != 0) { 118508f6c065Sgavinm /* 1186*b5016cbbSstephh * Reset any istat or serd engine associated with this path. 118708f6c065Sgavinm */ 118808f6c065Sgavinm char *path; 118908f6c065Sgavinm 119008f6c065Sgavinm if ((ipp = platform_fault2ipath(*nva++)) == NULL) 119108f6c065Sgavinm continue; 119208f6c065Sgavinm 119308f6c065Sgavinm path = ipath2str(NULL, ipp); 119408f6c065Sgavinm out(O_ALTFP, "fme_receive_repair_list: resetting state for %s", 119508f6c065Sgavinm path); 119608f6c065Sgavinm FREE(path); 119708f6c065Sgavinm 119808f6c065Sgavinm lut_walk(Istats, (lut_cb)istat_counter_reset_cb, (void *)ipp); 119908f6c065Sgavinm istat_save(); 120008f6c065Sgavinm 1201*b5016cbbSstephh lut_walk(SerdEngines, (lut_cb)serd_reset_cb, (void *)ipp); 1202*b5016cbbSstephh serd_save(); 120308f6c065Sgavinm } 120408f6c065Sgavinm } 120508f6c065Sgavinm 12067aec1d6eScindi static int mark_arrows(struct fme *fmep, struct event *ep, int mark, 120700d0963fSdilpreet unsigned long long at_latest_by, unsigned long long *pdelay, int keep); 12087aec1d6eScindi 12097aec1d6eScindi /* ARGSUSED */ 12107aec1d6eScindi static void 12117aec1d6eScindi clear_arrows(struct event *ep, struct event *ep2, struct fme *fmep) 12127aec1d6eScindi { 12137aec1d6eScindi struct bubble *bp; 12147aec1d6eScindi struct arrowlist *ap; 12157aec1d6eScindi 12167aec1d6eScindi ep->cached_state = 0; 121700d0963fSdilpreet ep->keep_in_tree = 0; 12187aec1d6eScindi for (bp = itree_next_bubble(ep, NULL); bp; 12197aec1d6eScindi bp = itree_next_bubble(ep, bp)) { 12207aec1d6eScindi if (bp->t != B_FROM) 12217aec1d6eScindi continue; 12227aec1d6eScindi bp->mark = 0; 12237aec1d6eScindi for (ap = itree_next_arrow(bp, NULL); ap; 12247aec1d6eScindi ap = itree_next_arrow(bp, ap)) 12257aec1d6eScindi ap->arrowp->mark = 0; 12267aec1d6eScindi } 12277aec1d6eScindi } 12287aec1d6eScindi 1229*b5016cbbSstephh static void 1230*b5016cbbSstephh fme_reload_cfgdata(struct fme *fmep) 1231*b5016cbbSstephh { 1232*b5016cbbSstephh size_t rawsz; 1233*b5016cbbSstephh 1234*b5016cbbSstephh fmep->cfgdata = MALLOC(sizeof (struct cfgdata)); 1235*b5016cbbSstephh fmep->cfgdata->cooked = NULL; 1236*b5016cbbSstephh fmep->cfgdata->devcache = NULL; 1237*b5016cbbSstephh fmep->cfgdata->cpucache = NULL; 1238*b5016cbbSstephh fmep->cfgdata->cooked_refcnt = 0; 1239*b5016cbbSstephh fmep->cfgdata->raw_refcnt = 1; 1240*b5016cbbSstephh fmd_buf_read(fmep->hdl, fmep->fmcase, WOBUF_CFGLEN, 1241*b5016cbbSstephh (void *)&rawsz, sizeof (size_t)); 1242*b5016cbbSstephh if (rawsz > 0) { 1243*b5016cbbSstephh fmep->cfgdata->begin = MALLOC(rawsz); 1244*b5016cbbSstephh fmep->cfgdata->end = fmep->cfgdata->nextfree = 1245*b5016cbbSstephh fmep->cfgdata->begin + rawsz; 1246*b5016cbbSstephh fmd_buf_read(fmep->hdl, fmep->fmcase, WOBUF_CFG, 1247*b5016cbbSstephh fmep->cfgdata->begin, rawsz); 1248*b5016cbbSstephh config_cook(fmep->cfgdata); 1249*b5016cbbSstephh FREE(fmep->cfgdata->begin); 1250*b5016cbbSstephh } 1251*b5016cbbSstephh fmep->cfgdata->begin = NULL; 1252*b5016cbbSstephh fmep->cfgdata->end = NULL; 1253*b5016cbbSstephh fmep->cfgdata->nextfree = NULL; 1254*b5016cbbSstephh } 1255*b5016cbbSstephh 12567c478bd9Sstevel@tonic-gate static void 12577c478bd9Sstevel@tonic-gate fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep, 12587c478bd9Sstevel@tonic-gate const char *eventstring, const struct ipath *ipp, nvlist_t *nvl) 12597c478bd9Sstevel@tonic-gate { 12607c478bd9Sstevel@tonic-gate struct event *ep; 12617c478bd9Sstevel@tonic-gate struct fme *fmep = NULL; 12620cc1f05eSjrutt struct fme *ofmep = NULL; 12630cc1f05eSjrutt struct fme *cfmep, *svfmep; 12647c478bd9Sstevel@tonic-gate int matched = 0; 12650cc1f05eSjrutt nvlist_t *defect; 1266*b5016cbbSstephh fmd_case_t *fmcase; 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate out(O_ALTFP|O_NONL, "fme_receive_report: "); 12697c478bd9Sstevel@tonic-gate ipath_print(O_ALTFP|O_NONL, eventstring, ipp); 12707c478bd9Sstevel@tonic-gate out(O_ALTFP|O_STAMP, NULL); 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate /* decide which FME it goes to */ 12737c478bd9Sstevel@tonic-gate for (fmep = FMElist; fmep; fmep = fmep->next) { 12747c478bd9Sstevel@tonic-gate int prev_verbose; 12757c478bd9Sstevel@tonic-gate unsigned long long my_delay = TIMEVAL_EVENTUALLY; 12767c478bd9Sstevel@tonic-gate enum fme_state state; 12777aec1d6eScindi nvlist_t *pre_peek_nvp = NULL; 12787c478bd9Sstevel@tonic-gate 12790cc1f05eSjrutt if (fmep->overflow) { 12800cc1f05eSjrutt if (!(fmd_case_closed(fmep->hdl, fmep->fmcase))) 12810cc1f05eSjrutt ofmep = fmep; 12820cc1f05eSjrutt 12830cc1f05eSjrutt continue; 12840cc1f05eSjrutt } 12850cc1f05eSjrutt 1286d96ce684Sstephh /* 1287d96ce684Sstephh * ignore solved or closed cases 1288d96ce684Sstephh */ 1289d96ce684Sstephh if (fmep->posted_suspects || 1290d96ce684Sstephh fmd_case_solved(fmep->hdl, fmep->fmcase) || 1291d96ce684Sstephh fmd_case_closed(fmep->hdl, fmep->fmcase)) 1292d96ce684Sstephh continue; 1293d96ce684Sstephh 12947c478bd9Sstevel@tonic-gate /* look up event in event tree for this FME */ 12957c478bd9Sstevel@tonic-gate if ((ep = itree_lookup(fmep->eventtree, 12967c478bd9Sstevel@tonic-gate eventstring, ipp)) == NULL) 12977c478bd9Sstevel@tonic-gate continue; 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate /* note observation */ 13007c478bd9Sstevel@tonic-gate fmep->ecurrent = ep; 13017c478bd9Sstevel@tonic-gate if (ep->count++ == 0) { 13027c478bd9Sstevel@tonic-gate /* link it into list of observations seen */ 13037c478bd9Sstevel@tonic-gate ep->observations = fmep->observations; 13047c478bd9Sstevel@tonic-gate fmep->observations = ep; 13057c478bd9Sstevel@tonic-gate ep->nvp = evnv_dupnvl(nvl); 13067aec1d6eScindi } else { 13077aec1d6eScindi /* use new payload values for peek */ 13087aec1d6eScindi pre_peek_nvp = ep->nvp; 13097aec1d6eScindi ep->nvp = evnv_dupnvl(nvl); 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate /* tell hypothesise() not to mess with suspect list */ 13137c478bd9Sstevel@tonic-gate fmep->peek = 1; 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate /* don't want this to be verbose (unless Debug is set) */ 13167c478bd9Sstevel@tonic-gate prev_verbose = Verbose; 13177c478bd9Sstevel@tonic-gate if (Debug == 0) 13187c478bd9Sstevel@tonic-gate Verbose = 0; 13197c478bd9Sstevel@tonic-gate 1320*b5016cbbSstephh fme_reload_cfgdata(fmep); 1321*b5016cbbSstephh 13227aec1d6eScindi lut_walk(fmep->eventtree, (lut_cb)clear_arrows, (void *)fmep); 13237aec1d6eScindi state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay); 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate fmep->peek = 0; 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate /* put verbose flag back */ 13287c478bd9Sstevel@tonic-gate Verbose = prev_verbose; 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate if (state != FME_DISPROVED) { 13317c478bd9Sstevel@tonic-gate /* found an FME that explains the ereport */ 13327c478bd9Sstevel@tonic-gate matched++; 13337c478bd9Sstevel@tonic-gate out(O_ALTFP|O_NONL, "["); 13347c478bd9Sstevel@tonic-gate ipath_print(O_ALTFP|O_NONL, eventstring, ipp); 13357c478bd9Sstevel@tonic-gate out(O_ALTFP, " explained by FME%d]", fmep->id); 13367c478bd9Sstevel@tonic-gate 13377aec1d6eScindi if (pre_peek_nvp) 13387aec1d6eScindi nvlist_free(pre_peek_nvp); 13397aec1d6eScindi 13407c478bd9Sstevel@tonic-gate if (ep->count == 1) 13417c478bd9Sstevel@tonic-gate serialize_observation(fmep, eventstring, ipp); 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate if (ffep) 13447c478bd9Sstevel@tonic-gate fmd_case_add_ereport(hdl, fmep->fmcase, ffep); 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate stats_counter_bump(fmep->Rcount); 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate /* re-eval FME */ 13497c478bd9Sstevel@tonic-gate fme_eval(fmep, ffep); 13507c478bd9Sstevel@tonic-gate } else { 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate /* not a match, undo noting of observation */ 1353*b5016cbbSstephh config_free(fmep->cfgdata); 1354*b5016cbbSstephh fmep->cfgdata = NULL; 13557c478bd9Sstevel@tonic-gate fmep->ecurrent = NULL; 13567c478bd9Sstevel@tonic-gate if (--ep->count == 0) { 13577c478bd9Sstevel@tonic-gate /* unlink it from observations */ 13587c478bd9Sstevel@tonic-gate fmep->observations = ep->observations; 13597c478bd9Sstevel@tonic-gate ep->observations = NULL; 13607c478bd9Sstevel@tonic-gate nvlist_free(ep->nvp); 13617c478bd9Sstevel@tonic-gate ep->nvp = NULL; 13627aec1d6eScindi } else { 13637aec1d6eScindi nvlist_free(ep->nvp); 13647aec1d6eScindi ep->nvp = pre_peek_nvp; 13657c478bd9Sstevel@tonic-gate } 13667c478bd9Sstevel@tonic-gate } 13677c478bd9Sstevel@tonic-gate } 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate if (matched) 13707c478bd9Sstevel@tonic-gate return; /* explained by at least one existing FME */ 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate /* clean up closed fmes */ 13730cc1f05eSjrutt cfmep = ClosedFMEs; 13740cc1f05eSjrutt while (cfmep != NULL) { 13750cc1f05eSjrutt svfmep = cfmep->next; 13760cc1f05eSjrutt destroy_fme(cfmep); 13770cc1f05eSjrutt cfmep = svfmep; 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate ClosedFMEs = NULL; 1380*b5016cbbSstephh prune_propagations(eventstring, ipp); 13817c478bd9Sstevel@tonic-gate 13820cc1f05eSjrutt if (ofmep) { 13830cc1f05eSjrutt out(O_ALTFP|O_NONL, "["); 13840cc1f05eSjrutt ipath_print(O_ALTFP|O_NONL, eventstring, ipp); 13850cc1f05eSjrutt out(O_ALTFP, " ADDING TO OVERFLOW FME]"); 13860cc1f05eSjrutt if (ffep) 13870cc1f05eSjrutt fmd_case_add_ereport(hdl, ofmep->fmcase, ffep); 13880cc1f05eSjrutt 13890cc1f05eSjrutt return; 13900cc1f05eSjrutt 13910cc1f05eSjrutt } else if (Max_fme && (Open_fme_count >= Max_fme)) { 13920cc1f05eSjrutt out(O_ALTFP|O_NONL, "["); 13930cc1f05eSjrutt ipath_print(O_ALTFP|O_NONL, eventstring, ipp); 13940cc1f05eSjrutt out(O_ALTFP, " MAX OPEN FME REACHED]"); 1395*b5016cbbSstephh 1396*b5016cbbSstephh fmcase = fmd_case_open(hdl, NULL); 1397*b5016cbbSstephh 13980cc1f05eSjrutt /* Create overflow fme */ 1399*b5016cbbSstephh if ((fmep = newfme(eventstring, ipp, hdl, fmcase)) == NULL) { 14000cc1f05eSjrutt out(O_ALTFP|O_NONL, "["); 14010cc1f05eSjrutt ipath_print(O_ALTFP|O_NONL, eventstring, ipp); 14020cc1f05eSjrutt out(O_ALTFP, " CANNOT OPEN OVERFLOW FME]"); 1403*b5016cbbSstephh publish_undiagnosable(hdl, ffep, fmcase); 14040cc1f05eSjrutt return; 14050cc1f05eSjrutt } 14060cc1f05eSjrutt 14070cc1f05eSjrutt Open_fme_count++; 14080cc1f05eSjrutt 14090cc1f05eSjrutt init_fme_bufs(fmep); 14100cc1f05eSjrutt fmep->overflow = B_TRUE; 14110cc1f05eSjrutt 14120cc1f05eSjrutt if (ffep) 14130cc1f05eSjrutt fmd_case_add_ereport(hdl, fmep->fmcase, ffep); 14140cc1f05eSjrutt 14150cc1f05eSjrutt defect = fmd_nvl_create_fault(hdl, UNDIAGNOSABLE_DEFECT, 100, 14160cc1f05eSjrutt NULL, NULL, NULL); 14170cc1f05eSjrutt (void) nvlist_add_string(defect, UNDIAG_REASON, UD_MAXFME); 14180cc1f05eSjrutt fmd_case_add_suspect(hdl, fmep->fmcase, defect); 14190cc1f05eSjrutt fmd_case_solve(hdl, fmep->fmcase); 14200cc1f05eSjrutt return; 14210cc1f05eSjrutt } 14220cc1f05eSjrutt 1423*b5016cbbSstephh /* open a case */ 1424*b5016cbbSstephh fmcase = fmd_case_open(hdl, NULL); 1425*b5016cbbSstephh 14267c478bd9Sstevel@tonic-gate /* start a new FME */ 1427*b5016cbbSstephh if ((fmep = newfme(eventstring, ipp, hdl, fmcase)) == NULL) { 14287c478bd9Sstevel@tonic-gate out(O_ALTFP|O_NONL, "["); 14297c478bd9Sstevel@tonic-gate ipath_print(O_ALTFP|O_NONL, eventstring, ipp); 14307c478bd9Sstevel@tonic-gate out(O_ALTFP, " CANNOT DIAGNOSE]"); 1431*b5016cbbSstephh publish_undiagnosable(hdl, ffep, fmcase); 14327c478bd9Sstevel@tonic-gate return; 14337c478bd9Sstevel@tonic-gate } 14347c478bd9Sstevel@tonic-gate 14350cc1f05eSjrutt Open_fme_count++; 14360cc1f05eSjrutt 14377c478bd9Sstevel@tonic-gate init_fme_bufs(fmep); 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate out(O_ALTFP|O_NONL, "["); 14407c478bd9Sstevel@tonic-gate ipath_print(O_ALTFP|O_NONL, eventstring, ipp); 14417c478bd9Sstevel@tonic-gate out(O_ALTFP, " created FME%d, case %s]", fmep->id, 14427c478bd9Sstevel@tonic-gate fmd_case_uuid(hdl, fmep->fmcase)); 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate ep = fmep->e0; 14457c478bd9Sstevel@tonic-gate ASSERT(ep != NULL); 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate /* note observation */ 14487c478bd9Sstevel@tonic-gate fmep->ecurrent = ep; 14497c478bd9Sstevel@tonic-gate if (ep->count++ == 0) { 14507c478bd9Sstevel@tonic-gate /* link it into list of observations seen */ 14517c478bd9Sstevel@tonic-gate ep->observations = fmep->observations; 14527c478bd9Sstevel@tonic-gate fmep->observations = ep; 14537c478bd9Sstevel@tonic-gate ep->nvp = evnv_dupnvl(nvl); 14547c478bd9Sstevel@tonic-gate serialize_observation(fmep, eventstring, ipp); 14557aec1d6eScindi } else { 14567aec1d6eScindi /* new payload overrides any previous */ 14577aec1d6eScindi nvlist_free(ep->nvp); 14587aec1d6eScindi ep->nvp = evnv_dupnvl(nvl); 14597c478bd9Sstevel@tonic-gate } 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate stats_counter_bump(fmep->Rcount); 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate if (ffep) { 14647c478bd9Sstevel@tonic-gate fmd_case_add_ereport(hdl, fmep->fmcase, ffep); 14657c478bd9Sstevel@tonic-gate fmd_case_setprincipal(hdl, fmep->fmcase, ffep); 14667c478bd9Sstevel@tonic-gate fmep->e0r = ffep; 14677c478bd9Sstevel@tonic-gate } 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate /* give the diagnosis algorithm a shot at the new FME state */ 14707c478bd9Sstevel@tonic-gate fme_eval(fmep, ffep); 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate void 14747c478bd9Sstevel@tonic-gate fme_status(int flags) 14757c478bd9Sstevel@tonic-gate { 14767c478bd9Sstevel@tonic-gate struct fme *fmep; 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate if (FMElist == NULL) { 14797c478bd9Sstevel@tonic-gate out(flags, "No fault management exercises underway."); 14807c478bd9Sstevel@tonic-gate return; 14817c478bd9Sstevel@tonic-gate } 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate for (fmep = FMElist; fmep; fmep = fmep->next) 14847c478bd9Sstevel@tonic-gate fme_print(flags, fmep); 14857c478bd9Sstevel@tonic-gate } 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate /* 14887c478bd9Sstevel@tonic-gate * "indent" routines used mostly for nicely formatted debug output, but also 14897c478bd9Sstevel@tonic-gate * for sanity checking for infinite recursion bugs. 14907c478bd9Sstevel@tonic-gate */ 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate #define MAX_INDENT 1024 14937c478bd9Sstevel@tonic-gate static const char *indent_s[MAX_INDENT]; 14947c478bd9Sstevel@tonic-gate static int current_indent; 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate static void 14977c478bd9Sstevel@tonic-gate indent_push(const char *s) 14987c478bd9Sstevel@tonic-gate { 14997c478bd9Sstevel@tonic-gate if (current_indent < MAX_INDENT) 15007c478bd9Sstevel@tonic-gate indent_s[current_indent++] = s; 15017c478bd9Sstevel@tonic-gate else 15027c478bd9Sstevel@tonic-gate out(O_DIE, "unexpected recursion depth (%d)", current_indent); 15037c478bd9Sstevel@tonic-gate } 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate static void 15067c478bd9Sstevel@tonic-gate indent_set(const char *s) 15077c478bd9Sstevel@tonic-gate { 15087c478bd9Sstevel@tonic-gate current_indent = 0; 15097c478bd9Sstevel@tonic-gate indent_push(s); 15107c478bd9Sstevel@tonic-gate } 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate static void 15137c478bd9Sstevel@tonic-gate indent_pop(void) 15147c478bd9Sstevel@tonic-gate { 15157c478bd9Sstevel@tonic-gate if (current_indent > 0) 15167c478bd9Sstevel@tonic-gate current_indent--; 15177c478bd9Sstevel@tonic-gate else 15187c478bd9Sstevel@tonic-gate out(O_DIE, "recursion underflow"); 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate static void 15227c478bd9Sstevel@tonic-gate indent(void) 15237c478bd9Sstevel@tonic-gate { 15247c478bd9Sstevel@tonic-gate int i; 15257c478bd9Sstevel@tonic-gate if (!Verbose) 15267c478bd9Sstevel@tonic-gate return; 15277c478bd9Sstevel@tonic-gate for (i = 0; i < current_indent; i++) 15287c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, indent_s[i]); 15297c478bd9Sstevel@tonic-gate } 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate #define SLNEW 1 15327c478bd9Sstevel@tonic-gate #define SLCHANGED 2 15337c478bd9Sstevel@tonic-gate #define SLWAIT 3 15347c478bd9Sstevel@tonic-gate #define SLDISPROVED 4 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate static void 15377c478bd9Sstevel@tonic-gate print_suspects(int circumstance, struct fme *fmep) 15387c478bd9Sstevel@tonic-gate { 15397c478bd9Sstevel@tonic-gate struct event *ep; 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate out(O_ALTFP|O_NONL, "["); 15427c478bd9Sstevel@tonic-gate if (circumstance == SLCHANGED) { 15437c478bd9Sstevel@tonic-gate out(O_ALTFP|O_NONL, "FME%d diagnosis changed. state: %s, " 15447c478bd9Sstevel@tonic-gate "suspect list:", fmep->id, fme_state2str(fmep->state)); 15457c478bd9Sstevel@tonic-gate } else if (circumstance == SLWAIT) { 1546*b5016cbbSstephh out(O_ALTFP|O_NONL, "FME%d set wait timer %ld ", fmep->id, 1547*b5016cbbSstephh fmep->timer); 15487c478bd9Sstevel@tonic-gate ptree_timeval(O_ALTFP|O_NONL, &fmep->wull); 15497c478bd9Sstevel@tonic-gate } else if (circumstance == SLDISPROVED) { 15507c478bd9Sstevel@tonic-gate out(O_ALTFP|O_NONL, "FME%d DIAGNOSIS UNKNOWN", fmep->id); 15517c478bd9Sstevel@tonic-gate } else { 15527c478bd9Sstevel@tonic-gate out(O_ALTFP|O_NONL, "FME%d DIAGNOSIS PRODUCED:", fmep->id); 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate if (circumstance == SLWAIT || circumstance == SLDISPROVED) { 15567c478bd9Sstevel@tonic-gate out(O_ALTFP, "]"); 15577c478bd9Sstevel@tonic-gate return; 15587c478bd9Sstevel@tonic-gate } 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate for (ep = fmep->suspects; ep; ep = ep->suspects) { 15617c478bd9Sstevel@tonic-gate out(O_ALTFP|O_NONL, " "); 15627c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_NONL, ep); 15637c478bd9Sstevel@tonic-gate } 15647c478bd9Sstevel@tonic-gate out(O_ALTFP, "]"); 15657c478bd9Sstevel@tonic-gate } 15667c478bd9Sstevel@tonic-gate 15677c478bd9Sstevel@tonic-gate static struct node * 15687c478bd9Sstevel@tonic-gate eventprop_lookup(struct event *ep, const char *propname) 15697c478bd9Sstevel@tonic-gate { 15707c478bd9Sstevel@tonic-gate return (lut_lookup(ep->props, (void *)propname, NULL)); 15717c478bd9Sstevel@tonic-gate } 15727c478bd9Sstevel@tonic-gate 15737c478bd9Sstevel@tonic-gate #define MAXDIGITIDX 23 15747c478bd9Sstevel@tonic-gate static char numbuf[MAXDIGITIDX + 1]; 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate static int 15777c478bd9Sstevel@tonic-gate node2uint(struct node *n, uint_t *valp) 15787c478bd9Sstevel@tonic-gate { 15797c478bd9Sstevel@tonic-gate struct evalue value; 15807c478bd9Sstevel@tonic-gate struct lut *globals = NULL; 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate if (n == NULL) 15837c478bd9Sstevel@tonic-gate return (1); 15847c478bd9Sstevel@tonic-gate 15857c478bd9Sstevel@tonic-gate /* 15867c478bd9Sstevel@tonic-gate * check value.v since we are being asked to convert an unsigned 15877c478bd9Sstevel@tonic-gate * long long int to an unsigned int 15887c478bd9Sstevel@tonic-gate */ 15897c478bd9Sstevel@tonic-gate if (! eval_expr(n, NULL, NULL, &globals, NULL, NULL, 0, &value) || 15907c478bd9Sstevel@tonic-gate value.t != UINT64 || value.v > (1ULL << 32)) 15917c478bd9Sstevel@tonic-gate return (1); 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate *valp = (uint_t)value.v; 15947c478bd9Sstevel@tonic-gate 15957c478bd9Sstevel@tonic-gate return (0); 15967c478bd9Sstevel@tonic-gate } 15977c478bd9Sstevel@tonic-gate 15987c478bd9Sstevel@tonic-gate static nvlist_t * 15997c478bd9Sstevel@tonic-gate node2fmri(struct node *n) 16007c478bd9Sstevel@tonic-gate { 16017c478bd9Sstevel@tonic-gate nvlist_t **pa, *f, *p; 16027c478bd9Sstevel@tonic-gate struct node *nc; 16037c478bd9Sstevel@tonic-gate uint_t depth = 0; 16047c478bd9Sstevel@tonic-gate char *numstr, *nullbyte; 16057c478bd9Sstevel@tonic-gate char *failure; 16067c478bd9Sstevel@tonic-gate int err, i; 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate /* XXX do we need to be able to handle a non-T_NAME node? */ 16097c478bd9Sstevel@tonic-gate if (n == NULL || n->t != T_NAME) 16107c478bd9Sstevel@tonic-gate return (NULL); 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate for (nc = n; nc != NULL; nc = nc->u.name.next) { 16137c478bd9Sstevel@tonic-gate if (nc->u.name.child == NULL || nc->u.name.child->t != T_NUM) 16147c478bd9Sstevel@tonic-gate break; 16157c478bd9Sstevel@tonic-gate depth++; 16167c478bd9Sstevel@tonic-gate } 16177c478bd9Sstevel@tonic-gate 16187c478bd9Sstevel@tonic-gate if (nc != NULL) { 16197c478bd9Sstevel@tonic-gate /* We bailed early, something went wrong */ 16207c478bd9Sstevel@tonic-gate return (NULL); 16217c478bd9Sstevel@tonic-gate } 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate if ((err = nvlist_xalloc(&f, NV_UNIQUE_NAME, &Eft_nv_hdl)) != 0) 16247c478bd9Sstevel@tonic-gate out(O_DIE|O_SYS, "alloc of fmri nvl failed"); 16257c478bd9Sstevel@tonic-gate pa = alloca(depth * sizeof (nvlist_t *)); 16267c478bd9Sstevel@tonic-gate for (i = 0; i < depth; i++) 16277c478bd9Sstevel@tonic-gate pa[i] = NULL; 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate err = nvlist_add_string(f, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC); 16307c478bd9Sstevel@tonic-gate err |= nvlist_add_uint8(f, FM_VERSION, FM_HC_SCHEME_VERSION); 16317c478bd9Sstevel@tonic-gate err |= nvlist_add_string(f, FM_FMRI_HC_ROOT, ""); 16327c478bd9Sstevel@tonic-gate err |= nvlist_add_uint32(f, FM_FMRI_HC_LIST_SZ, depth); 16337c478bd9Sstevel@tonic-gate if (err != 0) { 16347c478bd9Sstevel@tonic-gate failure = "basic construction of FMRI failed"; 16357c478bd9Sstevel@tonic-gate goto boom; 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate numbuf[MAXDIGITIDX] = '\0'; 16397c478bd9Sstevel@tonic-gate nullbyte = &numbuf[MAXDIGITIDX]; 16407c478bd9Sstevel@tonic-gate i = 0; 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate for (nc = n; nc != NULL; nc = nc->u.name.next) { 16437c478bd9Sstevel@tonic-gate err = nvlist_xalloc(&p, NV_UNIQUE_NAME, &Eft_nv_hdl); 16447c478bd9Sstevel@tonic-gate if (err != 0) { 16457c478bd9Sstevel@tonic-gate failure = "alloc of an hc-pair failed"; 16467c478bd9Sstevel@tonic-gate goto boom; 16477c478bd9Sstevel@tonic-gate } 16487c478bd9Sstevel@tonic-gate err = nvlist_add_string(p, FM_FMRI_HC_NAME, nc->u.name.s); 16497c478bd9Sstevel@tonic-gate numstr = ulltostr(nc->u.name.child->u.ull, nullbyte); 16507c478bd9Sstevel@tonic-gate err |= nvlist_add_string(p, FM_FMRI_HC_ID, numstr); 16517c478bd9Sstevel@tonic-gate if (err != 0) { 16527c478bd9Sstevel@tonic-gate failure = "construction of an hc-pair failed"; 16537c478bd9Sstevel@tonic-gate goto boom; 16547c478bd9Sstevel@tonic-gate } 16557c478bd9Sstevel@tonic-gate pa[i++] = p; 16567c478bd9Sstevel@tonic-gate } 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate err = nvlist_add_nvlist_array(f, FM_FMRI_HC_LIST, pa, depth); 16597c478bd9Sstevel@tonic-gate if (err == 0) { 16607c478bd9Sstevel@tonic-gate for (i = 0; i < depth; i++) 16617c478bd9Sstevel@tonic-gate if (pa[i] != NULL) 16627c478bd9Sstevel@tonic-gate nvlist_free(pa[i]); 16637c478bd9Sstevel@tonic-gate return (f); 16647c478bd9Sstevel@tonic-gate } 16657c478bd9Sstevel@tonic-gate failure = "addition of hc-pair array to FMRI failed"; 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate boom: 16687c478bd9Sstevel@tonic-gate for (i = 0; i < depth; i++) 16697c478bd9Sstevel@tonic-gate if (pa[i] != NULL) 16707c478bd9Sstevel@tonic-gate nvlist_free(pa[i]); 16717c478bd9Sstevel@tonic-gate nvlist_free(f); 16727c478bd9Sstevel@tonic-gate out(O_DIE, "%s", failure); 16737c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 167480ab886dSwesolows return (NULL); 16757c478bd9Sstevel@tonic-gate } 16767c478bd9Sstevel@tonic-gate 16777c478bd9Sstevel@tonic-gate static uint_t 16787c478bd9Sstevel@tonic-gate avg(uint_t sum, uint_t cnt) 16797c478bd9Sstevel@tonic-gate { 16807c478bd9Sstevel@tonic-gate unsigned long long s = sum * 10; 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate return ((s / cnt / 10) + (((s / cnt % 10) >= 5) ? 1 : 0)); 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate static uint8_t 16867c478bd9Sstevel@tonic-gate percentof(uint_t part, uint_t whole) 16877c478bd9Sstevel@tonic-gate { 16887c478bd9Sstevel@tonic-gate unsigned long long p = part * 1000; 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate return ((p / whole / 10) + (((p / whole % 10) >= 5) ? 1 : 0)); 16917c478bd9Sstevel@tonic-gate } 16927c478bd9Sstevel@tonic-gate 169380ab886dSwesolows struct rsl { 16947c478bd9Sstevel@tonic-gate struct event *suspect; 16957c478bd9Sstevel@tonic-gate nvlist_t *asru; 16967c478bd9Sstevel@tonic-gate nvlist_t *fru; 16977c478bd9Sstevel@tonic-gate nvlist_t *rsrc; 16987c478bd9Sstevel@tonic-gate }; 16997c478bd9Sstevel@tonic-gate 17007c478bd9Sstevel@tonic-gate /* 17017c478bd9Sstevel@tonic-gate * rslfree -- free internal members of struct rsl not expected to be 17027c478bd9Sstevel@tonic-gate * freed elsewhere. 17037c478bd9Sstevel@tonic-gate */ 17047c478bd9Sstevel@tonic-gate static void 17057c478bd9Sstevel@tonic-gate rslfree(struct rsl *freeme) 17067c478bd9Sstevel@tonic-gate { 17077c478bd9Sstevel@tonic-gate if (freeme->asru != NULL) 17087c478bd9Sstevel@tonic-gate nvlist_free(freeme->asru); 17097c478bd9Sstevel@tonic-gate if (freeme->fru != NULL) 17107c478bd9Sstevel@tonic-gate nvlist_free(freeme->fru); 17117c478bd9Sstevel@tonic-gate if (freeme->rsrc != NULL && freeme->rsrc != freeme->asru) 17127c478bd9Sstevel@tonic-gate nvlist_free(freeme->rsrc); 17137c478bd9Sstevel@tonic-gate } 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate /* 17167c478bd9Sstevel@tonic-gate * rslcmp -- compare two rsl structures. Use the following 17177c478bd9Sstevel@tonic-gate * comparisons to establish cardinality: 17187c478bd9Sstevel@tonic-gate * 17197c478bd9Sstevel@tonic-gate * 1. Name of the suspect's class. (simple strcmp) 17207c478bd9Sstevel@tonic-gate * 2. Name of the suspect's ASRU. (trickier, since nvlist) 17217c478bd9Sstevel@tonic-gate * 17227c478bd9Sstevel@tonic-gate */ 17237c478bd9Sstevel@tonic-gate static int 17247c478bd9Sstevel@tonic-gate rslcmp(const void *a, const void *b) 17257c478bd9Sstevel@tonic-gate { 17267c478bd9Sstevel@tonic-gate struct rsl *r1 = (struct rsl *)a; 17277c478bd9Sstevel@tonic-gate struct rsl *r2 = (struct rsl *)b; 17287c478bd9Sstevel@tonic-gate int rv; 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate rv = strcmp(r1->suspect->enode->u.event.ename->u.name.s, 17317c478bd9Sstevel@tonic-gate r2->suspect->enode->u.event.ename->u.name.s); 17327c478bd9Sstevel@tonic-gate if (rv != 0) 17337c478bd9Sstevel@tonic-gate return (rv); 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate if (r1->asru == NULL && r2->asru == NULL) 17367c478bd9Sstevel@tonic-gate return (0); 17377c478bd9Sstevel@tonic-gate if (r1->asru == NULL) 17387c478bd9Sstevel@tonic-gate return (-1); 17397c478bd9Sstevel@tonic-gate if (r2->asru == NULL) 17407c478bd9Sstevel@tonic-gate return (1); 17417c478bd9Sstevel@tonic-gate return (evnv_cmpnvl(r1->asru, r2->asru, 0)); 17427c478bd9Sstevel@tonic-gate } 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate /* 17457c478bd9Sstevel@tonic-gate * rsluniq -- given an array of rsl structures, seek out and "remove" 17467c478bd9Sstevel@tonic-gate * any duplicates. Dups are "remove"d by NULLing the suspect pointer 17477c478bd9Sstevel@tonic-gate * of the array element. Removal also means updating the number of 17487c478bd9Sstevel@tonic-gate * problems and the number of problems which are not faults. User 17497c478bd9Sstevel@tonic-gate * provides the first and last element pointers. 17507c478bd9Sstevel@tonic-gate */ 17517c478bd9Sstevel@tonic-gate static void 17527c478bd9Sstevel@tonic-gate rsluniq(struct rsl *first, struct rsl *last, int *nprobs, int *nnonf) 17537c478bd9Sstevel@tonic-gate { 17547c478bd9Sstevel@tonic-gate struct rsl *cr; 17557c478bd9Sstevel@tonic-gate 17567c478bd9Sstevel@tonic-gate if (*nprobs == 1) 17577c478bd9Sstevel@tonic-gate return; 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate /* 17607c478bd9Sstevel@tonic-gate * At this point, we only expect duplicate defects. 17617c478bd9Sstevel@tonic-gate * Eversholt's diagnosis algorithm prevents duplicate 17627c478bd9Sstevel@tonic-gate * suspects, but we rewrite defects in the platform code after 17637c478bd9Sstevel@tonic-gate * the diagnosis is made, and that can introduce new 17647c478bd9Sstevel@tonic-gate * duplicates. 17657c478bd9Sstevel@tonic-gate */ 17667c478bd9Sstevel@tonic-gate while (first <= last) { 17677c478bd9Sstevel@tonic-gate if (first->suspect == NULL || !is_defect(first->suspect->t)) { 17687c478bd9Sstevel@tonic-gate first++; 17697c478bd9Sstevel@tonic-gate continue; 17707c478bd9Sstevel@tonic-gate } 17717c478bd9Sstevel@tonic-gate cr = first + 1; 17727c478bd9Sstevel@tonic-gate while (cr <= last) { 17737c478bd9Sstevel@tonic-gate if (is_defect(first->suspect->t)) { 17747c478bd9Sstevel@tonic-gate if (rslcmp(first, cr) == 0) { 17757c478bd9Sstevel@tonic-gate cr->suspect = NULL; 17767c478bd9Sstevel@tonic-gate rslfree(cr); 17777c478bd9Sstevel@tonic-gate (*nprobs)--; 17787c478bd9Sstevel@tonic-gate (*nnonf)--; 17797c478bd9Sstevel@tonic-gate } 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate /* 17827c478bd9Sstevel@tonic-gate * assume all defects are in order after our 17837c478bd9Sstevel@tonic-gate * sort and short circuit here with "else break" ? 17847c478bd9Sstevel@tonic-gate */ 17857c478bd9Sstevel@tonic-gate cr++; 17867c478bd9Sstevel@tonic-gate } 17877c478bd9Sstevel@tonic-gate first++; 17887c478bd9Sstevel@tonic-gate } 17897c478bd9Sstevel@tonic-gate } 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate /* 17927c478bd9Sstevel@tonic-gate * get_resources -- for a given suspect, determine what ASRU, FRU and 17937c478bd9Sstevel@tonic-gate * RSRC nvlists should be advertised in the final suspect list. 17947c478bd9Sstevel@tonic-gate */ 17957c478bd9Sstevel@tonic-gate void 17967c478bd9Sstevel@tonic-gate get_resources(struct event *sp, struct rsl *rsrcs, struct config *croot) 17977c478bd9Sstevel@tonic-gate { 17987c478bd9Sstevel@tonic-gate struct node *asrudef, *frudef; 17997c478bd9Sstevel@tonic-gate nvlist_t *asru, *fru; 18007c478bd9Sstevel@tonic-gate nvlist_t *rsrc = NULL; 18017c478bd9Sstevel@tonic-gate char *pathstr; 18027c478bd9Sstevel@tonic-gate 18037c478bd9Sstevel@tonic-gate /* 18047c478bd9Sstevel@tonic-gate * First find any ASRU and/or FRU defined in the 18057c478bd9Sstevel@tonic-gate * initial fault tree. 18067c478bd9Sstevel@tonic-gate */ 18077c478bd9Sstevel@tonic-gate asrudef = eventprop_lookup(sp, L_ASRU); 18087c478bd9Sstevel@tonic-gate frudef = eventprop_lookup(sp, L_FRU); 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate /* 18117c478bd9Sstevel@tonic-gate * Create FMRIs based on those definitions 18127c478bd9Sstevel@tonic-gate */ 18137c478bd9Sstevel@tonic-gate asru = node2fmri(asrudef); 18147c478bd9Sstevel@tonic-gate fru = node2fmri(frudef); 18157c478bd9Sstevel@tonic-gate pathstr = ipath2str(NULL, sp->ipp); 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate /* 18187c478bd9Sstevel@tonic-gate * Allow for platform translations of the FMRIs 18197c478bd9Sstevel@tonic-gate */ 18207c478bd9Sstevel@tonic-gate platform_units_translate(is_defect(sp->t), croot, &asru, &fru, &rsrc, 18217c478bd9Sstevel@tonic-gate pathstr); 18227c478bd9Sstevel@tonic-gate 18237c478bd9Sstevel@tonic-gate FREE(pathstr); 18247c478bd9Sstevel@tonic-gate rsrcs->suspect = sp; 18257c478bd9Sstevel@tonic-gate rsrcs->asru = asru; 18267c478bd9Sstevel@tonic-gate rsrcs->fru = fru; 18277c478bd9Sstevel@tonic-gate rsrcs->rsrc = rsrc; 18287c478bd9Sstevel@tonic-gate } 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate /* 18317c478bd9Sstevel@tonic-gate * trim_suspects -- prior to publishing, we may need to remove some 18327c478bd9Sstevel@tonic-gate * suspects from the list. If we're auto-closing upsets, we don't 18337c478bd9Sstevel@tonic-gate * want any of those in the published list. If the ASRUs for multiple 18347c478bd9Sstevel@tonic-gate * defects resolve to the same ASRU (driver) we only want to publish 18357c478bd9Sstevel@tonic-gate * that as a single suspect. 18367c478bd9Sstevel@tonic-gate */ 18377c478bd9Sstevel@tonic-gate static void 18387c478bd9Sstevel@tonic-gate trim_suspects(struct fme *fmep, boolean_t no_upsets, struct rsl **begin, 18397c478bd9Sstevel@tonic-gate struct rsl **end) 18407c478bd9Sstevel@tonic-gate { 18417c478bd9Sstevel@tonic-gate struct event *ep; 18427c478bd9Sstevel@tonic-gate struct rsl *rp; 18437c478bd9Sstevel@tonic-gate int rpcnt; 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate /* 18467c478bd9Sstevel@tonic-gate * First save the suspects in the psuspects, then copy back 18477c478bd9Sstevel@tonic-gate * only the ones we wish to retain. This resets nsuspects to 18487c478bd9Sstevel@tonic-gate * zero. 18497c478bd9Sstevel@tonic-gate */ 18507c478bd9Sstevel@tonic-gate rpcnt = fmep->nsuspects; 18517c478bd9Sstevel@tonic-gate save_suspects(fmep); 18527c478bd9Sstevel@tonic-gate 18537c478bd9Sstevel@tonic-gate /* 18547c478bd9Sstevel@tonic-gate * allocate an array of resource pointers for the suspects. 18557c478bd9Sstevel@tonic-gate * We may end up using less than the full allocation, but this 18567c478bd9Sstevel@tonic-gate * is a very short-lived array. publish_suspects() will free 18577c478bd9Sstevel@tonic-gate * this array when it's done using it. 18587c478bd9Sstevel@tonic-gate */ 18597c478bd9Sstevel@tonic-gate rp = *begin = MALLOC(rpcnt * sizeof (struct rsl)); 18607c478bd9Sstevel@tonic-gate bzero(rp, rpcnt * sizeof (struct rsl)); 18617c478bd9Sstevel@tonic-gate 18627c478bd9Sstevel@tonic-gate /* first pass, remove any unwanted upsets and populate our array */ 18637c478bd9Sstevel@tonic-gate for (ep = fmep->psuspects; ep; ep = ep->psuspects) { 18647c478bd9Sstevel@tonic-gate if (no_upsets && is_upset(ep->t)) 18657c478bd9Sstevel@tonic-gate continue; 18667c478bd9Sstevel@tonic-gate get_resources(ep, rp, fmep->cfgdata->cooked); 18677c478bd9Sstevel@tonic-gate rp++; 18687c478bd9Sstevel@tonic-gate fmep->nsuspects++; 18697c478bd9Sstevel@tonic-gate if (!is_fault(ep->t)) 18707c478bd9Sstevel@tonic-gate fmep->nonfault++; 18717c478bd9Sstevel@tonic-gate } 18727c478bd9Sstevel@tonic-gate 18737c478bd9Sstevel@tonic-gate /* if all we had was unwanted upsets, we're done */ 18747c478bd9Sstevel@tonic-gate if (fmep->nsuspects == 0) 18757c478bd9Sstevel@tonic-gate return; 18767c478bd9Sstevel@tonic-gate 18777c478bd9Sstevel@tonic-gate *end = rp - 1; 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate /* sort the array */ 18807c478bd9Sstevel@tonic-gate qsort(*begin, fmep->nsuspects, sizeof (struct rsl), rslcmp); 18817c478bd9Sstevel@tonic-gate rsluniq(*begin, *end, &fmep->nsuspects, &fmep->nonfault); 18827c478bd9Sstevel@tonic-gate } 18837c478bd9Sstevel@tonic-gate 18847aec1d6eScindi /* 18857aec1d6eScindi * addpayloadprop -- add a payload prop to a problem 18867aec1d6eScindi */ 18877aec1d6eScindi static void 18887aec1d6eScindi addpayloadprop(const char *lhs, struct evalue *rhs, nvlist_t *fault) 18897aec1d6eScindi { 18907aec1d6eScindi ASSERT(fault != NULL); 18917aec1d6eScindi ASSERT(lhs != NULL); 18927aec1d6eScindi ASSERT(rhs != NULL); 18937aec1d6eScindi 18947aec1d6eScindi if (rhs->t == UINT64) { 18957aec1d6eScindi out(O_ALTFP|O_VERB2, "addpayloadprop: %s=%llu", lhs, rhs->v); 18967aec1d6eScindi 18977aec1d6eScindi if (nvlist_add_uint64(fault, lhs, rhs->v) != 0) 18987aec1d6eScindi out(O_DIE, 18997aec1d6eScindi "cannot add payloadprop \"%s\" to fault", lhs); 19007aec1d6eScindi } else { 19017aec1d6eScindi out(O_ALTFP|O_VERB2, "addpayloadprop: %s=\"%s\"", 190280ab886dSwesolows lhs, (char *)(uintptr_t)rhs->v); 19037aec1d6eScindi 190480ab886dSwesolows if (nvlist_add_string(fault, lhs, (char *)(uintptr_t)rhs->v) != 190580ab886dSwesolows 0) 19067aec1d6eScindi out(O_DIE, 19077aec1d6eScindi "cannot add payloadprop \"%s\" to fault", lhs); 19087aec1d6eScindi } 19097aec1d6eScindi } 19107aec1d6eScindi 19117aec1d6eScindi static char *Istatbuf; 19127aec1d6eScindi static char *Istatbufptr; 19137aec1d6eScindi static int Istatsz; 19147aec1d6eScindi 19157aec1d6eScindi /* 19167aec1d6eScindi * istataddsize -- calculate size of istat and add it to Istatsz 19177aec1d6eScindi */ 19187aec1d6eScindi /*ARGSUSED2*/ 19197aec1d6eScindi static void 19207aec1d6eScindi istataddsize(const struct istat_entry *lhs, struct stats *rhs, void *arg) 19217aec1d6eScindi { 19227aec1d6eScindi int val; 19237aec1d6eScindi 19247aec1d6eScindi ASSERT(lhs != NULL); 19257aec1d6eScindi ASSERT(rhs != NULL); 19267aec1d6eScindi 19277aec1d6eScindi if ((val = stats_counter_value(rhs)) == 0) 19287aec1d6eScindi return; /* skip zero-valued stats */ 19297aec1d6eScindi 19307aec1d6eScindi /* count up the size of the stat name */ 19317aec1d6eScindi Istatsz += ipath2strlen(lhs->ename, lhs->ipath); 19327aec1d6eScindi Istatsz++; /* for the trailing NULL byte */ 19337aec1d6eScindi 19347aec1d6eScindi /* count up the size of the stat value */ 19357aec1d6eScindi Istatsz += snprintf(NULL, 0, "%d", val); 19367aec1d6eScindi Istatsz++; /* for the trailing NULL byte */ 19377aec1d6eScindi } 19387aec1d6eScindi 19397aec1d6eScindi /* 19407aec1d6eScindi * istat2str -- serialize an istat, writing result to *Istatbufptr 19417aec1d6eScindi */ 19427aec1d6eScindi /*ARGSUSED2*/ 19437aec1d6eScindi static void 19447aec1d6eScindi istat2str(const struct istat_entry *lhs, struct stats *rhs, void *arg) 19457aec1d6eScindi { 19467aec1d6eScindi char *str; 19477aec1d6eScindi int len; 19487aec1d6eScindi int val; 19497aec1d6eScindi 19507aec1d6eScindi ASSERT(lhs != NULL); 19517aec1d6eScindi ASSERT(rhs != NULL); 19527aec1d6eScindi 19537aec1d6eScindi if ((val = stats_counter_value(rhs)) == 0) 19547aec1d6eScindi return; /* skip zero-valued stats */ 19557aec1d6eScindi 19567aec1d6eScindi /* serialize the stat name */ 19577aec1d6eScindi str = ipath2str(lhs->ename, lhs->ipath); 19587aec1d6eScindi len = strlen(str); 19597aec1d6eScindi 19607aec1d6eScindi ASSERT(Istatbufptr + len + 1 < &Istatbuf[Istatsz]); 19617aec1d6eScindi (void) strlcpy(Istatbufptr, str, &Istatbuf[Istatsz] - Istatbufptr); 19627aec1d6eScindi Istatbufptr += len; 19637aec1d6eScindi FREE(str); 19647aec1d6eScindi *Istatbufptr++ = '\0'; 19657aec1d6eScindi 19667aec1d6eScindi /* serialize the stat value */ 19677aec1d6eScindi Istatbufptr += snprintf(Istatbufptr, &Istatbuf[Istatsz] - Istatbufptr, 19687aec1d6eScindi "%d", val); 19697aec1d6eScindi *Istatbufptr++ = '\0'; 19707aec1d6eScindi 19717aec1d6eScindi ASSERT(Istatbufptr <= &Istatbuf[Istatsz]); 19727aec1d6eScindi } 19737aec1d6eScindi 19747aec1d6eScindi void 19757aec1d6eScindi istat_save() 19767aec1d6eScindi { 19777aec1d6eScindi if (Istat_need_save == 0) 19787aec1d6eScindi return; 19797aec1d6eScindi 19807aec1d6eScindi /* figure out how big the serialzed info is */ 19817aec1d6eScindi Istatsz = 0; 19827aec1d6eScindi lut_walk(Istats, (lut_cb)istataddsize, NULL); 19837aec1d6eScindi 19847aec1d6eScindi if (Istatsz == 0) { 19857aec1d6eScindi /* no stats to save */ 19867aec1d6eScindi fmd_buf_destroy(Hdl, NULL, WOBUF_ISTATS); 19877aec1d6eScindi return; 19887aec1d6eScindi } 19897aec1d6eScindi 19907aec1d6eScindi /* create the serialized buffer */ 19917aec1d6eScindi Istatbufptr = Istatbuf = MALLOC(Istatsz); 19927aec1d6eScindi lut_walk(Istats, (lut_cb)istat2str, NULL); 19937aec1d6eScindi 19947aec1d6eScindi /* clear out current saved stats */ 19957aec1d6eScindi fmd_buf_destroy(Hdl, NULL, WOBUF_ISTATS); 19967aec1d6eScindi 19977aec1d6eScindi /* write out the new version */ 19987aec1d6eScindi fmd_buf_write(Hdl, NULL, WOBUF_ISTATS, Istatbuf, Istatsz); 19997aec1d6eScindi FREE(Istatbuf); 20007aec1d6eScindi 20017aec1d6eScindi Istat_need_save = 0; 20027aec1d6eScindi } 20037aec1d6eScindi 20047aec1d6eScindi int 20057aec1d6eScindi istat_cmp(struct istat_entry *ent1, struct istat_entry *ent2) 20067aec1d6eScindi { 20077aec1d6eScindi if (ent1->ename != ent2->ename) 20087aec1d6eScindi return (ent2->ename - ent1->ename); 20097aec1d6eScindi if (ent1->ipath != ent2->ipath) 20107aec1d6eScindi return ((char *)ent2->ipath - (char *)ent1->ipath); 20117aec1d6eScindi 20127aec1d6eScindi return (0); 20137aec1d6eScindi } 20147aec1d6eScindi 20157aec1d6eScindi /* 20167aec1d6eScindi * istat-verify -- verify the component associated with a stat still exists 20177aec1d6eScindi * 20187aec1d6eScindi * if the component no longer exists, this routine resets the stat and 20197aec1d6eScindi * returns 0. if the component still exists, it returns 1. 20207aec1d6eScindi */ 20217aec1d6eScindi static int 20227aec1d6eScindi istat_verify(struct node *snp, struct istat_entry *entp) 20237aec1d6eScindi { 20247aec1d6eScindi struct stats *statp; 20257aec1d6eScindi nvlist_t *fmri; 20267aec1d6eScindi 20277aec1d6eScindi fmri = node2fmri(snp->u.event.epname); 20287aec1d6eScindi if (platform_path_exists(fmri)) { 20297aec1d6eScindi nvlist_free(fmri); 20307aec1d6eScindi return (1); 20317aec1d6eScindi } 20327aec1d6eScindi nvlist_free(fmri); 20337aec1d6eScindi 20347aec1d6eScindi /* component no longer in system. zero out the associated stats */ 20357aec1d6eScindi if ((statp = (struct stats *) 20367aec1d6eScindi lut_lookup(Istats, entp, (lut_cmp)istat_cmp)) == NULL || 20377aec1d6eScindi stats_counter_value(statp) == 0) 20387aec1d6eScindi return (0); /* stat is already reset */ 20397aec1d6eScindi 20407aec1d6eScindi Istat_need_save = 1; 20417aec1d6eScindi stats_counter_reset(statp); 20427aec1d6eScindi return (0); 20437aec1d6eScindi } 20447aec1d6eScindi 20457aec1d6eScindi static void 20467aec1d6eScindi istat_bump(struct node *snp, int n) 20477aec1d6eScindi { 20487aec1d6eScindi struct stats *statp; 20497aec1d6eScindi struct istat_entry ent; 20507aec1d6eScindi 20517aec1d6eScindi ASSERT(snp != NULL); 20527aec1d6eScindi ASSERTinfo(snp->t == T_EVENT, ptree_nodetype2str(snp->t)); 20537aec1d6eScindi ASSERT(snp->u.event.epname != NULL); 20547aec1d6eScindi 20557aec1d6eScindi /* class name should be hoisted into a single stable entry */ 20567aec1d6eScindi ASSERT(snp->u.event.ename->u.name.next == NULL); 20577aec1d6eScindi ent.ename = snp->u.event.ename->u.name.s; 20587aec1d6eScindi ent.ipath = ipath(snp->u.event.epname); 20597aec1d6eScindi 20607aec1d6eScindi if (!istat_verify(snp, &ent)) { 20617aec1d6eScindi /* component no longer exists in system, nothing to do */ 20627aec1d6eScindi return; 20637aec1d6eScindi } 20647aec1d6eScindi 20657aec1d6eScindi if ((statp = (struct stats *) 20667aec1d6eScindi lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL) { 20677aec1d6eScindi /* need to create the counter */ 20687aec1d6eScindi int cnt = 0; 20697aec1d6eScindi struct node *np; 20707aec1d6eScindi char *sname; 20717aec1d6eScindi char *snamep; 20727aec1d6eScindi struct istat_entry *newentp; 20737aec1d6eScindi 20747aec1d6eScindi /* count up the size of the stat name */ 20757aec1d6eScindi np = snp->u.event.ename; 20767aec1d6eScindi while (np != NULL) { 20777aec1d6eScindi cnt += strlen(np->u.name.s); 20787aec1d6eScindi cnt++; /* for the '.' or '@' */ 20797aec1d6eScindi np = np->u.name.next; 20807aec1d6eScindi } 20817aec1d6eScindi np = snp->u.event.epname; 20827aec1d6eScindi while (np != NULL) { 20837aec1d6eScindi cnt += snprintf(NULL, 0, "%s%llu", 20847aec1d6eScindi np->u.name.s, np->u.name.child->u.ull); 20857aec1d6eScindi cnt++; /* for the '/' or trailing NULL byte */ 20867aec1d6eScindi np = np->u.name.next; 20877aec1d6eScindi } 20887aec1d6eScindi 20897aec1d6eScindi /* build the stat name */ 20907aec1d6eScindi snamep = sname = alloca(cnt); 20917aec1d6eScindi np = snp->u.event.ename; 20927aec1d6eScindi while (np != NULL) { 20937aec1d6eScindi snamep += snprintf(snamep, &sname[cnt] - snamep, 20947aec1d6eScindi "%s", np->u.name.s); 20957aec1d6eScindi np = np->u.name.next; 20967aec1d6eScindi if (np) 20977aec1d6eScindi *snamep++ = '.'; 20987aec1d6eScindi } 20997aec1d6eScindi *snamep++ = '@'; 21007aec1d6eScindi np = snp->u.event.epname; 21017aec1d6eScindi while (np != NULL) { 21027aec1d6eScindi snamep += snprintf(snamep, &sname[cnt] - snamep, 21037aec1d6eScindi "%s%llu", np->u.name.s, np->u.name.child->u.ull); 21047aec1d6eScindi np = np->u.name.next; 21057aec1d6eScindi if (np) 21067aec1d6eScindi *snamep++ = '/'; 21077aec1d6eScindi } 21087aec1d6eScindi *snamep++ = '\0'; 21097aec1d6eScindi 21107aec1d6eScindi /* create the new stat & add it to our list */ 21117aec1d6eScindi newentp = MALLOC(sizeof (*newentp)); 21127aec1d6eScindi *newentp = ent; 21137aec1d6eScindi statp = stats_new_counter(NULL, sname, 0); 21147aec1d6eScindi Istats = lut_add(Istats, (void *)newentp, (void *)statp, 21157aec1d6eScindi (lut_cmp)istat_cmp); 21167aec1d6eScindi } 21177aec1d6eScindi 21187aec1d6eScindi /* if n is non-zero, set that value instead of bumping */ 21197aec1d6eScindi if (n) { 21207aec1d6eScindi stats_counter_reset(statp); 21217aec1d6eScindi stats_counter_add(statp, n); 21227aec1d6eScindi } else 21237aec1d6eScindi stats_counter_bump(statp); 21247aec1d6eScindi Istat_need_save = 1; 21258a40a695Sgavinm 21268a40a695Sgavinm ipath_print(O_ALTFP|O_VERB2, ent.ename, ent.ipath); 21278a40a695Sgavinm out(O_ALTFP|O_VERB2, " %s to value %d", n ? "set" : "incremented", 21288a40a695Sgavinm stats_counter_value(statp)); 21297aec1d6eScindi } 21307aec1d6eScindi 21317aec1d6eScindi /*ARGSUSED*/ 21327aec1d6eScindi static void 21337aec1d6eScindi istat_destructor(void *left, void *right, void *arg) 21347aec1d6eScindi { 21357aec1d6eScindi struct istat_entry *entp = (struct istat_entry *)left; 21367aec1d6eScindi struct stats *statp = (struct stats *)right; 21377aec1d6eScindi FREE(entp); 21387aec1d6eScindi stats_delete(statp); 21397aec1d6eScindi } 21407aec1d6eScindi 214108f6c065Sgavinm /* 214208f6c065Sgavinm * Callback used in a walk of the Istats to reset matching stat counters. 214308f6c065Sgavinm */ 214408f6c065Sgavinm static void 214508f6c065Sgavinm istat_counter_reset_cb(struct istat_entry *entp, struct stats *statp, 214608f6c065Sgavinm const struct ipath *ipp) 214708f6c065Sgavinm { 214808f6c065Sgavinm char *path; 214908f6c065Sgavinm 215008f6c065Sgavinm if (entp->ipath == ipp) { 215108f6c065Sgavinm path = ipath2str(entp->ename, ipp); 215208f6c065Sgavinm out(O_ALTFP, "istat_counter_reset_cb: resetting %s", path); 215308f6c065Sgavinm FREE(path); 215408f6c065Sgavinm stats_counter_reset(statp); 215508f6c065Sgavinm Istat_need_save = 1; 215608f6c065Sgavinm } 215708f6c065Sgavinm } 215808f6c065Sgavinm 21597aec1d6eScindi void 21607aec1d6eScindi istat_fini(void) 21617aec1d6eScindi { 21627aec1d6eScindi lut_free(Istats, istat_destructor, NULL); 21637aec1d6eScindi } 21647aec1d6eScindi 2165*b5016cbbSstephh static char *Serdbuf; 2166*b5016cbbSstephh static char *Serdbufptr; 2167*b5016cbbSstephh static int Serdsz; 2168*b5016cbbSstephh 2169*b5016cbbSstephh /* 2170*b5016cbbSstephh * serdaddsize -- calculate size of serd and add it to Serdsz 2171*b5016cbbSstephh */ 2172*b5016cbbSstephh /*ARGSUSED*/ 2173*b5016cbbSstephh static void 2174*b5016cbbSstephh serdaddsize(const struct serd_entry *lhs, struct stats *rhs, void *arg) 2175*b5016cbbSstephh { 2176*b5016cbbSstephh ASSERT(lhs != NULL); 2177*b5016cbbSstephh 2178*b5016cbbSstephh /* count up the size of the stat name */ 2179*b5016cbbSstephh Serdsz += ipath2strlen(lhs->ename, lhs->ipath); 2180*b5016cbbSstephh Serdsz++; /* for the trailing NULL byte */ 2181*b5016cbbSstephh } 2182*b5016cbbSstephh 2183*b5016cbbSstephh /* 2184*b5016cbbSstephh * serd2str -- serialize a serd engine, writing result to *Serdbufptr 2185*b5016cbbSstephh */ 2186*b5016cbbSstephh /*ARGSUSED*/ 2187*b5016cbbSstephh static void 2188*b5016cbbSstephh serd2str(const struct serd_entry *lhs, struct stats *rhs, void *arg) 2189*b5016cbbSstephh { 2190*b5016cbbSstephh char *str; 2191*b5016cbbSstephh int len; 2192*b5016cbbSstephh 2193*b5016cbbSstephh ASSERT(lhs != NULL); 2194*b5016cbbSstephh 2195*b5016cbbSstephh /* serialize the serd engine name */ 2196*b5016cbbSstephh str = ipath2str(lhs->ename, lhs->ipath); 2197*b5016cbbSstephh len = strlen(str); 2198*b5016cbbSstephh 2199*b5016cbbSstephh ASSERT(Serdbufptr + len + 1 <= &Serdbuf[Serdsz]); 2200*b5016cbbSstephh (void) strlcpy(Serdbufptr, str, &Serdbuf[Serdsz] - Serdbufptr); 2201*b5016cbbSstephh Serdbufptr += len; 2202*b5016cbbSstephh FREE(str); 2203*b5016cbbSstephh *Serdbufptr++ = '\0'; 2204*b5016cbbSstephh ASSERT(Serdbufptr <= &Serdbuf[Serdsz]); 2205*b5016cbbSstephh } 2206*b5016cbbSstephh 2207*b5016cbbSstephh void 2208*b5016cbbSstephh serd_save() 2209*b5016cbbSstephh { 2210*b5016cbbSstephh if (Serd_need_save == 0) 2211*b5016cbbSstephh return; 2212*b5016cbbSstephh 2213*b5016cbbSstephh /* figure out how big the serialzed info is */ 2214*b5016cbbSstephh Serdsz = 0; 2215*b5016cbbSstephh lut_walk(SerdEngines, (lut_cb)serdaddsize, NULL); 2216*b5016cbbSstephh 2217*b5016cbbSstephh if (Serdsz == 0) { 2218*b5016cbbSstephh /* no serd engines to save */ 2219*b5016cbbSstephh fmd_buf_destroy(Hdl, NULL, WOBUF_SERDS); 2220*b5016cbbSstephh return; 2221*b5016cbbSstephh } 2222*b5016cbbSstephh 2223*b5016cbbSstephh /* create the serialized buffer */ 2224*b5016cbbSstephh Serdbufptr = Serdbuf = MALLOC(Serdsz); 2225*b5016cbbSstephh lut_walk(SerdEngines, (lut_cb)serd2str, NULL); 2226*b5016cbbSstephh 2227*b5016cbbSstephh /* clear out current saved stats */ 2228*b5016cbbSstephh fmd_buf_destroy(Hdl, NULL, WOBUF_SERDS); 2229*b5016cbbSstephh 2230*b5016cbbSstephh /* write out the new version */ 2231*b5016cbbSstephh fmd_buf_write(Hdl, NULL, WOBUF_SERDS, Serdbuf, Serdsz); 2232*b5016cbbSstephh FREE(Serdbuf); 2233*b5016cbbSstephh Serd_need_save = 0; 2234*b5016cbbSstephh } 2235*b5016cbbSstephh 2236*b5016cbbSstephh int 2237*b5016cbbSstephh serd_cmp(struct serd_entry *ent1, struct serd_entry *ent2) 2238*b5016cbbSstephh { 2239*b5016cbbSstephh if (ent1->ename != ent2->ename) 2240*b5016cbbSstephh return (ent2->ename - ent1->ename); 2241*b5016cbbSstephh if (ent1->ipath != ent2->ipath) 2242*b5016cbbSstephh return ((char *)ent2->ipath - (char *)ent1->ipath); 2243*b5016cbbSstephh 2244*b5016cbbSstephh return (0); 2245*b5016cbbSstephh } 2246*b5016cbbSstephh 2247*b5016cbbSstephh void 2248*b5016cbbSstephh fme_serd_load(fmd_hdl_t *hdl) 2249*b5016cbbSstephh { 2250*b5016cbbSstephh int sz; 2251*b5016cbbSstephh char *sbuf; 2252*b5016cbbSstephh char *sepptr; 2253*b5016cbbSstephh char *ptr; 2254*b5016cbbSstephh struct serd_entry *newentp; 2255*b5016cbbSstephh struct node *epname; 2256*b5016cbbSstephh nvlist_t *fmri; 2257*b5016cbbSstephh char *namestring; 2258*b5016cbbSstephh 2259*b5016cbbSstephh if ((sz = fmd_buf_size(hdl, NULL, WOBUF_SERDS)) == 0) 2260*b5016cbbSstephh return; 2261*b5016cbbSstephh sbuf = alloca(sz); 2262*b5016cbbSstephh fmd_buf_read(hdl, NULL, WOBUF_SERDS, sbuf, sz); 2263*b5016cbbSstephh ptr = sbuf; 2264*b5016cbbSstephh while (ptr < &sbuf[sz]) { 2265*b5016cbbSstephh sepptr = strchr(ptr, '@'); 2266*b5016cbbSstephh *sepptr = '\0'; 2267*b5016cbbSstephh namestring = ptr; 2268*b5016cbbSstephh sepptr++; 2269*b5016cbbSstephh ptr = sepptr; 2270*b5016cbbSstephh ptr += strlen(ptr); 2271*b5016cbbSstephh ptr++; /* move past the '\0' separating paths */ 2272*b5016cbbSstephh epname = pathstring2epnamenp(sepptr); 2273*b5016cbbSstephh fmri = node2fmri(epname); 2274*b5016cbbSstephh if (platform_path_exists(fmri)) { 2275*b5016cbbSstephh newentp = MALLOC(sizeof (*newentp)); 2276*b5016cbbSstephh newentp->hdl = hdl; 2277*b5016cbbSstephh newentp->ipath = ipath(epname); 2278*b5016cbbSstephh newentp->ename = stable(namestring); 2279*b5016cbbSstephh SerdEngines = lut_add(SerdEngines, (void *)newentp, 2280*b5016cbbSstephh (void *)NULL, (lut_cmp)serd_cmp); 2281*b5016cbbSstephh } else 2282*b5016cbbSstephh Serd_need_save = 1; 2283*b5016cbbSstephh nvlist_free(fmri); 2284*b5016cbbSstephh } 2285*b5016cbbSstephh /* save it back again in case some of the paths no longer exist */ 2286*b5016cbbSstephh serd_save(); 2287*b5016cbbSstephh } 2288*b5016cbbSstephh 2289*b5016cbbSstephh /*ARGSUSED*/ 2290*b5016cbbSstephh static void 2291*b5016cbbSstephh serd_destructor(void *left, void *right, void *arg) 2292*b5016cbbSstephh { 2293*b5016cbbSstephh struct serd_entry *entp = (struct serd_entry *)left; 2294*b5016cbbSstephh FREE(entp); 2295*b5016cbbSstephh } 2296*b5016cbbSstephh 2297*b5016cbbSstephh /* 2298*b5016cbbSstephh * Callback used in a walk of the SerdEngines to reset matching serd engines. 2299*b5016cbbSstephh */ 2300*b5016cbbSstephh /*ARGSUSED*/ 2301*b5016cbbSstephh static void 2302*b5016cbbSstephh serd_reset_cb(struct serd_entry *entp, void *unused, const struct ipath *ipp) 2303*b5016cbbSstephh { 2304*b5016cbbSstephh char *path; 2305*b5016cbbSstephh 2306*b5016cbbSstephh if (entp->ipath == ipp) { 2307*b5016cbbSstephh path = ipath2str(entp->ename, ipp); 2308*b5016cbbSstephh out(O_ALTFP, "serd_reset_cb: resetting %s", path); 2309*b5016cbbSstephh fmd_serd_reset(entp->hdl, path); 2310*b5016cbbSstephh FREE(path); 2311*b5016cbbSstephh Serd_need_save = 1; 2312*b5016cbbSstephh } 2313*b5016cbbSstephh } 2314*b5016cbbSstephh 2315*b5016cbbSstephh void 2316*b5016cbbSstephh serd_fini(void) 2317*b5016cbbSstephh { 2318*b5016cbbSstephh lut_free(SerdEngines, serd_destructor, NULL); 2319*b5016cbbSstephh } 2320*b5016cbbSstephh 23217c478bd9Sstevel@tonic-gate static void 23227c478bd9Sstevel@tonic-gate publish_suspects(struct fme *fmep) 23237c478bd9Sstevel@tonic-gate { 23247c478bd9Sstevel@tonic-gate struct rsl *srl = NULL; 23257c478bd9Sstevel@tonic-gate struct rsl *erl; 23267c478bd9Sstevel@tonic-gate struct rsl *rp; 23277c478bd9Sstevel@tonic-gate nvlist_t *fault; 23287c478bd9Sstevel@tonic-gate uint8_t cert; 23297c478bd9Sstevel@tonic-gate uint_t *frs; 23307c478bd9Sstevel@tonic-gate uint_t fravg, frsum, fr; 23317aec1d6eScindi uint_t messval; 23327aec1d6eScindi struct node *snp; 23337c478bd9Sstevel@tonic-gate int frcnt, fridx; 23347c478bd9Sstevel@tonic-gate boolean_t no_upsets = B_FALSE; 23357aec1d6eScindi boolean_t allfaulty = B_TRUE; 23367c478bd9Sstevel@tonic-gate 23377c478bd9Sstevel@tonic-gate stats_counter_bump(fmep->diags); 23387c478bd9Sstevel@tonic-gate 23397c478bd9Sstevel@tonic-gate /* 23407c478bd9Sstevel@tonic-gate * If we're auto-closing upsets, we don't want to include them 23417c478bd9Sstevel@tonic-gate * in any produced suspect lists or certainty accounting. 23427c478bd9Sstevel@tonic-gate */ 23437c478bd9Sstevel@tonic-gate if (Autoclose != NULL) 23447c478bd9Sstevel@tonic-gate if (strcmp(Autoclose, "true") == 0 || 23457c478bd9Sstevel@tonic-gate strcmp(Autoclose, "all") == 0 || 23467c478bd9Sstevel@tonic-gate strcmp(Autoclose, "upsets") == 0) 23477c478bd9Sstevel@tonic-gate no_upsets = B_TRUE; 23487c478bd9Sstevel@tonic-gate 23497c478bd9Sstevel@tonic-gate trim_suspects(fmep, no_upsets, &srl, &erl); 23507c478bd9Sstevel@tonic-gate 23517c478bd9Sstevel@tonic-gate /* 23527c478bd9Sstevel@tonic-gate * If the resulting suspect list has no members, we're 23537c478bd9Sstevel@tonic-gate * done. Returning here will simply close the case. 23547c478bd9Sstevel@tonic-gate */ 23557c478bd9Sstevel@tonic-gate if (fmep->nsuspects == 0) { 23567c478bd9Sstevel@tonic-gate out(O_ALTFP, 23577c478bd9Sstevel@tonic-gate "[FME%d, case %s (all suspects are upsets)]", 23587c478bd9Sstevel@tonic-gate fmep->id, fmd_case_uuid(fmep->hdl, fmep->fmcase)); 23597c478bd9Sstevel@tonic-gate FREE(srl); 23607c478bd9Sstevel@tonic-gate restore_suspects(fmep); 23617c478bd9Sstevel@tonic-gate return; 23627c478bd9Sstevel@tonic-gate } 23637c478bd9Sstevel@tonic-gate 23647c478bd9Sstevel@tonic-gate /* 23657c478bd9Sstevel@tonic-gate * If the suspect list is all faults, then for a given fault, 23667c478bd9Sstevel@tonic-gate * say X of N, X's certainty is computed via: 23677c478bd9Sstevel@tonic-gate * 23687c478bd9Sstevel@tonic-gate * fitrate(X) / (fitrate(1) + ... + fitrate(N)) * 100 23697c478bd9Sstevel@tonic-gate * 23707c478bd9Sstevel@tonic-gate * If none of the suspects are faults, and there are N suspects, 23717c478bd9Sstevel@tonic-gate * the certainty of a given suspect is 100/N. 23727c478bd9Sstevel@tonic-gate * 23737c478bd9Sstevel@tonic-gate * If there are are a mixture of faults and other problems in 23747c478bd9Sstevel@tonic-gate * the suspect list, we take an average of the faults' 23757c478bd9Sstevel@tonic-gate * FITrates and treat this average as the FITrate for any 23767c478bd9Sstevel@tonic-gate * non-faults. The fitrate of any given suspect is then 23777c478bd9Sstevel@tonic-gate * computed per the first formula above. 23787c478bd9Sstevel@tonic-gate */ 23797c478bd9Sstevel@tonic-gate if (fmep->nonfault == fmep->nsuspects) { 23807c478bd9Sstevel@tonic-gate /* NO faults in the suspect list */ 23817c478bd9Sstevel@tonic-gate cert = percentof(1, fmep->nsuspects); 23827c478bd9Sstevel@tonic-gate } else { 23837c478bd9Sstevel@tonic-gate /* sum the fitrates */ 23847c478bd9Sstevel@tonic-gate frs = alloca(fmep->nsuspects * sizeof (uint_t)); 23857c478bd9Sstevel@tonic-gate fridx = frcnt = frsum = 0; 23867c478bd9Sstevel@tonic-gate 23877c478bd9Sstevel@tonic-gate for (rp = srl; rp <= erl; rp++) { 23887c478bd9Sstevel@tonic-gate struct node *n; 23897c478bd9Sstevel@tonic-gate 23907c478bd9Sstevel@tonic-gate if (rp->suspect == NULL) 23917c478bd9Sstevel@tonic-gate continue; 23927c478bd9Sstevel@tonic-gate if (!is_fault(rp->suspect->t)) { 23937c478bd9Sstevel@tonic-gate frs[fridx++] = 0; 23947c478bd9Sstevel@tonic-gate continue; 23957c478bd9Sstevel@tonic-gate } 23967c478bd9Sstevel@tonic-gate n = eventprop_lookup(rp->suspect, L_FITrate); 23977c478bd9Sstevel@tonic-gate if (node2uint(n, &fr) != 0) { 23987c478bd9Sstevel@tonic-gate out(O_DEBUG|O_NONL, "event "); 23997c478bd9Sstevel@tonic-gate ipath_print(O_DEBUG|O_NONL, 2400d96ce684Sstephh rp->suspect->enode->u.event.ename->u.name.s, 2401d96ce684Sstephh rp->suspect->ipp); 24027c478bd9Sstevel@tonic-gate out(O_DEBUG, " has no FITrate (using 1)"); 24037c478bd9Sstevel@tonic-gate fr = 1; 24047c478bd9Sstevel@tonic-gate } else if (fr == 0) { 24057c478bd9Sstevel@tonic-gate out(O_DEBUG|O_NONL, "event "); 24067c478bd9Sstevel@tonic-gate ipath_print(O_DEBUG|O_NONL, 2407d96ce684Sstephh rp->suspect->enode->u.event.ename->u.name.s, 2408d96ce684Sstephh rp->suspect->ipp); 24097c478bd9Sstevel@tonic-gate out(O_DEBUG, " has zero FITrate (using 1)"); 24107c478bd9Sstevel@tonic-gate fr = 1; 24117c478bd9Sstevel@tonic-gate } 24127c478bd9Sstevel@tonic-gate 24137c478bd9Sstevel@tonic-gate frs[fridx++] = fr; 24147c478bd9Sstevel@tonic-gate frsum += fr; 24157c478bd9Sstevel@tonic-gate frcnt++; 24167c478bd9Sstevel@tonic-gate } 24177c478bd9Sstevel@tonic-gate fravg = avg(frsum, frcnt); 24187c478bd9Sstevel@tonic-gate for (fridx = 0; fridx < fmep->nsuspects; fridx++) 24197c478bd9Sstevel@tonic-gate if (frs[fridx] == 0) { 24207c478bd9Sstevel@tonic-gate frs[fridx] = fravg; 24217c478bd9Sstevel@tonic-gate frsum += fravg; 24227c478bd9Sstevel@tonic-gate } 24237c478bd9Sstevel@tonic-gate } 24247c478bd9Sstevel@tonic-gate 24257c478bd9Sstevel@tonic-gate /* Add them in reverse order of our sort, as fmd reverses order */ 24267c478bd9Sstevel@tonic-gate for (rp = erl; rp >= srl; rp--) { 24277c478bd9Sstevel@tonic-gate if (rp->suspect == NULL) 24287c478bd9Sstevel@tonic-gate continue; 24297aec1d6eScindi if (!is_fault(rp->suspect->t)) 24307aec1d6eScindi allfaulty = B_FALSE; 24317c478bd9Sstevel@tonic-gate if (fmep->nonfault != fmep->nsuspects) 24327c478bd9Sstevel@tonic-gate cert = percentof(frs[--fridx], frsum); 24337c478bd9Sstevel@tonic-gate fault = fmd_nvl_create_fault(fmep->hdl, 24347c478bd9Sstevel@tonic-gate rp->suspect->enode->u.event.ename->u.name.s, 24357c478bd9Sstevel@tonic-gate cert, 24367c478bd9Sstevel@tonic-gate rp->asru, 24377c478bd9Sstevel@tonic-gate rp->fru, 24387c478bd9Sstevel@tonic-gate rp->rsrc); 24397c478bd9Sstevel@tonic-gate if (fault == NULL) 24407c478bd9Sstevel@tonic-gate out(O_DIE, "fault creation failed"); 24417aec1d6eScindi /* if "message" property exists, add it to the fault */ 24427aec1d6eScindi if (node2uint(eventprop_lookup(rp->suspect, L_message), 24437aec1d6eScindi &messval) == 0) { 24447aec1d6eScindi 24457aec1d6eScindi out(O_ALTFP, 24467aec1d6eScindi "[FME%d, %s adds message=%d to suspect list]", 24477aec1d6eScindi fmep->id, 24487aec1d6eScindi rp->suspect->enode->u.event.ename->u.name.s, 24497aec1d6eScindi messval); 24507aec1d6eScindi if (nvlist_add_boolean_value(fault, 24517aec1d6eScindi FM_SUSPECT_MESSAGE, 24527aec1d6eScindi (messval) ? B_TRUE : B_FALSE) != 0) { 24537aec1d6eScindi out(O_DIE, "cannot add no-message to fault"); 24547aec1d6eScindi } 24557aec1d6eScindi } 24567aec1d6eScindi /* add any payload properties */ 24577aec1d6eScindi lut_walk(rp->suspect->payloadprops, 24587aec1d6eScindi (lut_cb)addpayloadprop, (void *)fault); 24597c478bd9Sstevel@tonic-gate fmd_case_add_suspect(fmep->hdl, fmep->fmcase, fault); 24607c478bd9Sstevel@tonic-gate rslfree(rp); 24615f25dc2aSgavinm 24625f25dc2aSgavinm /* 24635f25dc2aSgavinm * If "action" property exists, evaluate it; this must be done 24645f25dc2aSgavinm * before the dupclose check below since some actions may 24655f25dc2aSgavinm * modify the asru to be used in fmd_nvl_fmri_faulty. This 24665f25dc2aSgavinm * needs to be restructured if any new actions are introduced 24675f25dc2aSgavinm * that have effects that we do not want to be visible if 24685f25dc2aSgavinm * we decide not to publish in the dupclose check below. 24695f25dc2aSgavinm */ 24707aec1d6eScindi if ((snp = eventprop_lookup(rp->suspect, L_action)) != NULL) { 24717aec1d6eScindi struct evalue evalue; 24727aec1d6eScindi 24737aec1d6eScindi out(O_ALTFP|O_NONL, 24747aec1d6eScindi "[FME%d, %s action ", fmep->id, 24757aec1d6eScindi rp->suspect->enode->u.event.ename->u.name.s); 24767aec1d6eScindi ptree_name_iter(O_ALTFP|O_NONL, snp); 24777aec1d6eScindi out(O_ALTFP, "]"); 24787aec1d6eScindi Action_nvl = fault; 24797aec1d6eScindi (void) eval_expr(snp, NULL, NULL, NULL, NULL, 24807aec1d6eScindi NULL, 0, &evalue); 24817aec1d6eScindi } 24825f25dc2aSgavinm 24837aec1d6eScindi /* 24847aec1d6eScindi * if "dupclose" tunable is set, check if the asru is 24857aec1d6eScindi * already marked as "faulty". 24867aec1d6eScindi */ 24877aec1d6eScindi if (Dupclose && allfaulty) { 24887aec1d6eScindi nvlist_t *asru; 24897aec1d6eScindi 24907aec1d6eScindi out(O_ALTFP|O_VERB, "FMD%d dupclose check ", fmep->id); 24917aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, rp->suspect); 24927aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, " "); 24937aec1d6eScindi if (nvlist_lookup_nvlist(fault, 24947aec1d6eScindi FM_FAULT_ASRU, &asru) != 0) { 24957aec1d6eScindi out(O_ALTFP|O_VERB, "NULL asru"); 24967aec1d6eScindi allfaulty = B_FALSE; 24977aec1d6eScindi } else if (fmd_nvl_fmri_faulty(fmep->hdl, asru)) { 24987aec1d6eScindi out(O_ALTFP|O_VERB, "faulty"); 24997aec1d6eScindi } else { 25007aec1d6eScindi out(O_ALTFP|O_VERB, "not faulty"); 25017aec1d6eScindi allfaulty = B_FALSE; 25027aec1d6eScindi } 25037aec1d6eScindi } 25047aec1d6eScindi 25057aec1d6eScindi } 25065f25dc2aSgavinm 25075f25dc2aSgavinm /* 25085f25dc2aSgavinm * Close the case if all asrus are already known to be faulty and if 25095f25dc2aSgavinm * Dupclose is enabled. Otherwise we are going to publish so take 25105f25dc2aSgavinm * any pre-publication actions. 25115f25dc2aSgavinm */ 25127aec1d6eScindi if (Dupclose && allfaulty) { 25137aec1d6eScindi out(O_ALTFP, "[dupclose FME%d, case %s]", fmep->id, 25147aec1d6eScindi fmd_case_uuid(fmep->hdl, fmep->fmcase)); 25157aec1d6eScindi fmd_case_close(fmep->hdl, fmep->fmcase); 25167aec1d6eScindi } else { 25175f25dc2aSgavinm for (rp = erl; rp >= srl; rp--) { 25185f25dc2aSgavinm struct event *suspect = rp->suspect; 25195f25dc2aSgavinm 25205f25dc2aSgavinm if (suspect == NULL) 25215f25dc2aSgavinm continue; 25225f25dc2aSgavinm 25235f25dc2aSgavinm /* if "count" exists, increment the appropriate stat */ 25245f25dc2aSgavinm if ((snp = eventprop_lookup(suspect, 25255f25dc2aSgavinm L_count)) != NULL) { 25265f25dc2aSgavinm out(O_ALTFP|O_NONL, 25275f25dc2aSgavinm "[FME%d, %s count ", fmep->id, 25285f25dc2aSgavinm suspect->enode->u.event.ename->u.name.s); 25295f25dc2aSgavinm ptree_name_iter(O_ALTFP|O_NONL, snp); 25305f25dc2aSgavinm out(O_ALTFP, "]"); 25315f25dc2aSgavinm istat_bump(snp, 0); 25325f25dc2aSgavinm 25335f25dc2aSgavinm } 25345f25dc2aSgavinm } 25355f25dc2aSgavinm istat_save(); /* write out any istat changes */ 25365f25dc2aSgavinm 25377aec1d6eScindi out(O_ALTFP, "[solving FME%d, case %s]", fmep->id, 25387aec1d6eScindi fmd_case_uuid(fmep->hdl, fmep->fmcase)); 25397aec1d6eScindi fmd_case_solve(fmep->hdl, fmep->fmcase); 25407c478bd9Sstevel@tonic-gate } 25417aec1d6eScindi 25427c478bd9Sstevel@tonic-gate /* 25437c478bd9Sstevel@tonic-gate * revert to the original suspect list 25447c478bd9Sstevel@tonic-gate */ 25457c478bd9Sstevel@tonic-gate FREE(srl); 25467c478bd9Sstevel@tonic-gate restore_suspects(fmep); 25477c478bd9Sstevel@tonic-gate } 25487c478bd9Sstevel@tonic-gate 25497c478bd9Sstevel@tonic-gate static void 2550*b5016cbbSstephh publish_undiagnosable(fmd_hdl_t *hdl, fmd_event_t *ffep, fmd_case_t *fmcase) 25517c478bd9Sstevel@tonic-gate { 25527c478bd9Sstevel@tonic-gate struct case_list *newcase; 25537c478bd9Sstevel@tonic-gate nvlist_t *defect; 25547c478bd9Sstevel@tonic-gate 25557c478bd9Sstevel@tonic-gate out(O_ALTFP, 25567c478bd9Sstevel@tonic-gate "[undiagnosable ereport received, " 25577c478bd9Sstevel@tonic-gate "creating and closing a new case (%s)]", 25587c478bd9Sstevel@tonic-gate Undiag_reason ? Undiag_reason : "reason not provided"); 25597c478bd9Sstevel@tonic-gate 25607c478bd9Sstevel@tonic-gate newcase = MALLOC(sizeof (struct case_list)); 25617c478bd9Sstevel@tonic-gate newcase->next = NULL; 2562*b5016cbbSstephh newcase->fmcase = fmcase; 25637c478bd9Sstevel@tonic-gate if (Undiagablecaselist != NULL) 25647c478bd9Sstevel@tonic-gate newcase->next = Undiagablecaselist; 25657c478bd9Sstevel@tonic-gate Undiagablecaselist = newcase; 25667c478bd9Sstevel@tonic-gate 25677c478bd9Sstevel@tonic-gate if (ffep != NULL) 25687c478bd9Sstevel@tonic-gate fmd_case_add_ereport(hdl, newcase->fmcase, ffep); 25697c478bd9Sstevel@tonic-gate 25707c478bd9Sstevel@tonic-gate defect = fmd_nvl_create_fault(hdl, UNDIAGNOSABLE_DEFECT, 100, 25717c478bd9Sstevel@tonic-gate NULL, NULL, NULL); 25727c478bd9Sstevel@tonic-gate if (Undiag_reason != NULL) 25737c478bd9Sstevel@tonic-gate (void) nvlist_add_string(defect, UNDIAG_REASON, Undiag_reason); 25747c478bd9Sstevel@tonic-gate fmd_case_add_suspect(hdl, newcase->fmcase, defect); 25757c478bd9Sstevel@tonic-gate 25767c478bd9Sstevel@tonic-gate fmd_case_solve(hdl, newcase->fmcase); 25777c478bd9Sstevel@tonic-gate fmd_case_close(hdl, newcase->fmcase); 25787c478bd9Sstevel@tonic-gate } 25797c478bd9Sstevel@tonic-gate 25807c478bd9Sstevel@tonic-gate static void 25817c478bd9Sstevel@tonic-gate fme_undiagnosable(struct fme *f) 25827c478bd9Sstevel@tonic-gate { 25837c478bd9Sstevel@tonic-gate nvlist_t *defect; 25847c478bd9Sstevel@tonic-gate 25857c478bd9Sstevel@tonic-gate out(O_ALTFP, "[solving/closing FME%d, case %s (%s)]", 25867c478bd9Sstevel@tonic-gate f->id, fmd_case_uuid(f->hdl, f->fmcase), 25877c478bd9Sstevel@tonic-gate Undiag_reason ? Undiag_reason : "undiagnosable"); 25887c478bd9Sstevel@tonic-gate 25897c478bd9Sstevel@tonic-gate defect = fmd_nvl_create_fault(f->hdl, UNDIAGNOSABLE_DEFECT, 100, 25907c478bd9Sstevel@tonic-gate NULL, NULL, NULL); 25917c478bd9Sstevel@tonic-gate if (Undiag_reason != NULL) 25927c478bd9Sstevel@tonic-gate (void) nvlist_add_string(defect, UNDIAG_REASON, Undiag_reason); 25937c478bd9Sstevel@tonic-gate fmd_case_add_suspect(f->hdl, f->fmcase, defect); 25947c478bd9Sstevel@tonic-gate fmd_case_solve(f->hdl, f->fmcase); 25957c478bd9Sstevel@tonic-gate fmd_case_close(f->hdl, f->fmcase); 25967c478bd9Sstevel@tonic-gate } 25977c478bd9Sstevel@tonic-gate 25987c478bd9Sstevel@tonic-gate /* 25997c478bd9Sstevel@tonic-gate * fme_close_case 26007c478bd9Sstevel@tonic-gate * 26017c478bd9Sstevel@tonic-gate * Find the requested case amongst our fmes and close it. Free up 26027c478bd9Sstevel@tonic-gate * the related fme. 26037c478bd9Sstevel@tonic-gate */ 26047c478bd9Sstevel@tonic-gate void 26057c478bd9Sstevel@tonic-gate fme_close_case(fmd_hdl_t *hdl, fmd_case_t *fmcase) 26067c478bd9Sstevel@tonic-gate { 26077c478bd9Sstevel@tonic-gate struct case_list *ucasep, *prevcasep = NULL; 26087c478bd9Sstevel@tonic-gate struct fme *prev = NULL; 26097c478bd9Sstevel@tonic-gate struct fme *fmep; 26107c478bd9Sstevel@tonic-gate 26117c478bd9Sstevel@tonic-gate for (ucasep = Undiagablecaselist; ucasep; ucasep = ucasep->next) { 26127c478bd9Sstevel@tonic-gate if (fmcase != ucasep->fmcase) { 26137c478bd9Sstevel@tonic-gate prevcasep = ucasep; 26147c478bd9Sstevel@tonic-gate continue; 26157c478bd9Sstevel@tonic-gate } 26167c478bd9Sstevel@tonic-gate 26177c478bd9Sstevel@tonic-gate if (prevcasep == NULL) 26187c478bd9Sstevel@tonic-gate Undiagablecaselist = Undiagablecaselist->next; 26197c478bd9Sstevel@tonic-gate else 26207c478bd9Sstevel@tonic-gate prevcasep->next = ucasep->next; 26217c478bd9Sstevel@tonic-gate 26227c478bd9Sstevel@tonic-gate FREE(ucasep); 26237c478bd9Sstevel@tonic-gate return; 26247c478bd9Sstevel@tonic-gate } 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate for (fmep = FMElist; fmep; fmep = fmep->next) { 26277c478bd9Sstevel@tonic-gate if (fmep->hdl == hdl && fmep->fmcase == fmcase) 26287c478bd9Sstevel@tonic-gate break; 26297c478bd9Sstevel@tonic-gate prev = fmep; 26307c478bd9Sstevel@tonic-gate } 26317c478bd9Sstevel@tonic-gate 26327c478bd9Sstevel@tonic-gate if (fmep == NULL) { 26337c478bd9Sstevel@tonic-gate out(O_WARN, "Eft asked to close unrecognized case [%s].", 26347c478bd9Sstevel@tonic-gate fmd_case_uuid(hdl, fmcase)); 26357c478bd9Sstevel@tonic-gate return; 26367c478bd9Sstevel@tonic-gate } 26377c478bd9Sstevel@tonic-gate 26387c478bd9Sstevel@tonic-gate if (EFMElist == fmep) 26397c478bd9Sstevel@tonic-gate EFMElist = prev; 26407c478bd9Sstevel@tonic-gate 26417c478bd9Sstevel@tonic-gate if (prev == NULL) 26427c478bd9Sstevel@tonic-gate FMElist = FMElist->next; 26437c478bd9Sstevel@tonic-gate else 26447c478bd9Sstevel@tonic-gate prev->next = fmep->next; 26457c478bd9Sstevel@tonic-gate 26467c478bd9Sstevel@tonic-gate fmep->next = NULL; 26477c478bd9Sstevel@tonic-gate 26487c478bd9Sstevel@tonic-gate /* Get rid of any timer this fme has set */ 26497c478bd9Sstevel@tonic-gate if (fmep->wull != 0) 26507c478bd9Sstevel@tonic-gate fmd_timer_remove(fmep->hdl, fmep->timer); 26517c478bd9Sstevel@tonic-gate 26527c478bd9Sstevel@tonic-gate if (ClosedFMEs == NULL) { 26537c478bd9Sstevel@tonic-gate ClosedFMEs = fmep; 26547c478bd9Sstevel@tonic-gate } else { 26557c478bd9Sstevel@tonic-gate fmep->next = ClosedFMEs; 26567c478bd9Sstevel@tonic-gate ClosedFMEs = fmep; 26577c478bd9Sstevel@tonic-gate } 26580cc1f05eSjrutt 26590cc1f05eSjrutt Open_fme_count--; 26600cc1f05eSjrutt 26610cc1f05eSjrutt /* See if we can close the overflow FME */ 26620cc1f05eSjrutt if (Open_fme_count <= Max_fme) { 26630cc1f05eSjrutt for (fmep = FMElist; fmep; fmep = fmep->next) { 26640cc1f05eSjrutt if (fmep->overflow && !(fmd_case_closed(fmep->hdl, 26650cc1f05eSjrutt fmep->fmcase))) 26660cc1f05eSjrutt break; 26670cc1f05eSjrutt } 26680cc1f05eSjrutt 26690cc1f05eSjrutt if (fmep != NULL) 26700cc1f05eSjrutt fmd_case_close(fmep->hdl, fmep->fmcase); 26710cc1f05eSjrutt } 26727c478bd9Sstevel@tonic-gate } 26737c478bd9Sstevel@tonic-gate 26747c478bd9Sstevel@tonic-gate /* 26757c478bd9Sstevel@tonic-gate * fme_set_timer() 26767c478bd9Sstevel@tonic-gate * If the time we need to wait for the given FME is less than the 26777c478bd9Sstevel@tonic-gate * current timer, kick that old timer out and establish a new one. 26787c478bd9Sstevel@tonic-gate */ 26797aec1d6eScindi static int 26807c478bd9Sstevel@tonic-gate fme_set_timer(struct fme *fmep, unsigned long long wull) 26817c478bd9Sstevel@tonic-gate { 26827c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, " fme_set_timer: request to wait "); 26837c478bd9Sstevel@tonic-gate ptree_timeval(O_ALTFP|O_VERB, &wull); 26847c478bd9Sstevel@tonic-gate 26857c478bd9Sstevel@tonic-gate if (wull <= fmep->pull) { 26867c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, "already have waited at least "); 26877c478bd9Sstevel@tonic-gate ptree_timeval(O_ALTFP|O_VERB, &fmep->pull); 26887c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 26897c478bd9Sstevel@tonic-gate /* we've waited at least wull already, don't need timer */ 26907aec1d6eScindi return (0); 26917c478bd9Sstevel@tonic-gate } 26927c478bd9Sstevel@tonic-gate 26937c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, " currently "); 26947c478bd9Sstevel@tonic-gate if (fmep->wull != 0) { 26957c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, "waiting "); 26967c478bd9Sstevel@tonic-gate ptree_timeval(O_ALTFP|O_VERB, &fmep->wull); 26977c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 26987c478bd9Sstevel@tonic-gate } else { 26997c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, "not waiting"); 27007c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 27017c478bd9Sstevel@tonic-gate } 27027c478bd9Sstevel@tonic-gate 27037c478bd9Sstevel@tonic-gate if (fmep->wull != 0) 27047c478bd9Sstevel@tonic-gate if (wull >= fmep->wull) 27057c478bd9Sstevel@tonic-gate /* New timer would fire later than established timer */ 27067aec1d6eScindi return (0); 27077c478bd9Sstevel@tonic-gate 27087aec1d6eScindi if (fmep->wull != 0) { 27097c478bd9Sstevel@tonic-gate fmd_timer_remove(fmep->hdl, fmep->timer); 27107aec1d6eScindi } 27117c478bd9Sstevel@tonic-gate 27127c478bd9Sstevel@tonic-gate fmep->timer = fmd_timer_install(fmep->hdl, (void *)fmep, 27137c478bd9Sstevel@tonic-gate fmep->e0r, wull); 27147c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, "timer set, id is %ld", fmep->timer); 27157c478bd9Sstevel@tonic-gate fmep->wull = wull; 27167aec1d6eScindi return (1); 27177c478bd9Sstevel@tonic-gate } 27187c478bd9Sstevel@tonic-gate 27197c478bd9Sstevel@tonic-gate void 27207c478bd9Sstevel@tonic-gate fme_timer_fired(struct fme *fmep, id_t tid) 27217c478bd9Sstevel@tonic-gate { 27227c478bd9Sstevel@tonic-gate struct fme *ffmep = NULL; 27237c478bd9Sstevel@tonic-gate 27247c478bd9Sstevel@tonic-gate for (ffmep = FMElist; ffmep; ffmep = ffmep->next) 27257c478bd9Sstevel@tonic-gate if (ffmep == fmep) 27267c478bd9Sstevel@tonic-gate break; 27277c478bd9Sstevel@tonic-gate 27287c478bd9Sstevel@tonic-gate if (ffmep == NULL) { 27297c478bd9Sstevel@tonic-gate out(O_WARN, "Timer fired for an FME (%p) not in FMEs list.", 27307c478bd9Sstevel@tonic-gate (void *)fmep); 27317c478bd9Sstevel@tonic-gate return; 27327c478bd9Sstevel@tonic-gate } 27337c478bd9Sstevel@tonic-gate 2734*b5016cbbSstephh out(O_ALTFP|O_VERB, "Timer fired %lx", tid); 2735d96ce684Sstephh fmep->pull = fmep->wull; 2736d96ce684Sstephh fmep->wull = 0; 2737d96ce684Sstephh fmd_buf_write(fmep->hdl, fmep->fmcase, 2738d96ce684Sstephh WOBUF_PULL, (void *)&fmep->pull, sizeof (fmep->pull)); 2739*b5016cbbSstephh 2740*b5016cbbSstephh fme_reload_cfgdata(fmep); 2741*b5016cbbSstephh 274200d0963fSdilpreet fme_eval(fmep, fmep->e0r); 27437c478bd9Sstevel@tonic-gate } 27447c478bd9Sstevel@tonic-gate 27457c478bd9Sstevel@tonic-gate /* 27467c478bd9Sstevel@tonic-gate * Preserve the fme's suspect list in its psuspects list, NULLing the 27477c478bd9Sstevel@tonic-gate * suspects list in the meantime. 27487c478bd9Sstevel@tonic-gate */ 27497c478bd9Sstevel@tonic-gate static void 27507c478bd9Sstevel@tonic-gate save_suspects(struct fme *fmep) 27517c478bd9Sstevel@tonic-gate { 27527c478bd9Sstevel@tonic-gate struct event *ep; 27537c478bd9Sstevel@tonic-gate struct event *nextep; 27547c478bd9Sstevel@tonic-gate 27557c478bd9Sstevel@tonic-gate /* zero out the previous suspect list */ 27567c478bd9Sstevel@tonic-gate for (ep = fmep->psuspects; ep; ep = nextep) { 27577c478bd9Sstevel@tonic-gate nextep = ep->psuspects; 27587c478bd9Sstevel@tonic-gate ep->psuspects = NULL; 27597c478bd9Sstevel@tonic-gate } 27607c478bd9Sstevel@tonic-gate fmep->psuspects = NULL; 27617c478bd9Sstevel@tonic-gate 27627c478bd9Sstevel@tonic-gate /* zero out the suspect list, copying it to previous suspect list */ 27637c478bd9Sstevel@tonic-gate fmep->psuspects = fmep->suspects; 27647c478bd9Sstevel@tonic-gate for (ep = fmep->suspects; ep; ep = nextep) { 27657c478bd9Sstevel@tonic-gate nextep = ep->suspects; 27667c478bd9Sstevel@tonic-gate ep->psuspects = ep->suspects; 27677c478bd9Sstevel@tonic-gate ep->suspects = NULL; 27687c478bd9Sstevel@tonic-gate ep->is_suspect = 0; 27697c478bd9Sstevel@tonic-gate } 27707c478bd9Sstevel@tonic-gate fmep->suspects = NULL; 27717c478bd9Sstevel@tonic-gate fmep->nsuspects = 0; 27727c478bd9Sstevel@tonic-gate fmep->nonfault = 0; 27737c478bd9Sstevel@tonic-gate } 27747c478bd9Sstevel@tonic-gate 27757c478bd9Sstevel@tonic-gate /* 27767c478bd9Sstevel@tonic-gate * Retrieve the fme's suspect list from its psuspects list. 27777c478bd9Sstevel@tonic-gate */ 27787c478bd9Sstevel@tonic-gate static void 27797c478bd9Sstevel@tonic-gate restore_suspects(struct fme *fmep) 27807c478bd9Sstevel@tonic-gate { 27817c478bd9Sstevel@tonic-gate struct event *ep; 27827c478bd9Sstevel@tonic-gate struct event *nextep; 27837c478bd9Sstevel@tonic-gate 27847c478bd9Sstevel@tonic-gate fmep->nsuspects = fmep->nonfault = 0; 27857c478bd9Sstevel@tonic-gate fmep->suspects = fmep->psuspects; 27867c478bd9Sstevel@tonic-gate for (ep = fmep->psuspects; ep; ep = nextep) { 27877c478bd9Sstevel@tonic-gate fmep->nsuspects++; 27887c478bd9Sstevel@tonic-gate if (!is_fault(ep->t)) 27897c478bd9Sstevel@tonic-gate fmep->nonfault++; 27907c478bd9Sstevel@tonic-gate nextep = ep->psuspects; 27917c478bd9Sstevel@tonic-gate ep->suspects = ep->psuspects; 27927c478bd9Sstevel@tonic-gate } 27937c478bd9Sstevel@tonic-gate } 27947c478bd9Sstevel@tonic-gate 27957c478bd9Sstevel@tonic-gate /* 27967c478bd9Sstevel@tonic-gate * this is what we use to call the Emrys prototype code instead of main() 27977c478bd9Sstevel@tonic-gate */ 27987c478bd9Sstevel@tonic-gate static void 27997c478bd9Sstevel@tonic-gate fme_eval(struct fme *fmep, fmd_event_t *ffep) 28007c478bd9Sstevel@tonic-gate { 28017c478bd9Sstevel@tonic-gate struct event *ep; 28027c478bd9Sstevel@tonic-gate unsigned long long my_delay = TIMEVAL_EVENTUALLY; 28037c478bd9Sstevel@tonic-gate 28047c478bd9Sstevel@tonic-gate save_suspects(fmep); 28057c478bd9Sstevel@tonic-gate 2806*b5016cbbSstephh out(O_ALTFP, "Evaluate FME %d", fmep->id); 28077c478bd9Sstevel@tonic-gate indent_set(" "); 28087c478bd9Sstevel@tonic-gate 28097aec1d6eScindi lut_walk(fmep->eventtree, (lut_cb)clear_arrows, (void *)fmep); 28107aec1d6eScindi fmep->state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay); 28117c478bd9Sstevel@tonic-gate 2812*b5016cbbSstephh out(O_ALTFP|O_NONL, "FME%d state: %s, suspect list:", fmep->id, 28137c478bd9Sstevel@tonic-gate fme_state2str(fmep->state)); 28147c478bd9Sstevel@tonic-gate for (ep = fmep->suspects; ep; ep = ep->suspects) { 2815*b5016cbbSstephh out(O_ALTFP|O_NONL, " "); 2816*b5016cbbSstephh itree_pevent_brief(O_ALTFP|O_NONL, ep); 28177c478bd9Sstevel@tonic-gate } 2818*b5016cbbSstephh out(O_ALTFP, NULL); 28197c478bd9Sstevel@tonic-gate 2820d96ce684Sstephh switch (fmep->state) { 2821d96ce684Sstephh case FME_CREDIBLE: 2822d96ce684Sstephh print_suspects(SLNEW, fmep); 2823d96ce684Sstephh (void) upsets_eval(fmep, ffep); 2824d96ce684Sstephh 28257c478bd9Sstevel@tonic-gate /* 2826d96ce684Sstephh * we may have already posted suspects in upsets_eval() which 2827d96ce684Sstephh * can recurse into fme_eval() again. If so then just return. 28287c478bd9Sstevel@tonic-gate */ 2829d96ce684Sstephh if (fmep->posted_suspects) 2830d96ce684Sstephh return; 28317c478bd9Sstevel@tonic-gate 2832d96ce684Sstephh publish_suspects(fmep); 2833d96ce684Sstephh fmep->posted_suspects = 1; 2834d96ce684Sstephh fmd_buf_write(fmep->hdl, fmep->fmcase, 2835d96ce684Sstephh WOBUF_POSTD, 2836d96ce684Sstephh (void *)&fmep->posted_suspects, 2837d96ce684Sstephh sizeof (fmep->posted_suspects)); 28387c478bd9Sstevel@tonic-gate 2839d96ce684Sstephh /* 2840d96ce684Sstephh * Now the suspects have been posted, we can clear up 2841d96ce684Sstephh * the instance tree as we won't be looking at it again. 2842d96ce684Sstephh * Also cancel the timer as the case is now solved. 2843d96ce684Sstephh */ 2844d96ce684Sstephh if (fmep->wull != 0) { 2845d96ce684Sstephh fmd_timer_remove(fmep->hdl, fmep->timer); 2846d96ce684Sstephh fmep->wull = 0; 28477c478bd9Sstevel@tonic-gate } 2848d96ce684Sstephh break; 2849d96ce684Sstephh 2850d96ce684Sstephh case FME_WAIT: 2851d96ce684Sstephh ASSERT(my_delay > fmep->ull); 2852d96ce684Sstephh (void) fme_set_timer(fmep, my_delay); 2853d96ce684Sstephh print_suspects(SLWAIT, fmep); 2854*b5016cbbSstephh itree_prune(fmep->eventtree); 2855*b5016cbbSstephh config_free(fmep->cfgdata); 2856*b5016cbbSstephh fmep->cfgdata = NULL; 2857*b5016cbbSstephh return; 2858d96ce684Sstephh 2859d96ce684Sstephh case FME_DISPROVED: 2860d96ce684Sstephh print_suspects(SLDISPROVED, fmep); 2861d96ce684Sstephh Undiag_reason = UD_UNSOLVD; 2862d96ce684Sstephh fme_undiagnosable(fmep); 2863d96ce684Sstephh break; 28647c478bd9Sstevel@tonic-gate } 28657c478bd9Sstevel@tonic-gate 28667c478bd9Sstevel@tonic-gate if (fmep->posted_suspects == 1 && Autoclose != NULL) { 28677c478bd9Sstevel@tonic-gate int doclose = 0; 28687c478bd9Sstevel@tonic-gate 28697c478bd9Sstevel@tonic-gate if (strcmp(Autoclose, "true") == 0 || 28707c478bd9Sstevel@tonic-gate strcmp(Autoclose, "all") == 0) 28717c478bd9Sstevel@tonic-gate doclose = 1; 28727c478bd9Sstevel@tonic-gate 28737c478bd9Sstevel@tonic-gate if (strcmp(Autoclose, "upsets") == 0) { 28747c478bd9Sstevel@tonic-gate doclose = 1; 28757c478bd9Sstevel@tonic-gate for (ep = fmep->suspects; ep; ep = ep->suspects) { 28767c478bd9Sstevel@tonic-gate if (ep->t != N_UPSET) { 28777c478bd9Sstevel@tonic-gate doclose = 0; 28787c478bd9Sstevel@tonic-gate break; 28797c478bd9Sstevel@tonic-gate } 28807c478bd9Sstevel@tonic-gate } 28817c478bd9Sstevel@tonic-gate } 28827c478bd9Sstevel@tonic-gate 28837c478bd9Sstevel@tonic-gate if (doclose) { 28847c478bd9Sstevel@tonic-gate out(O_ALTFP, "[closing FME%d, case %s (autoclose)]", 28857c478bd9Sstevel@tonic-gate fmep->id, fmd_case_uuid(fmep->hdl, fmep->fmcase)); 28867c478bd9Sstevel@tonic-gate fmd_case_close(fmep->hdl, fmep->fmcase); 28877c478bd9Sstevel@tonic-gate } 28887c478bd9Sstevel@tonic-gate } 2889*b5016cbbSstephh itree_free(fmep->eventtree); 2890*b5016cbbSstephh fmep->eventtree = NULL; 2891*b5016cbbSstephh config_free(fmep->cfgdata); 2892*b5016cbbSstephh fmep->cfgdata = NULL; 2893*b5016cbbSstephh destroy_fme_bufs(fmep); 28947c478bd9Sstevel@tonic-gate } 28957c478bd9Sstevel@tonic-gate 28967c478bd9Sstevel@tonic-gate static void indent(void); 28977c478bd9Sstevel@tonic-gate static int triggered(struct fme *fmep, struct event *ep, int mark); 28987c478bd9Sstevel@tonic-gate static enum fme_state effects_test(struct fme *fmep, 28997aec1d6eScindi struct event *fault_event, unsigned long long at_latest_by, 29007aec1d6eScindi unsigned long long *pdelay); 29017c478bd9Sstevel@tonic-gate static enum fme_state requirements_test(struct fme *fmep, struct event *ep, 29027aec1d6eScindi unsigned long long at_latest_by, unsigned long long *pdelay); 29037c478bd9Sstevel@tonic-gate static enum fme_state causes_test(struct fme *fmep, struct event *ep, 29047c478bd9Sstevel@tonic-gate unsigned long long at_latest_by, unsigned long long *pdelay); 29057c478bd9Sstevel@tonic-gate 29067aec1d6eScindi static int 29077aec1d6eScindi checkconstraints(struct fme *fmep, struct arrow *arrowp) 29087aec1d6eScindi { 29097aec1d6eScindi struct constraintlist *ctp; 29107aec1d6eScindi struct evalue value; 2911*b5016cbbSstephh char *sep = ""; 29127aec1d6eScindi 29137aec1d6eScindi if (arrowp->forever_false) { 29147aec1d6eScindi indent(); 29157aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, " Forever false constraint: "); 29167aec1d6eScindi for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) { 29177aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, sep); 29187aec1d6eScindi ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0); 29197aec1d6eScindi sep = ", "; 29207aec1d6eScindi } 29217aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 29227aec1d6eScindi return (0); 29237aec1d6eScindi } 2924*b5016cbbSstephh if (arrowp->forever_true) { 2925*b5016cbbSstephh indent(); 2926*b5016cbbSstephh out(O_ALTFP|O_VERB|O_NONL, " Forever true constraint: "); 2927*b5016cbbSstephh for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) { 2928*b5016cbbSstephh out(O_ALTFP|O_VERB|O_NONL, sep); 2929*b5016cbbSstephh ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0); 2930*b5016cbbSstephh sep = ", "; 2931*b5016cbbSstephh } 2932*b5016cbbSstephh out(O_ALTFP|O_VERB, NULL); 2933*b5016cbbSstephh return (1); 2934*b5016cbbSstephh } 29357aec1d6eScindi 29367aec1d6eScindi for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) { 29377aec1d6eScindi if (eval_expr(ctp->cnode, NULL, NULL, 29387aec1d6eScindi &fmep->globals, fmep->cfgdata->cooked, 29397aec1d6eScindi arrowp, 0, &value)) { 29407aec1d6eScindi /* evaluation successful */ 29417aec1d6eScindi if (value.t == UNDEFINED || value.v == 0) { 29427aec1d6eScindi /* known false */ 29437aec1d6eScindi arrowp->forever_false = 1; 29447aec1d6eScindi indent(); 29457aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, 29467aec1d6eScindi " False constraint: "); 29477aec1d6eScindi ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0); 29487aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 29497aec1d6eScindi return (0); 29507aec1d6eScindi } 29517aec1d6eScindi } else { 29527aec1d6eScindi /* evaluation unsuccessful -- unknown value */ 29537aec1d6eScindi indent(); 29547aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, 29557aec1d6eScindi " Deferred constraint: "); 29567aec1d6eScindi ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0); 29577aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 2958*b5016cbbSstephh return (1); 29597aec1d6eScindi } 29607aec1d6eScindi } 29617aec1d6eScindi /* known true */ 2962*b5016cbbSstephh arrowp->forever_true = 1; 2963*b5016cbbSstephh indent(); 2964*b5016cbbSstephh out(O_ALTFP|O_VERB|O_NONL, " True constraint: "); 2965*b5016cbbSstephh for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) { 2966*b5016cbbSstephh out(O_ALTFP|O_VERB|O_NONL, sep); 2967*b5016cbbSstephh ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0); 2968*b5016cbbSstephh sep = ", "; 2969*b5016cbbSstephh } 2970*b5016cbbSstephh out(O_ALTFP|O_VERB, NULL); 29717aec1d6eScindi return (1); 29727aec1d6eScindi } 29737aec1d6eScindi 29747c478bd9Sstevel@tonic-gate static int 29757c478bd9Sstevel@tonic-gate triggered(struct fme *fmep, struct event *ep, int mark) 29767c478bd9Sstevel@tonic-gate { 29777c478bd9Sstevel@tonic-gate struct bubble *bp; 29787c478bd9Sstevel@tonic-gate struct arrowlist *ap; 29797c478bd9Sstevel@tonic-gate int count = 0; 29807c478bd9Sstevel@tonic-gate 29817c478bd9Sstevel@tonic-gate stats_counter_bump(fmep->Tcallcount); 29827c478bd9Sstevel@tonic-gate for (bp = itree_next_bubble(ep, NULL); bp; 29837c478bd9Sstevel@tonic-gate bp = itree_next_bubble(ep, bp)) { 29847c478bd9Sstevel@tonic-gate if (bp->t != B_TO) 29857c478bd9Sstevel@tonic-gate continue; 29867c478bd9Sstevel@tonic-gate for (ap = itree_next_arrow(bp, NULL); ap; 29877c478bd9Sstevel@tonic-gate ap = itree_next_arrow(bp, ap)) { 29887c478bd9Sstevel@tonic-gate /* check count of marks against K in the bubble */ 29897aec1d6eScindi if ((ap->arrowp->mark & mark) && 29907c478bd9Sstevel@tonic-gate ++count >= bp->nork) 29917c478bd9Sstevel@tonic-gate return (1); 29927c478bd9Sstevel@tonic-gate } 29937c478bd9Sstevel@tonic-gate } 29947c478bd9Sstevel@tonic-gate return (0); 29957c478bd9Sstevel@tonic-gate } 29967c478bd9Sstevel@tonic-gate 29977aec1d6eScindi static int 29987aec1d6eScindi mark_arrows(struct fme *fmep, struct event *ep, int mark, 299900d0963fSdilpreet unsigned long long at_latest_by, unsigned long long *pdelay, int keep) 30007c478bd9Sstevel@tonic-gate { 30017c478bd9Sstevel@tonic-gate struct bubble *bp; 30027c478bd9Sstevel@tonic-gate struct arrowlist *ap; 30037aec1d6eScindi unsigned long long overall_delay = TIMEVAL_EVENTUALLY; 30047aec1d6eScindi unsigned long long my_delay; 30057aec1d6eScindi enum fme_state result; 30067aec1d6eScindi int retval = 0; 30077c478bd9Sstevel@tonic-gate 30087c478bd9Sstevel@tonic-gate for (bp = itree_next_bubble(ep, NULL); bp; 30097c478bd9Sstevel@tonic-gate bp = itree_next_bubble(ep, bp)) { 30107c478bd9Sstevel@tonic-gate if (bp->t != B_FROM) 30117c478bd9Sstevel@tonic-gate continue; 30127aec1d6eScindi stats_counter_bump(fmep->Marrowcount); 30137aec1d6eScindi for (ap = itree_next_arrow(bp, NULL); ap; 30147aec1d6eScindi ap = itree_next_arrow(bp, ap)) { 30157aec1d6eScindi struct event *ep2 = ap->arrowp->head->myevent; 30167aec1d6eScindi /* 30177aec1d6eScindi * if we're clearing marks, we can avoid doing 30187aec1d6eScindi * all that work evaluating constraints. 30197aec1d6eScindi */ 30207aec1d6eScindi if (mark == 0) { 3021*b5016cbbSstephh if (ap->arrowp->arrow_marked == 0) 3022*b5016cbbSstephh continue; 3023*b5016cbbSstephh ap->arrowp->arrow_marked = 0; 30247aec1d6eScindi ap->arrowp->mark &= ~EFFECTS_COUNTER; 302500d0963fSdilpreet if (keep && (ep2->cached_state & 302600d0963fSdilpreet (WAIT_EFFECT|CREDIBLE_EFFECT|PARENT_WAIT))) 302700d0963fSdilpreet ep2->keep_in_tree = 1; 30287aec1d6eScindi ep2->cached_state &= 30297aec1d6eScindi ~(WAIT_EFFECT|CREDIBLE_EFFECT|PARENT_WAIT); 303000d0963fSdilpreet (void) mark_arrows(fmep, ep2, mark, 0, NULL, 303100d0963fSdilpreet keep); 30327aec1d6eScindi continue; 30337aec1d6eScindi } 3034*b5016cbbSstephh ap->arrowp->arrow_marked = 1; 30357aec1d6eScindi if (ep2->cached_state & REQMNTS_DISPROVED) { 30367aec1d6eScindi indent(); 30377aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, 30387aec1d6eScindi " ALREADY DISPROVED "); 30397aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); 30407aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 30417aec1d6eScindi continue; 30427aec1d6eScindi } 30437aec1d6eScindi if (ep2->cached_state & WAIT_EFFECT) { 30447aec1d6eScindi indent(); 30457aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, 30467aec1d6eScindi " ALREADY EFFECTS WAIT "); 30477aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); 30487aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 30497aec1d6eScindi continue; 30507aec1d6eScindi } 30517aec1d6eScindi if (ep2->cached_state & CREDIBLE_EFFECT) { 30527aec1d6eScindi indent(); 30537aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, 30547aec1d6eScindi " ALREADY EFFECTS CREDIBLE "); 30557aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); 30567aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 30577aec1d6eScindi continue; 30587aec1d6eScindi } 30597aec1d6eScindi if ((ep2->cached_state & PARENT_WAIT) && 30607aec1d6eScindi (mark & PARENT_WAIT)) { 30617aec1d6eScindi indent(); 30627aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, 30637aec1d6eScindi " ALREADY PARENT EFFECTS WAIT "); 30647aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); 30657aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 30667aec1d6eScindi continue; 30677aec1d6eScindi } 30687aec1d6eScindi platform_set_payloadnvp(ep2->nvp); 306900d0963fSdilpreet if (checkconstraints(fmep, ap->arrowp) == 0) { 30707aec1d6eScindi platform_set_payloadnvp(NULL); 30717aec1d6eScindi indent(); 30727aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, 30737aec1d6eScindi " CONSTRAINTS FAIL "); 30747aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); 30757aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 30767aec1d6eScindi continue; 30777aec1d6eScindi } 30787aec1d6eScindi platform_set_payloadnvp(NULL); 30797aec1d6eScindi ap->arrowp->mark |= EFFECTS_COUNTER; 30807aec1d6eScindi if (!triggered(fmep, ep2, EFFECTS_COUNTER)) { 30817aec1d6eScindi indent(); 30827aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, 30837aec1d6eScindi " K-COUNT NOT YET MET "); 30847aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); 30857aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 30867aec1d6eScindi continue; 30877aec1d6eScindi } 30887aec1d6eScindi ep2->cached_state &= ~PARENT_WAIT; 3089d96ce684Sstephh /* 3090d96ce684Sstephh * if we've reached an ereport and no propagation time 3091d96ce684Sstephh * is specified, use the Hesitate value 3092d96ce684Sstephh */ 3093d96ce684Sstephh if (ep2->t == N_EREPORT && at_latest_by == 0ULL && 3094d96ce684Sstephh ap->arrowp->maxdelay == 0ULL) { 3095d96ce684Sstephh out(O_ALTFP|O_VERB|O_NONL, " default wait "); 3096d96ce684Sstephh itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); 3097d96ce684Sstephh out(O_ALTFP|O_VERB, NULL); 3098*b5016cbbSstephh result = requirements_test(fmep, ep2, Hesitate, 3099*b5016cbbSstephh &my_delay); 3100d96ce684Sstephh } else { 3101d96ce684Sstephh result = requirements_test(fmep, ep2, 3102d96ce684Sstephh at_latest_by + ap->arrowp->maxdelay, 3103d96ce684Sstephh &my_delay); 3104d96ce684Sstephh } 31057aec1d6eScindi if (result == FME_WAIT) { 31067aec1d6eScindi retval = WAIT_EFFECT; 31077aec1d6eScindi if (overall_delay > my_delay) 31087aec1d6eScindi overall_delay = my_delay; 31097aec1d6eScindi ep2->cached_state |= WAIT_EFFECT; 31107aec1d6eScindi indent(); 31117aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, " EFFECTS WAIT "); 31127aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); 31137aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 31147aec1d6eScindi indent_push(" E"); 31157aec1d6eScindi if (mark_arrows(fmep, ep2, PARENT_WAIT, 311600d0963fSdilpreet at_latest_by, &my_delay, 0) == 311700d0963fSdilpreet WAIT_EFFECT) { 31187aec1d6eScindi retval = WAIT_EFFECT; 31197aec1d6eScindi if (overall_delay > my_delay) 31207aec1d6eScindi overall_delay = my_delay; 31217c478bd9Sstevel@tonic-gate } 31227aec1d6eScindi indent_pop(); 31237aec1d6eScindi } else if (result == FME_DISPROVED) { 31247aec1d6eScindi indent(); 31257aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, 31267aec1d6eScindi " EFFECTS DISPROVED "); 31277aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); 31287aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 31297aec1d6eScindi } else { 31307aec1d6eScindi ep2->cached_state |= mark; 31317aec1d6eScindi indent(); 31327aec1d6eScindi if (mark == CREDIBLE_EFFECT) 31337c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, 31347aec1d6eScindi " EFFECTS CREDIBLE "); 31357aec1d6eScindi else 31367aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, 31377aec1d6eScindi " PARENT EFFECTS WAIT "); 31387aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2); 31397aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 31407aec1d6eScindi indent_push(" E"); 31417aec1d6eScindi if (mark_arrows(fmep, ep2, mark, at_latest_by, 314200d0963fSdilpreet &my_delay, 0) == WAIT_EFFECT) { 31437aec1d6eScindi retval = WAIT_EFFECT; 31447aec1d6eScindi if (overall_delay > my_delay) 31457aec1d6eScindi overall_delay = my_delay; 31467c478bd9Sstevel@tonic-gate } 31477aec1d6eScindi indent_pop(); 31487c478bd9Sstevel@tonic-gate } 31497c478bd9Sstevel@tonic-gate } 31507c478bd9Sstevel@tonic-gate } 31517aec1d6eScindi if (retval == WAIT_EFFECT) 31527aec1d6eScindi *pdelay = overall_delay; 31537aec1d6eScindi return (retval); 31547c478bd9Sstevel@tonic-gate } 31557c478bd9Sstevel@tonic-gate 31567c478bd9Sstevel@tonic-gate static enum fme_state 31577aec1d6eScindi effects_test(struct fme *fmep, struct event *fault_event, 31587aec1d6eScindi unsigned long long at_latest_by, unsigned long long *pdelay) 31597c478bd9Sstevel@tonic-gate { 31607c478bd9Sstevel@tonic-gate struct event *error_event; 31617c478bd9Sstevel@tonic-gate enum fme_state return_value = FME_CREDIBLE; 31627aec1d6eScindi unsigned long long overall_delay = TIMEVAL_EVENTUALLY; 31637aec1d6eScindi unsigned long long my_delay; 31647c478bd9Sstevel@tonic-gate 31657c478bd9Sstevel@tonic-gate stats_counter_bump(fmep->Ecallcount); 31667c478bd9Sstevel@tonic-gate indent_push(" E"); 31677c478bd9Sstevel@tonic-gate indent(); 31687c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, "->"); 31697c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, fault_event); 31707c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 31717c478bd9Sstevel@tonic-gate 3172d96ce684Sstephh if (mark_arrows(fmep, fault_event, CREDIBLE_EFFECT, at_latest_by, 3173d96ce684Sstephh &my_delay, 0) == WAIT_EFFECT) { 3174d96ce684Sstephh return_value = FME_WAIT; 3175d96ce684Sstephh if (overall_delay > my_delay) 3176d96ce684Sstephh overall_delay = my_delay; 3177d96ce684Sstephh } 31787c478bd9Sstevel@tonic-gate for (error_event = fmep->observations; 31797c478bd9Sstevel@tonic-gate error_event; error_event = error_event->observations) { 31807c478bd9Sstevel@tonic-gate indent(); 31817c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, " "); 31827c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, error_event); 31837aec1d6eScindi if (!(error_event->cached_state & CREDIBLE_EFFECT)) { 31847aec1d6eScindi if (error_event->cached_state & 31857aec1d6eScindi (PARENT_WAIT|WAIT_EFFECT)) { 31867aec1d6eScindi out(O_ALTFP|O_VERB, " NOT YET triggered"); 31877aec1d6eScindi continue; 31887aec1d6eScindi } 31897c478bd9Sstevel@tonic-gate return_value = FME_DISPROVED; 31907c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, " NOT triggered"); 31917c478bd9Sstevel@tonic-gate break; 31927c478bd9Sstevel@tonic-gate } else { 31937c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, " triggered"); 31947c478bd9Sstevel@tonic-gate } 31957c478bd9Sstevel@tonic-gate } 319600d0963fSdilpreet if (return_value == FME_DISPROVED) { 319700d0963fSdilpreet (void) mark_arrows(fmep, fault_event, 0, 0, NULL, 0); 319800d0963fSdilpreet } else { 319900d0963fSdilpreet fault_event->keep_in_tree = 1; 320000d0963fSdilpreet (void) mark_arrows(fmep, fault_event, 0, 0, NULL, 1); 320100d0963fSdilpreet } 32027c478bd9Sstevel@tonic-gate 32037c478bd9Sstevel@tonic-gate indent(); 32047aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, "<-EFFECTS %s ", 32057aec1d6eScindi fme_state2str(return_value)); 32067c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, fault_event); 32077c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 32087c478bd9Sstevel@tonic-gate indent_pop(); 32097aec1d6eScindi if (return_value == FME_WAIT) 32107aec1d6eScindi *pdelay = overall_delay; 32117c478bd9Sstevel@tonic-gate return (return_value); 32127c478bd9Sstevel@tonic-gate } 32137c478bd9Sstevel@tonic-gate 32147c478bd9Sstevel@tonic-gate static enum fme_state 32157c478bd9Sstevel@tonic-gate requirements_test(struct fme *fmep, struct event *ep, 32167aec1d6eScindi unsigned long long at_latest_by, unsigned long long *pdelay) 32177c478bd9Sstevel@tonic-gate { 32187c478bd9Sstevel@tonic-gate int waiting_events; 32197c478bd9Sstevel@tonic-gate int credible_events; 32207aec1d6eScindi int deferred_events; 32217c478bd9Sstevel@tonic-gate enum fme_state return_value = FME_CREDIBLE; 32227c478bd9Sstevel@tonic-gate unsigned long long overall_delay = TIMEVAL_EVENTUALLY; 32237c478bd9Sstevel@tonic-gate unsigned long long arrow_delay; 32247c478bd9Sstevel@tonic-gate unsigned long long my_delay; 32257c478bd9Sstevel@tonic-gate struct event *ep2; 32267c478bd9Sstevel@tonic-gate struct bubble *bp; 32277c478bd9Sstevel@tonic-gate struct arrowlist *ap; 32287c478bd9Sstevel@tonic-gate 32297aec1d6eScindi if (ep->cached_state & REQMNTS_CREDIBLE) { 32307aec1d6eScindi indent(); 32317aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, " REQMNTS ALREADY CREDIBLE "); 32327aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 32337aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 32347aec1d6eScindi return (FME_CREDIBLE); 32357aec1d6eScindi } 32367aec1d6eScindi if (ep->cached_state & REQMNTS_DISPROVED) { 32377aec1d6eScindi indent(); 32387aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, " REQMNTS ALREADY DISPROVED "); 32397aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 32407aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 32417aec1d6eScindi return (FME_DISPROVED); 32427aec1d6eScindi } 32437aec1d6eScindi if (ep->cached_state & REQMNTS_WAIT) { 32447aec1d6eScindi indent(); 32457aec1d6eScindi *pdelay = ep->cached_delay; 32467aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, " REQMNTS ALREADY WAIT "); 32477aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 32487aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, ", wait for: "); 32497aec1d6eScindi ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by); 32507aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 32517aec1d6eScindi return (FME_WAIT); 32527aec1d6eScindi } 32537c478bd9Sstevel@tonic-gate stats_counter_bump(fmep->Rcallcount); 32547c478bd9Sstevel@tonic-gate indent_push(" R"); 32557c478bd9Sstevel@tonic-gate indent(); 32567c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, "->"); 32577c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 32587c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, ", at latest by: "); 32597c478bd9Sstevel@tonic-gate ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by); 32607c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 32617c478bd9Sstevel@tonic-gate 32627c478bd9Sstevel@tonic-gate if (ep->t == N_EREPORT) { 32637c478bd9Sstevel@tonic-gate if (ep->count == 0) { 32647c478bd9Sstevel@tonic-gate if (fmep->pull >= at_latest_by) { 32657c478bd9Sstevel@tonic-gate return_value = FME_DISPROVED; 32667c478bd9Sstevel@tonic-gate } else { 32677aec1d6eScindi ep->cached_delay = *pdelay = at_latest_by; 32687c478bd9Sstevel@tonic-gate return_value = FME_WAIT; 32697c478bd9Sstevel@tonic-gate } 32707c478bd9Sstevel@tonic-gate } 32717c478bd9Sstevel@tonic-gate 32727c478bd9Sstevel@tonic-gate indent(); 32737c478bd9Sstevel@tonic-gate switch (return_value) { 32747c478bd9Sstevel@tonic-gate case FME_CREDIBLE: 32757aec1d6eScindi ep->cached_state |= REQMNTS_CREDIBLE; 32767aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS CREDIBLE "); 32777c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 32787c478bd9Sstevel@tonic-gate break; 32797c478bd9Sstevel@tonic-gate case FME_DISPROVED: 32807aec1d6eScindi ep->cached_state |= REQMNTS_DISPROVED; 32817aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS DISPROVED "); 32827c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 32837c478bd9Sstevel@tonic-gate break; 32847c478bd9Sstevel@tonic-gate case FME_WAIT: 32857aec1d6eScindi ep->cached_state |= REQMNTS_WAIT; 32867aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS WAIT "); 32877c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 32887c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, " to "); 32897c478bd9Sstevel@tonic-gate ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by); 32907c478bd9Sstevel@tonic-gate break; 32917c478bd9Sstevel@tonic-gate default: 32927c478bd9Sstevel@tonic-gate out(O_DIE, "requirements_test: unexpected fme_state"); 32937c478bd9Sstevel@tonic-gate break; 32947c478bd9Sstevel@tonic-gate } 32957c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 32967c478bd9Sstevel@tonic-gate indent_pop(); 32977c478bd9Sstevel@tonic-gate 32987c478bd9Sstevel@tonic-gate return (return_value); 32997c478bd9Sstevel@tonic-gate } 33007c478bd9Sstevel@tonic-gate 33017c478bd9Sstevel@tonic-gate /* this event is not a report, descend the tree */ 33027c478bd9Sstevel@tonic-gate for (bp = itree_next_bubble(ep, NULL); bp; 33037c478bd9Sstevel@tonic-gate bp = itree_next_bubble(ep, bp)) { 33047aec1d6eScindi int n; 33057aec1d6eScindi 33067c478bd9Sstevel@tonic-gate if (bp->t != B_FROM) 33077c478bd9Sstevel@tonic-gate continue; 33087c478bd9Sstevel@tonic-gate 33097aec1d6eScindi n = bp->nork; 33107aec1d6eScindi 33117aec1d6eScindi credible_events = 0; 33127aec1d6eScindi waiting_events = 0; 33137aec1d6eScindi deferred_events = 0; 33147aec1d6eScindi arrow_delay = TIMEVAL_EVENTUALLY; 33157aec1d6eScindi /* 33167aec1d6eScindi * n is -1 for 'A' so adjust it. 33177aec1d6eScindi * XXX just count up the arrows for now. 33187aec1d6eScindi */ 33197aec1d6eScindi if (n < 0) { 33207aec1d6eScindi n = 0; 33217aec1d6eScindi for (ap = itree_next_arrow(bp, NULL); ap; 33227aec1d6eScindi ap = itree_next_arrow(bp, ap)) 33237aec1d6eScindi n++; 33247aec1d6eScindi indent(); 33257aec1d6eScindi out(O_ALTFP|O_VERB, " Bubble Counted N=%d", n); 33267aec1d6eScindi } else { 33277aec1d6eScindi indent(); 33287aec1d6eScindi out(O_ALTFP|O_VERB, " Bubble N=%d", n); 33297aec1d6eScindi } 33307c478bd9Sstevel@tonic-gate 33317aec1d6eScindi if (n == 0) 33327aec1d6eScindi continue; 33337aec1d6eScindi if (!(bp->mark & (BUBBLE_ELIDED|BUBBLE_OK))) { 33347c478bd9Sstevel@tonic-gate for (ap = itree_next_arrow(bp, NULL); ap; 33357c478bd9Sstevel@tonic-gate ap = itree_next_arrow(bp, ap)) { 33367c478bd9Sstevel@tonic-gate ep2 = ap->arrowp->head->myevent; 33377aec1d6eScindi platform_set_payloadnvp(ep2->nvp); 33387aec1d6eScindi if (checkconstraints(fmep, ap->arrowp) == 0) { 33397aec1d6eScindi /* 33407aec1d6eScindi * if any arrow is invalidated by the 33417aec1d6eScindi * constraints, then we should elide the 33427aec1d6eScindi * whole bubble to be consistant with 33437aec1d6eScindi * the tree creation time behaviour 33447aec1d6eScindi */ 33457aec1d6eScindi bp->mark |= BUBBLE_ELIDED; 33467aec1d6eScindi platform_set_payloadnvp(NULL); 33477c478bd9Sstevel@tonic-gate break; 33487aec1d6eScindi } 33497aec1d6eScindi platform_set_payloadnvp(NULL); 33507aec1d6eScindi } 33517aec1d6eScindi } 33527aec1d6eScindi if (bp->mark & BUBBLE_ELIDED) 33537aec1d6eScindi continue; 33547aec1d6eScindi bp->mark |= BUBBLE_OK; 33557aec1d6eScindi for (ap = itree_next_arrow(bp, NULL); ap; 33567aec1d6eScindi ap = itree_next_arrow(bp, ap)) { 33577aec1d6eScindi ep2 = ap->arrowp->head->myevent; 33587aec1d6eScindi if (n <= credible_events) 33597aec1d6eScindi break; 33607c478bd9Sstevel@tonic-gate 33617aec1d6eScindi ap->arrowp->mark |= REQMNTS_COUNTER; 33627aec1d6eScindi if (triggered(fmep, ep2, REQMNTS_COUNTER)) 33637aec1d6eScindi /* XXX adding max timevals! */ 33647aec1d6eScindi switch (requirements_test(fmep, ep2, 33657aec1d6eScindi at_latest_by + ap->arrowp->maxdelay, 33667aec1d6eScindi &my_delay)) { 33677aec1d6eScindi case FME_DEFERRED: 33687aec1d6eScindi deferred_events++; 33697aec1d6eScindi break; 33707aec1d6eScindi case FME_CREDIBLE: 33717c478bd9Sstevel@tonic-gate credible_events++; 33727aec1d6eScindi break; 33737aec1d6eScindi case FME_DISPROVED: 33747aec1d6eScindi break; 33757aec1d6eScindi case FME_WAIT: 33767aec1d6eScindi if (my_delay < arrow_delay) 33777aec1d6eScindi arrow_delay = my_delay; 33787aec1d6eScindi waiting_events++; 33797aec1d6eScindi break; 33807aec1d6eScindi default: 33817aec1d6eScindi out(O_DIE, 33827aec1d6eScindi "Bug in requirements_test."); 33837aec1d6eScindi } 33847aec1d6eScindi else 33857aec1d6eScindi deferred_events++; 33867aec1d6eScindi } 33877aec1d6eScindi indent(); 33887aec1d6eScindi out(O_ALTFP|O_VERB, " Credible: %d Waiting %d", 33897aec1d6eScindi credible_events + deferred_events, waiting_events); 33907aec1d6eScindi if (credible_events + deferred_events + waiting_events < n) { 33917aec1d6eScindi /* Can never meet requirements */ 33927aec1d6eScindi ep->cached_state |= REQMNTS_DISPROVED; 33937c478bd9Sstevel@tonic-gate indent(); 33947aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS DISPROVED "); 33957c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 33967c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 33977aec1d6eScindi indent_pop(); 33987aec1d6eScindi return (FME_DISPROVED); 33997aec1d6eScindi } 34007aec1d6eScindi if (credible_events + deferred_events < n) { 34017aec1d6eScindi /* will have to wait */ 34027aec1d6eScindi /* wait time is shortest known */ 34037aec1d6eScindi if (arrow_delay < overall_delay) 34047aec1d6eScindi overall_delay = arrow_delay; 34057aec1d6eScindi return_value = FME_WAIT; 34067aec1d6eScindi } else if (credible_events < n) { 34077aec1d6eScindi if (return_value != FME_WAIT) 34087aec1d6eScindi return_value = FME_DEFERRED; 34097c478bd9Sstevel@tonic-gate } 34107c478bd9Sstevel@tonic-gate } 34117c478bd9Sstevel@tonic-gate 34127c478bd9Sstevel@tonic-gate /* 34137aec1d6eScindi * don't mark as FME_DEFERRED. If this event isn't reached by another 34147aec1d6eScindi * path, then this will be considered FME_CREDIBLE. But if it is 34157aec1d6eScindi * reached by a different path so the K-count is met, then might 34167aec1d6eScindi * get overridden by FME_WAIT or FME_DISPROVED. 34177c478bd9Sstevel@tonic-gate */ 34187aec1d6eScindi if (return_value == FME_WAIT) { 34197aec1d6eScindi ep->cached_state |= REQMNTS_WAIT; 34207aec1d6eScindi ep->cached_delay = *pdelay = overall_delay; 34217aec1d6eScindi } else if (return_value == FME_CREDIBLE) { 34227aec1d6eScindi ep->cached_state |= REQMNTS_CREDIBLE; 34237c478bd9Sstevel@tonic-gate } 34247c478bd9Sstevel@tonic-gate indent(); 34257aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS %s ", 34267aec1d6eScindi fme_state2str(return_value)); 34277c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 34287c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 34297c478bd9Sstevel@tonic-gate indent_pop(); 34307c478bd9Sstevel@tonic-gate return (return_value); 34317c478bd9Sstevel@tonic-gate } 34327c478bd9Sstevel@tonic-gate 34337c478bd9Sstevel@tonic-gate static enum fme_state 34347c478bd9Sstevel@tonic-gate causes_test(struct fme *fmep, struct event *ep, 34357c478bd9Sstevel@tonic-gate unsigned long long at_latest_by, unsigned long long *pdelay) 34367c478bd9Sstevel@tonic-gate { 34377c478bd9Sstevel@tonic-gate unsigned long long overall_delay = TIMEVAL_EVENTUALLY; 34387c478bd9Sstevel@tonic-gate unsigned long long my_delay; 34397c478bd9Sstevel@tonic-gate int credible_results = 0; 34407c478bd9Sstevel@tonic-gate int waiting_results = 0; 34417c478bd9Sstevel@tonic-gate enum fme_state fstate; 34427c478bd9Sstevel@tonic-gate struct event *tail_event; 34437c478bd9Sstevel@tonic-gate struct bubble *bp; 34447c478bd9Sstevel@tonic-gate struct arrowlist *ap; 34457c478bd9Sstevel@tonic-gate int k = 1; 34467c478bd9Sstevel@tonic-gate 34477c478bd9Sstevel@tonic-gate stats_counter_bump(fmep->Ccallcount); 34487c478bd9Sstevel@tonic-gate indent_push(" C"); 34497c478bd9Sstevel@tonic-gate indent(); 34507c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, "->"); 34517c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 34527c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 34537c478bd9Sstevel@tonic-gate 34547c478bd9Sstevel@tonic-gate for (bp = itree_next_bubble(ep, NULL); bp; 34557c478bd9Sstevel@tonic-gate bp = itree_next_bubble(ep, bp)) { 34567c478bd9Sstevel@tonic-gate if (bp->t != B_TO) 34577c478bd9Sstevel@tonic-gate continue; 34587c478bd9Sstevel@tonic-gate k = bp->nork; /* remember the K value */ 34597c478bd9Sstevel@tonic-gate for (ap = itree_next_arrow(bp, NULL); ap; 34607c478bd9Sstevel@tonic-gate ap = itree_next_arrow(bp, ap)) { 34617c478bd9Sstevel@tonic-gate int do_not_follow = 0; 34627aec1d6eScindi 34637aec1d6eScindi /* 34647aec1d6eScindi * if we get to the same event multiple times 34657aec1d6eScindi * only worry about the first one. 34667aec1d6eScindi */ 34677aec1d6eScindi if (ap->arrowp->tail->myevent->cached_state & 34687aec1d6eScindi CAUSES_TESTED) { 34697aec1d6eScindi indent(); 34707aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, 34717aec1d6eScindi " causes test already run for "); 34727aec1d6eScindi itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, 34737aec1d6eScindi ap->arrowp->tail->myevent); 34747aec1d6eScindi out(O_ALTFP|O_VERB, NULL); 34757aec1d6eScindi continue; 34767aec1d6eScindi } 34777aec1d6eScindi 34787c478bd9Sstevel@tonic-gate /* 34797c478bd9Sstevel@tonic-gate * see if false constraint prevents us 34807c478bd9Sstevel@tonic-gate * from traversing this arrow 34817c478bd9Sstevel@tonic-gate */ 34827c478bd9Sstevel@tonic-gate platform_set_payloadnvp(ep->nvp); 348300d0963fSdilpreet if (checkconstraints(fmep, ap->arrowp) == 0) 34847aec1d6eScindi do_not_follow = 1; 34857c478bd9Sstevel@tonic-gate platform_set_payloadnvp(NULL); 34867c478bd9Sstevel@tonic-gate if (do_not_follow) { 34877c478bd9Sstevel@tonic-gate indent(); 34887c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, 34897c478bd9Sstevel@tonic-gate " False arrow from "); 34907c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, 34917c478bd9Sstevel@tonic-gate ap->arrowp->tail->myevent); 34927c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 34937c478bd9Sstevel@tonic-gate continue; 34947c478bd9Sstevel@tonic-gate } 34957c478bd9Sstevel@tonic-gate 34967aec1d6eScindi ap->arrowp->tail->myevent->cached_state |= 34977aec1d6eScindi CAUSES_TESTED; 34987aec1d6eScindi tail_event = ap->arrowp->tail->myevent; 34997aec1d6eScindi fstate = hypothesise(fmep, tail_event, at_latest_by, 35007aec1d6eScindi &my_delay); 35017c478bd9Sstevel@tonic-gate 35027c478bd9Sstevel@tonic-gate switch (fstate) { 35037c478bd9Sstevel@tonic-gate case FME_WAIT: 35047c478bd9Sstevel@tonic-gate if (my_delay < overall_delay) 35057c478bd9Sstevel@tonic-gate overall_delay = my_delay; 35067c478bd9Sstevel@tonic-gate waiting_results++; 35077c478bd9Sstevel@tonic-gate break; 35087c478bd9Sstevel@tonic-gate case FME_CREDIBLE: 35097c478bd9Sstevel@tonic-gate credible_results++; 35107c478bd9Sstevel@tonic-gate break; 35117c478bd9Sstevel@tonic-gate case FME_DISPROVED: 35127c478bd9Sstevel@tonic-gate break; 35137c478bd9Sstevel@tonic-gate default: 35147c478bd9Sstevel@tonic-gate out(O_DIE, "Bug in causes_test"); 35157c478bd9Sstevel@tonic-gate } 35167c478bd9Sstevel@tonic-gate } 35177c478bd9Sstevel@tonic-gate } 35187c478bd9Sstevel@tonic-gate /* compare against K */ 35197c478bd9Sstevel@tonic-gate if (credible_results + waiting_results < k) { 35207c478bd9Sstevel@tonic-gate indent(); 35217aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES DISPROVED "); 35227c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 35237c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 35247c478bd9Sstevel@tonic-gate indent_pop(); 35257c478bd9Sstevel@tonic-gate return (FME_DISPROVED); 35267c478bd9Sstevel@tonic-gate } 35277c478bd9Sstevel@tonic-gate if (waiting_results != 0) { 35287c478bd9Sstevel@tonic-gate *pdelay = overall_delay; 35297c478bd9Sstevel@tonic-gate indent(); 35307aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES WAIT "); 35317c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 35327c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, " to "); 35337c478bd9Sstevel@tonic-gate ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by); 35347c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 35357c478bd9Sstevel@tonic-gate indent_pop(); 35367c478bd9Sstevel@tonic-gate return (FME_WAIT); 35377c478bd9Sstevel@tonic-gate } 35387c478bd9Sstevel@tonic-gate indent(); 35397aec1d6eScindi out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES CREDIBLE "); 35407c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 35417c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 35427c478bd9Sstevel@tonic-gate indent_pop(); 35437c478bd9Sstevel@tonic-gate return (FME_CREDIBLE); 35447c478bd9Sstevel@tonic-gate } 35457c478bd9Sstevel@tonic-gate 35467c478bd9Sstevel@tonic-gate static enum fme_state 35477c478bd9Sstevel@tonic-gate hypothesise(struct fme *fmep, struct event *ep, 35487aec1d6eScindi unsigned long long at_latest_by, unsigned long long *pdelay) 35497c478bd9Sstevel@tonic-gate { 35507c478bd9Sstevel@tonic-gate enum fme_state rtr, otr; 35517c478bd9Sstevel@tonic-gate unsigned long long my_delay; 35527c478bd9Sstevel@tonic-gate unsigned long long overall_delay = TIMEVAL_EVENTUALLY; 35537c478bd9Sstevel@tonic-gate 35547c478bd9Sstevel@tonic-gate stats_counter_bump(fmep->Hcallcount); 35557c478bd9Sstevel@tonic-gate indent_push(" H"); 35567c478bd9Sstevel@tonic-gate indent(); 35577c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, "->"); 35587c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 35597c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, ", at latest by: "); 35607c478bd9Sstevel@tonic-gate ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by); 35617c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 35627c478bd9Sstevel@tonic-gate 35637aec1d6eScindi rtr = requirements_test(fmep, ep, at_latest_by, &my_delay); 35647c478bd9Sstevel@tonic-gate if ((rtr == FME_WAIT) && (my_delay < overall_delay)) 35657c478bd9Sstevel@tonic-gate overall_delay = my_delay; 35667c478bd9Sstevel@tonic-gate if (rtr != FME_DISPROVED) { 35677c478bd9Sstevel@tonic-gate if (is_problem(ep->t)) { 35687aec1d6eScindi otr = effects_test(fmep, ep, at_latest_by, &my_delay); 35697c478bd9Sstevel@tonic-gate if (otr != FME_DISPROVED) { 3570*b5016cbbSstephh if (fmep->peek == 0 && ep->is_suspect == 0) { 35717c478bd9Sstevel@tonic-gate ep->suspects = fmep->suspects; 3572*b5016cbbSstephh ep->is_suspect = 1; 35737c478bd9Sstevel@tonic-gate fmep->suspects = ep; 35747c478bd9Sstevel@tonic-gate fmep->nsuspects++; 35757c478bd9Sstevel@tonic-gate if (!is_fault(ep->t)) 35767c478bd9Sstevel@tonic-gate fmep->nonfault++; 35777c478bd9Sstevel@tonic-gate } 35787c478bd9Sstevel@tonic-gate } 35797c478bd9Sstevel@tonic-gate } else 35807c478bd9Sstevel@tonic-gate otr = causes_test(fmep, ep, at_latest_by, &my_delay); 35817c478bd9Sstevel@tonic-gate if ((otr == FME_WAIT) && (my_delay < overall_delay)) 35827c478bd9Sstevel@tonic-gate overall_delay = my_delay; 35837c478bd9Sstevel@tonic-gate if ((otr != FME_DISPROVED) && 35847c478bd9Sstevel@tonic-gate ((rtr == FME_WAIT) || (otr == FME_WAIT))) 35857c478bd9Sstevel@tonic-gate *pdelay = overall_delay; 35867c478bd9Sstevel@tonic-gate } 35877c478bd9Sstevel@tonic-gate if (rtr == FME_DISPROVED) { 35887c478bd9Sstevel@tonic-gate indent(); 35897c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED "); 35907c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 35917c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, " (doesn't meet requirements)"); 35927c478bd9Sstevel@tonic-gate indent_pop(); 35937c478bd9Sstevel@tonic-gate return (FME_DISPROVED); 35947c478bd9Sstevel@tonic-gate } 35957c478bd9Sstevel@tonic-gate if ((otr == FME_DISPROVED) && is_problem(ep->t)) { 35967c478bd9Sstevel@tonic-gate indent(); 35977c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED "); 35987c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 35997c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, " (doesn't explain all reports)"); 36007c478bd9Sstevel@tonic-gate indent_pop(); 36017c478bd9Sstevel@tonic-gate return (FME_DISPROVED); 36027c478bd9Sstevel@tonic-gate } 36037c478bd9Sstevel@tonic-gate if (otr == FME_DISPROVED) { 36047c478bd9Sstevel@tonic-gate indent(); 36057c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED "); 36067c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 36077c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, " (causes are not credible)"); 36087c478bd9Sstevel@tonic-gate indent_pop(); 36097c478bd9Sstevel@tonic-gate return (FME_DISPROVED); 36107c478bd9Sstevel@tonic-gate } 36117c478bd9Sstevel@tonic-gate if ((rtr == FME_WAIT) || (otr == FME_WAIT)) { 36127c478bd9Sstevel@tonic-gate indent(); 36137c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, "<-WAIT "); 36147c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 36157c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, " to "); 36167c478bd9Sstevel@tonic-gate ptree_timeval(O_ALTFP|O_VERB|O_NONL, &overall_delay); 36177c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 36187c478bd9Sstevel@tonic-gate indent_pop(); 36197c478bd9Sstevel@tonic-gate return (FME_WAIT); 36207c478bd9Sstevel@tonic-gate } 36217c478bd9Sstevel@tonic-gate indent(); 36227c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB|O_NONL, "<-CREDIBLE "); 36237c478bd9Sstevel@tonic-gate itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep); 36247c478bd9Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 36257c478bd9Sstevel@tonic-gate indent_pop(); 36267c478bd9Sstevel@tonic-gate return (FME_CREDIBLE); 36277c478bd9Sstevel@tonic-gate } 36287aec1d6eScindi 36297aec1d6eScindi /* 36307aec1d6eScindi * fme_istat_load -- reconstitute any persistent istats 36317aec1d6eScindi */ 36327aec1d6eScindi void 36337aec1d6eScindi fme_istat_load(fmd_hdl_t *hdl) 36347aec1d6eScindi { 36357aec1d6eScindi int sz; 36367aec1d6eScindi char *sbuf; 36377aec1d6eScindi char *ptr; 36387aec1d6eScindi 36397aec1d6eScindi if ((sz = fmd_buf_size(hdl, NULL, WOBUF_ISTATS)) == 0) { 36407aec1d6eScindi out(O_ALTFP, "fme_istat_load: No stats"); 36417aec1d6eScindi return; 36427aec1d6eScindi } 36437aec1d6eScindi 36447aec1d6eScindi sbuf = alloca(sz); 36457aec1d6eScindi 36467aec1d6eScindi fmd_buf_read(hdl, NULL, WOBUF_ISTATS, sbuf, sz); 36477aec1d6eScindi 36487aec1d6eScindi /* 36497aec1d6eScindi * pick apart the serialized stats 36507aec1d6eScindi * 36517aec1d6eScindi * format is: 36527aec1d6eScindi * <class-name>, '@', <path>, '\0', <value>, '\0' 36537aec1d6eScindi * for example: 36547aec1d6eScindi * "stat.first@stat0/path0\02\0stat.second@stat0/path1\023\0" 36557aec1d6eScindi * 36567aec1d6eScindi * since this is parsing our own serialized data, any parsing issues 36577aec1d6eScindi * are fatal, so we check for them all with ASSERT() below. 36587aec1d6eScindi */ 36597aec1d6eScindi ptr = sbuf; 36607aec1d6eScindi while (ptr < &sbuf[sz]) { 36617aec1d6eScindi char *sepptr; 36627aec1d6eScindi struct node *np; 36637aec1d6eScindi int val; 36647aec1d6eScindi 36657aec1d6eScindi sepptr = strchr(ptr, '@'); 36667aec1d6eScindi ASSERT(sepptr != NULL); 36677aec1d6eScindi *sepptr = '\0'; 36687aec1d6eScindi 36697aec1d6eScindi /* construct the event */ 36707aec1d6eScindi np = newnode(T_EVENT, NULL, 0); 36717aec1d6eScindi np->u.event.ename = newnode(T_NAME, NULL, 0); 36727aec1d6eScindi np->u.event.ename->u.name.t = N_STAT; 36737aec1d6eScindi np->u.event.ename->u.name.s = stable(ptr); 36747aec1d6eScindi np->u.event.ename->u.name.it = IT_ENAME; 36757aec1d6eScindi np->u.event.ename->u.name.last = np->u.event.ename; 36767aec1d6eScindi 36777aec1d6eScindi ptr = sepptr + 1; 36787aec1d6eScindi ASSERT(ptr < &sbuf[sz]); 36797aec1d6eScindi ptr += strlen(ptr); 36807aec1d6eScindi ptr++; /* move past the '\0' separating path from value */ 36817aec1d6eScindi ASSERT(ptr < &sbuf[sz]); 36827aec1d6eScindi ASSERT(isdigit(*ptr)); 36837aec1d6eScindi val = atoi(ptr); 36847aec1d6eScindi ASSERT(val > 0); 36857aec1d6eScindi ptr += strlen(ptr); 36867aec1d6eScindi ptr++; /* move past the final '\0' for this entry */ 36877aec1d6eScindi 36887aec1d6eScindi np->u.event.epname = pathstring2epnamenp(sepptr + 1); 36897aec1d6eScindi ASSERT(np->u.event.epname != NULL); 36907aec1d6eScindi 36917aec1d6eScindi istat_bump(np, val); 36927aec1d6eScindi tree_free(np); 36937aec1d6eScindi } 36947aec1d6eScindi 36957aec1d6eScindi istat_save(); 36967aec1d6eScindi } 3697