Print this page
    
re #13388 rb4382 fmd_api.h uses bool which is a C99/C++ keyword
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/fm/fmd/common/fmd_module.c
          +++ new/usr/src/cmd/fm/fmd/common/fmd_module.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
  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   24   */
  25   25  
  26   26  #include <signal.h>
  27   27  #include <dirent.h>
  28   28  #include <limits.h>
  29   29  #include <alloca.h>
  30   30  #include <unistd.h>
  31   31  #include <stdio.h>
  32   32  
  33   33  #include <fmd_string.h>
  34   34  #include <fmd_alloc.h>
  35   35  #include <fmd_module.h>
  36   36  #include <fmd_error.h>
  37   37  #include <fmd_conf.h>
  38   38  #include <fmd_dispq.h>
  39   39  #include <fmd_eventq.h>
  40   40  #include <fmd_timerq.h>
  41   41  #include <fmd_subr.h>
  42   42  #include <fmd_thread.h>
  43   43  #include <fmd_ustat.h>
  44   44  #include <fmd_case.h>
  45   45  #include <fmd_protocol.h>
  46   46  #include <fmd_buf.h>
  47   47  #include <fmd_ckpt.h>
  48   48  #include <fmd_xprt.h>
  49   49  #include <fmd_topo.h>
  50   50  
  51   51  #include <fmd.h>
  52   52  
  53   53  /*
  54   54   * Template for per-module statistics installed by fmd on behalf of each active
  55   55   * module.  These are used to initialize the per-module mp->mod_stats below.
  56   56   * NOTE: FMD_TYPE_STRING statistics should not be used here.  If they are
  57   57   * required in the future, the FMD_ADM_MODDSTAT service routine must change.
  58   58   */
  59   59  static const fmd_modstat_t _fmd_modstat_tmpl = {
  60   60  {
  61   61  { "fmd.dispatched", FMD_TYPE_UINT64, "total events dispatched to module" },
  62   62  { "fmd.dequeued", FMD_TYPE_UINT64, "total events dequeued by module" },
  63   63  { "fmd.prdequeued", FMD_TYPE_UINT64, "protocol events dequeued by module" },
  64   64  { "fmd.dropped", FMD_TYPE_UINT64, "total events dropped on queue overflow" },
  65   65  { "fmd.wcnt", FMD_TYPE_UINT32, "count of events waiting on queue" },
  66   66  { "fmd.wtime", FMD_TYPE_TIME, "total wait time on queue" },
  67   67  { "fmd.wlentime", FMD_TYPE_TIME, "total wait length * time product" },
  68   68  { "fmd.wlastupdate", FMD_TYPE_TIME, "hrtime of last wait queue update" },
  69   69  { "fmd.dtime", FMD_TYPE_TIME, "total processing time after dequeue" },
  70   70  { "fmd.dlastupdate", FMD_TYPE_TIME, "hrtime of last event dequeue completion" },
  71   71  },
  72   72  { "fmd.loadtime", FMD_TYPE_TIME, "hrtime at which module was loaded" },
  73   73  { "fmd.snaptime", FMD_TYPE_TIME, "hrtime of last statistics snapshot" },
  74   74  { "fmd.accepted", FMD_TYPE_UINT64, "total events accepted by module" },
  75   75  { "fmd.debugdrop", FMD_TYPE_UINT64, "dropped debug messages" },
  76   76  { "fmd.memtotal", FMD_TYPE_SIZE, "total memory allocated by module" },
  77   77  { "fmd.memlimit", FMD_TYPE_SIZE, "limit on total memory allocated" },
  78   78  { "fmd.buftotal", FMD_TYPE_SIZE, "total buffer space used by module" },
  79   79  { "fmd.buflimit", FMD_TYPE_SIZE, "limit on total buffer space" },
  80   80  { "fmd.thrtotal", FMD_TYPE_UINT32, "total number of auxiliary threads" },
  81   81  { "fmd.thrlimit", FMD_TYPE_UINT32, "limit on number of auxiliary threads" },
  82   82  { "fmd.doorthrtotal", FMD_TYPE_UINT32, "total number of door server threads" },
  83   83  { "fmd.doorthrlimit", FMD_TYPE_UINT32, "limit on door server threads" },
  84   84  { "fmd.caseopen", FMD_TYPE_UINT64, "cases currently open by module" },
  85   85  { "fmd.casesolved", FMD_TYPE_UINT64, "total cases solved by module" },
  86   86  { "fmd.caseclosed", FMD_TYPE_UINT64, "total cases closed by module" },
  87   87  { "fmd.ckptsave", FMD_TYPE_BOOL, "save checkpoints for module" },
  88   88  { "fmd.ckptrestore", FMD_TYPE_BOOL, "restore checkpoints for module" },
  89   89  { "fmd.ckptzero", FMD_TYPE_BOOL, "zeroed checkpoint at startup" },
  90   90  { "fmd.ckptcnt", FMD_TYPE_UINT64, "number of checkpoints taken" },
  91   91  { "fmd.ckpttime", FMD_TYPE_TIME, "total checkpoint time" },
  92   92  { "fmd.xprtopen", FMD_TYPE_UINT32, "total number of open transports" },
  93   93  { "fmd.xprtlimit", FMD_TYPE_UINT32, "limit on number of open transports" },
  94   94  { "fmd.xprtqlimit", FMD_TYPE_UINT32, "limit on transport event queue length" },
  95   95  };
  96   96  
  97   97  static void
  98   98  fmd_module_start(void *arg)
  99   99  {
 100  100          fmd_module_t *mp = arg;
 101  101          fmd_event_t *ep;
 102  102          fmd_xprt_t *xp;
 103  103  
 104  104          (void) pthread_mutex_lock(&mp->mod_lock);
 105  105  
 106  106          if (mp->mod_ops->mop_init(mp) != 0 || mp->mod_error != 0) {
 107  107                  if (mp->mod_error == 0)
 108  108                          mp->mod_error = errno ? errno : EFMD_MOD_INIT;
 109  109                  goto out;
 110  110          }
 111  111  
 112  112          if (fmd.d_mod_event != NULL)
 113  113                  fmd_eventq_insert_at_head(mp->mod_queue, fmd.d_mod_event);
 114  114  
 115  115          ASSERT(MUTEX_HELD(&mp->mod_lock));
 116  116          mp->mod_flags |= FMD_MOD_INIT;
 117  117  
 118  118          (void) pthread_cond_broadcast(&mp->mod_cv);
 119  119          (void) pthread_mutex_unlock(&mp->mod_lock);
 120  120  
 121  121          /*
 122  122           * If the module opened any transports while executing _fmd_init(),
 123  123           * they are suspended. Now that _fmd_init() is done, wake them up.
 124  124           */
 125  125          for (xp = fmd_list_next(&mp->mod_transports);
 126  126              xp != NULL; xp = fmd_list_next(xp))
 127  127                  fmd_xprt_xresume(xp, FMD_XPRT_ISUSPENDED);
 128  128  
 129  129          /*
 130  130           * Wait for events to arrive by checking mod_error and then sleeping in
 131  131           * fmd_eventq_delete().  If a NULL event is returned, the eventq has
 132  132           * been aborted and we continue on to call fini and exit the thread.
 133  133           */
 134  134          while ((ep = fmd_eventq_delete(mp->mod_queue)) != NULL) {
 135  135                  /*
 136  136                   * If the module has failed, discard the event without ever
 137  137                   * passing it to the module and go back to sleep.
 138  138                   */
 139  139                  if (mp->mod_error != 0) {
 140  140                          fmd_eventq_done(mp->mod_queue);
 141  141                          fmd_event_rele(ep);
 142  142                          continue;
 143  143                  }
 144  144  
 145  145                  mp->mod_ops->mop_dispatch(mp, ep);
 146  146                  fmd_eventq_done(mp->mod_queue);
 147  147  
 148  148                  /*
 149  149                   * Once mop_dispatch() is complete, grab the lock and perform
 150  150                   * any event-specific post-processing.  Finally, if necessary,
 151  151                   * checkpoint the state of the module after this event.
 152  152                   */
 153  153                  fmd_module_lock(mp);
 154  154  
 155  155                  if (FMD_EVENT_TYPE(ep) == FMD_EVT_CLOSE)
 156  156                          fmd_case_delete(FMD_EVENT_DATA(ep));
 157  157  
 158  158                  fmd_ckpt_save(mp);
 159  159                  fmd_module_unlock(mp);
 160  160                  fmd_event_rele(ep);
 161  161          }
 162  162  
 163  163          if (mp->mod_ops->mop_fini(mp) != 0 && mp->mod_error == 0)
 164  164                  mp->mod_error = errno ? errno : EFMD_MOD_FINI;
 165  165  
 166  166          (void) pthread_mutex_lock(&mp->mod_lock);
 167  167          mp->mod_flags |= FMD_MOD_FINI;
 168  168  
 169  169  out:
 170  170          (void) pthread_cond_broadcast(&mp->mod_cv);
 171  171          (void) pthread_mutex_unlock(&mp->mod_lock);
 172  172  }
 173  173  
 174  174  fmd_module_t *
 175  175  fmd_module_create(const char *path, const fmd_modops_t *ops)
 176  176  {
 177  177          fmd_module_t *mp = fmd_zalloc(sizeof (fmd_module_t), FMD_SLEEP);
 178  178  
 179  179          char buf[PATH_MAX], *p;
 180  180          const char *dir;
 181  181          uint32_t limit;
 182  182          int err;
 183  183  
 184  184          (void) strlcpy(buf, fmd_strbasename(path), sizeof (buf));
 185  185          if ((p = strrchr(buf, '.')) != NULL && strcmp(p, ".so") == 0)
 186  186                  *p = '\0'; /* strip trailing .so from any module name */
 187  187  
 188  188          (void) pthread_mutex_init(&mp->mod_lock, NULL);
 189  189          (void) pthread_cond_init(&mp->mod_cv, NULL);
 190  190          (void) pthread_mutex_init(&mp->mod_stats_lock, NULL);
 191  191  
 192  192          mp->mod_name = fmd_strdup(buf, FMD_SLEEP);
 193  193          mp->mod_path = fmd_strdup(path, FMD_SLEEP);
 194  194          mp->mod_ops = ops;
 195  195          mp->mod_ustat = fmd_ustat_create();
 196  196  
 197  197          (void) fmd_conf_getprop(fmd.d_conf, "ckpt.dir", &dir);
 198  198          (void) snprintf(buf, sizeof (buf),
 199  199              "%s/%s/%s", fmd.d_rootdir, dir, mp->mod_name);
 200  200  
 201  201          mp->mod_ckpt = fmd_strdup(buf, FMD_SLEEP);
 202  202  
 203  203          (void) fmd_conf_getprop(fmd.d_conf, "client.tmrlim", &limit);
 204  204          mp->mod_timerids = fmd_idspace_create(mp->mod_name, 1, limit + 1);
 205  205          mp->mod_threads = fmd_idspace_create(mp->mod_name, 0, INT_MAX);
 206  206  
 207  207          fmd_buf_hash_create(&mp->mod_bufs);
 208  208          fmd_serd_hash_create(&mp->mod_serds);
 209  209  
 210  210          mp->mod_topo_current = fmd_topo_hold();
 211  211  
 212  212          (void) pthread_mutex_lock(&fmd.d_mod_lock);
 213  213          fmd_list_append(&fmd.d_mod_list, mp);
 214  214          (void) pthread_mutex_unlock(&fmd.d_mod_lock);
 215  215  
 216  216          /*
 217  217           * Initialize the module statistics that are kept on its behalf by fmd.
 218  218           * These are set up using a template defined at the top of this file.
 219  219           */
 220  220          if ((mp->mod_stats = (fmd_modstat_t *)fmd_ustat_insert(mp->mod_ustat,
 221  221              FMD_USTAT_ALLOC, sizeof (_fmd_modstat_tmpl) / sizeof (fmd_stat_t),
 222  222              (fmd_stat_t *)&_fmd_modstat_tmpl, NULL)) == NULL) {
 223  223                  fmd_error(EFMD_MOD_INIT, "failed to initialize per-mod stats");
 224  224                  fmd_module_destroy(mp);
 225  225                  return (NULL);
 226  226          }
 227  227  
 228  228          if (nv_alloc_init(&mp->mod_nva_sleep,
 229  229              &fmd_module_nva_ops_sleep, mp) != 0 ||
 230  230              nv_alloc_init(&mp->mod_nva_nosleep,
 231  231              &fmd_module_nva_ops_nosleep, mp) != 0) {
 232  232                  fmd_error(EFMD_MOD_INIT, "failed to initialize nvlist "
 233  233                      "allocation routines");
 234  234                  fmd_module_destroy(mp);
 235  235                  return (NULL);
 236  236          }
 237  237  
 238  238          (void) fmd_conf_getprop(fmd.d_conf, "client.evqlim", &limit);
 239  239  
 240  240          mp->mod_queue = fmd_eventq_create(mp,
 241  241              &mp->mod_stats->ms_evqstat, &mp->mod_stats_lock, limit);
 242  242  
 243  243          (void) fmd_conf_getprop(fmd.d_conf, "client.memlim",
 244  244              &mp->mod_stats->ms_memlimit.fmds_value.ui64);
 245  245  
 246  246          (void) fmd_conf_getprop(fmd.d_conf, "client.buflim",
 247  247              &mp->mod_stats->ms_buflimit.fmds_value.ui64);
 248  248  
 249  249          (void) fmd_conf_getprop(fmd.d_conf, "client.thrlim",
 250  250              &mp->mod_stats->ms_thrlimit.fmds_value.ui32);
 251  251  
  
    | 
      ↓ open down ↓ | 
    251 lines elided | 
    
      ↑ open up ↑ | 
  
 252  252          (void) fmd_conf_getprop(fmd.d_conf, "client.doorthrlim",
 253  253              &mp->mod_stats->ms_doorthrlimit.fmds_value.ui32);
 254  254  
 255  255          (void) fmd_conf_getprop(fmd.d_conf, "client.xprtlim",
 256  256              &mp->mod_stats->ms_xprtlimit.fmds_value.ui32);
 257  257  
 258  258          (void) fmd_conf_getprop(fmd.d_conf, "client.xprtqlim",
 259  259              &mp->mod_stats->ms_xprtqlimit.fmds_value.ui32);
 260  260  
 261  261          (void) fmd_conf_getprop(fmd.d_conf, "ckpt.save",
 262      -            &mp->mod_stats->ms_ckpt_save.fmds_value.bool);
      262 +            &mp->mod_stats->ms_ckpt_save.fmds_value.b);
 263  263  
 264  264          (void) fmd_conf_getprop(fmd.d_conf, "ckpt.restore",
 265      -            &mp->mod_stats->ms_ckpt_restore.fmds_value.bool);
      265 +            &mp->mod_stats->ms_ckpt_restore.fmds_value.b);
 266  266  
 267  267          (void) fmd_conf_getprop(fmd.d_conf, "ckpt.zero",
 268      -            &mp->mod_stats->ms_ckpt_zeroed.fmds_value.bool);
      268 +            &mp->mod_stats->ms_ckpt_zeroed.fmds_value.b);
 269  269  
 270      -        if (mp->mod_stats->ms_ckpt_zeroed.fmds_value.bool)
      270 +        if (mp->mod_stats->ms_ckpt_zeroed.fmds_value.b)
 271  271                  fmd_ckpt_delete(mp); /* blow away any pre-existing checkpoint */
 272  272  
 273  273          /*
 274  274           * Place a hold on the module and grab the module lock before creating
 275  275           * the module's thread to ensure that it cannot destroy the module and
 276  276           * that it cannot call ops->mop_init() before we're done setting up.
 277  277           * NOTE: from now on, we must use fmd_module_rele() for error paths.
 278  278           */
 279  279          fmd_module_hold(mp);
 280  280          (void) pthread_mutex_lock(&mp->mod_lock);
 281  281          mp->mod_stats->ms_loadtime.fmds_value.ui64 = gethrtime();
 282  282          mp->mod_thread = fmd_thread_create(mp, fmd_module_start, mp);
 283  283  
 284  284          if (mp->mod_thread == NULL) {
 285  285                  fmd_error(EFMD_MOD_THR, "failed to create thread for %s", path);
 286  286                  (void) pthread_mutex_unlock(&mp->mod_lock);
 287  287                  fmd_module_rele(mp);
 288  288                  return (NULL);
 289  289          }
 290  290  
 291  291          /*
 292  292           * At this point our module structure is nearly finished and its thread
 293  293           * is starting execution in fmd_module_start() above, which will begin
 294  294           * by blocking for mod_lock.  We now drop mod_lock and wait for either
 295  295           * FMD_MOD_INIT or mod_error to be set before proceeding.
 296  296           */
 297  297          while (!(mp->mod_flags & FMD_MOD_INIT) && mp->mod_error == 0)
 298  298                  (void) pthread_cond_wait(&mp->mod_cv, &mp->mod_lock);
 299  299  
 300  300          /*
 301  301           * If the module has failed to initialize, copy its errno to the errno
 302  302           * of the caller, wait for it to unload, and then destroy it.
 303  303           */
 304  304          if (!(mp->mod_flags & FMD_MOD_INIT)) {
 305  305                  err = mp->mod_error;
 306  306                  (void) pthread_mutex_unlock(&mp->mod_lock);
 307  307  
 308  308                  if (err == EFMD_CKPT_INVAL)
 309  309                          fmd_ckpt_rename(mp); /* move aside bad checkpoint */
 310  310  
 311  311                  /*
 312  312                   * If we're in the background, keep quiet about failure to
 313  313                   * load because a handle wasn't registered: this is a module's
 314  314                   * way of telling us it didn't want to be loaded for some
 315  315                   * reason related to system configuration.  If we're in the
 316  316                   * foreground we log this too in order to inform developers.
 317  317                   */
 318  318                  if (fmd.d_fg || err != EFMD_HDL_INIT) {
 319  319                          fmd_error(EFMD_MOD_INIT, "failed to load %s: %s\n",
 320  320                              path, fmd_strerror(err));
 321  321                  }
 322  322  
 323  323                  fmd_module_unload(mp);
 324  324                  fmd_module_rele(mp);
 325  325  
 326  326                  (void) fmd_set_errno(err);
 327  327                  return (NULL);
 328  328          }
 329  329  
 330  330          (void) pthread_cond_broadcast(&mp->mod_cv);
 331  331          (void) pthread_mutex_unlock(&mp->mod_lock);
 332  332  
 333  333          fmd_dprintf(FMD_DBG_MOD, "loaded module %s\n", mp->mod_name);
 334  334          return (mp);
 335  335  }
 336  336  
 337  337  static void
 338  338  fmd_module_untimeout(fmd_idspace_t *ids, id_t id, fmd_module_t *mp)
 339  339  {
 340  340          void *arg = fmd_timerq_remove(fmd.d_timers, ids, id);
 341  341  
 342  342          /*
 343  343           * The root module calls fmd_timerq_install() directly and must take
 344  344           * responsibility for any cleanup of timer arguments that is required.
 345  345           * All other modules use fmd_modtimer_t's as the arg data; free them.
 346  346           */
 347  347          if (arg != NULL && mp != fmd.d_rmod)
 348  348                  fmd_free(arg, sizeof (fmd_modtimer_t));
 349  349  }
 350  350  
 351  351  void
 352  352  fmd_module_unload(fmd_module_t *mp)
 353  353  {
 354  354          fmd_modtopo_t *mtp;
 355  355  
 356  356          (void) pthread_mutex_lock(&mp->mod_lock);
 357  357  
 358  358          if (mp->mod_flags & FMD_MOD_QUIT) {
 359  359                  (void) pthread_mutex_unlock(&mp->mod_lock);
 360  360                  return; /* module is already unloading */
 361  361          }
 362  362  
 363  363          ASSERT(mp->mod_thread != NULL);
 364  364          mp->mod_flags |= FMD_MOD_QUIT;
 365  365  
 366  366          if (mp->mod_queue != NULL)
 367  367                  fmd_eventq_abort(mp->mod_queue);
 368  368  
 369  369          /*
 370  370           * Wait for the module's thread to stop processing events and call
 371  371           * _fmd_fini() and exit.  We do this by waiting for FMD_MOD_FINI to be
 372  372           * set if INIT was set, and then attempting to join with the thread.
 373  373           */
 374  374          while ((mp->mod_flags & (FMD_MOD_INIT | FMD_MOD_FINI)) == FMD_MOD_INIT)
 375  375                  (void) pthread_cond_wait(&mp->mod_cv, &mp->mod_lock);
 376  376  
 377  377          (void) pthread_cond_broadcast(&mp->mod_cv);
 378  378          (void) pthread_mutex_unlock(&mp->mod_lock);
 379  379  
 380  380          fmd_thread_destroy(mp->mod_thread, FMD_THREAD_JOIN);
 381  381          mp->mod_thread = NULL;
 382  382  
 383  383          /*
 384  384           * Once the module is no longer active, clean up any data structures
 385  385           * that are only required when the module is loaded.
 386  386           */
 387  387          fmd_module_lock(mp);
 388  388  
 389  389          if (mp->mod_timerids != NULL) {
 390  390                  fmd_idspace_apply(mp->mod_timerids,
 391  391                      (void (*)())fmd_module_untimeout, mp);
 392  392  
 393  393                  fmd_idspace_destroy(mp->mod_timerids);
 394  394                  mp->mod_timerids = NULL;
 395  395          }
 396  396  
 397  397          if (mp->mod_threads != NULL) {
 398  398                  fmd_idspace_destroy(mp->mod_threads);
 399  399                  mp->mod_threads = NULL;
 400  400          }
 401  401  
 402  402          (void) fmd_buf_hash_destroy(&mp->mod_bufs);
 403  403          fmd_serd_hash_destroy(&mp->mod_serds);
 404  404  
 405  405          while ((mtp = fmd_list_next(&mp->mod_topolist)) != NULL) {
 406  406                  fmd_list_delete(&mp->mod_topolist, mtp);
 407  407                  fmd_topo_rele(mtp->mt_topo);
 408  408                  fmd_free(mtp, sizeof (fmd_modtopo_t));
 409  409          }
 410  410  
 411  411          fmd_module_unlock(mp);
 412  412          fmd_dprintf(FMD_DBG_MOD, "unloaded module %s\n", mp->mod_name);
 413  413  }
 414  414  
 415  415  void
 416  416  fmd_module_destroy(fmd_module_t *mp)
 417  417  {
 418  418          fmd_conf_formal_t *cfp = mp->mod_argv;
 419  419          int i;
 420  420  
 421  421          ASSERT(MUTEX_HELD(&mp->mod_lock));
 422  422  
 423  423          if (mp->mod_thread != NULL) {
 424  424                  (void) pthread_mutex_unlock(&mp->mod_lock);
 425  425                  fmd_module_unload(mp);
 426  426                  (void) pthread_mutex_lock(&mp->mod_lock);
 427  427          }
 428  428  
 429  429          ASSERT(mp->mod_thread == NULL);
 430  430          ASSERT(mp->mod_refs == 0);
 431  431  
 432  432          /*
 433  433           * Once the module's thread is dead, we can safely remove the module
 434  434           * from global visibility and by removing it from d_mod_list.  Any
 435  435           * modhash pointers are already gone by virtue of mod_refs being zero.
 436  436           */
 437  437          (void) pthread_mutex_lock(&fmd.d_mod_lock);
 438  438          fmd_list_delete(&fmd.d_mod_list, mp);
 439  439          (void) pthread_mutex_unlock(&fmd.d_mod_lock);
 440  440  
 441  441          if (mp->mod_topo_current != NULL)
 442  442                  fmd_topo_rele(mp->mod_topo_current);
 443  443  
 444  444          if (mp->mod_nva_sleep.nva_ops != NULL)
 445  445                  nv_alloc_fini(&mp->mod_nva_sleep);
 446  446          if (mp->mod_nva_nosleep.nva_ops != NULL)
 447  447                  nv_alloc_fini(&mp->mod_nva_nosleep);
 448  448  
 449  449          /*
 450  450           * Once the module is no longer processing events and no longer visible
 451  451           * through any program data structures, we can free all of its content.
 452  452           */
 453  453          if (mp->mod_queue != NULL) {
 454  454                  fmd_eventq_destroy(mp->mod_queue);
 455  455                  mp->mod_queue = NULL;
 456  456          }
 457  457  
 458  458          if (mp->mod_ustat != NULL) {
 459  459                  (void) pthread_mutex_lock(&mp->mod_stats_lock);
 460  460                  fmd_ustat_destroy(mp->mod_ustat);
 461  461                  mp->mod_ustat = NULL;
 462  462                  mp->mod_stats = NULL;
 463  463                  (void) pthread_mutex_unlock(&mp->mod_stats_lock);
 464  464          }
 465  465  
 466  466          for (i = 0; i < mp->mod_dictc; i++)
 467  467                  fm_dc_closedict(mp->mod_dictv[i]);
 468  468  
 469  469          fmd_free(mp->mod_dictv, sizeof (struct fm_dc_handle *) * mp->mod_dictc);
 470  470  
 471  471          if (mp->mod_conf != NULL)
 472  472                  fmd_conf_close(mp->mod_conf);
 473  473  
 474  474          for (i = 0; i < mp->mod_argc; i++, cfp++) {
 475  475                  fmd_strfree((char *)cfp->cf_name);
 476  476                  fmd_strfree((char *)cfp->cf_default);
 477  477          }
 478  478  
 479  479          fmd_free(mp->mod_argv, sizeof (fmd_conf_formal_t) * mp->mod_argc);
 480  480  
 481  481          fmd_strfree(mp->mod_name);
 482  482          fmd_strfree(mp->mod_path);
 483  483          fmd_strfree(mp->mod_ckpt);
 484  484          nvlist_free(mp->mod_fmri);
 485  485          fmd_strfree(mp->mod_vers);
 486  486  
 487  487          fmd_free(mp, sizeof (fmd_module_t));
 488  488  }
 489  489  
 490  490  /*
 491  491   * fmd_module_error() is called after the stack is unwound from a call to
 492  492   * fmd_module_abort() to indicate that the module has failed.  The mod_error
 493  493   * field is used to hold the error code of the first fatal error to the module.
 494  494   * An EFMD_MOD_FAIL event is then created and sent to fmd-self-diagnosis.
 495  495   */
 496  496  static void
 497  497  fmd_module_error(fmd_module_t *mp, int err)
 498  498  {
 499  499          fmd_event_t *e;
 500  500          nvlist_t *nvl;
 501  501          char *class;
 502  502  
 503  503          ASSERT(MUTEX_HELD(&mp->mod_lock));
 504  504          ASSERT(err != 0);
 505  505  
 506  506          TRACE((FMD_DBG_MOD, "module aborted: err=%d", err));
 507  507  
 508  508          if (mp->mod_error == 0)
 509  509                  mp->mod_error = err;
 510  510  
 511  511          if (mp == fmd.d_self)
 512  512                  return; /* do not post event if fmd.d_self itself fails */
 513  513  
 514  514          /*
 515  515           * Send an error indicating the module has now failed to fmd.d_self.
 516  516           * Since the error causing the failure has already been logged by
 517  517           * fmd_api_xerror(), we do not need to bother logging this event.
 518  518           * It only exists for the purpose of notifying fmd.d_self that it can
 519  519           * close the case associated with this module because mod_error is set.
 520  520           */
 521  521          nvl = fmd_protocol_moderror(mp, EFMD_MOD_FAIL, fmd_strerror(err));
 522  522          (void) nvlist_lookup_string(nvl, FM_CLASS, &class);
 523  523          e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class);
 524  524          fmd_dispq_dispatch(fmd.d_disp, e, class);
 525  525  }
 526  526  
 527  527  void
 528  528  fmd_module_dispatch(fmd_module_t *mp, fmd_event_t *e)
 529  529  {
 530  530          const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
 531  531          fmd_event_impl_t *ep = (fmd_event_impl_t *)e;
 532  532          fmd_hdl_t *hdl = (fmd_hdl_t *)mp;
 533  533          fmd_modtimer_t *t;
 534  534          fmd_topo_t *old_topo;
 535  535          volatile int err;
 536  536  
 537  537          /*
 538  538           * Before calling the appropriate module callback, enter the module as
 539  539           * if by fmd_module_enter() and establish mod_jmpbuf for any aborts.
 540  540           */
 541  541          (void) pthread_mutex_lock(&mp->mod_lock);
 542  542  
 543  543          ASSERT(!(mp->mod_flags & FMD_MOD_BUSY));
 544  544          mp->mod_flags |= FMD_MOD_BUSY;
 545  545  
 546  546          if ((err = setjmp(mp->mod_jmpbuf)) != 0) {
 547  547                  (void) pthread_mutex_lock(&mp->mod_lock);
 548  548                  fmd_module_error(mp, err);
 549  549          }
 550  550  
 551  551          (void) pthread_cond_broadcast(&mp->mod_cv);
 552  552          (void) pthread_mutex_unlock(&mp->mod_lock);
 553  553  
 554  554          /*
 555  555           * If it's the first time through fmd_module_dispatch(), call the
 556  556           * appropriate module callback based on the event type.  If the call
 557  557           * triggers an fmd_module_abort(), we'll return to setjmp() above with
 558  558           * err set to a non-zero value and then bypass this before exiting.
 559  559           */
 560  560          if (err == 0) {
 561  561                  switch (ep->ev_type) {
 562  562                  case FMD_EVT_PROTOCOL:
 563  563                          ops->fmdo_recv(hdl, e, ep->ev_nvl, ep->ev_data);
 564  564                          break;
 565  565                  case FMD_EVT_TIMEOUT:
 566  566                          t = ep->ev_data;
 567  567                          ASSERT(t->mt_mod == mp);
 568  568                          ops->fmdo_timeout(hdl, t->mt_id, t->mt_arg);
 569  569                          break;
 570  570                  case FMD_EVT_CLOSE:
 571  571                          ops->fmdo_close(hdl, ep->ev_data);
 572  572                          break;
 573  573                  case FMD_EVT_STATS:
 574  574                          ops->fmdo_stats(hdl);
 575  575                          fmd_modstat_publish(mp);
 576  576                          break;
 577  577                  case FMD_EVT_GC:
 578  578                          ops->fmdo_gc(hdl);
 579  579                          break;
 580  580                  case FMD_EVT_PUBLISH:
 581  581                          fmd_case_publish(ep->ev_data, FMD_CASE_CURRENT);
 582  582                          break;
 583  583                  case FMD_EVT_TOPO:
 584  584                          /*
 585  585                           * Save the pointer to the old topology and update
 586  586                           * the pointer with the updated topology.
 587  587                           * With this approach, other threads that reference the
 588  588                           * topology either
 589  589                           *  - finishes with old topology since
 590  590                           *      it is released after updating
 591  591                           *      mod_topo_current.
 592  592                           *  - or is blocked while mod_topo_current is updated.
 593  593                           */
 594  594                          old_topo = mp->mod_topo_current;
 595  595                          fmd_module_lock(mp);
 596  596                          mp->mod_topo_current = (fmd_topo_t *)ep->ev_data;
 597  597                          fmd_topo_addref(mp->mod_topo_current);
 598  598                          fmd_module_unlock(mp);
 599  599                          fmd_topo_rele(old_topo);
 600  600                          ops->fmdo_topo(hdl, mp->mod_topo_current->ft_hdl);
 601  601                          break;
 602  602                  }
 603  603          }
 604  604  
 605  605          fmd_module_exit(mp);
 606  606  }
 607  607  
 608  608  int
 609  609  fmd_module_transport(fmd_module_t *mp, fmd_xprt_t *xp, fmd_event_t *e)
 610  610  {
 611  611          fmd_event_impl_t *ep = (fmd_event_impl_t *)e;
 612  612          fmd_hdl_t *hdl = (fmd_hdl_t *)mp;
 613  613  
 614  614          ASSERT(ep->ev_type == FMD_EVT_PROTOCOL);
 615  615          return (mp->mod_info->fmdi_ops->fmdo_send(hdl, xp, e, ep->ev_nvl));
 616  616  }
 617  617  
 618  618  void
 619  619  fmd_module_timeout(fmd_modtimer_t *t, id_t id, hrtime_t hrt)
 620  620  {
 621  621          fmd_event_t *e;
 622  622  
 623  623          t->mt_id = id; /* save id in case we need to delete from eventq */
 624  624          e = fmd_event_create(FMD_EVT_TIMEOUT, hrt, NULL, t);
 625  625          fmd_eventq_insert_at_time(t->mt_mod->mod_queue, e);
 626  626  }
 627  627  
 628  628  /*
 629  629   * Garbage collection is initiated by a timer callback once per day or at the
 630  630   * request of fmadm.  Purge old SERD entries and send the module a GC event.
 631  631   */
 632  632  void
 633  633  fmd_module_gc(fmd_module_t *mp)
 634  634  {
 635  635          fmd_hdl_info_t *info;
 636  636          fmd_event_t *e;
 637  637  
 638  638          if (mp->mod_error != 0)
 639  639                  return; /* do not do anything if the module has failed */
 640  640  
 641  641          fmd_module_lock(mp);
 642  642  
 643  643          if ((info = mp->mod_info) != NULL) {
 644  644                  fmd_serd_hash_apply(&mp->mod_serds,
 645  645                      (fmd_serd_eng_f *)fmd_serd_eng_gc, NULL);
 646  646          }
 647  647  
 648  648          fmd_module_unlock(mp);
 649  649  
 650  650          if (info != NULL) {
 651  651                  e = fmd_event_create(FMD_EVT_GC, FMD_HRT_NOW, NULL, NULL);
 652  652                  fmd_eventq_insert_at_head(mp->mod_queue, e);
 653  653          }
 654  654  }
 655  655  
 656  656  void
 657  657  fmd_module_trygc(fmd_module_t *mp)
 658  658  {
 659  659          if (fmd_module_trylock(mp)) {
 660  660                  fmd_serd_hash_apply(&mp->mod_serds,
 661  661                      (fmd_serd_eng_f *)fmd_serd_eng_gc, NULL);
 662  662                  fmd_module_unlock(mp);
 663  663          }
 664  664  }
 665  665  
 666  666  int
 667  667  fmd_module_contains(fmd_module_t *mp, fmd_event_t *ep)
 668  668  {
 669  669          fmd_case_t *cp;
 670  670          int rv = 0;
 671  671  
 672  672          fmd_module_lock(mp);
 673  673  
 674  674          for (cp = fmd_list_next(&mp->mod_cases);
 675  675              cp != NULL; cp = fmd_list_next(cp)) {
 676  676                  if ((rv = fmd_case_contains(cp, ep)) != 0)
 677  677                          break;
 678  678          }
 679  679  
 680  680          if (rv == 0)
 681  681                  rv = fmd_serd_hash_contains(&mp->mod_serds, ep);
 682  682  
 683  683          fmd_module_unlock(mp);
 684  684          return (rv);
 685  685  }
 686  686  
 687  687  void
 688  688  fmd_module_setdirty(fmd_module_t *mp)
 689  689  {
 690  690          (void) pthread_mutex_lock(&mp->mod_lock);
 691  691          mp->mod_flags |= FMD_MOD_MDIRTY;
 692  692          (void) pthread_mutex_unlock(&mp->mod_lock);
 693  693  }
 694  694  
 695  695  void
 696  696  fmd_module_setcdirty(fmd_module_t *mp)
 697  697  {
 698  698          (void) pthread_mutex_lock(&mp->mod_lock);
 699  699          mp->mod_flags |= FMD_MOD_CDIRTY;
 700  700          (void) pthread_mutex_unlock(&mp->mod_lock);
 701  701  }
 702  702  
 703  703  void
 704  704  fmd_module_clrdirty(fmd_module_t *mp)
 705  705  {
 706  706          fmd_case_t *cp;
 707  707  
 708  708          fmd_module_lock(mp);
 709  709  
 710  710          if (mp->mod_flags & FMD_MOD_CDIRTY) {
 711  711                  for (cp = fmd_list_next(&mp->mod_cases);
 712  712                      cp != NULL; cp = fmd_list_next(cp))
 713  713                          fmd_case_clrdirty(cp);
 714  714          }
 715  715  
 716  716          if (mp->mod_flags & FMD_MOD_MDIRTY) {
 717  717                  fmd_serd_hash_apply(&mp->mod_serds,
 718  718                      (fmd_serd_eng_f *)fmd_serd_eng_clrdirty, NULL);
 719  719                  fmd_buf_hash_commit(&mp->mod_bufs);
 720  720          }
 721  721  
 722  722          (void) pthread_mutex_lock(&mp->mod_lock);
 723  723          mp->mod_flags &= ~(FMD_MOD_MDIRTY | FMD_MOD_CDIRTY);
 724  724          (void) pthread_mutex_unlock(&mp->mod_lock);
 725  725  
 726  726          fmd_module_unlock(mp);
 727  727  }
 728  728  
 729  729  void
 730  730  fmd_module_commit(fmd_module_t *mp)
 731  731  {
 732  732          fmd_case_t *cp;
 733  733  
 734  734          ASSERT(fmd_module_locked(mp));
 735  735  
 736  736          if (mp->mod_flags & FMD_MOD_CDIRTY) {
 737  737                  for (cp = fmd_list_next(&mp->mod_cases);
 738  738                      cp != NULL; cp = fmd_list_next(cp))
 739  739                          fmd_case_commit(cp);
 740  740          }
 741  741  
 742  742          if (mp->mod_flags & FMD_MOD_MDIRTY) {
 743  743                  fmd_serd_hash_apply(&mp->mod_serds,
 744  744                      (fmd_serd_eng_f *)fmd_serd_eng_commit, NULL);
 745  745                  fmd_buf_hash_commit(&mp->mod_bufs);
 746  746          }
 747  747  
 748  748          (void) pthread_mutex_lock(&mp->mod_lock);
 749  749          mp->mod_flags &= ~(FMD_MOD_MDIRTY | FMD_MOD_CDIRTY);
 750  750          (void) pthread_mutex_unlock(&mp->mod_lock);
 751  751  
 752  752          mp->mod_gen++;
 753  753  }
 754  754  
 755  755  void
 756  756  fmd_module_lock(fmd_module_t *mp)
 757  757  {
 758  758          pthread_t self = pthread_self();
 759  759  
 760  760          (void) pthread_mutex_lock(&mp->mod_lock);
 761  761  
 762  762          while (mp->mod_flags & FMD_MOD_LOCK) {
 763  763                  if (mp->mod_owner != self)
 764  764                          (void) pthread_cond_wait(&mp->mod_cv, &mp->mod_lock);
 765  765                  else
 766  766                          fmd_panic("recursive module lock of %p\n", (void *)mp);
 767  767          }
 768  768  
 769  769          mp->mod_owner = self;
 770  770          mp->mod_flags |= FMD_MOD_LOCK;
 771  771  
 772  772          (void) pthread_cond_broadcast(&mp->mod_cv);
 773  773          (void) pthread_mutex_unlock(&mp->mod_lock);
 774  774  }
 775  775  
 776  776  void
 777  777  fmd_module_unlock(fmd_module_t *mp)
 778  778  {
 779  779          (void) pthread_mutex_lock(&mp->mod_lock);
 780  780  
 781  781          ASSERT(mp->mod_owner == pthread_self());
 782  782          ASSERT(mp->mod_flags & FMD_MOD_LOCK);
 783  783  
 784  784          mp->mod_owner = 0;
 785  785          mp->mod_flags &= ~FMD_MOD_LOCK;
 786  786  
 787  787          (void) pthread_cond_broadcast(&mp->mod_cv);
 788  788          (void) pthread_mutex_unlock(&mp->mod_lock);
 789  789  }
 790  790  
 791  791  int
 792  792  fmd_module_trylock(fmd_module_t *mp)
 793  793  {
 794  794          (void) pthread_mutex_lock(&mp->mod_lock);
 795  795  
 796  796          if (mp->mod_flags & FMD_MOD_LOCK) {
 797  797                  (void) pthread_mutex_unlock(&mp->mod_lock);
 798  798                  return (0);
 799  799          }
 800  800  
 801  801          mp->mod_owner = pthread_self();
 802  802          mp->mod_flags |= FMD_MOD_LOCK;
 803  803  
 804  804          (void) pthread_cond_broadcast(&mp->mod_cv);
 805  805          (void) pthread_mutex_unlock(&mp->mod_lock);
 806  806  
 807  807          return (1);
 808  808  }
 809  809  
 810  810  int
 811  811  fmd_module_locked(fmd_module_t *mp)
 812  812  {
 813  813          return ((mp->mod_flags & FMD_MOD_LOCK) &&
 814  814              mp->mod_owner == pthread_self());
 815  815  }
 816  816  
 817  817  int
 818  818  fmd_module_enter(fmd_module_t *mp, void (*func)(fmd_hdl_t *))
 819  819  {
 820  820          volatile int err;
 821  821  
 822  822          (void) pthread_mutex_lock(&mp->mod_lock);
 823  823  
 824  824          ASSERT(!(mp->mod_flags & FMD_MOD_BUSY));
 825  825          mp->mod_flags |= FMD_MOD_BUSY;
 826  826  
 827  827          if ((err = setjmp(mp->mod_jmpbuf)) != 0) {
 828  828                  (void) pthread_mutex_lock(&mp->mod_lock);
 829  829                  fmd_module_error(mp, err);
 830  830          }
 831  831  
 832  832          (void) pthread_cond_broadcast(&mp->mod_cv);
 833  833          (void) pthread_mutex_unlock(&mp->mod_lock);
 834  834  
 835  835          /*
 836  836           * If it's the first time through fmd_module_enter(), call the provided
 837  837           * function on the module.  If no fmd_module_abort() results, we will
 838  838           * fall through and return zero.  Otherwise we'll longjmp with an err,
 839  839           * return to the setjmp() above, and return the error to our caller.
 840  840           */
 841  841          if (err == 0 && func != NULL)
 842  842                  (*func)((fmd_hdl_t *)mp);
 843  843  
 844  844          return (err);
 845  845  }
 846  846  
 847  847  void
 848  848  fmd_module_exit(fmd_module_t *mp)
 849  849  {
 850  850          (void) pthread_mutex_lock(&mp->mod_lock);
 851  851  
 852  852          ASSERT(mp->mod_flags & FMD_MOD_BUSY);
 853  853          mp->mod_flags &= ~FMD_MOD_BUSY;
 854  854  
 855  855          (void) pthread_cond_broadcast(&mp->mod_cv);
 856  856          (void) pthread_mutex_unlock(&mp->mod_lock);
 857  857  }
 858  858  
 859  859  /*
 860  860   * If the client.error policy has been set by a developer, stop or dump core
 861  861   * based on the policy; if we stop and are resumed we'll continue and execute
 862  862   * the default behavior to discard events in fmd_module_start().  If the caller
 863  863   * is the primary module thread, we reach this state by longjmp'ing back to
 864  864   * fmd_module_enter(), above.  If the caller is an auxiliary thread, we cancel
 865  865   * ourself and arrange for the primary thread to call fmd_module_abort().
 866  866   */
 867  867  void
 868  868  fmd_module_abort(fmd_module_t *mp, int err)
 869  869  {
 870  870          uint_t policy = FMD_CERROR_UNLOAD;
 871  871          pthread_t tid = pthread_self();
 872  872  
 873  873          (void) fmd_conf_getprop(fmd.d_conf, "client.error", &policy);
 874  874  
 875  875          if (policy == FMD_CERROR_STOP) {
 876  876                  fmd_error(err, "stopping after %s in client %s (%p)\n",
 877  877                      fmd_errclass(err), mp->mod_name, (void *)mp);
 878  878                  (void) raise(SIGSTOP);
 879  879          } else if (policy == FMD_CERROR_ABORT) {
 880  880                  fmd_panic("aborting due to %s in client %s (%p)\n",
 881  881                      fmd_errclass(err), mp->mod_name, (void *)mp);
 882  882          }
 883  883  
 884  884          /*
 885  885           * If the caller is an auxiliary thread, cancel the current thread.  We
 886  886           * prefer to cancel because it affords developers the option of using
 887  887           * the pthread_cleanup* APIs.  If cancellations have been disabled,
 888  888           * fall through to forcing the current thread to exit.  In either case
 889  889           * we update mod_error (if zero) to enter the failed state.  Once that
 890  890           * is set, further events received by the module will be discarded.
 891  891           *
 892  892           * We also set the FMD_MOD_FAIL bit, indicating an unrecoverable error.
 893  893           * When an auxiliary thread fails, the module is left in a delicate
 894  894           * state where it is likely not able to continue execution (even to
 895  895           * execute its _fmd_fini() routine) because our caller may hold locks
 896  896           * that are private to the module and can no longer be released.  The
 897  897           * FMD_MOD_FAIL bit forces fmd_api_module_lock() to abort if any other
 898  898           * module threads reach an API call, in an attempt to get them to exit.
 899  899           */
 900  900          if (tid != mp->mod_thread->thr_tid) {
 901  901                  (void) pthread_mutex_lock(&mp->mod_lock);
 902  902  
 903  903                  if (mp->mod_error == 0)
 904  904                          mp->mod_error = err;
 905  905  
 906  906                  mp->mod_flags |= FMD_MOD_FAIL;
 907  907                  (void) pthread_mutex_unlock(&mp->mod_lock);
 908  908  
 909  909                  (void) pthread_cancel(tid);
 910  910                  pthread_exit(NULL);
 911  911          }
 912  912  
 913  913          ASSERT(mp->mod_flags & FMD_MOD_BUSY);
 914  914          longjmp(mp->mod_jmpbuf, err);
 915  915  }
 916  916  
 917  917  void
 918  918  fmd_module_hold(fmd_module_t *mp)
 919  919  {
 920  920          (void) pthread_mutex_lock(&mp->mod_lock);
 921  921  
 922  922          TRACE((FMD_DBG_MOD, "hold %p (%s/%u)\n",
 923  923              (void *)mp, mp->mod_name, mp->mod_refs));
 924  924  
 925  925          mp->mod_refs++;
 926  926          ASSERT(mp->mod_refs != 0);
 927  927  
 928  928          (void) pthread_mutex_unlock(&mp->mod_lock);
 929  929  }
 930  930  
 931  931  void
 932  932  fmd_module_rele(fmd_module_t *mp)
 933  933  {
 934  934          (void) pthread_mutex_lock(&mp->mod_lock);
 935  935  
 936  936          TRACE((FMD_DBG_MOD, "rele %p (%s/%u)\n",
 937  937              (void *)mp, mp->mod_name, mp->mod_refs));
 938  938  
 939  939          ASSERT(mp->mod_refs != 0);
 940  940  
 941  941          if (--mp->mod_refs == 0)
 942  942                  fmd_module_destroy(mp);
 943  943          else
 944  944                  (void) pthread_mutex_unlock(&mp->mod_lock);
 945  945  }
 946  946  
 947  947  /*
 948  948   * Wrapper around libdiagcode's fm_dc_opendict() to load module dictionaries.
 949  949   * If the dictionary open is successful, the new dictionary is added to the
 950  950   * mod_dictv[] array and mod_codelen is updated with the new maximum length.
 951  951   */
 952  952  int
 953  953  fmd_module_dc_opendict(fmd_module_t *mp, const char *dict)
 954  954  {
 955  955          struct fm_dc_handle *dcp, **dcv;
 956  956          char *dictdir, *dictnam, *p;
 957  957          size_t len;
 958  958  
 959  959          ASSERT(fmd_module_locked(mp));
 960  960  
 961  961          dictnam = strdupa(fmd_strbasename(dict));
 962  962  
 963  963          if ((p = strrchr(dictnam, '.')) != NULL &&
 964  964              strcmp(p, ".dict") == 0)
 965  965                  *p = '\0'; /* eliminate any trailing .dict suffix */
 966  966  
 967  967          /*
 968  968           * If 'dict' is an absolute path, dictdir = $rootdir/`dirname dict`
 969  969           * If 'dict' is not an absolute path, dictdir = $dictdir/`dirname dict`
 970  970           */
 971  971          if (dict[0] == '/') {
 972  972                  len = strlen(fmd.d_rootdir) + strlen(dict) + 1;
 973  973                  dictdir = alloca(len);
 974  974                  (void) snprintf(dictdir, len, "%s%s", fmd.d_rootdir, dict);
 975  975                  (void) fmd_strdirname(dictdir);
 976  976          } else {
 977  977                  (void) fmd_conf_getprop(fmd.d_conf, "dictdir", &p);
 978  978                  len = strlen(fmd.d_rootdir) + strlen(p) + strlen(dict) + 3;
 979  979                  dictdir = alloca(len);
 980  980                  (void) snprintf(dictdir, len,
 981  981                      "%s/%s/%s", fmd.d_rootdir, p, dict);
 982  982                  (void) fmd_strdirname(dictdir);
 983  983          }
 984  984  
 985  985          fmd_dprintf(FMD_DBG_MOD, "module %s opening %s -> %s/%s.dict\n",
 986  986              mp->mod_name, dict, dictdir, dictnam);
 987  987  
 988  988          if ((dcp = fm_dc_opendict(FM_DC_VERSION, dictdir, dictnam)) == NULL)
 989  989                  return (-1); /* errno is set for us */
 990  990  
 991  991          dcv = fmd_alloc(sizeof (dcp) * (mp->mod_dictc + 1), FMD_SLEEP);
 992  992          bcopy(mp->mod_dictv, dcv, sizeof (dcp) * mp->mod_dictc);
 993  993          fmd_free(mp->mod_dictv, sizeof (dcp) * mp->mod_dictc);
 994  994          mp->mod_dictv = dcv;
 995  995          mp->mod_dictv[mp->mod_dictc++] = dcp;
 996  996  
 997  997          len = fm_dc_codelen(dcp);
 998  998          mp->mod_codelen = MAX(mp->mod_codelen, len);
 999  999  
1000 1000          return (0);
1001 1001  }
1002 1002  
1003 1003  /*
1004 1004   * Wrapper around libdiagcode's fm_dc_key2code() that examines all the module's
1005 1005   * dictionaries.  We adhere to the libdiagcode return values and semantics.
1006 1006   */
1007 1007  int
1008 1008  fmd_module_dc_key2code(fmd_module_t *mp,
1009 1009      char *const keys[], char *code, size_t codelen)
1010 1010  {
1011 1011          int i, err;
1012 1012  
1013 1013          for (i = 0; i < mp->mod_dictc; i++) {
1014 1014                  if ((err = fm_dc_key2code(mp->mod_dictv[i], (const char **)keys,
1015 1015                      code, codelen)) == 0 || errno != ENOMSG)
1016 1016                          return (err);
1017 1017          }
1018 1018  
1019 1019          return (fmd_set_errno(ENOMSG));
1020 1020  }
1021 1021  
1022 1022  fmd_modhash_t *
1023 1023  fmd_modhash_create(void)
1024 1024  {
1025 1025          fmd_modhash_t *mhp = fmd_alloc(sizeof (fmd_modhash_t), FMD_SLEEP);
1026 1026  
1027 1027          (void) pthread_rwlock_init(&mhp->mh_lock, NULL);
1028 1028          mhp->mh_hashlen = fmd.d_str_buckets;
1029 1029          mhp->mh_hash = fmd_zalloc(sizeof (void *) * mhp->mh_hashlen, FMD_SLEEP);
1030 1030          mhp->mh_nelems = 0;
1031 1031  
1032 1032          return (mhp);
1033 1033  }
1034 1034  
1035 1035  void
1036 1036  fmd_modhash_destroy(fmd_modhash_t *mhp)
1037 1037  {
1038 1038          fmd_module_t *mp, *nmp;
1039 1039          uint_t i;
1040 1040  
1041 1041          for (i = 0; i < mhp->mh_hashlen; i++) {
1042 1042                  for (mp = mhp->mh_hash[i]; mp != NULL; mp = nmp) {
1043 1043                          nmp = mp->mod_next;
1044 1044                          mp->mod_next = NULL;
1045 1045                          fmd_module_rele(mp);
1046 1046                  }
1047 1047          }
1048 1048  
1049 1049          fmd_free(mhp->mh_hash, sizeof (void *) * mhp->mh_hashlen);
1050 1050          (void) pthread_rwlock_destroy(&mhp->mh_lock);
1051 1051          fmd_free(mhp, sizeof (fmd_modhash_t));
1052 1052  }
1053 1053  
1054 1054  static void
1055 1055  fmd_modhash_loaddir(fmd_modhash_t *mhp, const char *dir,
1056 1056      const fmd_modops_t *ops, const char *suffix)
1057 1057  {
1058 1058          char path[PATH_MAX];
1059 1059          struct dirent *dp;
1060 1060          const char *p;
1061 1061          DIR *dirp;
1062 1062  
1063 1063          if ((dirp = opendir(dir)) == NULL)
1064 1064                  return; /* failed to open directory; just skip it */
1065 1065  
1066 1066          while ((dp = readdir(dirp)) != NULL) {
1067 1067                  if (dp->d_name[0] == '.')
1068 1068                          continue; /* skip "." and ".." */
1069 1069  
1070 1070                  p = strrchr(dp->d_name, '.');
1071 1071  
1072 1072                  if (p != NULL && strcmp(p, ".conf") == 0)
1073 1073                          continue; /* skip .conf files */
1074 1074  
1075 1075                  if (suffix != NULL && (p == NULL || strcmp(p, suffix) != 0))
1076 1076                          continue; /* skip files with the wrong suffix */
1077 1077  
1078 1078                  (void) snprintf(path, sizeof (path), "%s/%s", dir, dp->d_name);
1079 1079                  (void) fmd_modhash_load(mhp, path, ops);
1080 1080          }
1081 1081  
1082 1082          (void) closedir(dirp);
1083 1083  }
1084 1084  
1085 1085  void
1086 1086  fmd_modhash_loadall(fmd_modhash_t *mhp, const fmd_conf_path_t *pap,
1087 1087      const fmd_modops_t *ops, const char *suffix)
1088 1088  {
1089 1089          int i;
1090 1090  
1091 1091          for (i = 0; i < pap->cpa_argc; i++)
1092 1092                  fmd_modhash_loaddir(mhp, pap->cpa_argv[i], ops, suffix);
1093 1093  }
1094 1094  
1095 1095  void
1096 1096  fmd_modhash_apply(fmd_modhash_t *mhp, void (*func)(fmd_module_t *))
1097 1097  {
1098 1098          fmd_module_t *mp, *np;
1099 1099          uint_t i;
1100 1100  
1101 1101          (void) pthread_rwlock_rdlock(&mhp->mh_lock);
1102 1102  
1103 1103          for (i = 0; i < mhp->mh_hashlen; i++) {
1104 1104                  for (mp = mhp->mh_hash[i]; mp != NULL; mp = np) {
1105 1105                          np = mp->mod_next;
1106 1106                          func(mp);
1107 1107                  }
1108 1108          }
1109 1109  
1110 1110          (void) pthread_rwlock_unlock(&mhp->mh_lock);
1111 1111  }
1112 1112  
1113 1113  void
1114 1114  fmd_modhash_tryapply(fmd_modhash_t *mhp, void (*func)(fmd_module_t *))
1115 1115  {
1116 1116          fmd_module_t *mp, *np;
1117 1117          uint_t i;
1118 1118  
1119 1119          if (mhp == NULL || pthread_rwlock_tryrdlock(&mhp->mh_lock) != 0)
1120 1120                  return; /* not initialized or couldn't grab lock */
1121 1121  
1122 1122          for (i = 0; i < mhp->mh_hashlen; i++) {
1123 1123                  for (mp = mhp->mh_hash[i]; mp != NULL; mp = np) {
1124 1124                          np = mp->mod_next;
1125 1125                          func(mp);
1126 1126                  }
1127 1127          }
1128 1128  
1129 1129          (void) pthread_rwlock_unlock(&mhp->mh_lock);
1130 1130  }
1131 1131  
1132 1132  void
1133 1133  fmd_modhash_dispatch(fmd_modhash_t *mhp, fmd_event_t *ep)
1134 1134  {
1135 1135          fmd_module_t *mp;
1136 1136          uint_t i;
1137 1137  
1138 1138          fmd_event_hold(ep);
1139 1139          (void) pthread_rwlock_rdlock(&mhp->mh_lock);
1140 1140  
1141 1141          for (i = 0; i < mhp->mh_hashlen; i++) {
1142 1142                  for (mp = mhp->mh_hash[i]; mp != NULL; mp = mp->mod_next) {
1143 1143                          /*
1144 1144                           * If FMD_MOD_INIT is set but MOD_FINI, MOD_QUIT, and
1145 1145                           * mod_error are all zero, then the module is active:
1146 1146                           * enqueue the event in the corresponding event queue.
1147 1147                           */
1148 1148                          (void) pthread_mutex_lock(&mp->mod_lock);
1149 1149  
1150 1150                          if ((mp->mod_flags & (FMD_MOD_INIT | FMD_MOD_FINI |
1151 1151                              FMD_MOD_QUIT)) == FMD_MOD_INIT && !mp->mod_error) {
1152 1152  
1153 1153                                  /*
1154 1154                                   * If the event we're dispatching is of type
1155 1155                                   * FMD_EVT_TOPO and there are already redundant
1156 1156                                   * FMD_EVT_TOPO events in this module's queue,
1157 1157                                   * then drop those before adding the new one.
1158 1158                                   */
1159 1159                                  if (FMD_EVENT_TYPE(ep) == FMD_EVT_TOPO)
1160 1160                                          fmd_eventq_drop_topo(mp->mod_queue);
1161 1161  
1162 1162                                  fmd_eventq_insert_at_time(mp->mod_queue, ep);
1163 1163  
1164 1164                          }
1165 1165                          (void) pthread_mutex_unlock(&mp->mod_lock);
1166 1166                  }
1167 1167          }
1168 1168  
1169 1169          (void) pthread_rwlock_unlock(&mhp->mh_lock);
1170 1170          fmd_event_rele(ep);
1171 1171  }
1172 1172  
1173 1173  fmd_module_t *
1174 1174  fmd_modhash_lookup(fmd_modhash_t *mhp, const char *name)
1175 1175  {
1176 1176          fmd_module_t *mp;
1177 1177          uint_t h;
1178 1178  
1179 1179          (void) pthread_rwlock_rdlock(&mhp->mh_lock);
1180 1180          h = fmd_strhash(name) % mhp->mh_hashlen;
1181 1181  
1182 1182          for (mp = mhp->mh_hash[h]; mp != NULL; mp = mp->mod_next) {
1183 1183                  if (strcmp(name, mp->mod_name) == 0)
1184 1184                          break;
1185 1185          }
1186 1186  
1187 1187          if (mp != NULL)
1188 1188                  fmd_module_hold(mp);
1189 1189          else
1190 1190                  (void) fmd_set_errno(EFMD_MOD_NOMOD);
1191 1191  
1192 1192          (void) pthread_rwlock_unlock(&mhp->mh_lock);
1193 1193          return (mp);
1194 1194  }
1195 1195  
1196 1196  fmd_module_t *
1197 1197  fmd_modhash_load(fmd_modhash_t *mhp, const char *path, const fmd_modops_t *ops)
1198 1198  {
1199 1199          char name[PATH_MAX], *p;
1200 1200          fmd_module_t *mp;
1201 1201          int tries = 0;
1202 1202          uint_t h;
1203 1203  
1204 1204          (void) strlcpy(name, fmd_strbasename(path), sizeof (name));
1205 1205          if ((p = strrchr(name, '.')) != NULL && strcmp(p, ".so") == 0)
1206 1206                  *p = '\0'; /* strip trailing .so from any module name */
1207 1207  
1208 1208          (void) pthread_rwlock_wrlock(&mhp->mh_lock);
1209 1209          h = fmd_strhash(name) % mhp->mh_hashlen;
1210 1210  
1211 1211          /*
1212 1212           * First check to see if a module is already present in the hash table
1213 1213           * for this name.  If so, the module is already loaded: skip it.
1214 1214           */
1215 1215          for (mp = mhp->mh_hash[h]; mp != NULL; mp = mp->mod_next) {
1216 1216                  if (strcmp(name, mp->mod_name) == 0)
1217 1217                          break;
1218 1218          }
1219 1219  
1220 1220          if (mp != NULL) {
1221 1221                  (void) pthread_rwlock_unlock(&mhp->mh_lock);
1222 1222                  (void) fmd_set_errno(EFMD_MOD_LOADED);
1223 1223                  return (NULL);
1224 1224          }
1225 1225  
1226 1226          /*
1227 1227           * fmd_module_create() will return a held (as if by fmd_module_hold())
1228 1228           * module.  We leave this hold in place to correspond to the hash-in.
1229 1229           */
1230 1230          while ((mp = fmd_module_create(path, ops)) == NULL) {
1231 1231                  if (tries++ != 0 || errno != EFMD_CKPT_INVAL) {
1232 1232                          (void) pthread_rwlock_unlock(&mhp->mh_lock);
1233 1233                          return (NULL); /* errno is set for us */
1234 1234                  }
1235 1235          }
1236 1236  
1237 1237          mp->mod_hash = mhp;
1238 1238          mp->mod_next = mhp->mh_hash[h];
1239 1239  
1240 1240          mhp->mh_hash[h] = mp;
1241 1241          mhp->mh_nelems++;
1242 1242  
1243 1243          (void) pthread_rwlock_unlock(&mhp->mh_lock);
1244 1244          return (mp);
1245 1245  }
1246 1246  
1247 1247  int
1248 1248  fmd_modhash_unload(fmd_modhash_t *mhp, const char *name)
1249 1249  {
1250 1250          fmd_module_t *mp, **pp;
1251 1251          uint_t h;
1252 1252  
1253 1253          (void) pthread_rwlock_wrlock(&mhp->mh_lock);
1254 1254          h = fmd_strhash(name) % mhp->mh_hashlen;
1255 1255          pp = &mhp->mh_hash[h];
1256 1256  
1257 1257          for (mp = *pp; mp != NULL; mp = mp->mod_next) {
1258 1258                  if (strcmp(name, mp->mod_name) == 0)
1259 1259                          break;
1260 1260                  else
1261 1261                          pp = &mp->mod_next;
1262 1262          }
1263 1263  
1264 1264          if (mp == NULL) {
1265 1265                  (void) pthread_rwlock_unlock(&mhp->mh_lock);
1266 1266                  return (fmd_set_errno(EFMD_MOD_NOMOD));
1267 1267          }
1268 1268  
1269 1269          *pp = mp->mod_next;
1270 1270          mp->mod_next = NULL;
1271 1271  
1272 1272          ASSERT(mhp->mh_nelems != 0);
1273 1273          mhp->mh_nelems--;
1274 1274  
1275 1275          (void) pthread_rwlock_unlock(&mhp->mh_lock);
1276 1276  
1277 1277          fmd_module_unload(mp);
1278 1278          fmd_module_rele(mp);
1279 1279  
1280 1280          return (0);
1281 1281  }
1282 1282  
1283 1283  void
1284 1284  fmd_modstat_publish(fmd_module_t *mp)
1285 1285  {
1286 1286          (void) pthread_mutex_lock(&mp->mod_lock);
1287 1287  
1288 1288          ASSERT(mp->mod_flags & FMD_MOD_STSUB);
1289 1289          mp->mod_flags |= FMD_MOD_STPUB;
1290 1290          (void) pthread_cond_broadcast(&mp->mod_cv);
1291 1291  
1292 1292          while (mp->mod_flags & FMD_MOD_STPUB)
1293 1293                  (void) pthread_cond_wait(&mp->mod_cv, &mp->mod_lock);
1294 1294  
1295 1295          (void) pthread_mutex_unlock(&mp->mod_lock);
1296 1296  }
1297 1297  
1298 1298  int
1299 1299  fmd_modstat_snapshot(fmd_module_t *mp, fmd_ustat_snap_t *uss)
1300 1300  {
1301 1301          fmd_event_t *e;
1302 1302          int err;
1303 1303  
1304 1304          /*
1305 1305           * Grab the module lock and wait for the STSUB bit to be clear.  Then
1306 1306           * set it to indicate we are a subscriber and everyone else must wait.
1307 1307           */
1308 1308          (void) pthread_mutex_lock(&mp->mod_lock);
1309 1309  
1310 1310          while (mp->mod_error == 0 && (mp->mod_flags & FMD_MOD_STSUB))
1311 1311                  (void) pthread_cond_wait(&mp->mod_cv, &mp->mod_lock);
1312 1312  
1313 1313          if (mp->mod_error != 0) {
1314 1314                  (void) pthread_mutex_unlock(&mp->mod_lock);
1315 1315                  return (fmd_set_errno(EFMD_HDL_ABORT));
1316 1316          }
1317 1317  
1318 1318          mp->mod_flags |= FMD_MOD_STSUB;
1319 1319          (void) pthread_cond_broadcast(&mp->mod_cv);
1320 1320          (void) pthread_mutex_unlock(&mp->mod_lock);
1321 1321  
1322 1322          /*
1323 1323           * Create a stats pseudo-event and dispatch it to the module, forcing
1324 1324           * it to next execute its custom snapshot routine (or the empty one).
1325 1325           */
1326 1326          e = fmd_event_create(FMD_EVT_STATS, FMD_HRT_NOW, NULL, NULL);
1327 1327          fmd_eventq_insert_at_head(mp->mod_queue, e);
1328 1328  
1329 1329          /*
1330 1330           * Grab the module lock and then wait on mod_cv for STPUB to be set,
1331 1331           * indicating the snapshot routine is completed and the module is idle.
1332 1332           */
1333 1333          (void) pthread_mutex_lock(&mp->mod_lock);
1334 1334  
1335 1335          while (mp->mod_error == 0 && !(mp->mod_flags & FMD_MOD_STPUB)) {
1336 1336                  struct timespec tms;
1337 1337  
1338 1338                  (void) pthread_cond_wait(&mp->mod_cv, &mp->mod_lock);
1339 1339                  (void) pthread_mutex_unlock(&mp->mod_lock);
1340 1340                  tms.tv_sec = 0;
1341 1341                  tms.tv_nsec = 10000000;
1342 1342                  (void) nanosleep(&tms, NULL);
1343 1343                  (void) pthread_mutex_lock(&mp->mod_lock);
1344 1344          }
1345 1345  
1346 1346          if (mp->mod_error != 0) {
1347 1347                  (void) pthread_mutex_unlock(&mp->mod_lock);
1348 1348                  return (fmd_set_errno(EFMD_HDL_ABORT));
1349 1349          }
1350 1350  
1351 1351          (void) pthread_cond_broadcast(&mp->mod_cv);
1352 1352          (void) pthread_mutex_unlock(&mp->mod_lock);
1353 1353  
1354 1354          /*
1355 1355           * Update ms_snaptime and take the actual snapshot of the various
1356 1356           * statistics while the module is quiescent and waiting for us.
1357 1357           */
1358 1358          (void) pthread_mutex_lock(&mp->mod_stats_lock);
1359 1359  
1360 1360          if (mp->mod_stats != NULL) {
1361 1361                  mp->mod_stats->ms_snaptime.fmds_value.ui64 = gethrtime();
1362 1362                  err = fmd_ustat_snapshot(mp->mod_ustat, uss);
1363 1363          } else
1364 1364                  err = fmd_set_errno(EFMD_HDL_ABORT);
1365 1365  
1366 1366          (void) pthread_mutex_unlock(&mp->mod_stats_lock);
1367 1367  
1368 1368          /*
1369 1369           * With the snapshot complete, grab the module lock and clear both
1370 1370           * STSUB and STPUB, permitting everyone to wake up and continue.
1371 1371           */
1372 1372          (void) pthread_mutex_lock(&mp->mod_lock);
1373 1373  
1374 1374          ASSERT(mp->mod_flags & FMD_MOD_STSUB);
1375 1375          ASSERT(mp->mod_flags & FMD_MOD_STPUB);
1376 1376          mp->mod_flags &= ~(FMD_MOD_STSUB | FMD_MOD_STPUB);
1377 1377  
1378 1378          (void) pthread_cond_broadcast(&mp->mod_cv);
1379 1379          (void) pthread_mutex_unlock(&mp->mod_lock);
1380 1380  
1381 1381          return (err);
1382 1382  }
1383 1383  
1384 1384  struct topo_hdl *
1385 1385  fmd_module_topo_hold(fmd_module_t *mp)
1386 1386  {
1387 1387          fmd_modtopo_t *mtp;
1388 1388  
1389 1389          ASSERT(fmd_module_locked(mp));
1390 1390  
1391 1391          mtp = fmd_zalloc(sizeof (fmd_modtopo_t), FMD_SLEEP);
1392 1392          mtp->mt_topo = mp->mod_topo_current;
1393 1393          fmd_topo_addref(mtp->mt_topo);
1394 1394          fmd_list_prepend(&mp->mod_topolist, mtp);
1395 1395  
1396 1396          return (mtp->mt_topo->ft_hdl);
1397 1397  }
1398 1398  
1399 1399  int
1400 1400  fmd_module_topo_rele(fmd_module_t *mp, struct topo_hdl *hdl)
1401 1401  {
1402 1402          fmd_modtopo_t *mtp;
1403 1403  
1404 1404          ASSERT(fmd_module_locked(mp));
1405 1405  
1406 1406          for (mtp = fmd_list_next(&mp->mod_topolist); mtp != NULL;
1407 1407              mtp = fmd_list_next(mtp)) {
1408 1408                  if (mtp->mt_topo->ft_hdl == hdl)
1409 1409                          break;
1410 1410          }
1411 1411  
1412 1412          if (mtp == NULL)
1413 1413                  return (-1);
1414 1414  
1415 1415          fmd_list_delete(&mp->mod_topolist, mtp);
1416 1416          fmd_topo_rele(mtp->mt_topo);
1417 1417          fmd_free(mtp, sizeof (fmd_modtopo_t));
1418 1418          return (0);
1419 1419  }
  
    | 
      ↓ open down ↓ | 
    1139 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX