Print this page
7281 mdnsd needs to try harder to send goodbye requests

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/svc/startd/graph.c
          +++ new/usr/src/cmd/svc/startd/graph.c
↓ open down ↓ 14 lines elided ↑ open up ↑
  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   * Copyright (c) 2015, Syneto S.R.L. All rights reserved.
       25 + * Copyright 2016 RackTop Systems.
  25   26   */
  26   27  
  27   28  /*
  28   29   * graph.c - master restarter graph engine
  29   30   *
  30   31   *   The graph engine keeps a dependency graph of all service instances on the
  31   32   *   system, as recorded in the repository.  It decides when services should
  32   33   *   be brought up or down based on service states and dependencies and sends
  33   34   *   commands to restarters to effect any changes.  It also executes
  34   35   *   administrator commands sent by svcadm via the repository.
↓ open down ↓ 165 lines elided ↑ open up ↑
 200  201  /*
 201  202   * Services in these states are not considered 'down' by the
 202  203   * milestone/shutdown code.
 203  204   */
 204  205  #define up_state(state) ((state) == RESTARTER_STATE_ONLINE || \
 205  206          (state) == RESTARTER_STATE_DEGRADED || \
 206  207          (state) == RESTARTER_STATE_OFFLINE)
 207  208  
 208  209  #define is_depgrp_bypassed(v) ((v->gv_type == GVT_GROUP) && \
 209  210          ((v->gv_depgroup == DEPGRP_EXCLUDE_ALL) || \
 210      -        (v->gv_depgroup == DEPGRP_OPTIONAL_ALL) || \
 211  211          (v->gv_restart < RERR_RESTART)))
 212  212  
 213  213  static uu_list_pool_t *graph_edge_pool, *graph_vertex_pool;
 214  214  static uu_list_t *dgraph;
 215  215  static pthread_mutex_t dgraph_lock;
 216  216  
 217  217  /*
 218  218   * milestone indicates the current subgraph.  When NULL, it is the entire
 219  219   * graph.  When MILESTONE_NONE, it is the empty graph.  Otherwise, it is all
 220  220   * services on which the target vertex depends.
↓ open down ↓ 1100 lines elided ↑ open up ↑
1321 1321          any_qualified = B_FALSE;
1322 1322          any_unsatisfied = B_FALSE;
1323 1323  
1324 1324          for (edge = uu_list_first(groupv->gv_dependencies);
1325 1325              edge != NULL;
1326 1326              edge = uu_list_next(groupv->gv_dependencies, edge)) {
1327 1327                  v = edge->ge_vertex;
1328 1328  
1329 1329                  switch (v->gv_type) {
1330 1330                  case GVT_INST:
1331      -                        /* Skip missing or disabled instances */
1332      -                        if ((v->gv_flags & (GV_CONFIGURED | GV_ENABLED)) !=
1333      -                            (GV_CONFIGURED | GV_ENABLED))
     1331 +                        /* Skip missing instances */
     1332 +                        if ((v->gv_flags & GV_CONFIGURED) == 0)
1334 1333                                  continue;
1335 1334  
1336 1335                          if (v->gv_state == RESTARTER_STATE_MAINT)
1337 1336                                  continue;
1338 1337  
1339      -                        if (v->gv_flags & GV_TOOFFLINE)
1340      -                                continue;
1341      -
1342 1338                          any_qualified = B_TRUE;
1343 1339                          if (v->gv_state == RESTARTER_STATE_OFFLINE) {
1344 1340                                  /*
1345 1341                                   * For offline dependencies, treat unsatisfiable
1346 1342                                   * as satisfied.
1347 1343                                   */
1348 1344                                  i = dependency_satisfied(v, B_TRUE);
1349 1345                                  if (i == -1)
1350 1346                                          i = 1;
1351 1347                          } else if (v->gv_state == RESTARTER_STATE_DISABLED) {
1352 1348                                  /*
1353 1349                                   * The service is enabled, but hasn't
1354 1350                                   * transitioned out of disabled yet.  Treat it
1355 1351                                   * as unsatisfied (not unsatisfiable).
1356 1352                                   */
1357      -                                i = 0;
     1353 +                                i = v->gv_flags & GV_ENABLED ? 0 : 1;
1358 1354                          } else {
1359 1355                                  i = dependency_satisfied(v, satbility);
1360 1356                          }
1361 1357                          break;
1362 1358  
1363 1359                  case GVT_FILE:
1364 1360                          any_qualified = B_TRUE;
1365 1361                          i = dependency_satisfied(v, satbility);
1366 1362  
1367 1363                          break;
↓ open down ↓ 8 lines elided ↑ open up ↑
1376 1372                          svc_any_qualified = B_FALSE;
1377 1373                          svc_satisfied = B_FALSE;
1378 1374                          svc_satisfiable = B_FALSE;
1379 1375  
1380 1376                          for (e2 = uu_list_first(v->gv_dependencies);
1381 1377                              e2 != NULL;
1382 1378                              e2 = uu_list_next(v->gv_dependencies, e2)) {
1383 1379                                  v2 = e2->ge_vertex;
1384 1380                                  assert(v2->gv_type == GVT_INST);
1385 1381  
1386      -                                if ((v2->gv_flags &
1387      -                                    (GV_CONFIGURED | GV_ENABLED)) !=
1388      -                                    (GV_CONFIGURED | GV_ENABLED))
     1382 +                                if ((v2->gv_flags & GV_CONFIGURED) == 0)
1389 1383                                          continue;
1390 1384  
1391 1385                                  if (v2->gv_state == RESTARTER_STATE_MAINT)
1392 1386                                          continue;
1393 1387  
1394      -                                if (v2->gv_flags & GV_TOOFFLINE)
1395      -                                        continue;
1396      -
1397 1388                                  svc_any_qualified = B_TRUE;
1398 1389  
1399 1390                                  if (v2->gv_state == RESTARTER_STATE_OFFLINE) {
1400 1391                                          /*
1401 1392                                           * For offline dependencies, treat
1402 1393                                           * unsatisfiable as satisfied.
1403 1394                                           */
1404 1395                                          i = dependency_satisfied(v2, B_TRUE);
1405 1396                                          if (i == -1)
1406 1397                                                  i = 1;
1407 1398                                  } else if (v2->gv_state ==
1408 1399                                      RESTARTER_STATE_DISABLED) {
1409      -                                        i = 0;
     1400 +                                        i = v2->gv_flags & GV_ENABLED ? 0 : 1;
1410 1401                                  } else {
1411 1402                                          i = dependency_satisfied(v2, satbility);
1412 1403                                  }
1413 1404  
1414 1405                                  if (i == 1) {
1415 1406                                          svc_satisfied = B_TRUE;
1416 1407                                          break;
1417 1408                                  }
1418 1409                                  if (i == 0)
1419 1410                                          svc_satisfiable = B_TRUE;
↓ open down ↓ 181 lines elided ↑ open up ↑
1601 1592                                  /*
1602 1593                                   * A dependency on an instance with GV_DEATHROW
1603 1594                                   * flag is always considered as satisfied.
1604 1595                                   */
1605 1596                                  return (1);
1606 1597                          }
1607 1598                          return (-1);
1608 1599                  }
1609 1600  
1610 1601                  /*
1611      -                 * Any vertex with the GV_TOOFFLINE flag set is guaranteed
1612      -                 * to have its dependencies unsatisfiable.
     1602 +                 * Any vertex with the GV_TODISABLE flag set is guaranteed
     1603 +                 * to have its dependencies unsatisfiable.  Any vertex with
     1604 +                 * GV_TOOFFLINE may be satisfied after it transitions.
1613 1605                   */
1614      -                if (v->gv_flags & GV_TOOFFLINE)
     1606 +                if (v->gv_flags & GV_TODISABLE)
1615 1607                          return (-1);
     1608 +                if (v->gv_flags & GV_TOOFFLINE)
     1609 +                        return (0);
1616 1610  
1617 1611                  switch (v->gv_state) {
1618 1612                  case RESTARTER_STATE_ONLINE:
1619 1613                  case RESTARTER_STATE_DEGRADED:
1620 1614                          return (1);
1621 1615  
1622 1616                  case RESTARTER_STATE_OFFLINE:
1623 1617                          if (!satbility)
1624 1618                                  return (0);
1625 1619                          return (instance_satisfied(v, satbility) != -1 ?
↓ open down ↓ 95 lines elided ↑ open up ↑
1721 1715   * an optional_all dependency.  It's not possible for an optional_all dependency
1722 1716   * to change satisfiability without also coming online, in which case we get a
1723 1717   * start event and propagation continues naturally.  However, it does no harm to
1724 1718   * continue propagating satisfiability (as it is a relatively rare event), and
1725 1719   * keeps the walker code simple and generic.
1726 1720   */
1727 1721  /*ARGSUSED*/
1728 1722  static int
1729 1723  satbility_cb(graph_vertex_t *v, void *arg)
1730 1724  {
     1725 +        if (v->gv_flags & GV_TOOFFLINE)
     1726 +                return (UU_WALK_NEXT);
     1727 +
1731 1728          if (v->gv_type == GVT_INST)
1732 1729                  graph_start_if_satisfied(v);
1733 1730  
1734 1731          return (UU_WALK_NEXT);
1735 1732  }
1736 1733  
1737 1734  static void
1738 1735  propagate_satbility(graph_vertex_t *v)
1739 1736  {
1740 1737          graph_walk(v, WALK_DEPENDENTS, satbility_cb, NULL, NULL);
1741 1738  }
1742 1739  
1743 1740  static void propagate_stop(graph_vertex_t *, void *);
1744 1741  
1745      -/* ARGSUSED */
     1742 +/*
     1743 + * propagate_start()
     1744 + *
     1745 + * This function is used to propagate a start event to the dependents of the
     1746 + * given vertex.  Any dependents that are offline but have their dependencies
     1747 + * satisfied are started.  Any dependents that are online and have restart_on
     1748 + * set to "restart" or "refresh" are restarted because their dependencies have
     1749 + * just changed.  This only happens with optional_all dependencies.
     1750 + */
1746 1751  static void
1747 1752  propagate_start(graph_vertex_t *v, void *arg)
1748 1753  {
     1754 +        restarter_error_t err = (restarter_error_t)arg;
     1755 +
     1756 +        if (v->gv_flags & GV_TOOFFLINE)
     1757 +                return;
     1758 +
1749 1759          switch (v->gv_type) {
1750 1760          case GVT_INST:
1751      -                graph_start_if_satisfied(v);
     1761 +                /* Restarter */
     1762 +                if (inst_running(v)) {
     1763 +                        if (err == RERR_RESTART || err == RERR_REFRESH) {
     1764 +                                vertex_send_event(v,
     1765 +                                    RESTARTER_EVENT_TYPE_STOP_RESET);
     1766 +                        }
     1767 +                } else {
     1768 +                        graph_start_if_satisfied(v);
     1769 +                }
1752 1770                  break;
1753 1771  
1754 1772          case GVT_GROUP:
1755 1773                  if (v->gv_depgroup == DEPGRP_EXCLUDE_ALL) {
1756 1774                          graph_walk_dependents(v, propagate_stop,
1757 1775                              (void *)RERR_RESTART);
1758 1776                          break;
1759 1777                  }
     1778 +                err = v->gv_restart;
1760 1779                  /* FALLTHROUGH */
1761 1780  
1762 1781          case GVT_SVC:
1763      -                graph_walk_dependents(v, propagate_start, NULL);
     1782 +                graph_walk_dependents(v, propagate_start, (void *)err);
1764 1783                  break;
1765 1784  
1766 1785          case GVT_FILE:
1767 1786  #ifndef NDEBUG
1768 1787                  uu_warn("%s:%d: propagate_start() encountered GVT_FILE.\n",
1769 1788                      __FILE__, __LINE__);
1770 1789  #endif
1771 1790                  abort();
1772 1791                  /* NOTREACHED */
1773 1792  
1774 1793          default:
1775 1794  #ifndef NDEBUG
1776 1795                  uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__, __LINE__,
1777 1796                      v->gv_type);
1778 1797  #endif
1779 1798                  abort();
1780 1799          }
1781 1800  }
1782 1801  
     1802 +/*
     1803 + * propagate_stop()
     1804 + *
     1805 + * This function is used to propagate a stop event to the dependencies of the
     1806 + * given vertex.  Any dependencies that are online (or in degraded state) with
     1807 + * the restart_on property set to "restart" or "refresh" will be restarted as
     1808 + * their dependencies have just changed.  This only happens for optional_all
     1809 + * dependencies.
     1810 + */
1783 1811  static void
1784 1812  propagate_stop(graph_vertex_t *v, void *arg)
1785 1813  {
1786      -        graph_edge_t *e;
1787      -        graph_vertex_t *svc;
1788 1814          restarter_error_t err = (restarter_error_t)arg;
1789 1815  
     1816 +        if (v->gv_flags & GV_TOOFFLINE)
     1817 +                return;
     1818 +
1790 1819          switch (v->gv_type) {
1791 1820          case GVT_INST:
1792 1821                  /* Restarter */
1793 1822                  if (err > RERR_NONE && inst_running(v)) {
1794 1823                          if (err == RERR_RESTART || err == RERR_REFRESH) {
1795 1824                                  vertex_send_event(v,
1796 1825                                      RESTARTER_EVENT_TYPE_STOP_RESET);
1797 1826                          } else {
1798 1827                                  vertex_send_event(v, RESTARTER_EVENT_TYPE_STOP);
1799 1828                          }
↓ open down ↓ 14 lines elided ↑ open up ↑
1814 1843  
1815 1844          case GVT_GROUP:
1816 1845                  if (v->gv_depgroup == DEPGRP_EXCLUDE_ALL) {
1817 1846                          graph_walk_dependents(v, propagate_start, NULL);
1818 1847                          break;
1819 1848                  }
1820 1849  
1821 1850                  if (err == RERR_NONE || err > v->gv_restart)
1822 1851                          break;
1823 1852  
1824      -                assert(uu_list_numnodes(v->gv_dependents) == 1);
1825      -                e = uu_list_first(v->gv_dependents);
1826      -                svc = e->ge_vertex;
1827      -
1828      -                if (inst_running(svc)) {
1829      -                        if (err == RERR_RESTART || err == RERR_REFRESH) {
1830      -                                vertex_send_event(svc,
1831      -                                    RESTARTER_EVENT_TYPE_STOP_RESET);
1832      -                        } else {
1833      -                                vertex_send_event(svc,
1834      -                                    RESTARTER_EVENT_TYPE_STOP);
1835      -                        }
1836      -                }
     1853 +                graph_walk_dependents(v, propagate_stop, arg);
1837 1854                  break;
1838 1855  
1839 1856          default:
1840 1857  #ifndef NDEBUG
1841 1858                  uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__, __LINE__,
1842 1859                      v->gv_type);
1843 1860  #endif
1844 1861                  abort();
1845 1862          }
1846 1863  }
↓ open down ↓ 2544 lines elided ↑ open up ↑
4391 4408                                  continue;
4392 4409  
4393 4410                          if ((vv->gv_flags & GV_TOOFFLINE) == 0)
4394 4411                                  continue;
4395 4412  
4396 4413                          if ((vv->gv_state == RESTARTER_STATE_ONLINE) ||
4397 4414                              (vv->gv_state == RESTARTER_STATE_DEGRADED))
4398 4415                                  return (B_FALSE);
4399 4416                  } else {
4400 4417                          /*
4401      -                         * Skip all excluded and optional_all dependencies
4402      -                         * and decide whether to offline the service based
4403      -                         * on restart_on attribute.
     4418 +                         * Skip all excluded dependents and decide whether
     4419 +                         * to offline the service based on the restart_on
     4420 +                         * on attribute.
4404 4421                           */
4405 4422                          if (is_depgrp_bypassed(vv))
4406 4423                                  continue;
4407 4424  
4408 4425                          /*
4409 4426                           * For dependency groups or service vertices, keep
4410 4427                           * traversing to see if instances are running.
4411 4428                           */
4412 4429                          if (insubtree_dependents_down(vv) == B_FALSE)
4413 4430                                  return (B_FALSE);
↓ open down ↓ 544 lines elided ↑ open up ↑
4958 4975   * a state which can satisfy optional dependencies, like disabled or
4959 4976   * maintenance.
4960 4977   */
4961 4978  void
4962 4979  graph_transition_propagate(graph_vertex_t *v, propagate_event_t type,
4963 4980      restarter_error_t rerr)
4964 4981  {
4965 4982          if (type == PROPAGATE_STOP) {
4966 4983                  graph_walk_dependents(v, propagate_stop, (void *)rerr);
4967 4984          } else if (type == PROPAGATE_START || type == PROPAGATE_SAT) {
4968      -                graph_walk_dependents(v, propagate_start, NULL);
     4985 +                graph_walk_dependents(v, propagate_start, (void *)RERR_NONE);
4969 4986  
4970 4987                  if (type == PROPAGATE_SAT)
4971 4988                          propagate_satbility(v);
4972 4989          } else {
4973 4990  #ifndef NDEBUG
4974 4991                  uu_warn("%s:%d: Unexpected type value %d.\n",  __FILE__,
4975 4992                      __LINE__, type);
4976 4993  #endif
4977 4994                  abort();
4978 4995          }
↓ open down ↓ 50 lines elided ↑ open up ↑
5029 5046           * event -- deletion isn't a fault, just a normal stop.  This gives
5030 5047           * dependent services the chance to do a clean shutdown.  Then, mark
5031 5048           * the service as unconfigured and propagate the start event for the
5032 5049           * optional_all dependencies that might have become satisfied.
5033 5050           */
5034 5051          graph_walk_dependents(v, propagate_stop, (void *)RERR_RESTART);
5035 5052  
5036 5053          v->gv_flags &= ~GV_CONFIGURED;
5037 5054          v->gv_flags &= ~GV_DEATHROW;
5038 5055  
5039      -        graph_walk_dependents(v, propagate_start, NULL);
     5056 +        graph_walk_dependents(v, propagate_start, (void *)RERR_NONE);
5040 5057          propagate_satbility(v);
5041 5058  
5042 5059          /*
5043 5060           * If there are no (non-service) dependents, the vertex can be
5044 5061           * completely removed.
5045 5062           */
5046 5063          if (v != milestone && v->gv_refs == 0 &&
5047 5064              uu_list_numnodes(v->gv_dependents) == 1)
5048 5065                  remove_inst_vertex(v);
5049 5066  
↓ open down ↓ 404 lines elided ↑ open up ↑
5454 5471          case GVT_INST:
5455 5472                  /* If the instance is already disabled, skip it. */
5456 5473                  if (!(v->gv_flags & GV_ENABLED))
5457 5474                          return (UU_WALK_NEXT);
5458 5475  
5459 5476                  v->gv_flags |= GV_TOOFFLINE;
5460 5477                  log_framework(LOG_DEBUG, "%s added to subtree\n", v->gv_name);
5461 5478                  break;
5462 5479          case GVT_GROUP:
5463 5480                  /*
5464      -                 * Skip all excluded and optional_all dependencies and decide
5465      -                 * whether to offline the service based on restart_on attribute.
     5481 +                 * Skip all excluded dependents and decide whether to offline
     5482 +                 * the service based on the restart_on attribute.
5466 5483                   */
5467 5484                  if (is_depgrp_bypassed(v))
5468 5485                          return (UU_WALK_NEXT);
5469 5486                  break;
5470 5487          }
5471 5488  
5472 5489          r = uu_list_walk(v->gv_dependents, (uu_walk_fn_t *)mark_subtree, arg,
5473 5490              0);
5474 5491          assert(r == 0);
5475 5492          return (UU_WALK_NEXT);
↓ open down ↓ 1457 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX