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>


 194 int32_t stn_global;
 195 /*
 196  * info_events_all holds a flag to override notification parameters and send
 197  * Information events for all state transitions.
 198  * same about the need of a mutex here.
 199  */
 200 int info_events_all;
 201 
 202 /*
 203  * Services in these states are not considered 'down' by the
 204  * milestone/shutdown code.
 205  */
 206 #define up_state(state) ((state) == RESTARTER_STATE_ONLINE || \
 207         (state) == RESTARTER_STATE_DEGRADED || \
 208         (state) == RESTARTER_STATE_OFFLINE)
 209 
 210 #define is_depgrp_bypassed(v) ((v->gv_type == GVT_GROUP) && \
 211         ((v->gv_depgroup == DEPGRP_EXCLUDE_ALL) || \
 212         (v->gv_restart < RERR_RESTART)))
 213 




 214 static uu_list_pool_t *graph_edge_pool, *graph_vertex_pool;
 215 static uu_list_t *dgraph;
 216 static pthread_mutex_t dgraph_lock;
 217 
 218 /*
 219  * milestone indicates the current subgraph.  When NULL, it is the entire
 220  * graph.  When MILESTONE_NONE, it is the empty graph.  Otherwise, it is all
 221  * services on which the target vertex depends.
 222  */
 223 static graph_vertex_t *milestone = NULL;
 224 static boolean_t initial_milestone_set = B_FALSE;
 225 static pthread_cond_t initial_milestone_cv = PTHREAD_COND_INITIALIZER;
 226 
 227 /* protected by dgraph_lock */
 228 static boolean_t sulogin_thread_running = B_FALSE;
 229 static boolean_t sulogin_running = B_FALSE;
 230 static boolean_t console_login_ready = B_FALSE;
 231 
 232 /* Number of services to come down to complete milestone transition. */
 233 static uint_t non_subgraph_svcs;


1281 
1282         satisfiable = B_FALSE;
1283 
1284         for (edge = uu_list_first(groupv->gv_dependencies);
1285             edge != NULL;
1286             edge = uu_list_next(groupv->gv_dependencies, edge)) {
1287                 s = dependency_satisfied(edge->ge_vertex, satbility);
1288 
1289                 if (s == 1)
1290                         return (1);
1291 
1292                 log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES,
1293                     "require_any(%s): %s is unsatisfi%s.\n",
1294                     groupv->gv_name, edge->ge_vertex->gv_name,
1295                     s == 0 ? "ed" : "able");
1296 
1297                 if (satbility && s == 0)
1298                         satisfiable = B_TRUE;
1299         }
1300 
1301         return (!satbility || satisfiable ? 0 : -1);
1302 }
1303 
1304 /*
1305  * An optional_all dependency only considers elements which are configured,
1306  * enabled, and not in maintenance.  If any are unsatisfied, then the dependency
1307  * is unsatisfied.
1308  *
1309  * Offline dependencies which are waiting for a dependency to come online are
1310  * unsatisfied.  Offline dependences which cannot possibly come online
1311  * (unsatisfiable) are always considered satisfied.
1312  */
1313 static int
1314 optional_all_satisfied(graph_vertex_t *groupv, boolean_t satbility)
1315 {
1316         graph_edge_t *edge;
1317         graph_vertex_t *v;
1318         boolean_t any_qualified;
1319         boolean_t any_unsatisfied;
1320         int i;
1321 
1322         any_qualified = B_FALSE;
1323         any_unsatisfied = B_FALSE;
1324 
1325         for (edge = uu_list_first(groupv->gv_dependencies);
1326             edge != NULL;
1327             edge = uu_list_next(groupv->gv_dependencies, edge)) {
1328                 v = edge->ge_vertex;
1329 
1330                 switch (v->gv_type) {
1331                 case GVT_INST:
1332                         /* Skip missing instances */
1333                         if ((v->gv_flags & GV_CONFIGURED) == 0)
1334                                 continue;
1335 
1336                         if (v->gv_state == RESTARTER_STATE_MAINT)
1337                                 continue;
1338 
1339                         any_qualified = B_TRUE;
1340                         if (v->gv_state == RESTARTER_STATE_OFFLINE) {

1341                                 /*
1342                                  * For offline dependencies, treat unsatisfiable
1343                                  * as satisfied.
1344                                  */
1345                                 i = dependency_satisfied(v, B_TRUE);
1346                                 if (i == -1)
1347                                         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                         } else {
1356                                 i = dependency_satisfied(v, satbility);
1357                         }
1358                         break;
1359 
1360                 case GVT_FILE:
1361                         any_qualified = B_TRUE;
1362                         i = dependency_satisfied(v, satbility);
1363 
1364                         break;
1365 
1366                 case GVT_SVC: {
1367                         any_qualified = B_TRUE;
1368                         i = optional_all_satisfied(v, satbility);
1369 
1370                         break;
1371                 }
1372 
1373                 case GVT_GROUP:
1374                 default:


1529  * Decide whether v can satisfy a dependency.  v can either be a child of
1530  * a group vertex, or of an instance vertex.
1531  */
1532 static int
1533 dependency_satisfied(graph_vertex_t *v, boolean_t satbility)
1534 {
1535         switch (v->gv_type) {
1536         case GVT_INST:
1537                 if ((v->gv_flags & GV_CONFIGURED) == 0) {
1538                         if (v->gv_flags & GV_DEATHROW) {
1539                                 /*
1540                                  * A dependency on an instance with GV_DEATHROW
1541                                  * flag is always considered as satisfied.
1542                                  */
1543                                 return (1);
1544                         }
1545                         return (-1);
1546                 }
1547 
1548                 /*
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.




1552                  */



1553                 if (v->gv_flags & GV_TODISABLE)
1554                         return (-1);
1555                 if (v->gv_flags & GV_TOOFFLINE)
1556                         return (0);
1557 
1558                 switch (v->gv_state) {
1559                 case RESTARTER_STATE_ONLINE:
1560                 case RESTARTER_STATE_DEGRADED:
1561                         return (1);
1562 
1563                 case RESTARTER_STATE_OFFLINE:
1564                         if (!satbility)
1565                                 return (0);
1566                         return (instance_satisfied(v, satbility) != -1 ?
1567                             0 : -1);
1568 
1569                 case RESTARTER_STATE_DISABLED:





1570                 case RESTARTER_STATE_MAINT:
1571                         return (-1);
1572 
1573                 case RESTARTER_STATE_UNINIT:
1574                         return (0);
1575 
1576                 default:
1577 #ifndef NDEBUG
1578                         uu_warn("%s:%d: Unexpected vertex state %d.\n",
1579                             __FILE__, __LINE__, v->gv_state);
1580 #endif
1581                         abort();
1582                         /* NOTREACHED */
1583                 }
1584 
1585         case GVT_SVC:
1586                 if (uu_list_numnodes(v->gv_dependencies) == 0)
1587                         return (-1);
1588                 return (require_any_satisfied(v, satbility));
1589 


1652  *      |  A  |--------------->|  B  |-------------->|  C  |
1653  *      +-----+                +-----+               +-----+
1654  *
1655  *                                              offline -> maintenance
1656  *
1657  * If C goes into maintenance, it's not enough simply to check B.  Because A has
1658  * an optional dependency, what was previously an unsatisfiable situation is now
1659  * satisfied (B will never come online, even though its state hasn't changed).
1660  *
1661  * Note that it's not necessary to continue examining dependents after reaching
1662  * an optional_all dependency.  It's not possible for an optional_all dependency
1663  * to change satisfiability without also coming online, in which case we get a
1664  * start event and propagation continues naturally.  However, it does no harm to
1665  * continue propagating satisfiability (as it is a relatively rare event), and
1666  * keeps the walker code simple and generic.
1667  */
1668 /*ARGSUSED*/
1669 static int
1670 satbility_cb(graph_vertex_t *v, void *arg)
1671 {
1672         if (v->gv_flags & GV_TOOFFLINE)
1673                 return (UU_WALK_NEXT);
1674 
1675         if (v->gv_type == GVT_INST)
1676                 graph_start_if_satisfied(v);
1677 
1678         return (UU_WALK_NEXT);
1679 }
1680 
1681 static void
1682 propagate_satbility(graph_vertex_t *v)
1683 {
1684         graph_walk(v, WALK_DEPENDENTS, satbility_cb, NULL, NULL);
1685 }
1686 
1687 static void propagate_stop(graph_vertex_t *, void *);
1688 
1689 /*
1690  * propagate_start()
1691  *
1692  * This function is used to propagate a start event to the dependents of the
1693  * given vertex.  Any dependents that are offline but have their dependencies
1694  * satisfied are started.  Any dependents that are online and have restart_on
1695  * set to "restart" or "refresh" are restarted because their dependencies have
1696  * just changed.  This only happens with optional_all dependencies.
1697  */
1698 static void
1699 propagate_start(graph_vertex_t *v, void *arg)
1700 {
1701         restarter_error_t err = (restarter_error_t)arg;
1702 
1703         if (v->gv_flags & GV_TOOFFLINE)
1704                 return;
1705 
1706         switch (v->gv_type) {
1707         case GVT_INST:
1708                 /* Restarter */
1709                 if (inst_running(v)) {
1710                         if (err == RERR_RESTART || err == RERR_REFRESH) {
1711                                 vertex_send_event(v,
1712                                     RESTARTER_EVENT_TYPE_STOP_RESET);
1713                         }
1714                 } else {
1715                         graph_start_if_satisfied(v);
1716                 }
1717                 break;
1718 
1719         case GVT_GROUP:
1720                 if (v->gv_depgroup == DEPGRP_EXCLUDE_ALL) {
1721                         graph_walk_dependents(v, propagate_stop,
1722                             (void *)RERR_RESTART);
1723                         break;


1743                     v->gv_type);
1744 #endif
1745                 abort();
1746         }
1747 }
1748 
1749 /*
1750  * propagate_stop()
1751  *
1752  * This function is used to propagate a stop event to the dependents of the
1753  * given vertex.  Any dependents that are online (or in degraded state) with
1754  * the restart_on property set to "restart" or "refresh" will be stopped as
1755  * their dependencies have just changed, propagate_start() will start them
1756  * again once their dependencies have been re-satisfied.
1757  */
1758 static void
1759 propagate_stop(graph_vertex_t *v, void *arg)
1760 {
1761         restarter_error_t err = (restarter_error_t)arg;
1762 
1763         if (v->gv_flags & GV_TOOFFLINE)
1764                 return;
1765 
1766         switch (v->gv_type) {
1767         case GVT_INST:
1768                 /* Restarter */
1769                 if (err > RERR_NONE && inst_running(v)) {
1770                         if (err == RERR_RESTART || err == RERR_REFRESH) {
1771                                 vertex_send_event(v,
1772                                     RESTARTER_EVENT_TYPE_STOP_RESET);
1773                         } else {
1774                                 vertex_send_event(v, RESTARTER_EVENT_TYPE_STOP);
1775                         }
1776                 }
1777                 break;
1778 
1779         case GVT_SVC:
1780                 graph_walk_dependents(v, propagate_stop, arg);
1781                 break;
1782 
1783         case GVT_FILE:
1784 #ifndef NDEBUG
1785                 uu_warn("%s:%d: propagate_stop() encountered GVT_FILE.\n",
1786                     __FILE__, __LINE__);
1787 #endif
1788                 abort();
1789                 /* NOTREACHED */
1790 
1791         case GVT_GROUP:
1792                 if (v->gv_depgroup == DEPGRP_EXCLUDE_ALL) {
1793                         graph_walk_dependents(v, propagate_start, NULL);

1794                         break;
1795                 }
1796 
1797                 if (err == RERR_NONE || err > v->gv_restart)
1798                         break;
1799 
1800                 graph_walk_dependents(v, propagate_stop, arg);
1801                 break;
1802 
1803         default:
1804 #ifndef NDEBUG
1805                 uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__, __LINE__,
1806                     v->gv_type);
1807 #endif
1808                 abort();
1809         }
1810 }
1811 
1812 void
1813 offline_vertex(graph_vertex_t *v)


4341 
4342         assert(MUTEX_HELD(&dgraph_lock));
4343 
4344         for (e = uu_list_first(v->gv_dependents); e != NULL;
4345             e = uu_list_next(v->gv_dependents, e)) {
4346                 vv = e->ge_vertex;
4347                 if (vv->gv_type == GVT_INST) {
4348                         if ((vv->gv_flags & GV_CONFIGURED) == 0)
4349                                 continue;
4350 
4351                         if ((vv->gv_flags & GV_TOOFFLINE) == 0)
4352                                 continue;
4353 
4354                         if ((vv->gv_state == RESTARTER_STATE_ONLINE) ||
4355                             (vv->gv_state == RESTARTER_STATE_DEGRADED))
4356                                 return (B_FALSE);
4357                 } else {
4358                         /*
4359                          * Skip all excluded dependents and decide whether
4360                          * to offline the service based on the restart_on
4361                          * on attribute.
4362                          */
4363                         if (is_depgrp_bypassed(vv))
4364                                 continue;
4365 
4366                         /*
4367                          * For dependency groups or service vertices, keep
4368                          * traversing to see if instances are running.
4369                          */
4370                         if (insubtree_dependents_down(vv) == B_FALSE)
4371                                 return (B_FALSE);
4372                 }
4373         }
4374 
4375         return (B_TRUE);
4376 }
4377 
4378 /*
4379  * Returns true only if none of this service's dependents are 'up' -- online,
4380  * degraded, or offline.
4381  */


5393 
5394 /*
5395  * mark_subtree walks the dependents and add the GV_TOOFFLINE flag
5396  * to the instances that are supposed to go offline during an
5397  * administrative disable operation.
5398  */
5399 static int
5400 mark_subtree(graph_edge_t *e, void *arg)
5401 {
5402         graph_vertex_t *v;
5403         int r;
5404 
5405         v = e->ge_vertex;
5406 
5407         /* If it's already in the subgraph, skip. */
5408         if (v->gv_flags & GV_TOOFFLINE)
5409                 return (UU_WALK_NEXT);
5410 
5411         switch (v->gv_type) {
5412         case GVT_INST:
5413                 /* If the instance is already disabled, skip it. */
5414                 if (!(v->gv_flags & GV_ENABLED))
5415                         return (UU_WALK_NEXT);
5416 
5417                 v->gv_flags |= GV_TOOFFLINE;
5418                 log_framework(LOG_DEBUG, "%s added to subtree\n", v->gv_name);
5419                 break;
5420         case GVT_GROUP:
5421                 /*
5422                  * Skip all excluded dependents and decide whether to offline
5423                  * the service based on the restart_on attribute.
5424                  */
5425                 if (is_depgrp_bypassed(v))
5426                         return (UU_WALK_NEXT);
5427                 break;
5428         }
5429 
5430         r = uu_list_walk(v->gv_dependents, (uu_walk_fn_t *)mark_subtree, arg,
5431             0);
5432         assert(r == 0);
5433         return (UU_WALK_NEXT);
5434 }




 194 int32_t stn_global;
 195 /*
 196  * info_events_all holds a flag to override notification parameters and send
 197  * Information events for all state transitions.
 198  * same about the need of a mutex here.
 199  */
 200 int info_events_all;
 201 
 202 /*
 203  * Services in these states are not considered 'down' by the
 204  * milestone/shutdown code.
 205  */
 206 #define up_state(state) ((state) == RESTARTER_STATE_ONLINE || \
 207         (state) == RESTARTER_STATE_DEGRADED || \
 208         (state) == RESTARTER_STATE_OFFLINE)
 209 
 210 #define is_depgrp_bypassed(v) ((v->gv_type == GVT_GROUP) && \
 211         ((v->gv_depgroup == DEPGRP_EXCLUDE_ALL) || \
 212         (v->gv_restart < RERR_RESTART)))
 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 
 218 static uu_list_pool_t *graph_edge_pool, *graph_vertex_pool;
 219 static uu_list_t *dgraph;
 220 static pthread_mutex_t dgraph_lock;
 221 
 222 /*
 223  * milestone indicates the current subgraph.  When NULL, it is the entire
 224  * graph.  When MILESTONE_NONE, it is the empty graph.  Otherwise, it is all
 225  * services on which the target vertex depends.
 226  */
 227 static graph_vertex_t *milestone = NULL;
 228 static boolean_t initial_milestone_set = B_FALSE;
 229 static pthread_cond_t initial_milestone_cv = PTHREAD_COND_INITIALIZER;
 230 
 231 /* protected by dgraph_lock */
 232 static boolean_t sulogin_thread_running = B_FALSE;
 233 static boolean_t sulogin_running = B_FALSE;
 234 static boolean_t console_login_ready = B_FALSE;
 235 
 236 /* Number of services to come down to complete milestone transition. */
 237 static uint_t non_subgraph_svcs;


1285 
1286         satisfiable = B_FALSE;
1287 
1288         for (edge = uu_list_first(groupv->gv_dependencies);
1289             edge != NULL;
1290             edge = uu_list_next(groupv->gv_dependencies, edge)) {
1291                 s = dependency_satisfied(edge->ge_vertex, satbility);
1292 
1293                 if (s == 1)
1294                         return (1);
1295 
1296                 log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES,
1297                     "require_any(%s): %s is unsatisfi%s.\n",
1298                     groupv->gv_name, edge->ge_vertex->gv_name,
1299                     s == 0 ? "ed" : "able");
1300 
1301                 if (satbility && s == 0)
1302                         satisfiable = B_TRUE;
1303         }
1304 
1305         return ((!satbility || satisfiable) ? 0 : -1);
1306 }
1307 
1308 /*
1309  * An optional_all dependency only considers elements which are configured,
1310  * enabled, and not in maintenance.  If any are unsatisfied, then the dependency
1311  * is unsatisfied.
1312  *
1313  * Offline dependencies which are waiting for a dependency to come online are
1314  * unsatisfied.  Offline dependences which cannot possibly come online
1315  * (unsatisfiable) are always considered satisfied.
1316  */
1317 static int
1318 optional_all_satisfied(graph_vertex_t *groupv, boolean_t satbility)
1319 {
1320         graph_edge_t *edge;
1321         graph_vertex_t *v;
1322         boolean_t any_qualified;
1323         boolean_t any_unsatisfied;
1324         int i;
1325 
1326         any_qualified = B_FALSE;
1327         any_unsatisfied = B_FALSE;
1328 
1329         for (edge = uu_list_first(groupv->gv_dependencies);
1330             edge != NULL;
1331             edge = uu_list_next(groupv->gv_dependencies, edge)) {
1332                 v = edge->ge_vertex;
1333 
1334                 switch (v->gv_type) {
1335                 case GVT_INST:
1336                         /* Skip missing instances */
1337                         if ((v->gv_flags & GV_CONFIGURED) == 0)
1338                                 continue;
1339 
1340                         if (v->gv_state == RESTARTER_STATE_MAINT)
1341                                 continue;
1342 
1343                         any_qualified = B_TRUE;
1344                         if (v->gv_state == RESTARTER_STATE_OFFLINE ||
1345                             v->gv_state == RESTARTER_STATE_DISABLED) {
1346                                 /*
1347                                  * For offline/disabled dependencies,
1348                                  * treat unsatisfiable as satisfied.
1349                                  */
1350                                 i = dependency_satisfied(v, B_TRUE);
1351                                 if (i == -1)
1352                                         i = 1;







1353                         } else {
1354                                 i = dependency_satisfied(v, satbility);
1355                         }
1356                         break;
1357 
1358                 case GVT_FILE:
1359                         any_qualified = B_TRUE;
1360                         i = dependency_satisfied(v, satbility);
1361 
1362                         break;
1363 
1364                 case GVT_SVC: {
1365                         any_qualified = B_TRUE;
1366                         i = optional_all_satisfied(v, satbility);
1367 
1368                         break;
1369                 }
1370 
1371                 case GVT_GROUP:
1372                 default:


1527  * Decide whether v can satisfy a dependency.  v can either be a child of
1528  * a group vertex, or of an instance vertex.
1529  */
1530 static int
1531 dependency_satisfied(graph_vertex_t *v, boolean_t satbility)
1532 {
1533         switch (v->gv_type) {
1534         case GVT_INST:
1535                 if ((v->gv_flags & GV_CONFIGURED) == 0) {
1536                         if (v->gv_flags & GV_DEATHROW) {
1537                                 /*
1538                                  * A dependency on an instance with GV_DEATHROW
1539                                  * flag is always considered as satisfied.
1540                                  */
1541                                 return (1);
1542                         }
1543                         return (-1);
1544                 }
1545 
1546                 /*
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.
1554                  */
1555                 switch (v->gv_state) {
1556                 case RESTARTER_STATE_ONLINE:
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);




1562                         return (1);
1563 
1564                 case RESTARTER_STATE_OFFLINE:
1565                         if (!satbility || v->gv_flags & GV_TODISABLE)
1566                                 return (satbility ? -1 : 0);
1567                         return (instance_satisfied(v, satbility) != -1 ?
1568                             0 : -1);
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 
1576                 case RESTARTER_STATE_MAINT:
1577                         return (-1);
1578 
1579                 case RESTARTER_STATE_UNINIT:
1580                         return (0);
1581 
1582                 default:
1583 #ifndef NDEBUG
1584                         uu_warn("%s:%d: Unexpected vertex state %d.\n",
1585                             __FILE__, __LINE__, v->gv_state);
1586 #endif
1587                         abort();
1588                         /* NOTREACHED */
1589                 }
1590 
1591         case GVT_SVC:
1592                 if (uu_list_numnodes(v->gv_dependencies) == 0)
1593                         return (-1);
1594                 return (require_any_satisfied(v, satbility));
1595 


1658  *      |  A  |--------------->|  B  |-------------->|  C  |
1659  *      +-----+                +-----+               +-----+
1660  *
1661  *                                              offline -> maintenance
1662  *
1663  * If C goes into maintenance, it's not enough simply to check B.  Because A has
1664  * an optional dependency, what was previously an unsatisfiable situation is now
1665  * satisfied (B will never come online, even though its state hasn't changed).
1666  *
1667  * Note that it's not necessary to continue examining dependents after reaching
1668  * an optional_all dependency.  It's not possible for an optional_all dependency
1669  * to change satisfiability without also coming online, in which case we get a
1670  * start event and propagation continues naturally.  However, it does no harm to
1671  * continue propagating satisfiability (as it is a relatively rare event), and
1672  * keeps the walker code simple and generic.
1673  */
1674 /*ARGSUSED*/
1675 static int
1676 satbility_cb(graph_vertex_t *v, void *arg)
1677 {
1678         if (is_inst_bypassed(v))
1679                 return (UU_WALK_NEXT);
1680 
1681         if (v->gv_type == GVT_INST)
1682                 graph_start_if_satisfied(v);
1683 
1684         return (UU_WALK_NEXT);
1685 }
1686 
1687 static void
1688 propagate_satbility(graph_vertex_t *v)
1689 {
1690         graph_walk(v, WALK_DEPENDENTS, satbility_cb, NULL, NULL);
1691 }
1692 
1693 static void propagate_stop(graph_vertex_t *, void *);
1694 
1695 /*
1696  * propagate_start()
1697  *
1698  * This function is used to propagate a start event to the dependents of the
1699  * given vertex.  Any dependents that are offline but have their dependencies
1700  * satisfied are started.  Any dependents that are online and have restart_on
1701  * set to "restart" or "refresh" are restarted because their dependencies have
1702  * just changed.  This only happens with optional_all dependencies.
1703  */
1704 static void
1705 propagate_start(graph_vertex_t *v, void *arg)
1706 {
1707         restarter_error_t err = (restarter_error_t)arg;
1708 
1709         if (is_inst_bypassed(v))
1710                 return;
1711 
1712         switch (v->gv_type) {
1713         case GVT_INST:
1714                 /* Restarter */
1715                 if (inst_running(v)) {
1716                         if (err == RERR_RESTART || err == RERR_REFRESH) {
1717                                 vertex_send_event(v,
1718                                     RESTARTER_EVENT_TYPE_STOP_RESET);
1719                         }
1720                 } else {
1721                         graph_start_if_satisfied(v);
1722                 }
1723                 break;
1724 
1725         case GVT_GROUP:
1726                 if (v->gv_depgroup == DEPGRP_EXCLUDE_ALL) {
1727                         graph_walk_dependents(v, propagate_stop,
1728                             (void *)RERR_RESTART);
1729                         break;


1749                     v->gv_type);
1750 #endif
1751                 abort();
1752         }
1753 }
1754 
1755 /*
1756  * propagate_stop()
1757  *
1758  * This function is used to propagate a stop event to the dependents of the
1759  * given vertex.  Any dependents that are online (or in degraded state) with
1760  * the restart_on property set to "restart" or "refresh" will be stopped as
1761  * their dependencies have just changed, propagate_start() will start them
1762  * again once their dependencies have been re-satisfied.
1763  */
1764 static void
1765 propagate_stop(graph_vertex_t *v, void *arg)
1766 {
1767         restarter_error_t err = (restarter_error_t)arg;
1768 
1769         if (is_inst_bypassed(v))
1770                 return;
1771 
1772         switch (v->gv_type) {
1773         case GVT_INST:
1774                 /* Restarter */
1775                 if (err > RERR_NONE && inst_running(v)) {
1776                         if (err == RERR_RESTART || err == RERR_REFRESH) {
1777                                 vertex_send_event(v,
1778                                     RESTARTER_EVENT_TYPE_STOP_RESET);
1779                         } else {
1780                                 vertex_send_event(v, RESTARTER_EVENT_TYPE_STOP);
1781                         }
1782                 }
1783                 break;
1784 
1785         case GVT_SVC:
1786                 graph_walk_dependents(v, propagate_stop, arg);
1787                 break;
1788 
1789         case GVT_FILE:
1790 #ifndef NDEBUG
1791                 uu_warn("%s:%d: propagate_stop() encountered GVT_FILE.\n",
1792                     __FILE__, __LINE__);
1793 #endif
1794                 abort();
1795                 /* NOTREACHED */
1796 
1797         case GVT_GROUP:
1798                 if (v->gv_depgroup == DEPGRP_EXCLUDE_ALL) {
1799                         graph_walk_dependents(v, propagate_start,
1800                             (void *)RERR_NONE);
1801                         break;
1802                 }
1803 
1804                 if (err == RERR_NONE || err > v->gv_restart)
1805                         break;
1806 
1807                 graph_walk_dependents(v, propagate_stop, arg);
1808                 break;
1809 
1810         default:
1811 #ifndef NDEBUG
1812                 uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__, __LINE__,
1813                     v->gv_type);
1814 #endif
1815                 abort();
1816         }
1817 }
1818 
1819 void
1820 offline_vertex(graph_vertex_t *v)


4348 
4349         assert(MUTEX_HELD(&dgraph_lock));
4350 
4351         for (e = uu_list_first(v->gv_dependents); e != NULL;
4352             e = uu_list_next(v->gv_dependents, e)) {
4353                 vv = e->ge_vertex;
4354                 if (vv->gv_type == GVT_INST) {
4355                         if ((vv->gv_flags & GV_CONFIGURED) == 0)
4356                                 continue;
4357 
4358                         if ((vv->gv_flags & GV_TOOFFLINE) == 0)
4359                                 continue;
4360 
4361                         if ((vv->gv_state == RESTARTER_STATE_ONLINE) ||
4362                             (vv->gv_state == RESTARTER_STATE_DEGRADED))
4363                                 return (B_FALSE);
4364                 } else {
4365                         /*
4366                          * Skip all excluded dependents and decide whether
4367                          * to offline the service based on the restart_on
4368                          * attribute.
4369                          */
4370                         if (is_depgrp_bypassed(vv))
4371                                 continue;
4372 
4373                         /*
4374                          * For dependency groups or service vertices, keep
4375                          * traversing to see if instances are running.
4376                          */
4377                         if (insubtree_dependents_down(vv) == B_FALSE)
4378                                 return (B_FALSE);
4379                 }
4380         }
4381 
4382         return (B_TRUE);
4383 }
4384 
4385 /*
4386  * Returns true only if none of this service's dependents are 'up' -- online,
4387  * degraded, or offline.
4388  */


5400 
5401 /*
5402  * mark_subtree walks the dependents and add the GV_TOOFFLINE flag
5403  * to the instances that are supposed to go offline during an
5404  * administrative disable operation.
5405  */
5406 static int
5407 mark_subtree(graph_edge_t *e, void *arg)
5408 {
5409         graph_vertex_t *v;
5410         int r;
5411 
5412         v = e->ge_vertex;
5413 
5414         /* If it's already in the subgraph, skip. */
5415         if (v->gv_flags & GV_TOOFFLINE)
5416                 return (UU_WALK_NEXT);
5417 
5418         switch (v->gv_type) {
5419         case GVT_INST:
5420                 /* If the instance is already offline, skip it. */
5421                 if (!inst_running(v))
5422                         return (UU_WALK_NEXT);
5423 
5424                 v->gv_flags |= GV_TOOFFLINE;
5425                 log_framework(LOG_DEBUG, "%s added to subtree\n", v->gv_name);
5426                 break;
5427         case GVT_GROUP:
5428                 /*
5429                  * Skip all excluded dependents and decide whether to offline
5430                  * the service based on the restart_on attribute.
5431                  */
5432                 if (is_depgrp_bypassed(v))
5433                         return (UU_WALK_NEXT);
5434                 break;
5435         }
5436 
5437         r = uu_list_walk(v->gv_dependents, (uu_walk_fn_t *)mark_subtree, arg,
5438             0);
5439         assert(r == 0);
5440         return (UU_WALK_NEXT);
5441 }