Print this page
7267 SMF is fast and loose with optional dependencies (fixes)
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Albert Lee <trisk@omniti.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/svc/startd/graph.c
          +++ new/usr/src/cmd/svc/startd/graph.c
↓ open down ↓ 203 lines elided ↑ open up ↑
 204  204   * milestone/shutdown code.
 205  205   */
 206  206  #define up_state(state) ((state) == RESTARTER_STATE_ONLINE || \
 207  207          (state) == RESTARTER_STATE_DEGRADED || \
 208  208          (state) == RESTARTER_STATE_OFFLINE)
 209  209  
 210  210  #define is_depgrp_bypassed(v) ((v->gv_type == GVT_GROUP) && \
 211  211          ((v->gv_depgroup == DEPGRP_EXCLUDE_ALL) || \
 212  212          (v->gv_restart < RERR_RESTART)))
 213  213  
      214 +#define is_inst_bypassed(v) ((v->gv_type == GVT_INST) && \
      215 +        ((v->gv_flags & GV_TODISABLE) || \
      216 +        (v->gv_flags & GV_TOOFFLINE)))
      217 +
 214  218  static uu_list_pool_t *graph_edge_pool, *graph_vertex_pool;
 215  219  static uu_list_t *dgraph;
 216  220  static pthread_mutex_t dgraph_lock;
 217  221  
 218  222  /*
 219  223   * milestone indicates the current subgraph.  When NULL, it is the entire
 220  224   * graph.  When MILESTONE_NONE, it is the empty graph.  Otherwise, it is all
 221  225   * services on which the target vertex depends.
 222  226   */
 223  227  static graph_vertex_t *milestone = NULL;
↓ open down ↓ 1067 lines elided ↑ open up ↑
1291 1295  
1292 1296                  log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES,
1293 1297                      "require_any(%s): %s is unsatisfi%s.\n",
1294 1298                      groupv->gv_name, edge->ge_vertex->gv_name,
1295 1299                      s == 0 ? "ed" : "able");
1296 1300  
1297 1301                  if (satbility && s == 0)
1298 1302                          satisfiable = B_TRUE;
1299 1303          }
1300 1304  
1301      -        return (!satbility || satisfiable ? 0 : -1);
     1305 +        return ((!satbility || satisfiable) ? 0 : -1);
1302 1306  }
1303 1307  
1304 1308  /*
1305 1309   * An optional_all dependency only considers elements which are configured,
1306 1310   * enabled, and not in maintenance.  If any are unsatisfied, then the dependency
1307 1311   * is unsatisfied.
1308 1312   *
1309 1313   * Offline dependencies which are waiting for a dependency to come online are
1310 1314   * unsatisfied.  Offline dependences which cannot possibly come online
1311 1315   * (unsatisfiable) are always considered satisfied.
↓ open down ↓ 18 lines elided ↑ open up ↑
1330 1334                  switch (v->gv_type) {
1331 1335                  case GVT_INST:
1332 1336                          /* Skip missing instances */
1333 1337                          if ((v->gv_flags & GV_CONFIGURED) == 0)
1334 1338                                  continue;
1335 1339  
1336 1340                          if (v->gv_state == RESTARTER_STATE_MAINT)
1337 1341                                  continue;
1338 1342  
1339 1343                          any_qualified = B_TRUE;
1340      -                        if (v->gv_state == RESTARTER_STATE_OFFLINE) {
     1344 +                        if (v->gv_state == RESTARTER_STATE_OFFLINE ||
     1345 +                            v->gv_state == RESTARTER_STATE_DISABLED) {
1341 1346                                  /*
1342      -                                 * For offline dependencies, treat unsatisfiable
1343      -                                 * as satisfied.
     1347 +                                 * For offline/disabled dependencies,
     1348 +                                 * treat unsatisfiable as satisfied.
1344 1349                                   */
1345 1350                                  i = dependency_satisfied(v, B_TRUE);
1346 1351                                  if (i == -1)
1347 1352                                          i = 1;
1348      -                        } else if (v->gv_state == RESTARTER_STATE_DISABLED) {
1349      -                                /*
1350      -                                 * If the instance is transitioning out of
1351      -                                 * disabled the dependency is temporarily
1352      -                                 * unsatisfied (not unsatisfiable).
1353      -                                 */
1354      -                                i = v->gv_flags & GV_ENABLED ? 0 : 1;
1355 1353                          } else {
1356 1354                                  i = dependency_satisfied(v, satbility);
1357 1355                          }
1358 1356                          break;
1359 1357  
1360 1358                  case GVT_FILE:
1361 1359                          any_qualified = B_TRUE;
1362 1360                          i = dependency_satisfied(v, satbility);
1363 1361  
1364 1362                          break;
↓ open down ↓ 174 lines elided ↑ open up ↑
1539 1537                                  /*
1540 1538                                   * A dependency on an instance with GV_DEATHROW
1541 1539                                   * flag is always considered as satisfied.
1542 1540                                   */
1543 1541                                  return (1);
1544 1542                          }
1545 1543                          return (-1);
1546 1544                  }
1547 1545  
1548 1546                  /*
1549      -                 * Any vertex with the GV_TODISABLE flag set is guaranteed
1550      -                 * to have its dependencies unsatisfiable.  Any vertex with
1551      -                 * GV_TOOFFLINE may be satisfied after it transitions.
     1547 +                 * Vertices may be transitioning so we try to figure out if
     1548 +                 * the end state is likely to satisfy the dependency instead
     1549 +                 * of assuming the dependency is unsatisfied/unsatisfiable.
     1550 +                 *
     1551 +                 * Support for optional_all dependencies depends on us getting
     1552 +                 * this right because unsatisfiable dependencies are treated
     1553 +                 * as being satisfied.
1552 1554                   */
1553      -                if (v->gv_flags & GV_TODISABLE)
1554      -                        return (-1);
1555      -                if (v->gv_flags & GV_TOOFFLINE)
1556      -                        return (0);
1557      -
1558 1555                  switch (v->gv_state) {
1559 1556                  case RESTARTER_STATE_ONLINE:
1560 1557                  case RESTARTER_STATE_DEGRADED:
     1558 +                        if (v->gv_flags & GV_TODISABLE)
     1559 +                                return (-1);
     1560 +                        if (v->gv_flags & GV_TOOFFLINE)
     1561 +                                return (0);
1561 1562                          return (1);
1562 1563  
1563 1564                  case RESTARTER_STATE_OFFLINE:
1564      -                        if (!satbility)
1565      -                                return (0);
     1565 +                        if (!satbility || v->gv_flags & GV_TODISABLE)
     1566 +                                return (satbility ? -1 : 0);
1566 1567                          return (instance_satisfied(v, satbility) != -1 ?
1567 1568                              0 : -1);
1568 1569  
1569 1570                  case RESTARTER_STATE_DISABLED:
     1571 +                        if (!satbility || !(v->gv_flags & GV_ENABLED))
     1572 +                                return (satbility ? -1 : 0);
     1573 +                        return (instance_satisfied(v, satbility) != -1 ?
     1574 +                            0 : -1);
     1575 +
1570 1576                  case RESTARTER_STATE_MAINT:
1571 1577                          return (-1);
1572 1578  
1573 1579                  case RESTARTER_STATE_UNINIT:
1574 1580                          return (0);
1575 1581  
1576 1582                  default:
1577 1583  #ifndef NDEBUG
1578 1584                          uu_warn("%s:%d: Unexpected vertex state %d.\n",
1579 1585                              __FILE__, __LINE__, v->gv_state);
↓ open down ↓ 82 lines elided ↑ open up ↑
1662 1668   * an optional_all dependency.  It's not possible for an optional_all dependency
1663 1669   * to change satisfiability without also coming online, in which case we get a
1664 1670   * start event and propagation continues naturally.  However, it does no harm to
1665 1671   * continue propagating satisfiability (as it is a relatively rare event), and
1666 1672   * keeps the walker code simple and generic.
1667 1673   */
1668 1674  /*ARGSUSED*/
1669 1675  static int
1670 1676  satbility_cb(graph_vertex_t *v, void *arg)
1671 1677  {
1672      -        if (v->gv_flags & GV_TOOFFLINE)
     1678 +        if (is_inst_bypassed(v))
1673 1679                  return (UU_WALK_NEXT);
1674 1680  
1675 1681          if (v->gv_type == GVT_INST)
1676 1682                  graph_start_if_satisfied(v);
1677 1683  
1678 1684          return (UU_WALK_NEXT);
1679 1685  }
1680 1686  
1681 1687  static void
1682 1688  propagate_satbility(graph_vertex_t *v)
↓ open down ↓ 10 lines elided ↑ open up ↑
1693 1699   * given vertex.  Any dependents that are offline but have their dependencies
1694 1700   * satisfied are started.  Any dependents that are online and have restart_on
1695 1701   * set to "restart" or "refresh" are restarted because their dependencies have
1696 1702   * just changed.  This only happens with optional_all dependencies.
1697 1703   */
1698 1704  static void
1699 1705  propagate_start(graph_vertex_t *v, void *arg)
1700 1706  {
1701 1707          restarter_error_t err = (restarter_error_t)arg;
1702 1708  
1703      -        if (v->gv_flags & GV_TOOFFLINE)
     1709 +        if (is_inst_bypassed(v))
1704 1710                  return;
1705 1711  
1706 1712          switch (v->gv_type) {
1707 1713          case GVT_INST:
1708 1714                  /* Restarter */
1709 1715                  if (inst_running(v)) {
1710 1716                          if (err == RERR_RESTART || err == RERR_REFRESH) {
1711 1717                                  vertex_send_event(v,
1712 1718                                      RESTARTER_EVENT_TYPE_STOP_RESET);
1713 1719                          }
↓ open down ↓ 39 lines elided ↑ open up ↑
1753 1759   * given vertex.  Any dependents that are online (or in degraded state) with
1754 1760   * the restart_on property set to "restart" or "refresh" will be stopped as
1755 1761   * their dependencies have just changed, propagate_start() will start them
1756 1762   * again once their dependencies have been re-satisfied.
1757 1763   */
1758 1764  static void
1759 1765  propagate_stop(graph_vertex_t *v, void *arg)
1760 1766  {
1761 1767          restarter_error_t err = (restarter_error_t)arg;
1762 1768  
1763      -        if (v->gv_flags & GV_TOOFFLINE)
     1769 +        if (is_inst_bypassed(v))
1764 1770                  return;
1765 1771  
1766 1772          switch (v->gv_type) {
1767 1773          case GVT_INST:
1768 1774                  /* Restarter */
1769 1775                  if (err > RERR_NONE && inst_running(v)) {
1770 1776                          if (err == RERR_RESTART || err == RERR_REFRESH) {
1771 1777                                  vertex_send_event(v,
1772 1778                                      RESTARTER_EVENT_TYPE_STOP_RESET);
1773 1779                          } else {
↓ open down ↓ 9 lines elided ↑ open up ↑
1783 1789          case GVT_FILE:
1784 1790  #ifndef NDEBUG
1785 1791                  uu_warn("%s:%d: propagate_stop() encountered GVT_FILE.\n",
1786 1792                      __FILE__, __LINE__);
1787 1793  #endif
1788 1794                  abort();
1789 1795                  /* NOTREACHED */
1790 1796  
1791 1797          case GVT_GROUP:
1792 1798                  if (v->gv_depgroup == DEPGRP_EXCLUDE_ALL) {
1793      -                        graph_walk_dependents(v, propagate_start, NULL);
     1799 +                        graph_walk_dependents(v, propagate_start,
     1800 +                            (void *)RERR_NONE);
1794 1801                          break;
1795 1802                  }
1796 1803  
1797 1804                  if (err == RERR_NONE || err > v->gv_restart)
1798 1805                          break;
1799 1806  
1800 1807                  graph_walk_dependents(v, propagate_stop, arg);
1801 1808                  break;
1802 1809  
1803 1810          default:
↓ open down ↓ 2547 lines elided ↑ open up ↑
4351 4358                          if ((vv->gv_flags & GV_TOOFFLINE) == 0)
4352 4359                                  continue;
4353 4360  
4354 4361                          if ((vv->gv_state == RESTARTER_STATE_ONLINE) ||
4355 4362                              (vv->gv_state == RESTARTER_STATE_DEGRADED))
4356 4363                                  return (B_FALSE);
4357 4364                  } else {
4358 4365                          /*
4359 4366                           * Skip all excluded dependents and decide whether
4360 4367                           * to offline the service based on the restart_on
4361      -                         * on attribute.
     4368 +                         * attribute.
4362 4369                           */
4363 4370                          if (is_depgrp_bypassed(vv))
4364 4371                                  continue;
4365 4372  
4366 4373                          /*
4367 4374                           * For dependency groups or service vertices, keep
4368 4375                           * traversing to see if instances are running.
4369 4376                           */
4370 4377                          if (insubtree_dependents_down(vv) == B_FALSE)
4371 4378                                  return (B_FALSE);
↓ open down ↓ 1031 lines elided ↑ open up ↑
5403 5410          int r;
5404 5411  
5405 5412          v = e->ge_vertex;
5406 5413  
5407 5414          /* If it's already in the subgraph, skip. */
5408 5415          if (v->gv_flags & GV_TOOFFLINE)
5409 5416                  return (UU_WALK_NEXT);
5410 5417  
5411 5418          switch (v->gv_type) {
5412 5419          case GVT_INST:
5413      -                /* If the instance is already disabled, skip it. */
5414      -                if (!(v->gv_flags & GV_ENABLED))
     5420 +                /* If the instance is already offline, skip it. */
     5421 +                if (!inst_running(v))
5415 5422                          return (UU_WALK_NEXT);
5416 5423  
5417 5424                  v->gv_flags |= GV_TOOFFLINE;
5418 5425                  log_framework(LOG_DEBUG, "%s added to subtree\n", v->gv_name);
5419 5426                  break;
5420 5427          case GVT_GROUP:
5421 5428                  /*
5422 5429                   * Skip all excluded dependents and decide whether to offline
5423 5430                   * the service based on the restart_on attribute.
5424 5431                   */
↓ open down ↓ 1466 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX