Print this page
    
NEX-2846 Enable Automatic/Intelligent Hot Sparing capability
Reviewed by: Jeffry Molanus <jeffry.molanus@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/fm/fmd/common/fmd_api.c
          +++ new/usr/src/cmd/fm/fmd/common/fmd_api.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  24   25   */
  25   26  
  26   27  #include <sys/types.h>
  27   28  #include <sys/fm/protocol.h>
  28   29  #include <fm/topo_hc.h>
  29   30  #include <uuid/uuid.h>
  30   31  
  31   32  #include <unistd.h>
  32   33  #include <signal.h>
  33   34  #include <limits.h>
  34   35  #include <syslog.h>
  35   36  #include <alloca.h>
  36   37  #include <stddef.h>
  37   38  #include <door.h>
  38   39  
  39   40  #include <fmd_module.h>
  40   41  #include <fmd_api.h>
  41   42  #include <fmd_string.h>
  42   43  #include <fmd_subr.h>
  43   44  #include <fmd_error.h>
  44   45  #include <fmd_event.h>
  45   46  #include <fmd_eventq.h>
  46   47  #include <fmd_dispq.h>
  47   48  #include <fmd_timerq.h>
  48   49  #include <fmd_thread.h>
  49   50  #include <fmd_ustat.h>
  50   51  #include <fmd_case.h>
  51   52  #include <fmd_protocol.h>
  52   53  #include <fmd_buf.h>
  53   54  #include <fmd_asru.h>
  54   55  #include <fmd_fmri.h>
  55   56  #include <fmd_topo.h>
  56   57  #include <fmd_ckpt.h>
  57   58  #include <fmd_xprt.h>
  58   59  
  59   60  #include <fmd.h>
  60   61  
  61   62  /*
  62   63   * Table of configuration file variable types ops-vector pointers.  We use this
  63   64   * to convert from the property description array specified by the module to an
  64   65   * array of fmd_conf_formal_t's.  The order of this array must match the order
  65   66   * of #define values specified in <fmd_api.h> (i.e. FMD_TYPE_BOOL must be 0).
  66   67   * For now, the fmd_conf_list and fmd_conf_path types are not supported as we
  67   68   * do not believe modules need them and they would require more complexity.
  68   69   */
  69   70  static const fmd_conf_ops_t *const _fmd_prop_ops[] = {
  70   71          &fmd_conf_bool,         /* FMD_TYPE_BOOL */
  71   72          &fmd_conf_int32,        /* FMD_TYPE_INT32 */
  72   73          &fmd_conf_uint32,       /* FMD_TYPE_UINT32 */
  73   74          &fmd_conf_int64,        /* FMD_TYPE_INT64 */
  74   75          &fmd_conf_uint64,       /* FMD_TYPE_UINT64 */
  75   76          &fmd_conf_string,       /* FMD_TYPE_STRING */
  76   77          &fmd_conf_time,         /* FMD_TYPE_TIME */
  77   78          &fmd_conf_size,         /* FMD_TYPE_SIZE */
  78   79  };
  79   80  
  80   81  static void fmd_api_verror(fmd_module_t *, int, const char *, va_list)
  81   82      __NORETURN;
  82   83  static void fmd_api_error(fmd_module_t *, int, const char *, ...) __NORETURN;
  83   84  
  84   85  /*
  85   86   * fmd_api_vxerror() provides the engine underlying the fmd_hdl_[v]error() API
  86   87   * calls and the fmd_api_[v]error() utility routine defined below.  The routine
  87   88   * formats the error, optionally associated with a particular errno code 'err',
  88   89   * and logs it as an ereport associated with the calling module.  Depending on
  89   90   * other optional properties, we also emit a message to stderr and to syslog.
  90   91   */
  91   92  static void
  92   93  fmd_api_vxerror(fmd_module_t *mp, int err, const char *format, va_list ap)
  93   94  {
  94   95          int raw_err = err;
  95   96          nvlist_t *nvl;
  96   97          fmd_event_t *e;
  97   98          char *class, *msg;
  98   99          size_t len1, len2;
  99  100          char c;
 100  101  
 101  102          /*
 102  103           * fmd_api_vxerror() counts as both an error of class EFMD_MODULE
 103  104           * as well as an instance of 'err' w.r.t. our internal bean counters.
 104  105           */
 105  106          (void) pthread_mutex_lock(&fmd.d_err_lock);
 106  107          fmd.d_errstats[EFMD_MODULE - EFMD_UNKNOWN].fmds_value.ui64++;
 107  108  
 108  109          if (err > EFMD_UNKNOWN && err < EFMD_END)
 109  110                  fmd.d_errstats[err - EFMD_UNKNOWN].fmds_value.ui64++;
 110  111  
 111  112          (void) pthread_mutex_unlock(&fmd.d_err_lock);
 112  113  
 113  114          /*
 114  115           * Format the message using vsnprintf().  As usual, if the format has a
 115  116           * newline in it, it is printed alone; otherwise strerror() is added.
 116  117           */
 117  118          if (strchr(format, '\n') != NULL)
 118  119                  err = 0; /* err is not relevant in the message */
 119  120  
 120  121          len1 = vsnprintf(&c, 1, format, ap);
 121  122          len2 = err != 0 ? snprintf(&c, 1, ": %s\n", fmd_strerror(err)) : 0;
 122  123  
 123  124          msg = fmd_alloc(len1 + len2 + 1, FMD_SLEEP);
 124  125          (void) vsnprintf(msg, len1 + 1, format, ap);
 125  126  
 126  127          if (err != 0) {
 127  128                  (void) snprintf(&msg[len1], len2 + 1,
 128  129                      ": %s\n", fmd_strerror(err));
 129  130          }
 130  131  
 131  132          /*
 132  133           * Create an error event corresponding to the error, insert it into the
 133  134           * error log, and dispatch it to the fmd-self-diagnosis engine.
 134  135           */
 135  136          if (mp != fmd.d_self && (raw_err != EFMD_HDL_ABORT || fmd.d_running)) {
 136  137                  if ((c = msg[len1 + len2 - 1]) == '\n')
 137  138                          msg[len1 + len2 - 1] = '\0'; /* strip \n for event */
 138  139  
 139  140                  nvl = fmd_protocol_moderror(mp, err, msg);
 140  141  
 141  142                  if (c == '\n')
 142  143                          msg[len1 + len2 - 1] = c;
 143  144  
 144  145                  (void) nvlist_lookup_string(nvl, FM_CLASS, &class);
 145  146                  e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class);
 146  147  
 147  148                  (void) pthread_rwlock_rdlock(&fmd.d_log_lock);
 148  149                  fmd_log_append(fmd.d_errlog, e, NULL);
 149  150                  (void) pthread_rwlock_unlock(&fmd.d_log_lock);
 150  151  
 151  152                  fmd_event_transition(e, FMD_EVS_ACCEPTED);
 152  153                  fmd_event_commit(e);
 153  154  
 154  155                  fmd_dispq_dispatch(fmd.d_disp, e, class);
 155  156          }
 156  157  
 157  158          /*
 158  159           * Similar to fmd_vdebug(), if the debugging switches are enabled we
 159  160           * echo the module name and message to stderr and/or syslog.  Unlike
 160  161           * fmd_vdebug(), we also print to stderr if foreground mode is enabled.
 161  162           * We also print the message if a built-in module is aborting before
 162  163           * fmd has detached from its parent (e.g. default transport failure).
 163  164           */
 164  165          if (fmd.d_fg || (fmd.d_hdl_dbout & FMD_DBOUT_STDERR) || (
 165  166              raw_err == EFMD_HDL_ABORT && !fmd.d_running)) {
 166  167                  (void) pthread_mutex_lock(&fmd.d_err_lock);
 167  168                  (void) fprintf(stderr, "%s: %s: %s",
 168  169                      fmd.d_pname, mp->mod_name, msg);
 169  170                  (void) pthread_mutex_unlock(&fmd.d_err_lock);
 170  171          }
 171  172  
 172  173          if (fmd.d_hdl_dbout & FMD_DBOUT_SYSLOG) {
 173  174                  syslog(LOG_ERR | LOG_DAEMON, "%s ERROR: %s: %s",
 174  175                      fmd.d_pname, mp->mod_name, msg);
 175  176          }
 176  177  
 177  178          fmd_free(msg, len1 + len2 + 1);
 178  179  }
 179  180  
 180  181  /*PRINTFLIKE3*/
 181  182  static void
 182  183  fmd_api_xerror(fmd_module_t *mp, int err, const char *format, ...)
 183  184  {
 184  185          va_list ap;
 185  186  
 186  187          va_start(ap, format);
 187  188          fmd_api_vxerror(mp, err, format, ap);
 188  189          va_end(ap);
 189  190  }
 190  191  
 191  192  /*
 192  193   * fmd_api_verror() is a wrapper around fmd_api_vxerror() for API subroutines.
 193  194   * It calls fmd_module_unlock() on behalf of its caller, logs the error, and
 194  195   * then aborts the API call and the surrounding module entry point by doing an
 195  196   * fmd_module_abort(), which longjmps to the place where we entered the module.
 196  197   */
 197  198  static void
 198  199  fmd_api_verror(fmd_module_t *mp, int err, const char *format, va_list ap)
 199  200  {
 200  201          if (fmd_module_locked(mp))
 201  202                  fmd_module_unlock(mp);
 202  203  
 203  204          fmd_api_vxerror(mp, err, format, ap);
 204  205          fmd_module_abort(mp, err);
 205  206  }
 206  207  
 207  208  /*PRINTFLIKE3*/
 208  209  static void
 209  210  fmd_api_error(fmd_module_t *mp, int err, const char *format, ...)
 210  211  {
 211  212          va_list ap;
 212  213  
 213  214          va_start(ap, format);
 214  215          fmd_api_verror(mp, err, format, ap);
 215  216          va_end(ap);
 216  217  }
 217  218  
 218  219  /*
 219  220   * Common code for fmd_api_module_lock() and fmd_api_transport_impl().  This
 220  221   * code verifies that the handle is valid and associated with a proper thread.
 221  222   */
 222  223  static fmd_module_t *
 223  224  fmd_api_module(fmd_hdl_t *hdl)
 224  225  {
 225  226          fmd_thread_t *tp;
 226  227          fmd_module_t *mp;
 227  228  
 228  229          /*
 229  230           * If our TSD is not present at all, this is either a serious bug or
 230  231           * someone has created a thread behind our back and is using fmd's API.
 231  232           * We can't call fmd_api_error() because we can't be sure that we can
 232  233           * unwind our state back to an enclosing fmd_module_dispatch(), so we
 233  234           * must panic instead.  This is likely a module design or coding error.
 234  235           */
 235  236          if ((tp = pthread_getspecific(fmd.d_key)) == NULL) {
 236  237                  fmd_panic("fmd module api call made using "
 237  238                      "client handle %p from unknown thread\n", (void *)hdl);
 238  239          }
 239  240  
 240  241          /*
 241  242           * If our TSD refers to the root module and is a non-private
 242  243           * door server thread,  then it was created asynchronously at the
 243  244           * request of a module but is using now the module API as an
 244  245           * auxiliary module thread.  We reset tp->thr_mod to the module
 245  246           * handle so it can act as a module thread.
 246  247           *
 247  248           * If more than one module uses non-private doors then the
 248  249           * "client handle is not valid" check below can fail since
 249  250           * door server threads for such doors can service *any*
 250  251           * non-private door.  We use non-private door for legacy sysevent
 251  252           * alone.
 252  253           */
 253  254          if (tp->thr_mod == fmd.d_rmod && tp->thr_func == &fmd_door_server)
 254  255                  tp->thr_mod = (fmd_module_t *)hdl;
 255  256  
 256  257          if ((mp = tp->thr_mod) != (fmd_module_t *)hdl) {
 257  258                  fmd_api_error(mp, EFMD_HDL_INVAL,
 258  259                      "client handle %p is not valid\n", (void *)hdl);
 259  260          }
 260  261  
 261  262          if (mp->mod_flags & FMD_MOD_FAIL) {
 262  263                  fmd_api_error(mp, EFMD_MOD_FAIL,
 263  264                      "module has experienced an unrecoverable error\n");
 264  265          }
 265  266  
 266  267          return (mp);
 267  268  }
 268  269  
 269  270  /*
 270  271   * fmd_api_module_lock() is used as a wrapper around fmd_module_lock() and a
 271  272   * common prologue to each fmd_api.c routine.  It verifies that the handle is
 272  273   * valid and owned by the current server thread, locks the handle, and then
 273  274   * verifies that the caller is performing an operation on a registered handle.
 274  275   * If any tests fail, the entire API call is aborted by fmd_api_error().
 275  276   */
 276  277  static fmd_module_t *
 277  278  fmd_api_module_lock(fmd_hdl_t *hdl)
 278  279  {
 279  280          fmd_module_t *mp = fmd_api_module(hdl);
 280  281  
 281  282          fmd_module_lock(mp);
 282  283  
 283  284          if (mp->mod_info == NULL) {
 284  285                  fmd_api_error(mp, EFMD_HDL_NOTREG,
 285  286                      "client handle %p has not been registered\n", (void *)hdl);
 286  287          }
 287  288  
 288  289          return (mp);
 289  290  }
 290  291  
 291  292  /*
 292  293   * Utility function for API entry points that accept fmd_case_t's.  We cast cp
 293  294   * to fmd_case_impl_t and check to make sure the case is owned by the caller.
 294  295   */
 295  296  static fmd_case_impl_t *
 296  297  fmd_api_case_impl(fmd_module_t *mp, fmd_case_t *cp)
 297  298  {
 298  299          fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
 299  300  
 300  301          if (cip == NULL || cip->ci_mod != mp) {
 301  302                  fmd_api_error(mp, EFMD_CASE_OWNER,
 302  303                      "case %p is invalid or not owned by caller\n", (void *)cip);
 303  304          }
 304  305  
 305  306          return (cip);
 306  307  }
 307  308  
 308  309  /*
 309  310   * Utility function for API entry points that accept fmd_xprt_t's.  We cast xp
 310  311   * to fmd_transport_t and check to make sure the case is owned by the caller.
 311  312   * Note that we could make this check safer by actually walking mp's transport
 312  313   * list, but that requires holding the module lock and this routine needs to be
 313  314   * MT-hot w.r.t. auxiliary module threads.  Ultimately any loadable module can
 314  315   * cause us to crash anyway, so we optimize for scalability over safety here.
 315  316   */
 316  317  static fmd_xprt_impl_t *
 317  318  fmd_api_transport_impl(fmd_hdl_t *hdl, fmd_xprt_t *xp)
 318  319  {
 319  320          fmd_module_t *mp = fmd_api_module(hdl);
 320  321          fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
 321  322  
 322  323          if (xip == NULL || xip->xi_queue->eq_mod != mp) {
 323  324                  fmd_api_error(mp, EFMD_XPRT_OWNER,
 324  325                      "xprt %p is invalid or not owned by caller\n", (void *)xp);
 325  326          }
 326  327  
 327  328          return (xip);
 328  329  }
 329  330  
 330  331  /*
 331  332   * fmd_hdl_register() is the one function which cannot use fmd_api_error() to
 332  333   * report errors, because that routine causes the module to abort.  Failure to
 333  334   * register is instead handled by having fmd_hdl_register() return an error to
 334  335   * the _fmd_init() function and then detecting no registration when it returns.
 335  336   * So we use this routine for fmd_hdl_register() error paths instead.
 336  337   */
 337  338  static int
 338  339  fmd_hdl_register_error(fmd_module_t *mp, int err)
 339  340  {
 340  341          if (fmd_module_locked(mp))
 341  342                  fmd_module_unlock(mp);
 342  343  
 343  344          fmd_api_xerror(mp, err, "failed to register");
 344  345          return (fmd_set_errno(err));
 345  346  }
 346  347  
 347  348  static void
 348  349  fmd_hdl_nop(void)
 349  350  {
 350  351          /* empty function for use with unspecified module entry points */
 351  352  }
 352  353  
 353  354  int
 354  355  fmd_hdl_register(fmd_hdl_t *hdl, int version, const fmd_hdl_info_t *mip)
 355  356  {
 356  357          fmd_thread_t *tp = pthread_getspecific(fmd.d_key);
 357  358          fmd_module_t *mp = tp->thr_mod;
 358  359  
 359  360          const fmd_prop_t *prop;
 360  361          const fmd_conf_path_t *pap;
 361  362          fmd_conf_formal_t *cfp;
 362  363          fmd_hdl_ops_t ops;
 363  364  
 364  365          const char *conf = NULL;
 365  366          char buf[PATH_MAX];
 366  367          int i;
 367  368  
 368  369          if (mp != (fmd_module_t *)hdl)
 369  370                  return (fmd_hdl_register_error(mp, EFMD_HDL_INVAL));
 370  371  
 371  372          fmd_module_lock(mp);
 372  373  
 373  374          /*
 374  375           * First perform some sanity checks on our input.  The API version must
 375  376           * be supported by FMD and the handle can only be registered once by
 376  377           * the module thread to which we assigned this client handle.  The info
 377  378           * provided for the handle must be valid and have the minimal settings.
 378  379           */
 379  380          if (version > FMD_API_VERSION_5)
 380  381                  return (fmd_hdl_register_error(mp, EFMD_VER_NEW));
 381  382  
 382  383          if (version < FMD_API_VERSION_1)
 383  384                  return (fmd_hdl_register_error(mp, EFMD_VER_OLD));
 384  385  
 385  386          if (mp->mod_conf != NULL)
 386  387                  return (fmd_hdl_register_error(mp, EFMD_HDL_REG));
 387  388  
 388  389          if (pthread_self() != mp->mod_thread->thr_tid)
 389  390                  return (fmd_hdl_register_error(mp, EFMD_HDL_TID));
 390  391  
 391  392          if (mip == NULL || mip->fmdi_desc == NULL ||
 392  393              mip->fmdi_vers == NULL || mip->fmdi_ops == NULL)
 393  394                  return (fmd_hdl_register_error(mp, EFMD_HDL_INFO));
 394  395  
 395  396          /*
 396  397           * Copy the module's ops vector into a local variable to account for
 397  398           * changes in the module ABI.  Then if any of the optional entry points
 398  399           * are NULL, set them to nop so we don't have to check before calling.
 399  400           */
 400  401          bzero(&ops, sizeof (ops));
 401  402  
 402  403          if (version < FMD_API_VERSION_3)
 403  404                  bcopy(mip->fmdi_ops, &ops, offsetof(fmd_hdl_ops_t, fmdo_send));
 404  405          else if (version < FMD_API_VERSION_4)
 405  406                  bcopy(mip->fmdi_ops, &ops,
 406  407                      offsetof(fmd_hdl_ops_t, fmdo_topo));
 407  408          else
 408  409                  bcopy(mip->fmdi_ops, &ops, sizeof (ops));
 409  410  
 410  411          if (ops.fmdo_recv == NULL)
 411  412                  ops.fmdo_recv = (void (*)())fmd_hdl_nop;
 412  413          if (ops.fmdo_timeout == NULL)
 413  414                  ops.fmdo_timeout = (void (*)())fmd_hdl_nop;
 414  415          if (ops.fmdo_close == NULL)
 415  416                  ops.fmdo_close = (void (*)())fmd_hdl_nop;
 416  417          if (ops.fmdo_stats == NULL)
 417  418                  ops.fmdo_stats = (void (*)())fmd_hdl_nop;
 418  419          if (ops.fmdo_gc == NULL)
 419  420                  ops.fmdo_gc = (void (*)())fmd_hdl_nop;
 420  421          if (ops.fmdo_send == NULL)
 421  422                  ops.fmdo_send = (int (*)())fmd_hdl_nop;
 422  423          if (ops.fmdo_topo == NULL)
 423  424                  ops.fmdo_topo = (void (*)())fmd_hdl_nop;
 424  425  
 425  426          /*
 426  427           * Make two passes through the property array to initialize the formals
 427  428           * to use for processing the module's .conf file.  In the first pass,
 428  429           * we validate the types and count the number of properties.  In the
 429  430           * second pass we copy the strings and fill in the appropriate ops.
 430  431           */
 431  432          for (prop = mip->fmdi_props, i = 0; prop != NULL &&
 432  433              prop->fmdp_name != NULL; prop++, i++) {
 433  434                  if (prop->fmdp_type >=
 434  435                      sizeof (_fmd_prop_ops) / sizeof (_fmd_prop_ops[0])) {
 435  436                          fmd_api_xerror(mp, EFMD_HDL_PROP,
 436  437                              "property %s uses invalid type %u\n",
 437  438                              prop->fmdp_name, prop->fmdp_type);
 438  439                          return (fmd_hdl_register_error(mp, EFMD_HDL_PROP));
 439  440                  }
 440  441          }
 441  442  
 442  443          mp->mod_argc = i;
 443  444          mp->mod_argv = fmd_zalloc(sizeof (fmd_conf_formal_t) * i, FMD_SLEEP);
 444  445  
 445  446          prop = mip->fmdi_props;
 446  447          cfp = mp->mod_argv;
 447  448  
 448  449          for (i = 0; i < mp->mod_argc; i++, prop++, cfp++) {
 449  450                  cfp->cf_name = fmd_strdup(prop->fmdp_name, FMD_SLEEP);
 450  451                  cfp->cf_ops = _fmd_prop_ops[prop->fmdp_type];
 451  452                  cfp->cf_default = fmd_strdup(prop->fmdp_defv, FMD_SLEEP);
 452  453          }
 453  454  
 454  455          /*
 455  456           * If this module came from an on-disk file, compute the name of the
 456  457           * corresponding .conf file and parse properties from it if it exists.
 457  458           */
 458  459          if (mp->mod_path != NULL) {
 459  460                  (void) strlcpy(buf, mp->mod_path, sizeof (buf));
 460  461                  (void) fmd_strdirname(buf);
 461  462  
 462  463                  (void) strlcat(buf, "/", sizeof (buf));
 463  464                  (void) strlcat(buf, mp->mod_name, sizeof (buf));
 464  465                  (void) strlcat(buf, ".conf", sizeof (buf));
 465  466  
 466  467                  if (access(buf, F_OK) == 0)
 467  468                          conf = buf;
 468  469          }
 469  470  
 470  471          if ((mp->mod_conf = fmd_conf_open(conf,
 471  472              mp->mod_argc, mp->mod_argv, 0)) == NULL)
 472  473                  return (fmd_hdl_register_error(mp, EFMD_MOD_CONF));
 473  474  
 474  475          fmd_conf_propagate(fmd.d_conf, mp->mod_conf, mp->mod_name);
 475  476  
 476  477          /*
 477  478           * Look up the list of the libdiagcode dictionaries associated with the
 478  479           * module.  If none were specified, use the value from daemon's config.
 479  480           * We only fail if the module specified an explicit dictionary.
 480  481           */
 481  482          (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_DICTIONARIES, &pap);
 482  483          if (pap->cpa_argc == 0 && mp->mod_ops == &fmd_bltin_ops)
 483  484                  (void) fmd_conf_getprop(fmd.d_conf, "self.dict", &pap);
 484  485  
 485  486          for (i = 0; i < pap->cpa_argc; i++) {
 486  487                  if (fmd_module_dc_opendict(mp, pap->cpa_argv[i]) != 0) {
 487  488                          fmd_api_xerror(mp, errno,
 488  489                              "failed to open dictionary %s", pap->cpa_argv[i]);
 489  490                          return (fmd_hdl_register_error(mp, EFMD_MOD_CONF));
 490  491                  }
 491  492          }
 492  493  
 493  494          /*
 494  495           * Make a copy of the handle information and store it in mod_info.  We
 495  496           * do not need to bother copying fmdi_props since they're already read.
 496  497           */
 497  498          mp->mod_info = fmd_alloc(sizeof (fmd_hdl_info_t), FMD_SLEEP);
 498  499          mp->mod_info->fmdi_desc = fmd_strdup(mip->fmdi_desc, FMD_SLEEP);
 499  500          mp->mod_info->fmdi_vers = fmd_strdup(mip->fmdi_vers, FMD_SLEEP);
 500  501          mp->mod_info->fmdi_ops = fmd_alloc(sizeof (fmd_hdl_ops_t), FMD_SLEEP);
 501  502          bcopy(&ops, (void *)mp->mod_info->fmdi_ops, sizeof (fmd_hdl_ops_t));
 502  503          mp->mod_info->fmdi_props = NULL;
 503  504  
 504  505          /*
 505  506           * Store a copy of module version in mp for fmd_scheme_fmd_present()
 506  507           */
 507  508          if (mp->mod_vers == NULL)
 508  509                  mp->mod_vers = fmd_strdup(mip->fmdi_vers, FMD_SLEEP);
 509  510  
 510  511          /*
 511  512           * Allocate an FMRI representing this module.  We'll use this later
 512  513           * if the module decides to publish any events (e.g. list.suspects).
 513  514           */
 514  515          mp->mod_fmri = fmd_protocol_fmri_module(mp);
 515  516  
 516  517          /*
 517  518           * Any subscriptions specified in the conf file are now stored in the
 518  519           * corresponding property.  Add all of these to the dispatch queue.
 519  520           */
 520  521          (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_SUBSCRIPTIONS, &pap);
 521  522  
 522  523          for (i = 0; i < pap->cpa_argc; i++) {
 523  524                  fmd_dispq_insert(fmd.d_disp, mp->mod_queue, pap->cpa_argv[i]);
 524  525                  fmd_xprt_subscribe_all(pap->cpa_argv[i]);
 525  526          }
 526  527  
 527  528          /*
 528  529           * Unlock the module and restore any pre-existing module checkpoint.
 529  530           * If the checkpoint is missing or corrupt, we just keep going.
 530  531           */
 531  532          fmd_module_unlock(mp);
 532  533          fmd_ckpt_restore(mp);
 533  534          return (0);
 534  535  }
 535  536  
 536  537  /*
 537  538   * If an auxiliary thread exists for the specified module at unregistration
 538  539   * time, send it an asynchronous cancellation to force it to exit and then
 539  540   * join with it (we expect this to either succeed quickly or return ESRCH).
 540  541   * Once this is complete we can destroy the associated fmd_thread_t data.
 541  542   */
 542  543  static void
 543  544  fmd_module_thrcancel(fmd_idspace_t *ids, id_t id, fmd_module_t *mp)
 544  545  {
 545  546          fmd_thread_t *tp = fmd_idspace_getspecific(ids, id);
 546  547  
 547  548          /*
 548  549           * Door service threads are not cancellable (worse - if they're
 549  550           * waiting in door_return then that is interrupted, but they then spin
 550  551           * endlessly!).  Non-private door service threads are not tracked
 551  552           * in the module thread idspace so it's only private server threads
 552  553           * created via fmd_doorthr_create that we'll encounter.  In most
 553  554           * cases the module _fini should have tidied up (e.g., calling
 554  555           * sysevent_evc_unbind which will cleanup door threads if
 555  556           * sysevent_evc_xsubscribe was used).  One case that does not
 556  557           * clean up is sysev_fini which explicitly does not unbind the
 557  558           * channel, so we must skip any remaining door threads here.
 558  559           */
 559  560          if (tp->thr_isdoor) {
 560  561                  fmd_dprintf(FMD_DBG_MOD, "not cancelling %s private door "
 561  562                      "thread %u\n", mp->mod_name, tp->thr_tid);
 562  563                  fmd_thread_destroy(tp, FMD_THREAD_NOJOIN);
 563  564                  return;
 564  565          }
 565  566  
 566  567          fmd_dprintf(FMD_DBG_MOD, "cancelling %s auxiliary thread %u\n",
 567  568              mp->mod_name, tp->thr_tid);
 568  569  
 569  570          ASSERT(tp->thr_tid == id);
 570  571          (void) pthread_cancel(tp->thr_tid);
 571  572          (void) pthread_join(tp->thr_tid, NULL);
 572  573  
 573  574          fmd_thread_destroy(tp, FMD_THREAD_NOJOIN);
 574  575  }
 575  576  
 576  577  void
 577  578  fmd_module_unregister(fmd_module_t *mp)
 578  579  {
 579  580          fmd_conf_formal_t *cfp = mp->mod_argv;
 580  581          const fmd_conf_path_t *pap;
 581  582          fmd_case_t *cp;
 582  583          fmd_xprt_t *xp;
 583  584          int i;
 584  585  
 585  586          TRACE((FMD_DBG_MOD, "unregister %p (%s)", (void *)mp, mp->mod_name));
 586  587          ASSERT(fmd_module_locked(mp));
 587  588  
 588  589          /*
 589  590           * If any transports are still open, they have send threads that are
 590  591           * using the module handle: shut them down and join with these threads.
 591  592           */
 592  593          while ((xp = fmd_list_next(&mp->mod_transports)) != NULL)
 593  594                  fmd_xprt_destroy(xp);
 594  595  
 595  596          /*
 596  597           * If any auxiliary threads exist, they may be using our module handle,
 597  598           * and therefore could cause a fault as soon as we start destroying it.
 598  599           * Module writers should clean up any threads before unregistering: we
 599  600           * forcibly cancel any remaining auxiliary threads before proceeding.
 600  601           */
 601  602          fmd_idspace_apply(mp->mod_threads,
 602  603              (void (*)())fmd_module_thrcancel, mp);
 603  604  
 604  605          if (mp->mod_error == 0)
 605  606                  fmd_ckpt_save(mp); /* take one more checkpoint if needed */
 606  607  
 607  608          /*
 608  609           * Delete any cases associated with the module (UNSOLVED, SOLVED, or
 609  610           * CLOSE_WAIT) as if fmdo_close() has finished processing them.
 610  611           */
 611  612          while ((cp = fmd_list_next(&mp->mod_cases)) != NULL)
 612  613                  fmd_case_delete(cp);
 613  614  
 614  615          fmd_ustat_delete_references(mp->mod_ustat);
 615  616          (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_SUBSCRIPTIONS, &pap);
 616  617  
 617  618          for (i = 0; i < pap->cpa_argc; i++) {
 618  619                  fmd_xprt_unsubscribe_all(pap->cpa_argv[i]);
 619  620                  fmd_dispq_delete(fmd.d_disp, mp->mod_queue, pap->cpa_argv[i]);
 620  621          }
 621  622  
 622  623          fmd_conf_close(mp->mod_conf);
 623  624          mp->mod_conf = NULL;
 624  625  
 625  626          for (i = 0; i < mp->mod_argc; i++, cfp++) {
 626  627                  fmd_strfree((char *)cfp->cf_name);
 627  628                  fmd_strfree((char *)cfp->cf_default);
 628  629          }
 629  630  
 630  631          fmd_free(mp->mod_argv, sizeof (fmd_conf_formal_t) * mp->mod_argc);
 631  632          mp->mod_argv = NULL;
 632  633          mp->mod_argc = 0;
 633  634  
 634  635          nvlist_free(mp->mod_fmri);
 635  636          mp->mod_fmri = NULL;
 636  637  
 637  638          fmd_strfree((char *)mp->mod_info->fmdi_desc);
 638  639          fmd_strfree((char *)mp->mod_info->fmdi_vers);
 639  640          fmd_free((void *)mp->mod_info->fmdi_ops, sizeof (fmd_hdl_ops_t));
 640  641          fmd_free(mp->mod_info, sizeof (fmd_hdl_info_t));
 641  642          mp->mod_info = NULL;
 642  643  
 643  644          fmd_eventq_abort(mp->mod_queue);
 644  645  }
 645  646  
 646  647  void
 647  648  fmd_hdl_unregister(fmd_hdl_t *hdl)
 648  649  {
 649  650          fmd_module_t *mp = fmd_api_module_lock(hdl);
 650  651          fmd_module_unregister(mp);
 651  652          fmd_module_unlock(mp);
 652  653  }
 653  654  
 654  655  void
 655  656  fmd_hdl_subscribe(fmd_hdl_t *hdl, const char *class)
 656  657  {
 657  658          fmd_module_t *mp = fmd_api_module_lock(hdl);
 658  659  
 659  660          if (fmd_conf_setprop(mp->mod_conf,
 660  661              FMD_PROP_SUBSCRIPTIONS, class) == 0) {
 661  662                  fmd_dispq_insert(fmd.d_disp, mp->mod_queue, class);
 662  663                  fmd_xprt_subscribe_all(class);
 663  664          }
 664  665  
 665  666          fmd_module_unlock(mp);
 666  667  }
 667  668  
 668  669  
 669  670  void
 670  671  fmd_hdl_unsubscribe(fmd_hdl_t *hdl, const char *class)
 671  672  {
 672  673          fmd_module_t *mp = fmd_api_module_lock(hdl);
 673  674  
 674  675          if (fmd_conf_delprop(mp->mod_conf,
 675  676              FMD_PROP_SUBSCRIPTIONS, class) == 0) {
 676  677                  fmd_xprt_unsubscribe_all(class);
 677  678                  fmd_dispq_delete(fmd.d_disp, mp->mod_queue, class);
 678  679          }
 679  680  
 680  681          fmd_module_unlock(mp);
 681  682          fmd_eventq_cancel(mp->mod_queue, FMD_EVT_PROTOCOL, (void *)class);
 682  683  }
 683  684  
 684  685  void
 685  686  fmd_hdl_setspecific(fmd_hdl_t *hdl, void *spec)
 686  687  {
 687  688          fmd_module_t *mp = fmd_api_module_lock(hdl);
 688  689  
 689  690          mp->mod_spec = spec;
 690  691          fmd_module_unlock(mp);
 691  692  }
 692  693  
 693  694  void *
 694  695  fmd_hdl_getspecific(fmd_hdl_t *hdl)
 695  696  {
 696  697          fmd_module_t *mp = fmd_api_module_lock(hdl);
 697  698          void *spec = mp->mod_spec;
 698  699  
 699  700          fmd_module_unlock(mp);
 700  701          return (spec);
 701  702  }
 702  703  
 703  704  void
 704  705  fmd_hdl_opendict(fmd_hdl_t *hdl, const char *dict)
 705  706  {
 706  707          fmd_module_t *mp = fmd_api_module_lock(hdl);
 707  708          const fmd_conf_path_t *pap;
 708  709          int i;
 709  710  
 710  711          /*
 711  712           * Update the dictionary property in order to preserve the list of
 712  713           * pathnames and expand any % tokens in the path.  Then retrieve the
 713  714           * new dictionary names from cpa_argv[] and open them one at a time.
 714  715           */
 715  716          (void) fmd_conf_setprop(mp->mod_conf, FMD_PROP_DICTIONARIES, dict);
 716  717          (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_DICTIONARIES, &pap);
 717  718  
 718  719          ASSERT(pap->cpa_argc > mp->mod_dictc);
 719  720  
 720  721          for (i = mp->mod_dictc; i < pap->cpa_argc; i++) {
 721  722                  if (fmd_module_dc_opendict(mp, pap->cpa_argv[i]) != 0) {
 722  723                          fmd_api_error(mp, EFMD_MOD_DICT,
 723  724                              "failed to open dictionary %s for module %s",
 724  725                              pap->cpa_argv[i], mp->mod_name);
 725  726                  }
 726  727          }
 727  728  
 728  729          fmd_module_unlock(mp);
 729  730  }
 730  731  
 731  732  topo_hdl_t *
 732  733  fmd_hdl_topo_hold(fmd_hdl_t *hdl, int v)
 733  734  {
 734  735          fmd_module_t *mp = fmd_api_module_lock(hdl);
 735  736          topo_hdl_t *thp;
 736  737  
 737  738          if (v != TOPO_VERSION) {
 738  739                  fmd_api_error(mp, EFMD_MOD_TOPO, "libtopo version mismatch: "
 739  740                      "fmd version %d != client version %d\n", TOPO_VERSION, v);
 740  741          }
 741  742  
 742  743          thp = fmd_module_topo_hold(mp);
 743  744          ASSERT(thp != NULL);
 744  745  
 745  746          fmd_module_unlock(mp);
 746  747          return (thp);
 747  748  }
 748  749  
 749  750  void
 750  751  fmd_hdl_topo_rele(fmd_hdl_t *hdl, topo_hdl_t *thp)
  
    | 
      ↓ open down ↓ | 
    717 lines elided | 
    
      ↑ open up ↑ | 
  
 751  752  {
 752  753          fmd_module_t *mp = fmd_api_module_lock(hdl);
 753  754  
 754  755          if (fmd_module_topo_rele(mp, thp) != 0)
 755  756                  fmd_api_error(mp, EFMD_MOD_TOPO, "failed to release invalid "
 756  757                      "topo handle: %p\n", (void *)thp);
 757  758  
 758  759          fmd_module_unlock(mp);
 759  760  }
 760  761  
      762 +/*
      763 + * Visit a libtopo node trying to find a disk with the specified devid.
      764 + * If we find it, copy it's FRU and resource fields.
      765 + */
      766 +static int
      767 +fmd_hdl_topo_walk_cb(topo_hdl_t *thp, tnode_t *tn, void *arg)
      768 +{
      769 +
      770 +        fmd_hdl_topo_node_info_t *node = (fmd_hdl_topo_node_info_t *)arg;
      771 +        char *cur_devid;
      772 +        nvlist_t *fru;
      773 +        nvlist_t *resource;
      774 +        int err = 0;
      775 +        _NOTE(ARGUNUSED(thp));
      776 +
      777 +        if (strcmp(topo_node_name(tn), "disk") != 0)
      778 +                return (TOPO_WALK_NEXT);
      779 +
      780 +        if (topo_prop_get_string(tn, "io", "devid", &cur_devid, &err) != 0)
      781 +                return (TOPO_WALK_NEXT);
      782 +
      783 +        if (strcmp(cur_devid, node->device) == 0) {
      784 +                if (topo_node_fru(tn, &fru, NULL, &err) == 0 && err == 0 &&
      785 +                    topo_node_resource(tn, &resource, &err) == 0 && err == 0) {
      786 +                        node->fru = fnvlist_dup(fru);
      787 +                        node->resource = fnvlist_dup(resource);
      788 +                        return (TOPO_WALK_TERMINATE);
      789 +                }
      790 +        }
      791 +
      792 +        return (TOPO_WALK_NEXT);
      793 +}
      794 +
      795 +/*
      796 + * Extract FRU and resource values from a libtopo node with the matching devid
      797 + */
      798 +fmd_hdl_topo_node_info_t *
      799 +fmd_hdl_topo_node_get_by_devid(fmd_hdl_t *hdl, char *device)
      800 +{
      801 +
      802 +        int err = 0;
      803 +        topo_hdl_t *thp;
      804 +        topo_walk_t *twp;
      805 +
      806 +        fmd_hdl_topo_node_info_t *node = (fmd_hdl_topo_node_info_t *)
      807 +            fmd_hdl_zalloc(hdl, sizeof (fmd_hdl_topo_node_info_t), FMD_SLEEP);
      808 +
      809 +        thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION);
      810 +
      811 +        node->device = device;
      812 +
      813 +        if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, fmd_hdl_topo_walk_cb,
      814 +            node, &err)) == NULL) {
      815 +                fmd_hdl_error(hdl, "failed to get topology: %s",
      816 +                    topo_strerror(err));
      817 +                fmd_hdl_topo_rele(hdl, thp);
      818 +                return (NULL);
      819 +        }
      820 +
      821 +        (void) topo_walk_step(twp, TOPO_WALK_CHILD);
      822 +        topo_walk_fini(twp);
      823 +        fmd_hdl_topo_rele(hdl, thp);
      824 +
      825 +        if (node->fru == NULL || node->resource == NULL) {
      826 +                fmd_hdl_debug(hdl, "Could not find device with matching FRU");
      827 +                fmd_hdl_free(hdl, node, sizeof (fmd_hdl_topo_node_info_t));
      828 +                return (NULL);
      829 +        } else {
      830 +                fmd_hdl_debug(hdl, "Found FRU for device %s", device);
      831 +                return (node);
      832 +        }
      833 +}
      834 +
 761  835  static void *
 762  836  fmd_hdl_alloc_locked(fmd_module_t *mp, size_t size, int flags)
 763  837  {
 764  838          void *data;
 765  839  
 766  840          if (mp->mod_stats->ms_memlimit.fmds_value.ui64 -
 767  841              mp->mod_stats->ms_memtotal.fmds_value.ui64 < size) {
 768  842                  fmd_api_error(mp, EFMD_HDL_NOMEM, "%s's allocation of %lu "
 769  843                      "bytes exceeds module memory limit (%llu)\n",
 770  844                      mp->mod_name, (ulong_t)size, (u_longlong_t)
 771  845                      mp->mod_stats->ms_memtotal.fmds_value.ui64);
 772  846          }
 773  847  
 774  848          if ((data = fmd_alloc(size, flags)) != NULL)
 775  849                  mp->mod_stats->ms_memtotal.fmds_value.ui64 += size;
 776  850  
 777  851          return (data);
 778  852  }
 779  853  
 780  854  void *
 781  855  fmd_hdl_alloc(fmd_hdl_t *hdl, size_t size, int flags)
 782  856  {
 783  857          fmd_module_t *mp = fmd_api_module_lock(hdl);
 784  858          void *data;
 785  859  
 786  860          data = fmd_hdl_alloc_locked(mp, size, flags);
 787  861  
 788  862          fmd_module_unlock(mp);
 789  863          return (data);
 790  864  }
 791  865  
 792  866  void *
 793  867  fmd_hdl_zalloc(fmd_hdl_t *hdl, size_t size, int flags)
 794  868  {
 795  869          void *data = fmd_hdl_alloc(hdl, size, flags);
 796  870  
 797  871          if (data != NULL)
 798  872                  bzero(data, size);
 799  873  
 800  874          return (data);
 801  875  }
 802  876  
 803  877  static void
 804  878  fmd_hdl_free_locked(fmd_module_t *mp, void *data, size_t size)
 805  879  {
 806  880          fmd_free(data, size);
 807  881          mp->mod_stats->ms_memtotal.fmds_value.ui64 -= size;
 808  882  }
 809  883  
 810  884  void
 811  885  fmd_hdl_free(fmd_hdl_t *hdl, void *data, size_t size)
 812  886  {
 813  887          fmd_module_t *mp = fmd_api_module_lock(hdl);
 814  888  
 815  889          fmd_hdl_free_locked(mp, data, size);
 816  890  
 817  891          fmd_module_unlock(mp);
 818  892  }
 819  893  
 820  894  char *
 821  895  fmd_hdl_strdup(fmd_hdl_t *hdl, const char *s, int flags)
 822  896  {
 823  897          char *p;
 824  898  
 825  899          if (s != NULL)
 826  900                  p = fmd_hdl_alloc(hdl, strlen(s) + 1, flags);
 827  901          else
 828  902                  p = NULL;
 829  903  
 830  904          if (p != NULL)
 831  905                  (void) strcpy(p, s);
 832  906  
 833  907          return (p);
 834  908  }
 835  909  
 836  910  void
 837  911  fmd_hdl_strfree(fmd_hdl_t *hdl, char *s)
 838  912  {
 839  913          if (s != NULL)
 840  914                  fmd_hdl_free(hdl, s, strlen(s) + 1);
 841  915  }
 842  916  
 843  917  void
 844  918  fmd_hdl_vabort(fmd_hdl_t *hdl, const char *format, va_list ap)
 845  919  {
 846  920          fmd_api_verror(fmd_api_module_lock(hdl), EFMD_HDL_ABORT, format, ap);
 847  921  }
 848  922  
 849  923  /*PRINTFLIKE2*/
 850  924  void
 851  925  fmd_hdl_abort(fmd_hdl_t *hdl, const char *format, ...)
 852  926  {
 853  927          fmd_module_t *mp = fmd_api_module_lock(hdl);
 854  928          va_list ap;
 855  929  
 856  930          va_start(ap, format);
 857  931          fmd_api_verror(mp, EFMD_HDL_ABORT, format, ap);
 858  932          va_end(ap);
 859  933  }
 860  934  
 861  935  void
 862  936  fmd_hdl_verror(fmd_hdl_t *hdl, const char *format, va_list ap)
 863  937  {
 864  938          fmd_module_t *mp = fmd_api_module_lock(hdl);
 865  939          fmd_api_vxerror(mp, errno, format, ap);
 866  940          fmd_module_unlock(mp);
 867  941  }
 868  942  
 869  943  /*PRINTFLIKE2*/
 870  944  void
 871  945  fmd_hdl_error(fmd_hdl_t *hdl, const char *format, ...)
 872  946  {
 873  947          va_list ap;
 874  948  
 875  949          va_start(ap, format);
 876  950          fmd_hdl_verror(hdl, format, ap);
 877  951          va_end(ap);
 878  952  }
 879  953  
 880  954  void
 881  955  fmd_hdl_vdebug(fmd_hdl_t *hdl, const char *format, va_list ap)
 882  956  {
 883  957          fmd_module_t *mp = fmd_api_module_lock(hdl);
 884  958  
 885  959          char *msg;
 886  960          size_t len;
 887  961          char c;
 888  962  
 889  963          if (!(fmd.d_hdl_debug)) {
 890  964                  mp->mod_stats->ms_debugdrop.fmds_value.ui64++;
 891  965                  fmd_module_unlock(mp);
 892  966                  return;
 893  967          }
 894  968  
 895  969          len = vsnprintf(&c, 1, format, ap);
 896  970  
 897  971          if ((msg = fmd_alloc(len + 2, FMD_NOSLEEP)) == NULL) {
 898  972                  mp->mod_stats->ms_debugdrop.fmds_value.ui64++;
 899  973                  fmd_module_unlock(mp);
 900  974                  return;
 901  975          }
 902  976  
 903  977          (void) vsnprintf(msg, len + 1, format, ap);
 904  978  
 905  979          if (msg[len - 1] != '\n')
 906  980                  (void) strcpy(&msg[len], "\n");
 907  981  
 908  982          if (fmd.d_hdl_dbout & FMD_DBOUT_STDERR) {
 909  983                  (void) pthread_mutex_lock(&fmd.d_err_lock);
 910  984                  (void) fprintf(stderr, "%s DEBUG: %s: %s",
 911  985                      fmd.d_pname, mp->mod_name, msg);
 912  986                  (void) pthread_mutex_unlock(&fmd.d_err_lock);
 913  987          }
 914  988  
 915  989          if (fmd.d_hdl_dbout & FMD_DBOUT_SYSLOG) {
 916  990                  syslog(LOG_DEBUG | LOG_DAEMON, "%s DEBUG: %s: %s",
 917  991                      fmd.d_pname, mp->mod_name, msg);
 918  992          }
 919  993  
 920  994          fmd_free(msg, len + 2);
 921  995          fmd_module_unlock(mp);
 922  996  }
 923  997  
 924  998  /*PRINTFLIKE2*/
 925  999  void
 926 1000  fmd_hdl_debug(fmd_hdl_t *hdl, const char *format, ...)
 927 1001  {
 928 1002          va_list ap;
 929 1003  
 930 1004          va_start(ap, format);
 931 1005          fmd_hdl_vdebug(hdl, format, ap);
 932 1006          va_end(ap);
 933 1007  }
 934 1008  
 935 1009  int32_t
 936 1010  fmd_prop_get_int32(fmd_hdl_t *hdl, const char *name)
 937 1011  {
 938 1012          fmd_module_t *mp = fmd_api_module_lock(hdl);
 939 1013          const fmd_conf_ops_t *ops = fmd_conf_gettype(mp->mod_conf, name);
 940 1014          int32_t value = 0;
 941 1015  
 942 1016          if (ops == &fmd_conf_bool || ops == &fmd_conf_int32 ||
 943 1017              ops == &fmd_conf_uint32)
 944 1018                  (void) fmd_conf_getprop(mp->mod_conf, name, &value);
 945 1019          else if (ops != NULL) {
 946 1020                  fmd_api_error(mp, EFMD_PROP_TYPE,
 947 1021                      "property %s is not of int32 type\n", name);
 948 1022          } else {
 949 1023                  fmd_api_error(mp, EFMD_PROP_DEFN,
 950 1024                      "property %s is not defined\n", name);
 951 1025          }
 952 1026  
 953 1027          fmd_module_unlock(mp);
 954 1028          return (value);
 955 1029  }
 956 1030  
 957 1031  int64_t
 958 1032  fmd_prop_get_int64(fmd_hdl_t *hdl, const char *name)
 959 1033  {
 960 1034          fmd_module_t *mp = fmd_api_module_lock(hdl);
 961 1035          const fmd_conf_ops_t *ops = fmd_conf_gettype(mp->mod_conf, name);
 962 1036          int64_t value = 0;
 963 1037  
 964 1038          if (ops == &fmd_conf_int64 || ops == &fmd_conf_uint64 ||
 965 1039              ops == &fmd_conf_time || ops == &fmd_conf_size)
 966 1040                  (void) fmd_conf_getprop(mp->mod_conf, name, &value);
 967 1041          else if (ops != NULL) {
 968 1042                  fmd_api_error(mp, EFMD_PROP_TYPE,
 969 1043                      "property %s is not of int64 type\n", name);
 970 1044          } else {
 971 1045                  fmd_api_error(mp, EFMD_PROP_DEFN,
 972 1046                      "property %s is not defined\n", name);
 973 1047          }
 974 1048  
 975 1049          fmd_module_unlock(mp);
 976 1050          return (value);
 977 1051  }
 978 1052  
 979 1053  char *
 980 1054  fmd_prop_get_string(fmd_hdl_t *hdl, const char *name)
 981 1055  {
 982 1056          fmd_module_t *mp = fmd_api_module_lock(hdl);
 983 1057          const fmd_conf_ops_t *ops = fmd_conf_gettype(mp->mod_conf, name);
 984 1058          char *value = NULL;
 985 1059          const char *s;
 986 1060  
 987 1061          if (ops == &fmd_conf_string) {
 988 1062                  (void) fmd_conf_getprop(mp->mod_conf, name, &s);
 989 1063                  value = fmd_strdup(s, FMD_SLEEP);
 990 1064          } else if (ops != NULL) {
 991 1065                  fmd_api_error(mp, EFMD_PROP_TYPE,
 992 1066                      "property %s is not of string type\n", name);
 993 1067          } else {
 994 1068                  fmd_api_error(mp, EFMD_PROP_DEFN,
 995 1069                      "property %s is not defined\n", name);
 996 1070          }
 997 1071  
 998 1072          fmd_module_unlock(mp);
 999 1073          return (value);
1000 1074  }
1001 1075  
1002 1076  void
1003 1077  fmd_prop_free_string(fmd_hdl_t *hdl, char *s)
1004 1078  {
1005 1079          fmd_module_t *mp = fmd_api_module_lock(hdl);
1006 1080          fmd_strfree(s);
1007 1081          fmd_module_unlock(mp);
1008 1082  }
1009 1083  
1010 1084  fmd_stat_t *
1011 1085  fmd_stat_create(fmd_hdl_t *hdl, uint_t flags, uint_t argc, fmd_stat_t *argv)
1012 1086  {
1013 1087          fmd_module_t *mp = fmd_api_module_lock(hdl);
1014 1088          fmd_stat_t *ep, *sp;
1015 1089  
1016 1090          if (flags & ~FMD_STAT_ALLOC) {
1017 1091                  fmd_api_error(mp, EFMD_STAT_FLAGS,
1018 1092                      "invalid flags 0x%x passed to fmd_stat_create\n", flags);
1019 1093          }
1020 1094  
1021 1095          if ((sp = fmd_ustat_insert(mp->mod_ustat,
1022 1096              flags | FMD_USTAT_VALIDATE, argc, argv, &ep)) == NULL) {
1023 1097                  fmd_api_error(mp, errno,
1024 1098                      "failed to publish stat '%s'", ep->fmds_name);
1025 1099          }
1026 1100  
1027 1101          fmd_module_unlock(mp);
1028 1102          return (sp);
1029 1103  }
1030 1104  
1031 1105  void
1032 1106  fmd_stat_destroy(fmd_hdl_t *hdl, uint_t argc, fmd_stat_t *argv)
1033 1107  {
1034 1108          fmd_module_t *mp = fmd_api_module_lock(hdl);
1035 1109          fmd_ustat_delete(mp->mod_ustat, argc, argv);
1036 1110          fmd_module_unlock(mp);
1037 1111  }
1038 1112  
1039 1113  void
1040 1114  fmd_stat_setstr(fmd_hdl_t *hdl, fmd_stat_t *sp, const char *s)
1041 1115  {
1042 1116          char *str = fmd_strdup(s, FMD_SLEEP);
1043 1117          fmd_module_t *mp = fmd_api_module_lock(hdl);
1044 1118  
1045 1119          if (sp->fmds_type != FMD_TYPE_STRING) {
1046 1120                  fmd_strfree(str);
1047 1121                  fmd_api_error(mp, EFMD_STAT_TYPE,
1048 1122                      "stat '%s' is not a string\n", sp->fmds_name);
1049 1123          }
1050 1124  
1051 1125          fmd_strfree(sp->fmds_value.str);
1052 1126          sp->fmds_value.str = str;
1053 1127  
1054 1128          fmd_module_unlock(mp);
1055 1129  }
1056 1130  
1057 1131  fmd_case_t *
1058 1132  fmd_case_open(fmd_hdl_t *hdl, void *data)
1059 1133  {
1060 1134          fmd_module_t *mp = fmd_api_module_lock(hdl);
1061 1135          fmd_case_t *cp = fmd_case_create(mp, NULL, data);
1062 1136          fmd_module_unlock(mp);
1063 1137          return (cp);
1064 1138  }
1065 1139  
1066 1140  fmd_case_t *
1067 1141  fmd_case_open_uuid(fmd_hdl_t *hdl, const char *uuidstr, void *data)
1068 1142  {
1069 1143          fmd_module_t *mp;
1070 1144          fmd_case_t *cp;
1071 1145          uint_t uuidlen;
1072 1146          uuid_t uuid;
1073 1147  
1074 1148          mp = fmd_api_module_lock(hdl);
1075 1149  
1076 1150          (void) fmd_conf_getprop(fmd.d_conf, "uuidlen", &uuidlen);
1077 1151  
1078 1152          if (uuidstr == NULL) {
1079 1153                  fmd_api_error(mp, EFMD_CASE_INVAL, "NULL uuid string\n");
1080 1154          } else if (strnlen(uuidstr, uuidlen + 1) != uuidlen) {
1081 1155                  fmd_api_error(mp, EFMD_CASE_INVAL, "invalid uuid string: '%s' "
1082 1156                      "(expected length %d)\n", uuidstr, uuidlen);
1083 1157          } else if (uuid_parse((char *)uuidstr, uuid) == -1) {
1084 1158                  fmd_api_error(mp, EFMD_CASE_INVAL, "cannot parse uuid string: "
1085 1159                      "'%s'\n", uuidstr);
1086 1160          }
1087 1161  
1088 1162          if ((cp = fmd_case_hash_lookup(fmd.d_cases, uuidstr)) == NULL) {
1089 1163                  cp = fmd_case_create(mp, uuidstr, data);
1090 1164          } else {
1091 1165                  fmd_case_rele(cp);
1092 1166                  cp = NULL;
1093 1167          }
1094 1168  
1095 1169          fmd_module_unlock(mp);
1096 1170          return (cp);    /* May be NULL iff case already exists */
1097 1171  }
1098 1172  
1099 1173  void
1100 1174  fmd_case_reset(fmd_hdl_t *hdl, fmd_case_t *cp)
1101 1175  {
1102 1176          fmd_module_t *mp = fmd_api_module_lock(hdl);
1103 1177          fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp);
1104 1178  
1105 1179          if (cip->ci_state >= FMD_CASE_SOLVED) {
1106 1180                  fmd_api_error(mp, EFMD_CASE_STATE, "cannot solve %s: "
1107 1181                      "case is already solved or closed\n", cip->ci_uuid);
1108 1182          }
1109 1183  
1110 1184          fmd_case_reset_suspects(cp);
1111 1185          fmd_module_unlock(mp);
1112 1186  }
1113 1187  
1114 1188  void
1115 1189  fmd_case_solve(fmd_hdl_t *hdl, fmd_case_t *cp)
1116 1190  {
1117 1191          fmd_module_t *mp = fmd_api_module_lock(hdl);
1118 1192          fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp);
1119 1193  
1120 1194          if (cip->ci_state >= FMD_CASE_SOLVED) {
1121 1195                  fmd_api_error(mp, EFMD_CASE_STATE, "cannot solve %s: "
1122 1196                      "case is already solved or closed\n", cip->ci_uuid);
1123 1197          }
1124 1198  
1125 1199          fmd_case_transition(cp, FMD_CASE_SOLVED, FMD_CF_SOLVED);
1126 1200          fmd_module_unlock(mp);
1127 1201  }
1128 1202  
1129 1203  void
1130 1204  fmd_case_close(fmd_hdl_t *hdl, fmd_case_t *cp)
1131 1205  {
1132 1206          fmd_module_t *mp = fmd_api_module_lock(hdl);
1133 1207  
1134 1208          (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */
1135 1209          fmd_case_transition(cp, FMD_CASE_CLOSE_WAIT, FMD_CF_ISOLATED);
1136 1210  
1137 1211          fmd_module_unlock(mp);
1138 1212  }
1139 1213  
1140 1214  const char *
1141 1215  fmd_case_uuid(fmd_hdl_t *hdl, fmd_case_t *cp)
1142 1216  {
1143 1217          fmd_module_t *mp = fmd_api_module_lock(hdl);
1144 1218          fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp);
1145 1219          const char *uuid = cip->ci_uuid;
1146 1220  
1147 1221          fmd_module_unlock(mp);
1148 1222          return (uuid);
1149 1223  }
1150 1224  
1151 1225  fmd_case_t *
1152 1226  fmd_case_uulookup(fmd_hdl_t *hdl, const char *uuid)
1153 1227  {
1154 1228          fmd_module_t *cmp, *mp = fmd_api_module_lock(hdl);
1155 1229          fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid);
1156 1230  
1157 1231          if (cp != NULL) {
1158 1232                  cmp = ((fmd_case_impl_t *)cp)->ci_mod;
1159 1233                  fmd_case_rele(cp);
1160 1234          } else
1161 1235                  cmp = NULL;
1162 1236  
1163 1237          fmd_module_unlock(mp);
1164 1238          return (cmp == mp ? cp : NULL);
1165 1239  }
1166 1240  
1167 1241  void
1168 1242  fmd_case_uuclose(fmd_hdl_t *hdl, const char *uuid)
1169 1243  {
1170 1244          fmd_module_t *mp = fmd_api_module_lock(hdl);
1171 1245          fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid);
1172 1246  
1173 1247          if (cp != NULL) {
1174 1248                  fmd_case_transition(cp, FMD_CASE_CLOSE_WAIT, FMD_CF_ISOLATED);
1175 1249                  fmd_case_rele(cp);
1176 1250          }
1177 1251  
1178 1252          fmd_module_unlock(mp);
1179 1253  }
1180 1254  
1181 1255  int
1182 1256  fmd_case_uuclosed(fmd_hdl_t *hdl, const char *uuid)
1183 1257  {
1184 1258          fmd_module_t *mp = fmd_api_module_lock(hdl);
1185 1259          fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid);
1186 1260          fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
1187 1261          int rv = FMD_B_TRUE;
1188 1262  
1189 1263          if (cip != NULL) {
1190 1264                  rv = cip->ci_state >= FMD_CASE_CLOSE_WAIT;
1191 1265                  fmd_case_rele(cp);
1192 1266          }
1193 1267  
1194 1268          fmd_module_unlock(mp);
1195 1269          return (rv);
1196 1270  }
1197 1271  
1198 1272  void
1199 1273  fmd_case_uuresolved(fmd_hdl_t *hdl, const char *uuid)
1200 1274  {
1201 1275          fmd_module_t *mp = fmd_api_module_lock(hdl);
1202 1276          fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid);
1203 1277  
1204 1278          if (cp != NULL) {
1205 1279                  fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
1206 1280                  /*
1207 1281                   * For a proxy, we notify the diagnosing side, and then
1208 1282                   * wait for it to send us back a list.resolved.
1209 1283                   */
1210 1284                  if (cip->ci_xprt != NULL)
1211 1285                          fmd_xprt_uuresolved(cip->ci_xprt, cip->ci_uuid);
1212 1286                  else
1213 1287                          fmd_case_transition(cp, FMD_CASE_RESOLVED, 0);
1214 1288                  fmd_case_rele(cp);
1215 1289          }
1216 1290  
1217 1291          fmd_module_unlock(mp);
1218 1292  }
1219 1293  
1220 1294  int
1221 1295  fmd_case_uuisresolved(fmd_hdl_t *hdl, const char *uuid)
1222 1296  {
1223 1297          fmd_module_t *mp = fmd_api_module_lock(hdl);
1224 1298          fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid);
1225 1299          fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
1226 1300          int rv = FMD_B_FALSE;
1227 1301  
1228 1302          if (cip != NULL) {
1229 1303                  rv = (cip->ci_state >= FMD_CASE_RESOLVED);
1230 1304                  fmd_case_rele(cp);
1231 1305          }
1232 1306  
1233 1307          fmd_module_unlock(mp);
1234 1308          return (rv);
1235 1309  }
1236 1310  
1237 1311  static int
1238 1312  fmd_case_instate(fmd_hdl_t *hdl, fmd_case_t *cp, uint_t state)
1239 1313  {
1240 1314          fmd_module_t *mp = fmd_api_module_lock(hdl);
1241 1315          fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp);
1242 1316          int rv = cip->ci_state >= state;
1243 1317  
1244 1318          fmd_module_unlock(mp);
1245 1319          return (rv);
1246 1320  }
1247 1321  
1248 1322  int
1249 1323  fmd_case_solved(fmd_hdl_t *hdl, fmd_case_t *cp)
1250 1324  {
1251 1325          return (fmd_case_instate(hdl, cp, FMD_CASE_SOLVED));
1252 1326  }
1253 1327  
1254 1328  int
1255 1329  fmd_case_closed(fmd_hdl_t *hdl, fmd_case_t *cp)
1256 1330  {
1257 1331          return (fmd_case_instate(hdl, cp, FMD_CASE_CLOSE_WAIT));
1258 1332  }
1259 1333  
1260 1334  void
1261 1335  fmd_case_add_ereport(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep)
1262 1336  {
1263 1337          fmd_module_t *mp = fmd_api_module_lock(hdl);
1264 1338  
1265 1339          (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */
1266 1340  
1267 1341          if (fmd_case_insert_event(cp, ep))
1268 1342                  mp->mod_stats->ms_accepted.fmds_value.ui64++;
1269 1343  
1270 1344          fmd_module_unlock(mp);
1271 1345  }
1272 1346  
1273 1347  void
1274 1348  fmd_case_add_serd(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name)
1275 1349  {
1276 1350          fmd_module_t *mp = fmd_api_module_lock(hdl);
1277 1351          fmd_serd_elem_t *sep;
1278 1352          fmd_serd_eng_t *sgp;
1279 1353  
1280 1354          if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
1281 1355                  fmd_api_error(mp, EFMD_SERD_NAME,
1282 1356                      "failed to add events from serd engine '%s'", name);
1283 1357          }
1284 1358  
1285 1359          (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */
1286 1360  
1287 1361          for (sep = fmd_list_next(&sgp->sg_list);
1288 1362              sep != NULL; sep = fmd_list_next(sep)) {
1289 1363                  if (fmd_case_insert_event(cp, sep->se_event))
1290 1364                          mp->mod_stats->ms_accepted.fmds_value.ui64++;
1291 1365          }
1292 1366  
1293 1367          fmd_module_unlock(mp);
1294 1368  }
1295 1369  
1296 1370  void
1297 1371  fmd_case_add_suspect(fmd_hdl_t *hdl, fmd_case_t *cp, nvlist_t *nvl)
1298 1372  {
1299 1373          fmd_module_t *mp = fmd_api_module_lock(hdl);
1300 1374          fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp);
1301 1375          char *class;
1302 1376          topo_hdl_t *thp;
1303 1377          int err;
1304 1378          nvlist_t *rsrc = NULL, *asru_prop = NULL, *asru = NULL, *fru = NULL;
1305 1379          char *loc = NULL, *serial = NULL;
1306 1380  
1307 1381          if (cip->ci_state >= FMD_CASE_SOLVED) {
1308 1382                  fmd_api_error(mp, EFMD_CASE_STATE, "cannot add suspect to "
1309 1383                      "%s: case is already solved or closed\n", cip->ci_uuid);
1310 1384          }
1311 1385  
1312 1386          if (nvlist_lookup_string(nvl, FM_CLASS, &class) != 0 ||
1313 1387              class == NULL || *class == '\0') {
1314 1388                  fmd_api_error(mp, EFMD_CASE_EVENT, "cannot add suspect to "
1315 1389                      "%s: suspect event is missing a class\n", cip->ci_uuid);
1316 1390          }
1317 1391  
1318 1392          thp = fmd_module_topo_hold(mp);
1319 1393          (void) nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc);
1320 1394          (void) nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &asru);
1321 1395          (void) nvlist_lookup_nvlist(nvl, FM_FAULT_FRU, &fru);
1322 1396          if (rsrc != NULL) {
1323 1397                  if (strncmp(class, "defect", 6) == 0) {
1324 1398                          if (asru == NULL && topo_fmri_getprop(thp, rsrc,
1325 1399                              TOPO_PGROUP_IO, TOPO_IO_MODULE, rsrc,
1326 1400                              &asru_prop, &err) == 0 &&
1327 1401                              nvlist_lookup_nvlist(asru_prop, TOPO_PROP_VAL_VAL,
1328 1402                              &asru) == 0) {
1329 1403                                  (void) nvlist_add_nvlist(nvl, FM_FAULT_ASRU,
1330 1404                                      asru);
1331 1405                                  nvlist_free(asru_prop);
1332 1406                                  (void) nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU,
1333 1407                                      &asru);
1334 1408                          }
1335 1409                  } else {
1336 1410                          if (topo_fmri_asru(thp, rsrc, &asru, &err) == 0) {
1337 1411                                  (void) nvlist_remove(nvl, FM_FAULT_ASRU,
1338 1412                                      DATA_TYPE_NVLIST);
1339 1413                                  (void) nvlist_add_nvlist(nvl, FM_FAULT_ASRU,
1340 1414                                      asru);
1341 1415                                  nvlist_free(asru);
1342 1416                                  (void) nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU,
1343 1417                                      &asru);
1344 1418                          }
1345 1419                          if (topo_fmri_fru(thp, rsrc, &fru, &err) == 0) {
1346 1420                                  (void) nvlist_remove(nvl, FM_FAULT_FRU,
1347 1421                                      DATA_TYPE_NVLIST);
1348 1422                                  (void) nvlist_add_nvlist(nvl, FM_FAULT_FRU,
1349 1423                                      fru);
1350 1424                                  nvlist_free(fru);
1351 1425                                  (void) nvlist_lookup_nvlist(nvl, FM_FAULT_FRU,
1352 1426                                      &fru);
1353 1427                          }
1354 1428                  }
1355 1429          }
1356 1430  
1357 1431          /*
1358 1432           * Try to find the location label for this resource
1359 1433           */
1360 1434          if (strncmp(class, "defect", 6) != 0) {
1361 1435                  if (fru != NULL)
1362 1436                          (void) topo_fmri_label(thp, fru, &loc, &err);
1363 1437                  else if (rsrc != NULL)
1364 1438                          (void) topo_fmri_label(thp, rsrc, &loc, &err);
1365 1439                  if (loc != NULL) {
1366 1440                          (void) nvlist_remove(nvl, FM_FAULT_LOCATION,
1367 1441                              DATA_TYPE_STRING);
1368 1442                          (void) nvlist_add_string(nvl, FM_FAULT_LOCATION, loc);
1369 1443                          topo_hdl_strfree(thp, loc);
1370 1444                  }
1371 1445          }
1372 1446  
1373 1447          /*
1374 1448           * In some cases, serial information for the resource will not be
1375 1449           * available at enumeration but may instead be available by invoking
1376 1450           * a dynamic property method on the FRU.  In order to ensure the serial
1377 1451           * number is persisted properly in the ASRU cache, we'll fetch the
1378 1452           * property, if it exists, and add it to the resource and fru fmris.
1379 1453           * If the DE has not listed a fru in the suspect, see if we can
1380 1454           * retrieve the serial from the resource instead.
1381 1455           */
1382 1456          if (fru != NULL) {
1383 1457                  (void) topo_fmri_serial(thp, fru, &serial, &err);
1384 1458                  if (serial != NULL) {
1385 1459                          (void) nvlist_add_string(fru, "serial", serial);
1386 1460                          topo_hdl_strfree(thp, serial);
1387 1461                  }
1388 1462          }
1389 1463  
1390 1464          err = fmd_module_topo_rele(mp, thp);
1391 1465          ASSERT(err == 0);
1392 1466  
1393 1467          fmd_case_insert_suspect(cp, nvl);
1394 1468          fmd_module_unlock(mp);
1395 1469  }
1396 1470  
1397 1471  void
1398 1472  fmd_case_setspecific(fmd_hdl_t *hdl, fmd_case_t *cp, void *data)
1399 1473  {
1400 1474          fmd_module_t *mp = fmd_api_module_lock(hdl);
1401 1475          fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp);
1402 1476  
1403 1477          (void) pthread_mutex_lock(&cip->ci_lock);
1404 1478          cip->ci_data = data;
1405 1479          (void) pthread_mutex_unlock(&cip->ci_lock);
1406 1480  
1407 1481          fmd_module_unlock(mp);
1408 1482  }
1409 1483  
1410 1484  void *
1411 1485  fmd_case_getspecific(fmd_hdl_t *hdl, fmd_case_t *cp)
1412 1486  {
1413 1487          fmd_module_t *mp = fmd_api_module_lock(hdl);
1414 1488          fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp);
1415 1489          void *data;
1416 1490  
1417 1491          (void) pthread_mutex_lock(&cip->ci_lock);
1418 1492          data = cip->ci_data;
1419 1493          (void) pthread_mutex_unlock(&cip->ci_lock);
1420 1494  
1421 1495          fmd_module_unlock(mp);
1422 1496          return (data);
1423 1497  }
1424 1498  
1425 1499  void
1426 1500  fmd_case_setprincipal(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep)
1427 1501  {
1428 1502          fmd_module_t *mp = fmd_api_module_lock(hdl);
1429 1503  
1430 1504          (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */
1431 1505  
1432 1506          if (fmd_case_insert_principal(cp, ep))
1433 1507                  mp->mod_stats->ms_accepted.fmds_value.ui64++;
1434 1508  
1435 1509          fmd_module_unlock(mp);
1436 1510  }
1437 1511  
1438 1512  fmd_event_t *
1439 1513  fmd_case_getprincipal(fmd_hdl_t *hdl, fmd_case_t *cp)
1440 1514  {
1441 1515          fmd_module_t *mp = fmd_api_module_lock(hdl);
1442 1516          fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp);
1443 1517          fmd_event_t *ep;
1444 1518  
1445 1519          (void) pthread_mutex_lock(&cip->ci_lock);
1446 1520          ep = cip->ci_principal;
1447 1521          (void) pthread_mutex_unlock(&cip->ci_lock);
1448 1522  
1449 1523          fmd_module_unlock(mp);
1450 1524          return (ep);
1451 1525  }
1452 1526  
1453 1527  fmd_case_t *
1454 1528  fmd_case_next(fmd_hdl_t *hdl, fmd_case_t *cp)
1455 1529  {
1456 1530          fmd_module_t *mp = fmd_api_module_lock(hdl);
1457 1531  
1458 1532          if (cp != NULL)
1459 1533                  cp = fmd_list_next(fmd_api_case_impl(mp, cp));
1460 1534          else
1461 1535                  cp = fmd_list_next(&mp->mod_cases);
1462 1536  
1463 1537          fmd_module_unlock(mp);
1464 1538          return (cp);
1465 1539  }
1466 1540  
1467 1541  fmd_case_t *
1468 1542  fmd_case_prev(fmd_hdl_t *hdl, fmd_case_t *cp)
1469 1543  {
1470 1544          fmd_module_t *mp = fmd_api_module_lock(hdl);
1471 1545  
1472 1546          if (cp != NULL)
1473 1547                  cp = fmd_list_prev(fmd_api_case_impl(mp, cp));
1474 1548          else
1475 1549                  cp = fmd_list_prev(&mp->mod_cases);
1476 1550  
1477 1551          fmd_module_unlock(mp);
1478 1552          return (cp);
1479 1553  }
1480 1554  
1481 1555  /*
1482 1556   * Utility function for fmd_buf_* routines.  If a case is specified, use the
1483 1557   * case's ci_bufs hash; otherwise use the module's global mod_bufs hash.
1484 1558   */
1485 1559  static fmd_buf_hash_t *
1486 1560  fmd_buf_gethash(fmd_module_t *mp, fmd_case_t *cp)
1487 1561  {
1488 1562          return (cp ? &fmd_api_case_impl(mp, cp)->ci_bufs : &mp->mod_bufs);
1489 1563  }
1490 1564  
1491 1565  void
1492 1566  fmd_buf_create(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name, size_t size)
1493 1567  {
1494 1568          fmd_module_t *mp = fmd_api_module_lock(hdl);
1495 1569          fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp);
1496 1570          fmd_buf_t *bp = fmd_buf_lookup(bhp, name);
1497 1571  
1498 1572          if (bp == NULL) {
1499 1573                  if (fmd_strbadid(name, FMD_B_TRUE) != NULL || size == 0) {
1500 1574                          fmd_api_error(mp, EFMD_BUF_INVAL, "cannot create '%s' "
1501 1575                              "(size %lu): %s\n", name, (ulong_t)size,
1502 1576                              fmd_strerror(EFMD_BUF_INVAL));
1503 1577                  }
1504 1578  
1505 1579                  if (mp->mod_stats->ms_buflimit.fmds_value.ui64 -
1506 1580                      mp->mod_stats->ms_buftotal.fmds_value.ui64 < size) {
1507 1581                          fmd_api_error(mp, EFMD_BUF_LIMIT, "cannot create '%s': "
1508 1582                              "buf limit exceeded (%llu)\n", name, (u_longlong_t)
1509 1583                              mp->mod_stats->ms_buflimit.fmds_value.ui64);
1510 1584                  }
1511 1585  
1512 1586                  mp->mod_stats->ms_buftotal.fmds_value.ui64 += size;
1513 1587                  bp = fmd_buf_insert(bhp, name, size);
1514 1588  
1515 1589          } else {
1516 1590                  fmd_api_error(mp, EFMD_BUF_EXISTS,
1517 1591                      "cannot create '%s': buffer already exists\n", name);
1518 1592          }
1519 1593  
1520 1594          if (cp != NULL)
1521 1595                  fmd_case_setdirty(cp);
1522 1596          else
1523 1597                  fmd_module_setdirty(mp);
1524 1598  
1525 1599          fmd_module_unlock(mp);
1526 1600  }
1527 1601  
1528 1602  void
1529 1603  fmd_buf_destroy(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name)
1530 1604  {
1531 1605          fmd_module_t *mp = fmd_api_module_lock(hdl);
1532 1606          fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp);
1533 1607          fmd_buf_t *bp = fmd_buf_lookup(bhp, name);
1534 1608  
1535 1609          if (bp != NULL) {
1536 1610                  mp->mod_stats->ms_buftotal.fmds_value.ui64 -= bp->buf_size;
1537 1611                  fmd_buf_delete(bhp, name);
1538 1612  
1539 1613                  if (cp != NULL)
1540 1614                          fmd_case_setdirty(cp);
1541 1615                  else
1542 1616                          fmd_module_setdirty(mp);
1543 1617          }
1544 1618  
1545 1619          fmd_module_unlock(mp);
1546 1620  }
1547 1621  
1548 1622  void
1549 1623  fmd_buf_read(fmd_hdl_t *hdl, fmd_case_t *cp,
1550 1624      const char *name, void *buf, size_t size)
1551 1625  {
1552 1626          fmd_module_t *mp = fmd_api_module_lock(hdl);
1553 1627          fmd_buf_t *bp = fmd_buf_lookup(fmd_buf_gethash(mp, cp), name);
1554 1628  
1555 1629          if (bp == NULL) {
1556 1630                  fmd_api_error(mp, EFMD_BUF_NOENT, "no buf named '%s' is "
1557 1631                      "associated with %s\n", name, cp ? "case" : "module");
1558 1632          }
1559 1633  
1560 1634          bcopy(bp->buf_data, buf, MIN(bp->buf_size, size));
1561 1635          if (size > bp->buf_size)
1562 1636                  bzero((char *)buf + bp->buf_size, size - bp->buf_size);
1563 1637  
1564 1638          fmd_module_unlock(mp);
1565 1639  }
1566 1640  
1567 1641  void
1568 1642  fmd_buf_write(fmd_hdl_t *hdl, fmd_case_t *cp,
1569 1643      const char *name, const void *buf, size_t size)
1570 1644  {
1571 1645          fmd_module_t *mp = fmd_api_module_lock(hdl);
1572 1646          fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp);
1573 1647          fmd_buf_t *bp = fmd_buf_lookup(bhp, name);
1574 1648  
1575 1649          if (bp == NULL) {
1576 1650                  if (fmd_strbadid(name, FMD_B_TRUE) != NULL || size == 0) {
1577 1651                          fmd_api_error(mp, EFMD_BUF_INVAL, "cannot write '%s' "
1578 1652                              "(size %lu): %s\n", name, (ulong_t)size,
1579 1653                              fmd_strerror(EFMD_BUF_INVAL));
1580 1654                  }
1581 1655  
1582 1656                  if (mp->mod_stats->ms_buflimit.fmds_value.ui64 -
1583 1657                      mp->mod_stats->ms_buftotal.fmds_value.ui64 < size) {
1584 1658                          fmd_api_error(mp, EFMD_BUF_LIMIT, "cannot write '%s': "
1585 1659                              "buf limit exceeded (%llu)\n", name, (u_longlong_t)
1586 1660                              mp->mod_stats->ms_buflimit.fmds_value.ui64);
1587 1661                  }
1588 1662  
1589 1663                  mp->mod_stats->ms_buftotal.fmds_value.ui64 += size;
1590 1664                  bp = fmd_buf_insert(bhp, name, size);
1591 1665  
1592 1666          } else if (size > bp->buf_size) {
1593 1667                  fmd_api_error(mp, EFMD_BUF_OFLOW,
1594 1668                      "write to buf '%s' overflows buf size (%lu > %lu)\n",
1595 1669                      name, (ulong_t)size, (ulong_t)bp->buf_size);
1596 1670          }
1597 1671  
1598 1672          bcopy(buf, bp->buf_data, MIN(bp->buf_size, size));
1599 1673          bp->buf_flags |= FMD_BUF_DIRTY;
1600 1674  
1601 1675          if (cp != NULL)
1602 1676                  fmd_case_setdirty(cp);
1603 1677          else
1604 1678                  fmd_module_setdirty(mp);
1605 1679  
1606 1680          fmd_module_unlock(mp);
1607 1681  }
1608 1682  
1609 1683  size_t
1610 1684  fmd_buf_size(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name)
1611 1685  {
1612 1686          fmd_module_t *mp = fmd_api_module_lock(hdl);
1613 1687          fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp);
1614 1688  
1615 1689          fmd_buf_t *bp;
1616 1690          size_t size;
1617 1691  
1618 1692          if ((bp = fmd_buf_lookup(bhp, name)) != NULL)
1619 1693                  size = bp->buf_size;
1620 1694          else
1621 1695                  size = 0;
1622 1696  
1623 1697          fmd_module_unlock(mp);
1624 1698          return (size);
1625 1699  }
1626 1700  
1627 1701  void
1628 1702  fmd_serd_create(fmd_hdl_t *hdl, const char *name, uint_t n, hrtime_t t)
1629 1703  {
1630 1704          fmd_module_t *mp = fmd_api_module_lock(hdl);
1631 1705  
1632 1706          if (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL) {
1633 1707                  fmd_api_error(mp, EFMD_SERD_EXISTS,
1634 1708                      "failed to create serd engine '%s': %s\n",
1635 1709                      name, fmd_strerror(EFMD_SERD_EXISTS));
1636 1710          }
1637 1711  
1638 1712          (void) fmd_serd_eng_insert(&mp->mod_serds, name, n, t);
1639 1713          fmd_module_setdirty(mp);
1640 1714          fmd_module_unlock(mp);
1641 1715  }
1642 1716  
1643 1717  void
1644 1718  fmd_serd_destroy(fmd_hdl_t *hdl, const char *name)
1645 1719  {
1646 1720          fmd_module_t *mp = fmd_api_module_lock(hdl);
1647 1721  
1648 1722          fmd_serd_eng_delete(&mp->mod_serds, name);
1649 1723          fmd_module_setdirty(mp);
1650 1724          fmd_module_unlock(mp);
1651 1725  }
1652 1726  
1653 1727  int
1654 1728  fmd_serd_exists(fmd_hdl_t *hdl, const char *name)
1655 1729  {
1656 1730          fmd_module_t *mp = fmd_api_module_lock(hdl);
1657 1731          int rv = (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL);
1658 1732          fmd_module_unlock(mp);
1659 1733  
1660 1734          return (rv);
1661 1735  }
1662 1736  
1663 1737  void
1664 1738  fmd_serd_reset(fmd_hdl_t *hdl, const char *name)
1665 1739  {
1666 1740          fmd_module_t *mp = fmd_api_module_lock(hdl);
1667 1741          fmd_serd_eng_t *sgp;
1668 1742  
1669 1743          if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
1670 1744                  fmd_api_error(mp, EFMD_SERD_NAME,
1671 1745                      "serd engine '%s' does not exist\n", name);
1672 1746          }
1673 1747  
1674 1748          fmd_serd_eng_reset(sgp);
1675 1749          fmd_module_setdirty(mp);
1676 1750          fmd_module_unlock(mp);
1677 1751  }
1678 1752  
1679 1753  int
1680 1754  fmd_serd_record(fmd_hdl_t *hdl, const char *name, fmd_event_t *ep)
1681 1755  {
1682 1756          fmd_module_t *mp = fmd_api_module_lock(hdl);
1683 1757          fmd_serd_eng_t *sgp;
1684 1758          int err;
1685 1759  
1686 1760          if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
1687 1761                  fmd_api_error(mp, EFMD_SERD_NAME,
1688 1762                      "failed to add record to serd engine '%s'", name);
1689 1763          }
1690 1764  
1691 1765          err = fmd_serd_eng_record(sgp, ep);
1692 1766  
1693 1767          if (sgp->sg_flags & FMD_SERD_DIRTY)
1694 1768                  fmd_module_setdirty(mp);
1695 1769  
1696 1770          fmd_module_unlock(mp);
1697 1771          return (err);
1698 1772  }
1699 1773  
1700 1774  int
1701 1775  fmd_serd_fired(fmd_hdl_t *hdl, const char *name)
1702 1776  {
1703 1777          fmd_module_t *mp = fmd_api_module_lock(hdl);
1704 1778          fmd_serd_eng_t *sgp;
1705 1779          int err;
1706 1780  
1707 1781          if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
1708 1782                  fmd_api_error(mp, EFMD_SERD_NAME,
1709 1783                      "serd engine '%s' does not exist\n", name);
1710 1784          }
1711 1785  
1712 1786          err = fmd_serd_eng_fired(sgp);
1713 1787          fmd_module_unlock(mp);
1714 1788          return (err);
1715 1789  }
1716 1790  
1717 1791  int
1718 1792  fmd_serd_empty(fmd_hdl_t *hdl, const char *name)
1719 1793  {
1720 1794          fmd_module_t *mp = fmd_api_module_lock(hdl);
1721 1795          fmd_serd_eng_t *sgp;
1722 1796          int empty;
1723 1797  
1724 1798          if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
1725 1799                  fmd_api_error(mp, EFMD_SERD_NAME,
1726 1800                      "serd engine '%s' does not exist\n", name);
1727 1801          }
1728 1802  
1729 1803          empty = fmd_serd_eng_empty(sgp);
1730 1804          fmd_module_unlock(mp);
1731 1805          return (empty);
1732 1806  }
1733 1807  
1734 1808  pthread_t
1735 1809  fmd_thr_create(fmd_hdl_t *hdl, void (*func)(void *), void *arg)
1736 1810  {
1737 1811          fmd_module_t *mp = fmd_api_module_lock(hdl);
1738 1812          fmd_thread_t *tp;
1739 1813          pthread_t tid;
1740 1814  
1741 1815          if (mp->mod_stats->ms_thrtotal.fmds_value.ui32 >=
1742 1816              mp->mod_stats->ms_thrlimit.fmds_value.ui32) {
1743 1817                  fmd_api_error(mp, EFMD_THR_LIMIT, "%s request to create an "
1744 1818                      "auxiliary thread exceeds module thread limit (%u)\n",
1745 1819                      mp->mod_name, mp->mod_stats->ms_thrlimit.fmds_value.ui32);
1746 1820          }
1747 1821  
1748 1822          if ((tp = fmd_thread_create(mp, func, arg)) == NULL) {
1749 1823                  fmd_api_error(mp, EFMD_THR_CREATE,
1750 1824                      "failed to create auxiliary thread");
1751 1825          }
1752 1826  
1753 1827          tid = tp->thr_tid;
1754 1828          mp->mod_stats->ms_thrtotal.fmds_value.ui32++;
1755 1829          (void) fmd_idspace_xalloc(mp->mod_threads, tid, tp);
1756 1830  
1757 1831          fmd_module_unlock(mp);
1758 1832          return (tid);
1759 1833  }
1760 1834  
1761 1835  void
1762 1836  fmd_thr_destroy(fmd_hdl_t *hdl, pthread_t tid)
1763 1837  {
1764 1838          fmd_module_t *mp = fmd_api_module_lock(hdl);
1765 1839          fmd_thread_t *tp;
1766 1840          int err;
1767 1841  
1768 1842          if (pthread_self() == tid) {
1769 1843                  fmd_api_error(mp, EFMD_THR_INVAL, "auxiliary thread tried to "
1770 1844                      "destroy itself (tid %u)\n", tid);
1771 1845          }
1772 1846  
1773 1847          if ((tp = fmd_idspace_getspecific(mp->mod_threads, tid)) == NULL) {
1774 1848                  fmd_api_error(mp, EFMD_THR_INVAL, "auxiliary thread tried to "
1775 1849                      "destroy an invalid thread (tid %u)\n", tid);
1776 1850          }
1777 1851  
1778 1852          /*
1779 1853           * Wait for the specified thread to exit and then join with it.  Since
1780 1854           * the thread may need to make API calls in order to complete its work
1781 1855           * we must sleep with the module lock unheld, and then reacquire it.
1782 1856           */
1783 1857          fmd_module_unlock(mp);
1784 1858          err = pthread_join(tid, NULL);
1785 1859          mp = fmd_api_module_lock(hdl);
1786 1860  
1787 1861          /*
1788 1862           * Since pthread_join() was called without the module lock held, if
1789 1863           * multiple callers attempted to destroy the same auxiliary thread
1790 1864           * simultaneously, one will succeed and the others will get ESRCH.
1791 1865           * Therefore we silently ignore ESRCH but only allow the caller who
1792 1866           * succeessfully joined with the auxiliary thread to destroy it.
1793 1867           */
1794 1868          if (err != 0 && err != ESRCH) {
1795 1869                  fmd_api_error(mp, EFMD_THR_JOIN,
1796 1870                      "failed to join with auxiliary thread %u\n", tid);
1797 1871          }
1798 1872  
1799 1873          if (err == 0) {
1800 1874                  fmd_thread_destroy(tp, FMD_THREAD_NOJOIN);
1801 1875                  mp->mod_stats->ms_thrtotal.fmds_value.ui32--;
1802 1876                  (void) fmd_idspace_free(mp->mod_threads, tid);
1803 1877          }
1804 1878  
1805 1879          fmd_module_unlock(mp);
1806 1880  }
1807 1881  
1808 1882  void
1809 1883  fmd_thr_signal(fmd_hdl_t *hdl, pthread_t tid)
1810 1884  {
1811 1885          fmd_module_t *mp = fmd_api_module_lock(hdl);
1812 1886  
1813 1887          if (tid != mp->mod_thread->thr_tid &&
1814 1888              fmd_idspace_getspecific(mp->mod_threads, tid) == NULL) {
1815 1889                  fmd_api_error(mp, EFMD_THR_INVAL, "tid %u is not a valid "
1816 1890                      "thread id for module %s\n", tid, mp->mod_name);
1817 1891          }
1818 1892  
1819 1893          (void) pthread_kill(tid, fmd.d_thr_sig);
1820 1894          fmd_module_unlock(mp);
1821 1895  }
1822 1896  
1823 1897  void
1824 1898  fmd_thr_checkpoint(fmd_hdl_t *hdl)
1825 1899  {
1826 1900          fmd_module_t *mp = fmd_api_module_lock(hdl);
1827 1901          pthread_t tid = pthread_self();
1828 1902  
1829 1903          if (tid == mp->mod_thread->thr_tid ||
1830 1904              fmd_idspace_getspecific(mp->mod_threads, tid) == NULL) {
1831 1905                  fmd_api_error(mp, EFMD_THR_INVAL, "tid %u is not a valid "
1832 1906                      "auxiliary thread id for module %s\n", tid, mp->mod_name);
1833 1907          }
1834 1908  
1835 1909          fmd_ckpt_save(mp);
1836 1910  
1837 1911          fmd_module_unlock(mp);
1838 1912  }
1839 1913  
1840 1914  /*ARGSUSED3*/
1841 1915  int
1842 1916  fmd_doorthr_create(door_info_t *dip, void *(*crf)(void *), void *crarg,
1843 1917      void *cookie)
1844 1918  {
1845 1919          fmd_thread_t *old_tp, *new_tp;
1846 1920          fmd_module_t *mp;
1847 1921          pthread_t tid;
1848 1922  
1849 1923          /*
1850 1924           * We're called either during initial door_xcreate or during
1851 1925           * a depletion callback.  In both cases the current thread
1852 1926           * is already setup so we can retrieve the fmd_thread_t.
1853 1927           * If not then we panic.  The new thread will be associated with
1854 1928           * the same module as the old.
1855 1929           *
1856 1930           * If dip == NULL we're being called as part of the
1857 1931           * sysevent_bind_subscriber hack - see comments there.
1858 1932           */
1859 1933          if ((old_tp = pthread_getspecific(fmd.d_key)) == NULL)
1860 1934                  fmd_panic("fmd_doorthr_create from unrecognized thread\n");
1861 1935  
1862 1936          mp = old_tp->thr_mod;
1863 1937          (void) fmd_api_module_lock((fmd_hdl_t *)mp);
1864 1938  
1865 1939          if (dip && mp->mod_stats->ms_doorthrtotal.fmds_value.ui32 >=
1866 1940              mp->mod_stats->ms_doorthrlimit.fmds_value.ui32) {
1867 1941                  fmd_module_unlock(mp);
1868 1942                  (void) fmd_dprintf(FMD_DBG_XPRT, "door server %s for %p "
1869 1943                      "not attemped - at max\n",
1870 1944                      dip->di_attributes & DOOR_DEPLETION_CB ?
1871 1945                      "depletion callback" : "startup", (void *)dip);
1872 1946                  return (0);
1873 1947          }
1874 1948  
1875 1949          if ((new_tp = fmd_doorthread_create(mp, (fmd_thread_f *)crf,
1876 1950              crarg)) != NULL) {
1877 1951                  tid = new_tp->thr_tid;
1878 1952                  mp->mod_stats->ms_doorthrtotal.fmds_value.ui32++;
1879 1953                  (void) fmd_idspace_xalloc(mp->mod_threads, tid, new_tp);
1880 1954          }
1881 1955  
1882 1956          fmd_module_unlock(mp);
1883 1957  
1884 1958          if (dip) {
1885 1959                  fmd_dprintf(FMD_DBG_XPRT, "door server startup for %p %s\n",
1886 1960                      (void *)dip, new_tp ? "successful" : "failed");
1887 1961          }
1888 1962  
1889 1963          return (new_tp ? 1 : -1);
1890 1964  }
1891 1965  
1892 1966  /*ARGSUSED*/
1893 1967  void
1894 1968  fmd_doorthr_setup(void *cookie)
1895 1969  {
1896 1970          (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
1897 1971  }
1898 1972  
1899 1973  id_t
1900 1974  fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta)
1901 1975  {
1902 1976          fmd_module_t *mp = fmd_api_module_lock(hdl);
1903 1977          fmd_modtimer_t *t;
1904 1978          id_t id;
1905 1979  
1906 1980          if (delta < 0) {
1907 1981                  fmd_api_error(mp, EFMD_TIMER_INVAL,
1908 1982                      "timer delta %lld is not a valid interval\n", delta);
1909 1983          }
1910 1984  
1911 1985          t = fmd_alloc(sizeof (fmd_modtimer_t), FMD_SLEEP);
1912 1986          t->mt_mod = mp;
1913 1987          t->mt_arg = arg;
1914 1988          t->mt_id = -1;
1915 1989  
1916 1990          if ((id = fmd_timerq_install(fmd.d_timers, mp->mod_timerids,
1917 1991              (fmd_timer_f *)fmd_module_timeout, t, ep, delta)) == -1) {
1918 1992                  fmd_free(t, sizeof (fmd_modtimer_t));
1919 1993                  fmd_api_error(mp, EFMD_TIMER_LIMIT,
1920 1994                      "failed to install timer +%lld", delta);
1921 1995          }
1922 1996  
1923 1997          fmd_module_unlock(mp);
1924 1998          return (id);
1925 1999  }
1926 2000  
1927 2001  void
1928 2002  fmd_timer_remove(fmd_hdl_t *hdl, id_t id)
1929 2003  {
1930 2004          fmd_module_t *mp = fmd_api_module_lock(hdl);
1931 2005          fmd_modtimer_t *t;
1932 2006  
1933 2007          if (!fmd_idspace_valid(mp->mod_timerids, id)) {
1934 2008                  fmd_api_error(mp, EFMD_TIMER_INVAL,
1935 2009                      "id %ld is not a valid timer id\n", id);
1936 2010          }
1937 2011  
1938 2012          /*
1939 2013           * If the timer has not fired (t != NULL), remove it from the timer
1940 2014           * queue.  If the timer has fired (t == NULL), we could be in one of
1941 2015           * two situations: a) we are processing the timer callback or b)
1942 2016           * the timer event is on the module queue awaiting dispatch.  For a),
1943 2017           * fmd_timerq_remove() will wait for the timer callback function
1944 2018           * to complete and queue an event for dispatch.  For a) and b),
1945 2019           * we cancel the outstanding timer event from the module's dispatch
1946 2020           * queue.
1947 2021           */
1948 2022          if ((t = fmd_timerq_remove(fmd.d_timers, mp->mod_timerids, id)) != NULL)
1949 2023                  fmd_free(t, sizeof (fmd_modtimer_t));
1950 2024          fmd_module_unlock(mp);
1951 2025  
1952 2026          fmd_eventq_cancel(mp->mod_queue, FMD_EVT_TIMEOUT, (void *)id);
1953 2027  }
1954 2028  
1955 2029  static nvlist_t *
1956 2030  fmd_nvl_create_suspect(fmd_hdl_t *hdl, const char *class,
1957 2031      uint8_t certainty, nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc,
1958 2032      const char *pfx, boolean_t chkpfx)
1959 2033  {
1960 2034          fmd_module_t *mp;
1961 2035          nvlist_t *nvl;
1962 2036  
1963 2037          mp = fmd_api_module_lock(hdl);
1964 2038          if (class == NULL || class[0] == '\0' ||
1965 2039              chkpfx == B_TRUE && strncmp(class, pfx, strlen(pfx)) != 0)
1966 2040                  fmd_api_error(mp, EFMD_NVL_INVAL, "invalid %s class: '%s'\n",
1967 2041                      pfx, class ? class : "(empty)");
1968 2042  
1969 2043          nvl = fmd_protocol_fault(class, certainty, asru, fru, rsrc, NULL);
1970 2044  
1971 2045          fmd_module_unlock(mp);
1972 2046  
1973 2047          return (nvl);
1974 2048  }
1975 2049  
1976 2050  nvlist_t *
1977 2051  fmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class,
1978 2052      uint8_t certainty, nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc)
1979 2053  {
1980 2054          /*
1981 2055           * We can't enforce that callers only specifiy classes matching
1982 2056           * fault.* since there are already a number of modules that
1983 2057           * use fmd_nvl_create_fault to create a defect event.  Since
1984 2058           * fmd_nvl_create_{fault,defect} are equivalent, for now anyway,
1985 2059           * no harm is done.  So call fmd_nvl_create_suspect with last
1986 2060           * argument B_FALSE.
1987 2061           */
1988 2062          return (fmd_nvl_create_suspect(hdl, class, certainty, asru,
1989 2063              fru, rsrc, FM_FAULT_CLASS ".", B_FALSE));
1990 2064  }
1991 2065  
1992 2066  nvlist_t *
1993 2067  fmd_nvl_create_defect(fmd_hdl_t *hdl, const char *class,
1994 2068      uint8_t certainty, nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc)
1995 2069  {
1996 2070          return (fmd_nvl_create_suspect(hdl, class, certainty, asru,
1997 2071              fru, rsrc, FM_DEFECT_CLASS ".", B_TRUE));
1998 2072  }
1999 2073  
2000 2074  const nvlist_t *
2001 2075  fmd_hdl_fmauth(fmd_hdl_t *hdl)
2002 2076  {
2003 2077          fmd_module_t *mp = fmd_api_module_lock(hdl);
2004 2078          const nvlist_t *auth;
2005 2079  
2006 2080          auth = (const nvlist_t *)fmd.d_rmod->mod_fmri;
2007 2081  
2008 2082          fmd_module_unlock(mp);
2009 2083  
2010 2084          return (auth);
2011 2085  }
2012 2086  
2013 2087  const nvlist_t *
2014 2088  fmd_hdl_modauth(fmd_hdl_t *hdl)
2015 2089  {
2016 2090          fmd_module_t *mp = fmd_api_module_lock(hdl);
2017 2091          const nvlist_t *auth;
2018 2092  
2019 2093          auth = (const nvlist_t *)mp->mod_fmri;
2020 2094  
2021 2095          fmd_module_unlock(mp);
2022 2096  
2023 2097          return (auth);
2024 2098  }
2025 2099  
2026 2100  
2027 2101  int
2028 2102  fmd_nvl_class_match(fmd_hdl_t *hdl, nvlist_t *nvl, const char *pattern)
2029 2103  {
2030 2104          fmd_module_t *mp = fmd_api_module_lock(hdl);
2031 2105          char *class;
2032 2106          int rv;
2033 2107  
2034 2108          rv = (nvl != NULL && nvlist_lookup_string(nvl,
2035 2109              FM_CLASS, &class) == 0 && fmd_strmatch(class, pattern));
2036 2110  
2037 2111          fmd_module_unlock(mp);
2038 2112          return (rv);
2039 2113  }
2040 2114  
2041 2115  int
2042 2116  fmd_nvl_fmri_expand(fmd_hdl_t *hdl, nvlist_t *nvl)
2043 2117  {
2044 2118          fmd_module_t *mp = fmd_api_module_lock(hdl);
2045 2119          int rv;
2046 2120  
2047 2121          if (nvl == NULL) {
2048 2122                  fmd_api_error(mp, EFMD_NVL_INVAL,
2049 2123                      "invalid nvlist %p\n", (void *)nvl);
2050 2124          }
2051 2125  
2052 2126          rv = fmd_fmri_expand(nvl);
2053 2127          fmd_module_unlock(mp);
2054 2128          return (rv);
2055 2129  }
2056 2130  
2057 2131  int
2058 2132  fmd_nvl_fmri_present(fmd_hdl_t *hdl, nvlist_t *nvl)
2059 2133  {
2060 2134          fmd_module_t *mp = fmd_api_module_lock(hdl);
2061 2135          int rv;
2062 2136  
2063 2137          if (nvl == NULL) {
2064 2138                  fmd_api_error(mp, EFMD_NVL_INVAL,
2065 2139                      "invalid nvlist %p\n", (void *)nvl);
2066 2140          }
2067 2141  
2068 2142          rv = fmd_fmri_present(nvl);
2069 2143          fmd_module_unlock(mp);
2070 2144  
2071 2145          if (rv < 0) {
2072 2146                  fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for "
2073 2147                      "fmd_nvl_fmri_present\n");
2074 2148          }
2075 2149  
2076 2150          return (rv);
2077 2151  }
2078 2152  
2079 2153  int
2080 2154  fmd_nvl_fmri_replaced(fmd_hdl_t *hdl, nvlist_t *nvl)
2081 2155  {
2082 2156          fmd_module_t *mp = fmd_api_module_lock(hdl);
2083 2157          int rv;
2084 2158  
2085 2159          if (nvl == NULL) {
2086 2160                  fmd_api_error(mp, EFMD_NVL_INVAL,
2087 2161                      "invalid nvlist %p\n", (void *)nvl);
2088 2162          }
2089 2163  
2090 2164          rv = fmd_fmri_replaced(nvl);
2091 2165          fmd_module_unlock(mp);
2092 2166  
2093 2167          return (rv);
2094 2168  }
2095 2169  
2096 2170  int
2097 2171  fmd_nvl_fmri_unusable(fmd_hdl_t *hdl, nvlist_t *nvl)
2098 2172  {
2099 2173          fmd_module_t *mp = fmd_api_module_lock(hdl);
2100 2174          int rv;
2101 2175  
2102 2176          if (nvl == NULL) {
2103 2177                  fmd_api_error(mp, EFMD_NVL_INVAL,
2104 2178                      "invalid nvlist %p\n", (void *)nvl);
2105 2179          }
2106 2180  
2107 2181          rv = fmd_fmri_unusable(nvl);
2108 2182          fmd_module_unlock(mp);
2109 2183  
2110 2184          if (rv < 0) {
2111 2185                  fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for "
2112 2186                      "fmd_nvl_fmri_unusable\n");
2113 2187          }
2114 2188  
2115 2189          return (rv);
2116 2190  }
2117 2191  
2118 2192  int
2119 2193  fmd_nvl_fmri_retire(fmd_hdl_t *hdl, nvlist_t *nvl)
2120 2194  {
2121 2195          fmd_module_t *mp = fmd_api_module_lock(hdl);
2122 2196          int rv;
2123 2197  
2124 2198          if (nvl == NULL) {
2125 2199                  fmd_api_error(mp, EFMD_NVL_INVAL,
2126 2200                      "invalid nvlist %p\n", (void *)nvl);
2127 2201          }
2128 2202  
2129 2203          rv = fmd_fmri_retire(nvl);
2130 2204          fmd_module_unlock(mp);
2131 2205  
2132 2206          return (rv);
2133 2207  }
2134 2208  
2135 2209  int
2136 2210  fmd_nvl_fmri_unretire(fmd_hdl_t *hdl, nvlist_t *nvl)
2137 2211  {
2138 2212          fmd_module_t *mp = fmd_api_module_lock(hdl);
2139 2213          int rv;
2140 2214  
2141 2215          if (nvl == NULL) {
2142 2216                  fmd_api_error(mp, EFMD_NVL_INVAL,
2143 2217                      "invalid nvlist %p\n", (void *)nvl);
2144 2218          }
2145 2219  
2146 2220          rv = fmd_fmri_unretire(nvl);
2147 2221          fmd_module_unlock(mp);
2148 2222  
2149 2223          return (rv);
2150 2224  }
2151 2225  
2152 2226  int
2153 2227  fmd_nvl_fmri_service_state(fmd_hdl_t *hdl, nvlist_t *nvl)
2154 2228  {
2155 2229          fmd_module_t *mp = fmd_api_module_lock(hdl);
2156 2230          int rv;
2157 2231  
2158 2232          if (nvl == NULL) {
2159 2233                  fmd_api_error(mp, EFMD_NVL_INVAL,
2160 2234                      "invalid nvlist %p\n", (void *)nvl);
2161 2235          }
2162 2236  
2163 2237          rv = fmd_fmri_service_state(nvl);
2164 2238          if (rv < 0)
2165 2239                  rv = fmd_fmri_unusable(nvl) ? FMD_SERVICE_STATE_UNUSABLE :
2166 2240                      FMD_SERVICE_STATE_OK;
2167 2241          fmd_module_unlock(mp);
2168 2242  
2169 2243          if (rv < 0) {
2170 2244                  fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for "
2171 2245                      "fmd_nvl_fmri_service_state\n");
2172 2246          }
2173 2247  
2174 2248          return (rv);
2175 2249  }
2176 2250  
2177 2251  typedef struct {
2178 2252          const char      *class;
2179 2253          int     *rvp;
2180 2254  } fmd_has_fault_arg_t;
2181 2255  
2182 2256  static void
2183 2257  fmd_rsrc_has_fault(fmd_asru_link_t *alp, void *arg)
2184 2258  {
2185 2259          fmd_has_fault_arg_t *fhfp = (fmd_has_fault_arg_t *)arg;
2186 2260          char *class;
2187 2261  
2188 2262          if (fhfp->class == NULL) {
2189 2263                  if (alp->al_flags & FMD_ASRU_FAULTY)
2190 2264                          *fhfp->rvp = 1;
2191 2265          } else {
2192 2266                  if ((alp->al_flags & FMD_ASRU_FAULTY) &&
2193 2267                      alp->al_event != NULL && nvlist_lookup_string(alp->al_event,
2194 2268                      FM_CLASS, &class) == 0 && fmd_strmatch(class, fhfp->class))
2195 2269                          *fhfp->rvp = 1;
2196 2270          }
2197 2271  }
2198 2272  
2199 2273  int
2200 2274  fmd_nvl_fmri_has_fault(fmd_hdl_t *hdl, nvlist_t *nvl, int type, char *class)
2201 2275  {
2202 2276          fmd_module_t *mp = fmd_api_module_lock(hdl);
2203 2277          fmd_asru_hash_t *ahp = fmd.d_asrus;
2204 2278          int rv = 0;
2205 2279          char *name;
2206 2280          int namelen;
2207 2281          fmd_has_fault_arg_t fhf;
2208 2282  
2209 2283          if (nvl == NULL) {
2210 2284                  fmd_api_error(mp, EFMD_NVL_INVAL,
2211 2285                      "invalid nvlist %p\n", (void *)nvl);
2212 2286          }
2213 2287          if ((namelen = fmd_fmri_nvl2str(nvl, NULL, 0)) == -1)
2214 2288                  fmd_api_error(mp, EFMD_NVL_INVAL,
2215 2289                      "invalid nvlist: %p\n", (void *)nvl);
2216 2290          name = fmd_alloc(namelen + 1, FMD_SLEEP);
2217 2291          if (fmd_fmri_nvl2str(nvl, name, namelen + 1) == -1) {
2218 2292                  if (name != NULL)
2219 2293                          fmd_free(name, namelen + 1);
2220 2294                  fmd_api_error(mp, EFMD_NVL_INVAL,
2221 2295                      "invalid nvlist: %p\n", (void *)nvl);
2222 2296          }
2223 2297  
2224 2298          fhf.class = class;
2225 2299          fhf.rvp = &rv;
2226 2300          if (type == FMD_HAS_FAULT_RESOURCE)
2227 2301                  fmd_asru_hash_apply_by_rsrc(ahp, name, fmd_rsrc_has_fault,
2228 2302                      &fhf);
2229 2303          else if (type == FMD_HAS_FAULT_ASRU)
2230 2304                  fmd_asru_hash_apply_by_asru(ahp, name, fmd_rsrc_has_fault,
2231 2305                      &fhf);
2232 2306          else if (type == FMD_HAS_FAULT_FRU)
2233 2307                  fmd_asru_hash_apply_by_fru(ahp, name, fmd_rsrc_has_fault,
2234 2308                      &fhf);
2235 2309  
2236 2310          if (name != NULL)
2237 2311                  fmd_free(name, namelen + 1);
2238 2312          fmd_module_unlock(mp);
2239 2313          return (rv);
2240 2314  }
2241 2315  
2242 2316  int
2243 2317  fmd_nvl_fmri_contains(fmd_hdl_t *hdl, nvlist_t *n1, nvlist_t *n2)
2244 2318  {
2245 2319          fmd_module_t *mp = fmd_api_module_lock(hdl);
2246 2320          int rv;
2247 2321  
2248 2322          if (n1 == NULL || n2 == NULL) {
2249 2323                  fmd_api_error(mp, EFMD_NVL_INVAL,
2250 2324                      "invalid nvlist(s): %p, %p\n", (void *)n1, (void *)n2);
2251 2325          }
2252 2326  
2253 2327          rv = fmd_fmri_contains(n1, n2);
2254 2328          fmd_module_unlock(mp);
2255 2329  
2256 2330          if (rv < 0) {
2257 2331                  fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for "
2258 2332                      "fmd_nvl_fmri_contains\n");
2259 2333          }
2260 2334  
2261 2335          return (rv);
2262 2336  }
2263 2337  
2264 2338  nvlist_t *
2265 2339  fmd_nvl_fmri_translate(fmd_hdl_t *hdl, nvlist_t *fmri, nvlist_t *auth)
2266 2340  {
2267 2341          fmd_module_t *mp = fmd_api_module_lock(hdl);
2268 2342          nvlist_t *xfmri;
2269 2343  
2270 2344          if (fmri == NULL || auth == NULL) {
2271 2345                  fmd_api_error(mp, EFMD_NVL_INVAL,
2272 2346                      "invalid nvlist(s): %p, %p\n", (void *)fmri, (void *)auth);
2273 2347          }
2274 2348  
2275 2349          xfmri = fmd_fmri_translate(fmri, auth);
2276 2350          fmd_module_unlock(mp);
2277 2351          return (xfmri);
2278 2352  }
2279 2353  
2280 2354  static int
2281 2355  fmd_nvl_op_init(nv_alloc_t *ops, va_list ap)
2282 2356  {
2283 2357          fmd_module_t *mp = va_arg(ap, fmd_module_t *);
2284 2358  
2285 2359          ops->nva_arg = mp;
2286 2360  
2287 2361          return (0);
2288 2362  }
2289 2363  
2290 2364  static void *
2291 2365  fmd_nvl_op_alloc_sleep(nv_alloc_t *ops, size_t size)
2292 2366  {
2293 2367          fmd_module_t *mp = ops->nva_arg;
2294 2368  
2295 2369          return (fmd_hdl_alloc_locked(mp, size, FMD_SLEEP));
2296 2370  }
2297 2371  
2298 2372  static void *
2299 2373  fmd_nvl_op_alloc_nosleep(nv_alloc_t *ops, size_t size)
2300 2374  {
2301 2375          fmd_module_t *mp = ops->nva_arg;
2302 2376  
2303 2377          return (fmd_hdl_alloc_locked(mp, size, FMD_NOSLEEP));
2304 2378  }
2305 2379  
2306 2380  static void
2307 2381  fmd_nvl_op_free(nv_alloc_t *ops, void *data, size_t size)
2308 2382  {
2309 2383          fmd_module_t *mp = ops->nva_arg;
2310 2384  
2311 2385          fmd_hdl_free_locked(mp, data, size);
2312 2386  }
2313 2387  
2314 2388  nv_alloc_ops_t fmd_module_nva_ops_sleep = {
2315 2389          fmd_nvl_op_init,
2316 2390          NULL,
2317 2391          fmd_nvl_op_alloc_sleep,
2318 2392          fmd_nvl_op_free,
2319 2393          NULL
2320 2394  };
2321 2395  
2322 2396  nv_alloc_ops_t fmd_module_nva_ops_nosleep = {
2323 2397          fmd_nvl_op_init,
2324 2398          NULL,
2325 2399          fmd_nvl_op_alloc_nosleep,
2326 2400          fmd_nvl_op_free,
2327 2401          NULL
2328 2402  };
2329 2403  
2330 2404  nvlist_t *
2331 2405  fmd_nvl_alloc(fmd_hdl_t *hdl, int flags)
2332 2406  {
2333 2407          fmd_module_t *mp = fmd_api_module_lock(hdl);
2334 2408          nv_alloc_t *nva;
2335 2409          nvlist_t *nvl;
2336 2410          int ret;
2337 2411  
2338 2412          if (flags == FMD_SLEEP)
2339 2413                  nva = &mp->mod_nva_sleep;
2340 2414          else
2341 2415                  nva = &mp->mod_nva_nosleep;
2342 2416  
2343 2417          ret = nvlist_xalloc(&nvl, NV_UNIQUE_NAME, nva);
2344 2418  
2345 2419          fmd_module_unlock(mp);
2346 2420  
2347 2421          if (ret != 0)
2348 2422                  return (NULL);
2349 2423          else
2350 2424                  return (nvl);
2351 2425  }
2352 2426  
2353 2427  nvlist_t *
2354 2428  fmd_nvl_dup(fmd_hdl_t *hdl, nvlist_t *src, int flags)
2355 2429  {
2356 2430          fmd_module_t *mp = fmd_api_module_lock(hdl);
2357 2431          nv_alloc_t *nva;
2358 2432          nvlist_t *nvl;
2359 2433          int ret;
2360 2434  
2361 2435          if (flags == FMD_SLEEP)
2362 2436                  nva = &mp->mod_nva_sleep;
2363 2437          else
2364 2438                  nva = &mp->mod_nva_nosleep;
2365 2439  
2366 2440          ret = nvlist_xdup(src, &nvl, nva);
2367 2441  
2368 2442          fmd_module_unlock(mp);
2369 2443  
2370 2444          if (ret != 0)
2371 2445                  return (NULL);
2372 2446          else
2373 2447                  return (nvl);
2374 2448  }
2375 2449  
2376 2450  /*ARGSUSED*/
2377 2451  void
2378 2452  fmd_repair_fru(fmd_hdl_t *hdl, const char *fmri)
2379 2453  {
2380 2454          int err;
2381 2455          fmd_asru_rep_arg_t fara;
2382 2456  
2383 2457          fara.fara_reason = FMD_ASRU_REPAIRED;
2384 2458          fara.fara_bywhat = FARA_BY_FRU;
2385 2459          fara.fara_rval = &err;
2386 2460          fmd_asru_hash_apply_by_fru(fmd.d_asrus, (char *)fmri,
2387 2461              fmd_asru_repaired, &fara);
2388 2462  }
2389 2463  
2390 2464  /*ARGSUSED*/
2391 2465  int
2392 2466  fmd_repair_asru(fmd_hdl_t *hdl, const char *fmri)
2393 2467  {
2394 2468          int err = FARA_ERR_RSRCNOTF;
2395 2469          fmd_asru_rep_arg_t fara;
2396 2470  
2397 2471          fara.fara_reason = FMD_ASRU_REPAIRED;
2398 2472          fara.fara_rval = &err;
2399 2473          fara.fara_uuid = NULL;
2400 2474          fara.fara_bywhat = FARA_BY_ASRU;
2401 2475          fmd_asru_hash_apply_by_asru(fmd.d_asrus, fmri,
2402 2476              fmd_asru_repaired, &fara);
2403 2477          return (err);
2404 2478  }
2405 2479  
2406 2480  int
2407 2481  fmd_event_local(fmd_hdl_t *hdl, fmd_event_t *ep)
2408 2482  {
2409 2483          if (hdl == NULL || ep == NULL) {
2410 2484                  fmd_api_error(fmd_api_module_lock(hdl), EFMD_EVENT_INVAL,
2411 2485                      "NULL parameter specified to fmd_event_local\n");
2412 2486          }
2413 2487  
2414 2488          return (((fmd_event_impl_t *)ep)->ev_flags & FMD_EVF_LOCAL);
2415 2489  }
2416 2490  
2417 2491  /*ARGSUSED*/
2418 2492  uint64_t
2419 2493  fmd_event_ena_create(fmd_hdl_t *hdl)
2420 2494  {
2421 2495          return (fmd_ena());
2422 2496  }
2423 2497  
2424 2498  fmd_xprt_t *
2425 2499  fmd_xprt_open(fmd_hdl_t *hdl, uint_t flags, nvlist_t *auth, void *data)
2426 2500  {
2427 2501          fmd_module_t *mp = fmd_api_module_lock(hdl);
2428 2502          fmd_xprt_t *xp;
2429 2503  
2430 2504          if (flags & ~FMD_XPRT_CMASK) {
2431 2505                  fmd_api_error(mp, EFMD_XPRT_INVAL,
2432 2506                      "invalid transport flags 0x%x\n", flags);
2433 2507          }
2434 2508  
2435 2509          if ((flags & FMD_XPRT_RDWR) != FMD_XPRT_RDWR &&
2436 2510              (flags & FMD_XPRT_RDWR) != FMD_XPRT_RDONLY) {
2437 2511                  fmd_api_error(mp, EFMD_XPRT_INVAL,
2438 2512                      "cannot open write-only transport\n");
2439 2513          }
2440 2514  
2441 2515          if (mp->mod_stats->ms_xprtopen.fmds_value.ui32 >=
2442 2516              mp->mod_stats->ms_xprtlimit.fmds_value.ui32) {
2443 2517                  fmd_api_error(mp, EFMD_XPRT_LIMIT, "%s request to create a "
2444 2518                      "transport exceeds module transport limit (%u)\n",
2445 2519                      mp->mod_name, mp->mod_stats->ms_xprtlimit.fmds_value.ui32);
2446 2520          }
2447 2521  
2448 2522          if ((xp = fmd_xprt_create(mp, flags, auth, data)) == NULL)
2449 2523                  fmd_api_error(mp, errno, "cannot create transport");
2450 2524  
2451 2525          fmd_module_unlock(mp);
2452 2526          return (xp);
2453 2527  }
2454 2528  
2455 2529  void
2456 2530  fmd_xprt_close(fmd_hdl_t *hdl, fmd_xprt_t *xp)
2457 2531  {
2458 2532          fmd_module_t *mp = fmd_api_module_lock(hdl);
2459 2533          fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp);
2460 2534  
2461 2535          /*
2462 2536           * Although this could be supported, it doesn't seem necessary or worth
2463 2537           * the trouble.  For now, just detect this and trigger a module abort.
2464 2538           * If it is needed, transports should grow reference counts and a new
2465 2539           * event type will need to be enqueued for the main thread to reap it.
2466 2540           */
2467 2541          if (xip->xi_thread != NULL &&
2468 2542              xip->xi_thread->thr_tid == pthread_self()) {
2469 2543                  fmd_api_error(mp, EFMD_XPRT_INVAL,
2470 2544                      "fmd_xprt_close() cannot be called from fmdo_send()\n");
2471 2545          }
2472 2546  
2473 2547          fmd_xprt_destroy(xp);
2474 2548          fmd_module_unlock(mp);
2475 2549  }
2476 2550  
2477 2551  void
2478 2552  fmd_xprt_post(fmd_hdl_t *hdl, fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt)
2479 2553  {
2480 2554          nv_alloc_t *nva = nvlist_lookup_nv_alloc(nvl);
2481 2555          fmd_module_t *mp = fmd_api_module(hdl);
2482 2556          fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp);
2483 2557          nvlist_t *tmp;
2484 2558  
2485 2559          /*
2486 2560           * If this event was allocated using the module-specific nvlist ops, we
2487 2561           * need to create a copy using the standard fmd nvlist ops.  Otherwise,
2488 2562           * the event may persist after the module has been unloaded and we'll
2489 2563           * die when attempting to free the nvlist.
2490 2564           */
2491 2565          if (nva == &mp->mod_nva_sleep || nva == &mp->mod_nva_nosleep) {
2492 2566                  (void) nvlist_xdup(nvl, &tmp, &fmd.d_nva);
2493 2567                  nvlist_free(nvl);
2494 2568                  nvl = tmp;
2495 2569          }
2496 2570  
2497 2571          /*
2498 2572           * fmd_xprt_recv() must block during startup waiting for fmd to globally
2499 2573           * clear FMD_XPRT_DSUSPENDED.  As such, we can't allow it to be called
2500 2574           * from a module's _fmd_init() routine, because that would block
2501 2575           * fmd from completing initial module loading, resulting in a deadlock.
2502 2576           */
2503 2577          if ((xip->xi_flags & FMD_XPRT_ISUSPENDED) &&
2504 2578              (pthread_self() == xip->xi_queue->eq_mod->mod_thread->thr_tid)) {
2505 2579                  fmd_api_error(fmd_api_module_lock(hdl), EFMD_XPRT_INVAL,
2506 2580                      "fmd_xprt_post() cannot be called from _fmd_init()\n");
2507 2581          }
2508 2582  
2509 2583          fmd_xprt_recv(xp, nvl, hrt, FMD_B_FALSE);
2510 2584  }
2511 2585  
2512 2586  void
2513 2587  fmd_xprt_log(fmd_hdl_t *hdl, fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt)
2514 2588  {
2515 2589          fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp);
2516 2590  
2517 2591          /*
2518 2592           * fmd_xprt_recv() must block during startup waiting for fmd to globally
2519 2593           * clear FMD_XPRT_DSUSPENDED.  As such, we can't allow it to be called
2520 2594           * from a module's _fmd_init() routine, because that would block
2521 2595           * fmd from completing initial module loading, resulting in a deadlock.
2522 2596           */
2523 2597          if ((xip->xi_flags & FMD_XPRT_ISUSPENDED) &&
2524 2598              (pthread_self() == xip->xi_queue->eq_mod->mod_thread->thr_tid)) {
2525 2599                  fmd_api_error(fmd_api_module_lock(hdl), EFMD_XPRT_INVAL,
2526 2600                      "fmd_xprt_log() cannot be called from _fmd_init()\n");
2527 2601          }
2528 2602  
2529 2603          fmd_xprt_recv(xp, nvl, hrt, FMD_B_TRUE);
2530 2604  }
2531 2605  
2532 2606  void
2533 2607  fmd_xprt_suspend(fmd_hdl_t *hdl, fmd_xprt_t *xp)
2534 2608  {
2535 2609          (void) fmd_api_transport_impl(hdl, xp); /* validate 'xp' */
2536 2610          fmd_xprt_xsuspend(xp, FMD_XPRT_SUSPENDED);
2537 2611  }
2538 2612  
2539 2613  void
2540 2614  fmd_xprt_resume(fmd_hdl_t *hdl, fmd_xprt_t *xp)
2541 2615  {
2542 2616          (void) fmd_api_transport_impl(hdl, xp); /* validate 'xp' */
2543 2617          fmd_xprt_xresume(xp, FMD_XPRT_SUSPENDED);
2544 2618  }
2545 2619  
2546 2620  int
2547 2621  fmd_xprt_error(fmd_hdl_t *hdl, fmd_xprt_t *xp)
2548 2622  {
2549 2623          fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp);
2550 2624          return (xip->xi_state == _fmd_xprt_state_err);
2551 2625  }
2552 2626  
2553 2627  /*
2554 2628   * Translate all FMRIs in the specified name-value pair list for the specified
2555 2629   * FMRI authority, and return a new name-value pair list for the translation.
2556 2630   * This function is the recursive engine used by fmd_xprt_translate(), below.
2557 2631   */
2558 2632  static nvlist_t *
2559 2633  fmd_xprt_xtranslate(nvlist_t *nvl, nvlist_t *auth)
2560 2634  {
2561 2635          uint_t i, j, n;
2562 2636          nvpair_t *nvp, **nvps;
2563 2637          uint_t nvpslen = 0;
2564 2638          char *name;
2565 2639          size_t namelen = 0;
2566 2640  
2567 2641          nvlist_t **a, **b;
2568 2642          nvlist_t *l, *r;
2569 2643          data_type_t type;
2570 2644          char *s;
2571 2645          int err;
2572 2646  
2573 2647          (void) nvlist_xdup(nvl, &nvl, &fmd.d_nva);
2574 2648  
2575 2649          /*
2576 2650           * Count up the number of name-value pairs in 'nvl' and compute the
2577 2651           * maximum length of a name used in this list for use below.
2578 2652           */
2579 2653          for (nvp = nvlist_next_nvpair(nvl, NULL);
2580 2654              nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp), nvpslen++) {
2581 2655                  size_t len = strlen(nvpair_name(nvp));
2582 2656                  namelen = MAX(namelen, len);
2583 2657          }
2584 2658  
2585 2659          nvps = alloca(sizeof (nvpair_t *) * nvpslen);
2586 2660          name = alloca(namelen + 1);
2587 2661  
2588 2662          /*
2589 2663           * Store a snapshot of the name-value pairs in 'nvl' into nvps[] so
2590 2664           * that we can iterate over the original pairs in the loop below while
2591 2665           * performing arbitrary insert and delete operations on 'nvl' itself.
2592 2666           */
2593 2667          for (i = 0, nvp = nvlist_next_nvpair(nvl, NULL);
2594 2668              nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp))
2595 2669                  nvps[i++] = nvp;
2596 2670  
2597 2671          /*
2598 2672           * Now iterate over the snapshot of the name-value pairs.  If we find a
2599 2673           * value that is of type NVLIST or NVLIST_ARRAY, we translate that
2600 2674           * object by either calling ourself recursively on it, or calling into
2601 2675           * fmd_fmri_translate() if the object is an FMRI.  We then rip out the
2602 2676           * original name-value pair and replace it with the translated one.
2603 2677           */
2604 2678          for (i = 0; i < nvpslen; i++) {
2605 2679                  nvp = nvps[i];
2606 2680                  type = nvpair_type(nvp);
2607 2681  
2608 2682                  switch (type) {
2609 2683                  case DATA_TYPE_NVLIST_ARRAY:
2610 2684                          if (nvpair_value_nvlist_array(nvp, &a, &n) != 0 ||
2611 2685                              a == NULL || n == 0)
2612 2686                                  continue; /* array is zero-sized; skip it */
2613 2687  
2614 2688                          b = fmd_alloc(sizeof (nvlist_t *) * n, FMD_SLEEP);
2615 2689  
2616 2690                          /*
2617 2691                           * If the first array nvlist element looks like an FMRI
2618 2692                           * then assume the other elements are FMRIs as well.
2619 2693                           * If any b[j]'s can't be translated, then EINVAL will
2620 2694                           * be returned from nvlist_add_nvlist_array() below.
2621 2695                           */
2622 2696                          if (nvlist_lookup_string(*a, FM_FMRI_SCHEME, &s) == 0) {
2623 2697                                  for (j = 0; j < n; j++)
2624 2698                                          b[j] = fmd_fmri_translate(a[j], auth);
2625 2699                          } else {
2626 2700                                  for (j = 0; j < n; j++)
2627 2701                                          b[j] = fmd_xprt_xtranslate(a[j], auth);
2628 2702                          }
2629 2703  
2630 2704                          (void) strcpy(name, nvpair_name(nvp));
2631 2705                          (void) nvlist_remove(nvl, name, type);
2632 2706                          err = nvlist_add_nvlist_array(nvl, name, b, n);
2633 2707  
2634 2708                          for (j = 0; j < n; j++)
2635 2709                                  nvlist_free(b[j]);
2636 2710  
2637 2711                          fmd_free(b, sizeof (nvlist_t *) * n);
2638 2712  
2639 2713                          if (err != 0) {
2640 2714                                  nvlist_free(nvl);
2641 2715                                  errno = err;
2642 2716                                  return (NULL);
2643 2717                          }
2644 2718                          break;
2645 2719  
2646 2720                  case DATA_TYPE_NVLIST:
2647 2721                          if (nvpair_value_nvlist(nvp, &l) == 0 &&
2648 2722                              nvlist_lookup_string(l, FM_FMRI_SCHEME, &s) == 0)
2649 2723                                  r = fmd_fmri_translate(l, auth);
2650 2724                          else
2651 2725                                  r = fmd_xprt_xtranslate(l, auth);
2652 2726  
2653 2727                          if (r == NULL) {
2654 2728                                  nvlist_free(nvl);
2655 2729                                  return (NULL);
2656 2730                          }
2657 2731  
2658 2732                          (void) strcpy(name, nvpair_name(nvp));
2659 2733                          (void) nvlist_remove(nvl, name, type);
2660 2734                          (void) nvlist_add_nvlist(nvl, name, r);
2661 2735  
2662 2736                          nvlist_free(r);
2663 2737                          break;
2664 2738                  }
2665 2739          }
2666 2740  
2667 2741          return (nvl);
2668 2742  }
2669 2743  
2670 2744  nvlist_t *
2671 2745  fmd_xprt_translate(fmd_hdl_t *hdl, fmd_xprt_t *xp, fmd_event_t *ep)
2672 2746  {
2673 2747          fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp);
2674 2748  
2675 2749          if (xip->xi_auth == NULL) {
2676 2750                  fmd_api_error(fmd_api_module_lock(hdl), EFMD_XPRT_INVAL,
2677 2751                      "no authority defined for transport %p\n", (void *)xp);
2678 2752          }
2679 2753  
2680 2754          return (fmd_xprt_xtranslate(FMD_EVENT_NVL(ep), xip->xi_auth));
2681 2755  }
2682 2756  
2683 2757  /*ARGSUSED*/
2684 2758  void
2685 2759  fmd_xprt_add_domain(fmd_hdl_t *hdl, nvlist_t *nvl, char *domain)
2686 2760  {
2687 2761          nvpair_t *nvp, *nvp2;
2688 2762          nvlist_t *nvl2, *nvl3;
2689 2763          char *class;
2690 2764  
2691 2765          if (nvl == NULL || domain == NULL)
2692 2766                  return;
2693 2767          for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2694 2768              nvp = nvlist_next_nvpair(nvl, nvp)) {
2695 2769                  if (strcmp(nvpair_name(nvp), FM_CLASS) == 0) {
2696 2770                          (void) nvpair_value_string(nvp, &class);
2697 2771                          if (strcmp(class, FM_LIST_SUSPECT_CLASS) != 0)
2698 2772                                  return;
2699 2773                  }
2700 2774          }
2701 2775          for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2702 2776              nvp = nvlist_next_nvpair(nvl, nvp)) {
2703 2777                  if (strcmp(nvpair_name(nvp), FM_SUSPECT_DE) == 0) {
2704 2778                          (void) nvpair_value_nvlist(nvp, &nvl2);
2705 2779                          for (nvp2 = nvlist_next_nvpair(nvl2, NULL);
2706 2780                              nvp2 != NULL;
2707 2781                              nvp2 = nvlist_next_nvpair(nvl2, nvp2)) {
2708 2782                                  if (strcmp(nvpair_name(nvp2),
2709 2783                                      FM_FMRI_AUTHORITY) == 0) {
2710 2784                                          (void) nvpair_value_nvlist(nvp2, &nvl3);
2711 2785                                          (void) nvlist_add_string(nvl3,
2712 2786                                              FM_FMRI_AUTH_DOMAIN, domain);
2713 2787                                          break;
2714 2788                                  }
2715 2789                          }
2716 2790                          break;
2717 2791                  }
2718 2792          }
2719 2793  }
2720 2794  
2721 2795  void
2722 2796  fmd_xprt_setspecific(fmd_hdl_t *hdl, fmd_xprt_t *xp, void *data)
2723 2797  {
2724 2798          fmd_api_transport_impl(hdl, xp)->xi_data = data;
2725 2799  }
2726 2800  
2727 2801  void *
2728 2802  fmd_xprt_getspecific(fmd_hdl_t *hdl, fmd_xprt_t *xp)
2729 2803  {
2730 2804          return (fmd_api_transport_impl(hdl, xp)->xi_data);
2731 2805  }
  
    | 
      ↓ open down ↓ | 
    1961 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX