fme.c revision c333dd99c762d509c7eb6cce222221958e23b4c8
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* fme.c -- fault management exercise module
*
* this module provides the simulated fault management exercise.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <alloca.h>
#include <libnvpair.h>
#include "alloc.h"
#include "out.h"
#include "stats.h"
#include "stable.h"
#include "literals.h"
#include "lut.h"
#include "tree.h"
#include "ptree.h"
#include "itree.h"
#include "ipath.h"
#include "fme.h"
#include "evnv.h"
#include "eval.h"
#include "config.h"
#include "platform.h"
#include "esclex.h"
/* imported from eft.c... */
extern char *Autoclose;
extern char *Serd_Override;
extern nv_alloc_t Eft_nv_hdl;
extern int Max_fme;
static int Istat_need_save;
static int Serd_need_save;
void istat_save(void);
void serd_save(void);
/* fme under construction is global so we can free it on module abort */
static const char *Undiag_reason;
static int Nextid = 0;
static int Open_fme_count = 0; /* Count of open FMEs */
/* list of fault management exercises underway */
static struct fme {
unsigned long long ull; /* time when fme was created */
int id; /* FME id */
/*
* The initial error report that created this FME is kept in
* two forms. e0 points to the instance tree node and is used
* by fme_eval() as the starting point for the inference
* algorithm. e0r is the event handle FMD passed to us when
* the ereport first arrived and is used when setting timers,
* which are always relative to the time of this initial
* report.
*/
int nsuspects; /* count of suspects */
int nonfault; /* zero if all suspects T_FAULT */
int posted_suspects; /* true if we've posted a diagnosis */
int uniqobs; /* number of unique events observed */
int peek; /* just peeking, don't track suspects */
int overflow; /* true if overflow FME */
enum fme_state {
FME_WAIT, /* need to wait for more info */
FME_CREDIBLE, /* suspect list is credible */
FME_DISPROVED, /* no valid suspects found */
FME_DEFERRED /* don't know yet (k-count not met) */
} state;
unsigned long long pull; /* time passed since created */
unsigned long long wull; /* wait until this time for re-eval */
/* fmd interfacing */
/* stats */
struct stats *Hcallcount;
struct stats *Rcallcount;
struct stats *Ccallcount;
struct stats *Ecallcount;
struct stats *Tcallcount;
struct stats *Marrowcount;
static struct case_list {
unsigned long long at_latest_by, unsigned long long *pdelay);
fmd_case_t *fmcase);
static void destroy_fme(struct fme *f);
void *unused2);
static struct fme *
alloc_fme(void)
{
return (fmep);
}
/*
* fme_ready -- called when all initialization of the FME (except for
* stats) has completed successfully. Adds the fme to global lists
* and establishes its stats.
*/
static struct fme *
{
char nbuf[100];
if (EFMElist) {
} else
"calls to requirements_test()", 1);
fmep->Ecallcount =
"arrows marked by mark_arrows()", 1);
return (fmep);
}
extern void ipath_dummy_lut(struct arrow *);
/* ARGSUSED */
static void
{
continue;
}
}
}
/* ARGSUSED */
static void
{
continue;
}
}
static void
{
char nbuf[100];
unsigned long long my_delay = TIMEVAL_EVENTUALLY;
return;
}
Nfmep->Hcallcount =
"calls to requirements_test()", 1);
Nfmep->Ccallcount =
Nfmep->Ecallcount =
"arrows marked by mark_arrows()", 1);
}
static struct fme *
{
int init_size;
extern int alloc_total();
init_size = alloc_total();
return (NULL);
}
alloc_total() - init_size);
Nfmep->posted_suspects = 0;
return (NULL);
}
return (NULL);
}
}
void
fme_fini(void)
{
}
/* clean up closed fmes */
fp = ClosedFMEs;
}
ClosedFMEs = NULL;
}
/* if we were in the middle of creating an fme, free it now */
if (Nfmep) {
}
}
/*
* Allocated space for a buffer name. 20 bytes allows for
* a ridiculous 9,999,999 unique observations.
*/
#define OBBUFNMSZ 20
/*
* serialize_observation
*
* Create a recoverable version of the current observation
* (f->ecurrent). We keep a serialized version of each unique
* observation in order that we may resume correctly the fme in the
* correct state if eft or fmd crashes and we're restarted.
*/
static void
{
char *estr;
}
}
/*
* init_fme_bufs -- We keep several bits of state about an fme for
* use if eft or fmd crashes and we're restarted.
*/
static void
{
sizeof (fp->posted_suspects));
}
static void
{
int o;
}
}
/*
* reconstitute_observations -- convert a case's serialized observations
* back into struct events. Returns zero if all observations are
* successfully reconstituted.
*/
static int
{
char *sepptr;
char *estr;
int ocnt;
int elen;
if (elen == 0) {
"reconstitute_observation: no %s buffer found.",
tmpbuf);
break;
}
"reconstitute_observation: %s: "
"missing @ separator in %s.",
break;
}
*sepptr = '\0';
"reconstitute_observation: %s: "
"trouble converting path string \"%s\" "
"to internal representation.",
break;
}
/* construct the event */
"reconstitute_observation: %s: "
"lookup of \"%s\" in itree failed.",
break;
}
/*
* We may or may not have a saved nvlist for the observation
*/
if (pkdlen != 0) {
if (nvlist_xunpack(pkd,
}
if (ocnt == 0)
/* link it into list of observations seen */
}
return (0);
}
return (1);
}
/*
* restart_fme -- called during eft initialization. Reconstitutes
* an in-progress fme.
*/
void
{
char *sepptr;
char *estr;
int elen;
int init_size;
extern int alloc_total();
/*
* ignore solved or closed cases
*/
return;
goto badcase;
} else {
(void *)&fmep->posted_suspects,
sizeof (fmep->posted_suspects));
}
goto badcase;
} else {
}
goto badcase;
}
sizeof (size_t));
goto badcase;
}
goto badcase;
} else {
}
goto badcase;
} else {
}
if (elen == 0) {
tmpbuf);
goto badcase;
}
"missing @ separator in %s.",
goto badcase;
}
*sepptr = '\0';
"trouble converting path string \"%s\" "
goto badcase;
}
init_size = alloc_total();
if (rawsz > 0) {
goto badcase;
}
} else {
}
alloc_total() - init_size);
/* case not properly saved or irretrievable */
goto badcase;
}
if (reconstitute_observations(fmep) != 0)
goto badcase;
}
/* give the diagnosis algorithm a shot at the new FME state */
return;
/*
* Since we're unable to restart the case, add it to the undiagable
* list and solve and close it as appropriate.
*/
if (Undiagablecaselist != NULL)
} else {
if (Undiag_reason != NULL)
(void) nvlist_add_string(defect,
}
} else {
}
}
/*ARGSUSED*/
static void
{
}
void
destroy_fme(struct fme *f)
{
stats_delete(f->Rcount);
stats_delete(f->Hcallcount);
stats_delete(f->Rcallcount);
stats_delete(f->Ccallcount);
stats_delete(f->Ecallcount);
stats_delete(f->Tcallcount);
stats_delete(f->Marrowcount);
stats_delete(f->diags);
itree_free(f->eventtree);
if (f->config)
structconfig_free(f->config);
FREE(f);
}
static const char *
fme_state2str(enum fme_state s)
{
switch (s) {
case FME_NOTHING: return ("NOTHING");
case FME_WAIT: return ("WAIT");
case FME_CREDIBLE: return ("CREDIBLE");
case FME_DISPROVED: return ("DISPROVED");
case FME_DEFERRED: return ("DEFERRED");
default: return ("UNKNOWN");
}
}
static int
is_problem(enum nametype t)
{
}
static int
{
return (t == N_FAULT);
}
static int
{
return (t == N_DEFECT);
}
static int
{
return (t == N_UPSET);
}
static void
{
}
else
}
}
}
}
static struct node *
pathstring2epnamenp(char *path)
{
char *sep = "/";
char *ptr;
return (ret);
}
/*
* for a given upset sp, increment the corresponding SERD engine. if the
* SERD engine trips, return the ename and ipp of the resulting ereport.
* returns true if engine tripped and *enamep and *ippp were filled in.
*/
static int
{
char *serdname;
struct serd_entry *newentp;
/*
* obtain instanced SERD engine from the upset sp. from this
* derive serdname, the string used to identify the SERD engine.
*/
return (NULL);
/* handle serd engine "id" property, if there is one */
if ((nid =
char suffixbuf[200];
char *suffix;
char *nserdname;
} else {
}
}
const char *s;
char *path;
const char *name;
char *serd_name;
int i;
char *ptr;
int got_n_override = 0, got_t_override = 0;
/* no SERD engine yet, so create it */
/*
* We allow serd paramaters to be overridden, either from
* eft.conf file values (if Serd_Override is set) or from
* driver properties (for "serd.io.device" engines).
*/
if (Serd_Override != NULL) {
while (*ptr3 != '\0') {
*ptr1 = '\0';
*ptr2 = '\0';
if (ptr3)
*ptr3 = '\0';
got_n_override = 1;
got_t_override = 1;
break;
} else {
break;
}
ptr3++;
}
}
if (cp && got_n_override == 0) {
/*
* convert serd engine name into property name
*/
if (name[i] == '.')
serd_name[i] = '_';
else
}
serd_name[i++] = '_';
serd_name[i++] = 'n';
serd_name[i] = '\0';
got_n_override = 1;
}
got_t_override = 1;
}
}
if (!got_n_override) {
NULL);
}
if (!got_t_override) {
NULL);
} else {
const unsigned long long *ullp;
const char *suffix;
int len;
}
}
Serd_need_save = 1;
serd_save();
} else {
}
/*
* increment SERD engine. if engine fires, reset serd
* engine and return trip_strcode
*/
return (1);
}
return (0);
}
/*
* search a suspect list for upsets. feed each upset to serd_eval() and
* build up tripped[], an array of ereports produced by the firing of
* any SERD engines. then feed each ereport back into
* fme_receive_report().
*
* returns ntrip, the number of these ereports produced.
*/
static int
{
/* we build an array of tripped ereports that we send ourselves */
struct {
const char *ename;
} *tripped;
/*
* count the number of upsets to determine the upper limit on
* expected trip ereport strings. remember that one upset can
* lead to at most one ereport.
*/
nupset = 0;
nupset++;
}
if (nupset == 0)
return (0);
/*
* get to this point if we have upsets and expect some trip
* ereports
*/
ntrip = 0;
ntrip++;
for (i = 0; i < ntrip; i++) {
const char *eventstring;
int prev_verbose;
unsigned long long my_delay = TIMEVAL_EVENTUALLY;
/*
* First try and evaluate a case with the trip ereport plus
* all the other ereports that cause the trip. If that fails
* to evaluate then try again with just this ereport on its own.
*/
/*
* create a duplicate fme and case
*/
continue;
}
if (ffep) {
}
/*
* add the original ereports
*/
}
if (ffep)
ffep);
}
/*
* add the serd trigger ereport
*/
/*
* The trigger ereport is not in the instance tree. It
* was presumably removed by prune_propagations() as
* this combination of events is not present in the
* rules.
*/
goto retry_lone_ereport;
}
/*
* just peek first.
*/
if (Debug == 0)
Verbose = 0;
if (state == FME_DISPROVED) {
/*
* However the trigger ereport on its own might be
* diagnosable, so check for that. Undo the new fme
* and case we just created and call fme_receive_report.
*/
continue;
}
/*
* and evaluate
*/
if (ffep)
}
return (ntrip);
}
/*
* fme_receive_external_report -- call when an external ereport comes in
*
* this routine just converts the relevant information from the ereport
* into a format used internally and passes it on to fme_receive_report().
*/
void
const char *eventstring)
{
/*
* XFILE: If we ended up without a path, it's an X-file.
* For now, use our undiagnosable interface.
*/
return;
}
}
/*ARGSUSED*/
void
const char *eventstring)
{
char *uuid;
return;
}
while (nvc-- != 0) {
/*
* Reset any istat or serd engine associated with this path.
*/
char *path;
continue;
path);
istat_save();
serd_save();
}
}
/*ARGSUSED*/
void
{
istat_save();
serd_save();
}
/* ARGSUSED */
static void
{
ep->cached_state = 0;
ep->keep_in_tree = 0;
continue;
}
}
static void
{
int matched = 0;
/* decide which FME it goes to */
int prev_verbose;
unsigned long long my_delay = TIMEVAL_EVENTUALLY;
continue;
}
/*
* ignore solved or closed cases
*/
if (fmep->posted_suspects ||
continue;
/* look up event in event tree for this FME */
continue;
/* note observation */
/* link it into list of observations seen */
} else {
/* use new payload values for peek */
}
/* tell hypothesise() not to mess with suspect list */
/* don't want this to be verbose (unless Debug is set) */
if (Debug == 0)
Verbose = 0;
/* put verbose flag back */
if (state != FME_DISPROVED) {
/* found an FME that explains the ereport */
matched++;
if (pre_peek_nvp)
if (ffep)
/* re-eval FME */
} else {
/* not a match, undo noting of observation */
/* unlink it from observations */
} else {
}
}
}
if (matched)
return; /* explained by at least one existing FME */
/* clean up closed fmes */
cfmep = ClosedFMEs;
}
ClosedFMEs = NULL;
if (ofmep) {
if (ffep)
return;
/* Create overflow fme */
return;
}
if (ffep)
return;
}
/* open a case */
/* start a new FME */
return;
}
/* note observation */
/* link it into list of observations seen */
} else {
/* new payload overrides any previous */
}
if (ffep) {
}
/* give the diagnosis algorithm a shot at the new FME state */
}
void
fme_status(int flags)
{
return;
}
}
/*
* "indent" routines used mostly for nicely formatted debug output, but also
* for sanity checking for infinite recursion bugs.
*/
#define MAX_INDENT 1024
static const char *indent_s[MAX_INDENT];
static int current_indent;
static void
indent_push(const char *s)
{
if (current_indent < MAX_INDENT)
indent_s[current_indent++] = s;
else
}
static void
indent_set(const char *s)
{
current_indent = 0;
indent_push(s);
}
static void
indent_pop(void)
{
if (current_indent > 0)
else
}
static void
indent(void)
{
int i;
if (!Verbose)
return;
for (i = 0; i < current_indent; i++)
}
#define SLNEW 1
#define SLCHANGED 2
#define SLWAIT 3
#define SLDISPROVED 4
static void
{
if (circumstance == SLCHANGED) {
} else if (circumstance == SLWAIT) {
} else if (circumstance == SLDISPROVED) {
} else {
}
return;
}
}
}
static struct node *
{
}
#define MAXDIGITIDX 23
static int
{
if (n == NULL)
return (1);
/*
* check value.v since we are being asked to convert an unsigned
* long long int to an unsigned int
*/
return (1);
return (0);
}
static nvlist_t *
{
char *failure;
int err, i;
/* XXX do we need to be able to handle a non-T_NAME node? */
return (NULL);
break;
depth++;
}
/* We bailed early, something went wrong */
return (NULL);
}
for (i = 0; i < depth; i++)
if (err != 0) {
failure = "basic construction of FMRI failed";
goto boom;
}
i = 0;
if (err != 0) {
failure = "alloc of an hc-pair failed";
goto boom;
}
if (err != 0) {
failure = "construction of an hc-pair failed";
goto boom;
}
pa[i++] = p;
}
if (err == 0) {
for (i = 0; i < depth; i++)
nvlist_free(pa[i]);
return (f);
}
failure = "addition of hc-pair array to FMRI failed";
boom:
for (i = 0; i < depth; i++)
nvlist_free(pa[i]);
nvlist_free(f);
/*NOTREACHED*/
return (NULL);
}
/* an ipath cache entry is an array of these, with s==NULL at the end */
struct ipath {
const char *s; /* component name (in stable) */
int i; /* instance number */
};
static nvlist_t *
{
char *failure;
int err, i;
depth++;
for (i = 0; i < depth; i++)
if (err != 0) {
failure = "basic construction of FMRI failed";
goto boom;
}
i = 0;
if (err != 0) {
failure = "alloc of an hc-pair failed";
goto boom;
}
if (err != 0) {
failure = "construction of an hc-pair failed";
goto boom;
}
pa[i++] = p;
}
if (err == 0) {
for (i = 0; i < depth; i++)
nvlist_free(pa[i]);
return (f);
}
failure = "addition of hc-pair array to FMRI failed";
boom:
for (i = 0; i < depth; i++)
nvlist_free(pa[i]);
nvlist_free(f);
/*NOTREACHED*/
return (NULL);
}
static uint_t
{
unsigned long long s = sum * 10;
}
static uint8_t
{
unsigned long long p = part * 1000;
}
struct rsl {
};
/*
* rslfree -- free internal members of struct rsl not expected to be
* freed elsewhere.
*/
static void
{
}
/*
* rslcmp -- compare two rsl structures. Use the following
* comparisons to establish cardinality:
*
* 1. Name of the suspect's class. (simple strcmp)
* 2. Name of the suspect's ASRU. (trickier, since nvlist)
*
*/
static int
rslcmp(const void *a, const void *b)
{
int rv;
if (rv != 0)
return (rv);
return (0);
return (-1);
return (1);
}
/*
* rsluniq -- given an array of rsl structures, seek out and "remove"
* any duplicates. Dups are "remove"d by NULLing the suspect pointer
* of the array element. Removal also means updating the number of
* problems and the number of problems which are not faults. User
* provides the first and last element pointers.
*/
static void
{
if (*nprobs == 1)
return;
/*
* At this point, we only expect duplicate defects.
* Eversholt's diagnosis algorithm prevents duplicate
* suspects, but we rewrite defects in the platform code after
* the diagnosis is made, and that can introduce new
* duplicates.
*/
first++;
continue;
}
(*nprobs)--;
(*nnonf)--;
}
}
/*
* assume all defects are in order after our
* sort and short circuit here with "else break" ?
*/
cr++;
}
first++;
}
}
/*
* get_resources -- for a given suspect, determine what ASRU, FRU and
* RSRC nvlists should be advertised in the final suspect list.
*/
void
{
char *pathstr;
/*
* initial fault tree.
*/
/*
* Create FMRIs based on those definitions
*/
/*
* Allow for platform translations of the FMRIs
*/
pathstr);
}
/*
* trim_suspects -- prior to publishing, we may need to remove some
* suspects from the list. If we're auto-closing upsets, we don't
* want any of those in the published list. If the ASRUs for multiple
* defects resolve to the same ASRU (driver) we only want to publish
* that as a single suspect.
*/
static void
{
int rpcnt;
/*
* First save the suspects in the psuspects, then copy back
* only the ones we wish to retain. This resets nsuspects to
* zero.
*/
/*
* allocate an array of resource pointers for the suspects.
* We may end up using less than the full allocation, but this
* is a very short-lived array. publish_suspects() will free
* this array when it's done using it.
*/
/* first pass, remove any unwanted upsets and populate our array */
continue;
rp++;
}
/* if all we had was unwanted upsets, we're done */
return;
/* sort the array */
}
/*
* addpayloadprop -- add a payload prop to a problem
*/
static void
{
"cannot add payloadprop \"%s\" to fault", lhs);
} else {
0)
"cannot add payloadprop \"%s\" to fault", lhs);
}
}
static char *Istatbuf;
static char *Istatbufptr;
static int Istatsz;
/*
* istataddsize -- calculate size of istat and add it to Istatsz
*/
/*ARGSUSED2*/
static void
{
int val;
return; /* skip zero-valued stats */
/* count up the size of the stat name */
Istatsz++; /* for the trailing NULL byte */
/* count up the size of the stat value */
Istatsz++; /* for the trailing NULL byte */
}
/*
* istat2str -- serialize an istat, writing result to *Istatbufptr
*/
/*ARGSUSED2*/
static void
{
char *str;
int len;
int val;
return; /* skip zero-valued stats */
/* serialize the stat name */
Istatbufptr += len;
*Istatbufptr++ = '\0';
/* serialize the stat value */
"%d", val);
*Istatbufptr++ = '\0';
}
void
{
if (Istat_need_save == 0)
return;
/* figure out how big the serialzed info is */
Istatsz = 0;
if (Istatsz == 0) {
/* no stats to save */
return;
}
/* create the serialized buffer */
/* clear out current saved stats */
/* write out the new version */
Istat_need_save = 0;
}
int
{
return (0);
}
/*
* istat-verify -- verify the component associated with a stat still exists
*
* if the component no longer exists, this routine resets the stat and
* returns 0. if the component still exists, it returns 1.
*/
static int
{
if (platform_path_exists(fmri)) {
return (1);
}
/* component no longer in system. zero out the associated stats */
stats_counter_value(statp) == 0)
return (0); /* stat is already reset */
Istat_need_save = 1;
return (0);
}
static void
{
struct istat_entry ent;
/* class name should be hoisted into a single stable entry */
/* component no longer exists in system, nothing to do */
return;
}
/* need to create the counter */
int cnt = 0;
char *sname;
char *snamep;
struct istat_entry *newentp;
/* count up the size of the stat name */
cnt++; /* for the '.' or '@' */
}
cnt++; /* for the '/' or trailing NULL byte */
}
/* build the stat name */
if (np)
*snamep++ = '.';
}
*snamep++ = '@';
if (np)
*snamep++ = '/';
}
*snamep++ = '\0';
/* create the new stat & add it to our list */
}
/* if n is non-zero, set that value instead of bumping */
if (n) {
stats_counter_add(statp, n);
} else
Istat_need_save = 1;
}
/*ARGSUSED*/
static void
{
}
/*
* Callback used in a walk of the Istats to reset matching stat counters.
*/
static void
{
char *path;
Istat_need_save = 1;
}
}
/*ARGSUSED*/
static void
void *unused)
{
char *path;
if (!platform_path_exists(fmri)) {
Istat_need_save = 1;
}
}
void
istat_fini(void)
{
}
static char *Serdbuf;
static char *Serdbufptr;
static int Serdsz;
/*
* serdaddsize -- calculate size of serd and add it to Serdsz
*/
/*ARGSUSED*/
static void
{
/* count up the size of the stat name */
Serdsz++; /* for the trailing NULL byte */
}
/*
* serd2str -- serialize a serd engine, writing result to *Serdbufptr
*/
/*ARGSUSED*/
static void
{
char *str;
int len;
/* serialize the serd engine name */
Serdbufptr += len;
*Serdbufptr++ = '\0';
}
void
{
if (Serd_need_save == 0)
return;
/* figure out how big the serialzed info is */
Serdsz = 0;
if (Serdsz == 0) {
/* no serd engines to save */
return;
}
/* create the serialized buffer */
/* clear out current saved stats */
/* write out the new version */
Serd_need_save = 0;
}
int
{
return (0);
}
void
{
int sz;
char *sbuf;
char *sepptr;
char *ptr;
struct serd_entry *newentp;
char *namestring;
return;
*sepptr = '\0';
namestring = ptr;
sepptr++;
ptr++; /* move past the '\0' separating paths */
if (platform_path_exists(fmri)) {
} else
Serd_need_save = 1;
}
/* save it back again in case some of the paths no longer exist */
serd_save();
}
/*ARGSUSED*/
static void
{
}
/*
* Callback used in a walk of the SerdEngines to reset matching serd engines.
*/
/*ARGSUSED*/
static void
{
char *path;
Serd_need_save = 1;
}
}
/*ARGSUSED*/
static void
{
char *path;
if (!platform_path_exists(fmri)) {
Serd_need_save = 1;
}
}
void
serd_fini(void)
{
}
static void
{
/*
* If we're auto-closing upsets, we don't want to include them
* in any produced suspect lists or certainty accounting.
*/
/*
* If the resulting suspect list has no members, we're
* done. Returning here will simply close the case.
*/
"[FME%d, case %s (all suspects are upsets)]",
return;
}
/*
* If the suspect list is all faults, then for a given fault,
* say X of N, X's certainty is computed via:
*
* fitrate(X) / (fitrate(1) + ... + fitrate(N)) * 100
*
* If none of the suspects are faults, and there are N suspects,
* the certainty of a given suspect is 100/N.
*
* If there are are a mixture of faults and other problems in
* the suspect list, we take an average of the faults'
* FITrates and treat this average as the FITrate for any
* non-faults. The fitrate of any given suspect is then
* computed per the first formula above.
*/
/* NO faults in the suspect list */
} else {
/* sum the fitrates */
struct node *n;
continue;
continue;
}
fr = 1;
} else if (fr == 0) {
fr = 1;
}
frcnt++;
}
}
}
/* Add them in reverse order of our sort, as fmd reverses order */
continue;
cert,
/* if "message" property exists, add it to the fault */
&messval) == 0) {
"[FME%d, %s adds message=%d to suspect list]",
messval);
}
}
/* add any payload properties */
/*
* If "action" property exists, evaluate it; this must be done
* before the dupclose check below since some actions may
* modify the asru to be used in fmd_nvl_fmri_faulty. This
* needs to be restructured if any new actions are introduced
* that have effects that we do not want to be visible if
* we decide not to publish in the dupclose check below.
*/
Action_nvl = fault;
}
/*
* check if the asru is already marked as "faulty".
*/
if (allfaulty) {
FM_FAULT_ASRU, &asru) != 0) {
} else {
}
}
}
/*
* We are going to publish so take any pre-publication actions.
*/
if (!allfaulty) {
/*
* don't update the count stat if all asrus are already
* present and unrepaired in the asru cache
*/
continue;
/* if "count" exists, increment the appropriate stat */
istat_bump(snp, 0);
}
}
istat_save(); /* write out any istat changes */
}
/*
* revert to the original suspect list
*/
}
static void
{
"[undiagnosable ereport received, "
"creating and closing a new case (%s)]",
if (Undiagablecaselist != NULL)
if (Undiag_reason != NULL)
}
static void
fme_undiagnosable(struct fme *f)
{
if (Undiag_reason != NULL)
}
/*
* fme_close_case
*
* Find the requested case amongst our fmes and close it. Free up
* the related fme.
*/
void
{
continue;
}
else
return;
}
break;
}
return;
}
else
/* Get rid of any timer this fme has set */
if (ClosedFMEs == NULL) {
ClosedFMEs = fmep;
} else {
ClosedFMEs = fmep;
}
/* See if we can close the overflow FME */
if (Open_fme_count <= Max_fme) {
break;
}
}
}
/*
* fme_set_timer()
* If the time we need to wait for the given FME is less than the
* current timer, kick that old timer out and establish a new one.
*/
static int
{
/* we've waited at least wull already, don't need timer */
return (0);
}
} else {
}
/* New timer would fire later than established timer */
return (0);
}
return (1);
}
void
{
break;
(void *)fmep);
return;
}
}
/*
* Preserve the fme's suspect list in its psuspects list, NULLing the
* suspects list in the meantime.
*/
static void
{
/* zero out the previous suspect list */
}
/* zero out the suspect list, copying it to previous suspect list */
ep->is_suspect = 0;
}
}
/*
* Retrieve the fme's suspect list from its psuspects list.
*/
static void
{
}
}
/*
* this is what we use to call the Emrys prototype code instead of main()
*/
static void
{
unsigned long long my_delay = TIMEVAL_EVENTUALLY;
indent_set(" ");
}
case FME_CREDIBLE:
/*
* we may have already posted suspects in upsets_eval() which
* can recurse into fme_eval() again. If so then just return.
*/
if (fmep->posted_suspects)
return;
(void *)&fmep->posted_suspects,
sizeof (fmep->posted_suspects));
/*
* Now the suspects have been posted, we can clear up
* the instance tree as we won't be looking at it again.
* Also cancel the timer as the case is now solved.
*/
}
break;
case FME_WAIT:
return;
case FME_DISPROVED:
break;
}
int doclose = 0;
doclose = 1;
doclose = 1;
doclose = 0;
break;
}
}
}
if (doclose) {
}
}
}
static void indent(void);
unsigned long long *pdelay);
unsigned long long at_latest_by, unsigned long long *pdelay);
unsigned long long at_latest_by, unsigned long long *pdelay);
static int
{
struct constraintlist *ctp;
char *sep = "";
if (arrowp->forever_false) {
indent();
sep = ", ";
}
return (0);
}
if (arrowp->forever_true) {
indent();
sep = ", ";
}
return (1);
}
/* evaluation successful */
/* known false */
indent();
" False constraint: ");
return (0);
}
} else {
/* evaluation unsuccessful -- unknown value */
indent();
" Deferred constraint: ");
return (1);
}
}
/* known true */
indent();
sep = ", ";
}
return (1);
}
static int
{
int count = 0;
continue;
/* check count of marks against K in the bubble */
return (1);
}
}
return (0);
}
static int
{
unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
unsigned long long my_delay;
int retval = 0;
continue;
/*
* if we're clearing marks, we can avoid doing
* all that work evaluating constraints.
*/
if (mark == 0) {
continue;
ep2->cached_state &=
keep);
continue;
}
indent();
" ALREADY DISPROVED ");
continue;
}
indent();
" ALREADY EFFECTS WAIT ");
continue;
}
indent();
" ALREADY EFFECTS CREDIBLE ");
continue;
}
(mark & PARENT_WAIT)) {
indent();
" ALREADY PARENT EFFECTS WAIT ");
continue;
}
indent();
" CONSTRAINTS FAIL ");
continue;
}
indent();
" K-COUNT NOT YET MET ");
continue;
}
/*
* if we've reached an ereport and no propagation time
* is specified, use the Hesitate value
*/
&my_delay);
} else {
&my_delay);
}
if (overall_delay > my_delay)
indent();
indent_push(" E");
at_latest_by, &my_delay, 0) ==
WAIT_EFFECT) {
if (overall_delay > my_delay)
}
indent_pop();
} else if (result == FME_DISPROVED) {
indent();
" EFFECTS DISPROVED ");
} else {
indent();
if (mark == CREDIBLE_EFFECT)
" EFFECTS CREDIBLE ");
else
" PARENT EFFECTS WAIT ");
indent_push(" E");
&my_delay, 0) == WAIT_EFFECT) {
if (overall_delay > my_delay)
}
indent_pop();
}
}
}
if (retval == WAIT_EFFECT)
*pdelay = overall_delay;
return (retval);
}
static enum fme_state
unsigned long long at_latest_by, unsigned long long *pdelay)
{
struct event *error_event;
unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
unsigned long long my_delay;
indent_push(" E");
indent();
&my_delay, 0) == WAIT_EFFECT) {
if (overall_delay > my_delay)
}
indent();
if (error_event->cached_state &
(PARENT_WAIT|WAIT_EFFECT)) {
continue;
}
break;
} else {
}
}
if (return_value == FME_DISPROVED) {
} else {
}
indent();
indent_pop();
if (return_value == FME_WAIT)
*pdelay = overall_delay;
return (return_value);
}
static enum fme_state
unsigned long long at_latest_by, unsigned long long *pdelay)
{
int waiting_events;
int credible_events;
int deferred_events;
unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
unsigned long long arrow_delay;
unsigned long long my_delay;
indent();
return (FME_CREDIBLE);
}
indent();
return (FME_DISPROVED);
}
indent();
return (FME_WAIT);
}
indent_push(" R");
indent();
} else {
}
}
indent();
switch (return_value) {
case FME_CREDIBLE:
break;
case FME_DISPROVED:
break;
case FME_WAIT:
break;
default:
break;
}
indent_pop();
return (return_value);
}
/* this event is not a report, descend the tree */
int n;
continue;
credible_events = 0;
waiting_events = 0;
deferred_events = 0;
/*
* n is -1 for 'A' so adjust it.
* XXX just count up the arrows for now.
*/
if (n < 0) {
n = 0;
n++;
indent();
} else {
indent();
}
if (n == 0)
continue;
/*
* if any arrow is invalidated by the
* constraints, then we should elide the
* whole bubble to be consistant with
* the tree creation time behaviour
*/
break;
}
}
}
continue;
if (n <= credible_events)
break;
/* XXX adding max timevals! */
&my_delay)) {
case FME_DEFERRED:
break;
case FME_CREDIBLE:
break;
case FME_DISPROVED:
break;
case FME_WAIT:
if (my_delay < arrow_delay)
break;
default:
"Bug in requirements_test.");
}
else
}
indent();
/* Can never meet requirements */
indent();
indent_pop();
return (FME_DISPROVED);
}
if (credible_events + deferred_events < n) {
/* will have to wait */
/* wait time is shortest known */
if (arrow_delay < overall_delay)
} else if (credible_events < n) {
if (return_value != FME_WAIT)
}
}
/*
* don't mark as FME_DEFERRED. If this event isn't reached by another
* path, then this will be considered FME_CREDIBLE. But if it is
* reached by a different path so the K-count is met, then might
* get overridden by FME_WAIT or FME_DISPROVED.
*/
if (return_value == FME_WAIT) {
} else if (return_value == FME_CREDIBLE) {
}
indent();
indent_pop();
return (return_value);
}
static enum fme_state
unsigned long long at_latest_by, unsigned long long *pdelay)
{
unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
unsigned long long my_delay;
int credible_results = 0;
int waiting_results = 0;
struct event *tail_event;
int k = 1;
indent_push(" C");
indent();
continue;
int do_not_follow = 0;
/*
* if we get to the same event multiple times
* only worry about the first one.
*/
indent();
" causes test already run for ");
continue;
}
/*
* see if false constraint prevents us
* from traversing this arrow
*/
do_not_follow = 1;
if (do_not_follow) {
indent();
" False arrow from ");
continue;
}
&my_delay);
switch (fstate) {
case FME_WAIT:
if (my_delay < overall_delay)
break;
case FME_CREDIBLE:
break;
case FME_DISPROVED:
break;
default:
}
}
}
/* compare against K */
if (credible_results + waiting_results < k) {
indent();
indent_pop();
return (FME_DISPROVED);
}
if (waiting_results != 0) {
*pdelay = overall_delay;
indent();
indent_pop();
return (FME_WAIT);
}
indent();
indent_pop();
return (FME_CREDIBLE);
}
static enum fme_state
unsigned long long at_latest_by, unsigned long long *pdelay)
{
unsigned long long my_delay;
unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
indent_push(" H");
indent();
if (rtr != FME_DISPROVED) {
if (is_problem(ep->t)) {
if (otr != FME_DISPROVED) {
}
}
} else
if ((otr != FME_DISPROVED) &&
*pdelay = overall_delay;
}
if (rtr == FME_DISPROVED) {
indent();
indent_pop();
return (FME_DISPROVED);
}
indent();
indent_pop();
return (FME_DISPROVED);
}
if (otr == FME_DISPROVED) {
indent();
indent_pop();
return (FME_DISPROVED);
}
indent();
indent_pop();
return (FME_WAIT);
}
indent();
indent_pop();
return (FME_CREDIBLE);
}
/*
* fme_istat_load -- reconstitute any persistent istats
*/
void
{
int sz;
char *sbuf;
char *ptr;
return;
}
/*
* pick apart the serialized stats
*
* format is:
* <class-name>, '@', <path>, '\0', <value>, '\0'
* for example:
*
* since this is parsing our own serialized data, any parsing issues
* are fatal, so we check for them all with ASSERT() below.
*/
char *sepptr;
int val;
*sepptr = '\0';
/* construct the event */
ptr++; /* move past the '\0' separating path from value */
ptr++; /* move past the final '\0' for this entry */
}
istat_save();
}