Print this page
7246 SMF stops dependents in the wrong order
7267 SMF is fast and loose with optional dependencies


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2015, Syneto S.R.L. All rights reserved.

  25  */
  26 
  27 /*
  28  * graph.c - master restarter graph engine
  29  *
  30  *   The graph engine keeps a dependency graph of all service instances on the
  31  *   system, as recorded in the repository.  It decides when services should
  32  *   be brought up or down based on service states and dependencies and sends
  33  *   commands to restarters to effect any changes.  It also executes
  34  *   administrator commands sent by svcadm via the repository.
  35  *
  36  *   The graph is stored in uu_list_t *dgraph and its vertices are
  37  *   graph_vertex_t's, each of which has a name and an integer id unique to
  38  *   its name (see dict.c).  A vertex's type attribute designates the type
  39  *   of object it represents: GVT_INST for service instances, GVT_SVC for
  40  *   service objects (since service instances may depend on another service,
  41  *   rather than service instance), GVT_FILE for files (which services may
  42  *   depend on), and GVT_GROUP for dependencies on multiple objects.  GVT_GROUP
  43  *   vertices are necessary because dependency lists may have particular
  44  *   grouping types (require any, require all, optional, or exclude) and


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


 288         SCF_MILESTONE_SINGLE_USER,
 289         CONSOLE_LOGIN_FMRI,
 290         "svc:/system/install-setup:default",
 291         "svc:/system/install:default",
 292         NULL
 293 };
 294 
 295 /* This array must have an element for each non-NULL element of up_svcs[]. */
 296 static graph_vertex_t *up_svcs_p[] = { NULL, NULL, NULL, NULL };
 297 
 298 /* These are for seed repository magic.  See can_come_up(). */
 299 static const char * const manifest_import = SCF_INSTANCE_MI;
 300 static graph_vertex_t *manifest_import_p = NULL;
 301 
 302 
 303 static char target_milestone_as_runlevel(void);
 304 static void graph_runlevel_changed(char rl, int online);
 305 static int dgraph_set_milestone(const char *, scf_handle_t *, boolean_t);
 306 static boolean_t should_be_in_subgraph(graph_vertex_t *v);
 307 static int mark_subtree(graph_edge_t *, void *);
 308 static boolean_t insubtree_dependents_down(graph_vertex_t *);
 309 
 310 /*
 311  * graph_vertex_compare()
 312  *      This function can compare either int *id or * graph_vertex_t *gv
 313  *      values, as the vertex id is always the first element of a
 314  *      graph_vertex structure.
 315  */
 316 /* ARGSUSED */
 317 static int
 318 graph_vertex_compare(const void *lc_arg, const void *rc_arg, void *private)
 319 {
 320         int lc_id = ((const graph_vertex_t *)lc_arg)->gv_id;
 321         int rc_id = *(int *)rc_arg;
 322 
 323         if (lc_id > rc_id)
 324                 return (1);
 325         if (lc_id < rc_id)
 326                 return (-1);
 327         return (0);
 328 }


1311  */
1312 static int
1313 optional_all_satisfied(graph_vertex_t *groupv, boolean_t satbility)
1314 {
1315         graph_edge_t *edge;
1316         graph_vertex_t *v;
1317         boolean_t any_qualified;
1318         boolean_t any_unsatisfied;
1319         int i;
1320 
1321         any_qualified = B_FALSE;
1322         any_unsatisfied = B_FALSE;
1323 
1324         for (edge = uu_list_first(groupv->gv_dependencies);
1325             edge != NULL;
1326             edge = uu_list_next(groupv->gv_dependencies, edge)) {
1327                 v = edge->ge_vertex;
1328 
1329                 switch (v->gv_type) {
1330                 case GVT_INST:
1331                         /* Skip missing or disabled instances */
1332                         if ((v->gv_flags & (GV_CONFIGURED | GV_ENABLED)) !=
1333                             (GV_CONFIGURED | GV_ENABLED))
1334                                 continue;
1335 
1336                         if (v->gv_state == RESTARTER_STATE_MAINT)
1337                                 continue;
1338 
1339                         if (v->gv_flags & GV_TOOFFLINE)
1340                                 continue;
1341 
1342                         any_qualified = B_TRUE;
1343                         if (v->gv_state == RESTARTER_STATE_OFFLINE) {
1344                                 /*
1345                                  * For offline dependencies, treat unsatisfiable
1346                                  * as satisfied.
1347                                  */
1348                                 i = dependency_satisfied(v, B_TRUE);
1349                                 if (i == -1)
1350                                         i = 1;
1351                         } else if (v->gv_state == RESTARTER_STATE_DISABLED) {
1352                                 /*
1353                                  * The service is enabled, but hasn't
1354                                  * transitioned out of disabled yet.  Treat it
1355                                  * as unsatisfied (not unsatisfiable).
1356                                  */
1357                                 i = 0;
1358                         } else {
1359                                 i = dependency_satisfied(v, satbility);
1360                         }
1361                         break;
1362 
1363                 case GVT_FILE:
1364                         any_qualified = B_TRUE;
1365                         i = dependency_satisfied(v, satbility);
1366 
1367                         break;
1368 
1369                 case GVT_SVC: {
1370                         boolean_t svc_any_qualified;
1371                         boolean_t svc_satisfied;
1372                         boolean_t svc_satisfiable;
1373                         graph_vertex_t *v2;
1374                         graph_edge_t *e2;
1375 
1376                         svc_any_qualified = B_FALSE;
1377                         svc_satisfied = B_FALSE;
1378                         svc_satisfiable = B_FALSE;
1379 
1380                         for (e2 = uu_list_first(v->gv_dependencies);
1381                             e2 != NULL;
1382                             e2 = uu_list_next(v->gv_dependencies, e2)) {
1383                                 v2 = e2->ge_vertex;
1384                                 assert(v2->gv_type == GVT_INST);
1385 
1386                                 if ((v2->gv_flags &
1387                                     (GV_CONFIGURED | GV_ENABLED)) !=
1388                                     (GV_CONFIGURED | GV_ENABLED))
1389                                         continue;
1390 
1391                                 if (v2->gv_state == RESTARTER_STATE_MAINT)
1392                                         continue;
1393 
1394                                 if (v2->gv_flags & GV_TOOFFLINE)
1395                                         continue;
1396 
1397                                 svc_any_qualified = B_TRUE;
1398 
1399                                 if (v2->gv_state == RESTARTER_STATE_OFFLINE) {
1400                                         /*
1401                                          * For offline dependencies, treat
1402                                          * unsatisfiable as satisfied.
1403                                          */
1404                                         i = dependency_satisfied(v2, B_TRUE);
1405                                         if (i == -1)
1406                                                 i = 1;
1407                                 } else if (v2->gv_state ==
1408                                     RESTARTER_STATE_DISABLED) {
1409                                         i = 0;
1410                                 } else {
1411                                         i = dependency_satisfied(v2, satbility);
1412                                 }
1413 
1414                                 if (i == 1) {
1415                                         svc_satisfied = B_TRUE;
1416                                         break;
1417                                 }
1418                                 if (i == 0)
1419                                         svc_satisfiable = B_TRUE;
1420                         }
1421 
1422                         if (!svc_any_qualified)
1423                                 continue;
1424                         any_qualified = B_TRUE;
1425                         if (svc_satisfied) {
1426                                 i = 1;
1427                         } else if (svc_satisfiable) {
1428                                 i = 0;
1429                         } else {


4358         r = libscf_snapshots_refresh(inst, v->gv_name);
4359         if (r != 0) {
4360                 if (r != -1)
4361                         bad_error("libscf_snapshots_refresh", r);
4362 
4363                 /* error logged */
4364                 return (r);
4365         }
4366 
4367         r = refresh_vertex(v, inst);
4368         if (r != 0 && r != ECONNABORTED)
4369                 bad_error("refresh_vertex", r);
4370         return (r);
4371 }
4372 
4373 /*
4374  * Returns true only if none of this service's dependents are 'up' -- online
4375  * or degraded (offline is considered down in this situation). This function
4376  * is somehow similar to is_nonsubgraph_leaf() but works on subtrees.
4377  */
4378 static boolean_t
4379 insubtree_dependents_down(graph_vertex_t *v)
4380 {
4381         graph_vertex_t *vv;
4382         graph_edge_t *e;
4383 
4384         assert(MUTEX_HELD(&dgraph_lock));
4385 
4386         for (e = uu_list_first(v->gv_dependents); e != NULL;
4387             e = uu_list_next(v->gv_dependents, e)) {
4388                 vv = e->ge_vertex;
4389                 if (vv->gv_type == GVT_INST) {
4390                         if ((vv->gv_flags & GV_CONFIGURED) == 0)
4391                                 continue;
4392 
4393                         if ((vv->gv_flags & GV_TOOFFLINE) == 0)
4394                                 continue;
4395 
4396                         if ((vv->gv_state == RESTARTER_STATE_ONLINE) ||
4397                             (vv->gv_state == RESTARTER_STATE_DEGRADED))
4398                                 return (B_FALSE);
4399                 } else {
4400                         /*
4401                          * Skip all excluded and optional_all dependencies
4402                          * and decide whether to offline the service based
4403                          * on restart_on attribute.
4404                          */
4405                         if (is_depgrp_bypassed(vv))
4406                                 continue;
4407 
4408                         /*
4409                          * For dependency groups or service vertices, keep
4410                          * traversing to see if instances are running.
4411                          */
4412                         if (insubtree_dependents_down(vv) == B_FALSE)
4413                                 return (B_FALSE);
4414                 }
4415         }
4416 
4417         return (B_TRUE);
4418 }
4419 
4420 /*
4421  * Returns true only if none of this service's dependents are 'up' -- online,
4422  * degraded, or offline.
4423  */


4545                     "the repository is read-only");
4546                 graph_enable_by_vertex(v, 0, 0);
4547                 return (0);
4548 
4549         default:
4550                 bad_error("libscf_set_enable_ovr", r);
4551                 /* NOTREACHED */
4552         }
4553 }
4554 
4555 /*
4556  * Of the transitive instance dependencies of v, offline those which are
4557  * in the subtree and which are leaves (i.e., have no dependents which are
4558  * "up").
4559  */
4560 void
4561 offline_subtree_leaves(graph_vertex_t *v, void *arg)
4562 {
4563         assert(MUTEX_HELD(&dgraph_lock));
4564 









4565         /* If v isn't an instance, recurse on its dependencies. */
4566         if (v->gv_type != GVT_INST) {
4567                 graph_walk_dependencies(v, offline_subtree_leaves, arg);
4568                 return;
4569         }
4570 
4571         /*
4572          * If v is not in the subtree, so should all of its dependencies,
4573          * so do nothing.
4574          */
4575         if ((v->gv_flags & GV_TOOFFLINE) == 0)
4576                 return;
4577 
4578         /* If v isn't a leaf because it's already down, recurse. */
4579         if (!up_state(v->gv_state)) {
4580                 graph_walk_dependencies(v, offline_subtree_leaves, arg);
4581                 return;
4582         }
4583 
4584         /* if v is a leaf, offline it or disable it if it's the last one */


5444         graph_vertex_t *v;
5445         int r;
5446 
5447         v = e->ge_vertex;
5448 
5449         /* If it's already in the subgraph, skip. */
5450         if (v->gv_flags & GV_TOOFFLINE)
5451                 return (UU_WALK_NEXT);
5452 
5453         switch (v->gv_type) {
5454         case GVT_INST:
5455                 /* If the instance is already disabled, skip it. */
5456                 if (!(v->gv_flags & GV_ENABLED))
5457                         return (UU_WALK_NEXT);
5458 
5459                 v->gv_flags |= GV_TOOFFLINE;
5460                 log_framework(LOG_DEBUG, "%s added to subtree\n", v->gv_name);
5461                 break;
5462         case GVT_GROUP:
5463                 /*
5464                  * Skip all excluded and optional_all dependencies and decide
5465                  * whether to offline the service based on restart_on attribute.
5466                  */
5467                 if (is_depgrp_bypassed(v))
5468                         return (UU_WALK_NEXT);
5469                 break;
5470         }
5471 
5472         r = uu_list_walk(v->gv_dependents, (uu_walk_fn_t *)mark_subtree, arg,
5473             0);
5474         assert(r == 0);
5475         return (UU_WALK_NEXT);
5476 }
5477 
5478 static int
5479 mark_subgraph(graph_edge_t *e, void *arg)
5480 {
5481         graph_vertex_t *v;
5482         int r;
5483         int optional = (int)arg;
5484 
5485         v = e->ge_vertex;




   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2015, Syneto S.R.L. All rights reserved.
  25  * Copyright 2016 RackTop Systems.
  26  */
  27 
  28 /*
  29  * graph.c - master restarter graph engine
  30  *
  31  *   The graph engine keeps a dependency graph of all service instances on the
  32  *   system, as recorded in the repository.  It decides when services should
  33  *   be brought up or down based on service states and dependencies and sends
  34  *   commands to restarters to effect any changes.  It also executes
  35  *   administrator commands sent by svcadm via the repository.
  36  *
  37  *   The graph is stored in uu_list_t *dgraph and its vertices are
  38  *   graph_vertex_t's, each of which has a name and an integer id unique to
  39  *   its name (see dict.c).  A vertex's type attribute designates the type
  40  *   of object it represents: GVT_INST for service instances, GVT_SVC for
  41  *   service objects (since service instances may depend on another service,
  42  *   rather than service instance), GVT_FILE for files (which services may
  43  *   depend on), and GVT_GROUP for dependencies on multiple objects.  GVT_GROUP
  44  *   vertices are necessary because dependency lists may have particular
  45  *   grouping types (require any, require all, optional, or exclude) and


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

 211         (v->gv_restart < RERR_RESTART)))
 212 
 213 static uu_list_pool_t *graph_edge_pool, *graph_vertex_pool;
 214 static uu_list_t *dgraph;
 215 static pthread_mutex_t dgraph_lock;
 216 
 217 /*
 218  * milestone indicates the current subgraph.  When NULL, it is the entire
 219  * graph.  When MILESTONE_NONE, it is the empty graph.  Otherwise, it is all
 220  * services on which the target vertex depends.
 221  */
 222 static graph_vertex_t *milestone = NULL;
 223 static boolean_t initial_milestone_set = B_FALSE;
 224 static pthread_cond_t initial_milestone_cv = PTHREAD_COND_INITIALIZER;
 225 
 226 /* protected by dgraph_lock */
 227 static boolean_t sulogin_thread_running = B_FALSE;
 228 static boolean_t sulogin_running = B_FALSE;
 229 static boolean_t console_login_ready = B_FALSE;
 230 


 288         SCF_MILESTONE_SINGLE_USER,
 289         CONSOLE_LOGIN_FMRI,
 290         "svc:/system/install-setup:default",
 291         "svc:/system/install:default",
 292         NULL
 293 };
 294 
 295 /* This array must have an element for each non-NULL element of up_svcs[]. */
 296 static graph_vertex_t *up_svcs_p[] = { NULL, NULL, NULL, NULL };
 297 
 298 /* These are for seed repository magic.  See can_come_up(). */
 299 static const char * const manifest_import = SCF_INSTANCE_MI;
 300 static graph_vertex_t *manifest_import_p = NULL;
 301 
 302 
 303 static char target_milestone_as_runlevel(void);
 304 static void graph_runlevel_changed(char rl, int online);
 305 static int dgraph_set_milestone(const char *, scf_handle_t *, boolean_t);
 306 static boolean_t should_be_in_subgraph(graph_vertex_t *v);
 307 static int mark_subtree(graph_edge_t *, void *);

 308 
 309 /*
 310  * graph_vertex_compare()
 311  *      This function can compare either int *id or * graph_vertex_t *gv
 312  *      values, as the vertex id is always the first element of a
 313  *      graph_vertex structure.
 314  */
 315 /* ARGSUSED */
 316 static int
 317 graph_vertex_compare(const void *lc_arg, const void *rc_arg, void *private)
 318 {
 319         int lc_id = ((const graph_vertex_t *)lc_arg)->gv_id;
 320         int rc_id = *(int *)rc_arg;
 321 
 322         if (lc_id > rc_id)
 323                 return (1);
 324         if (lc_id < rc_id)
 325                 return (-1);
 326         return (0);
 327 }


1310  */
1311 static int
1312 optional_all_satisfied(graph_vertex_t *groupv, boolean_t satbility)
1313 {
1314         graph_edge_t *edge;
1315         graph_vertex_t *v;
1316         boolean_t any_qualified;
1317         boolean_t any_unsatisfied;
1318         int i;
1319 
1320         any_qualified = B_FALSE;
1321         any_unsatisfied = B_FALSE;
1322 
1323         for (edge = uu_list_first(groupv->gv_dependencies);
1324             edge != NULL;
1325             edge = uu_list_next(groupv->gv_dependencies, edge)) {
1326                 v = edge->ge_vertex;
1327 
1328                 switch (v->gv_type) {
1329                 case GVT_INST:
1330                         /* Skip missing instances */
1331                         if ((v->gv_flags & GV_CONFIGURED) == 0)

1332                                 continue;
1333 
1334                         if (v->gv_state == RESTARTER_STATE_MAINT)
1335                                 continue;
1336 



1337                         any_qualified = B_TRUE;
1338                         if (v->gv_state == RESTARTER_STATE_OFFLINE) {
1339                                 /*
1340                                  * For offline dependencies, treat unsatisfiable
1341                                  * as satisfied.
1342                                  */
1343                                 i = dependency_satisfied(v, B_TRUE);
1344                                 if (i == -1)
1345                                         i = 1;
1346                         } else if (v->gv_state == RESTARTER_STATE_DISABLED) {
1347                                 /*
1348                                  * The service is enabled, but hasn't
1349                                  * transitioned out of disabled yet.  Treat it
1350                                  * as unsatisfied (not unsatisfiable).
1351                                  */
1352                                 i = v->gv_flags & GV_ENABLED ? 0 : 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                         boolean_t svc_any_qualified;
1366                         boolean_t svc_satisfied;
1367                         boolean_t svc_satisfiable;
1368                         graph_vertex_t *v2;
1369                         graph_edge_t *e2;
1370 
1371                         svc_any_qualified = B_FALSE;
1372                         svc_satisfied = B_FALSE;
1373                         svc_satisfiable = B_FALSE;
1374 
1375                         for (e2 = uu_list_first(v->gv_dependencies);
1376                             e2 != NULL;
1377                             e2 = uu_list_next(v->gv_dependencies, e2)) {
1378                                 v2 = e2->ge_vertex;
1379                                 assert(v2->gv_type == GVT_INST);
1380 
1381                                 if ((v2->gv_flags & GV_CONFIGURED) == 0)


1382                                         continue;
1383 
1384                                 if (v2->gv_state == RESTARTER_STATE_MAINT)
1385                                         continue;
1386 



1387                                 svc_any_qualified = B_TRUE;

1388                                 if (v2->gv_state == RESTARTER_STATE_OFFLINE) {
1389                                         /*
1390                                          * For offline dependencies, treat
1391                                          * unsatisfiable as satisfied.
1392                                          */
1393                                         i = dependency_satisfied(v2, B_TRUE);
1394                                         if (i == -1)
1395                                                 i = 1;
1396                                 } else if (v2->gv_state ==
1397                                     RESTARTER_STATE_DISABLED) {
1398                                         i = v2->gv_flags & GV_ENABLED ? 0 : 1;
1399                                 } else {
1400                                         i = dependency_satisfied(v2, satbility);
1401                                 }
1402 
1403                                 if (i == 1) {
1404                                         svc_satisfied = B_TRUE;
1405                                         break;
1406                                 }
1407                                 if (i == 0)
1408                                         svc_satisfiable = B_TRUE;
1409                         }
1410 
1411                         if (!svc_any_qualified)
1412                                 continue;
1413                         any_qualified = B_TRUE;
1414                         if (svc_satisfied) {
1415                                 i = 1;
1416                         } else if (svc_satisfiable) {
1417                                 i = 0;
1418                         } else {


4347         r = libscf_snapshots_refresh(inst, v->gv_name);
4348         if (r != 0) {
4349                 if (r != -1)
4350                         bad_error("libscf_snapshots_refresh", r);
4351 
4352                 /* error logged */
4353                 return (r);
4354         }
4355 
4356         r = refresh_vertex(v, inst);
4357         if (r != 0 && r != ECONNABORTED)
4358                 bad_error("refresh_vertex", r);
4359         return (r);
4360 }
4361 
4362 /*
4363  * Returns true only if none of this service's dependents are 'up' -- online
4364  * or degraded (offline is considered down in this situation). This function
4365  * is somehow similar to is_nonsubgraph_leaf() but works on subtrees.
4366  */
4367 boolean_t
4368 insubtree_dependents_down(graph_vertex_t *v)
4369 {
4370         graph_vertex_t *vv;
4371         graph_edge_t *e;
4372 
4373         assert(MUTEX_HELD(&dgraph_lock));
4374 
4375         for (e = uu_list_first(v->gv_dependents); e != NULL;
4376             e = uu_list_next(v->gv_dependents, e)) {
4377                 vv = e->ge_vertex;
4378                 if (vv->gv_type == GVT_INST) {
4379                         if ((vv->gv_flags & GV_CONFIGURED) == 0)
4380                                 continue;
4381 
4382                         if ((vv->gv_flags & GV_TOOFFLINE) == 0)
4383                                 return (B_FALSE);
4384 
4385                         if ((vv->gv_state == RESTARTER_STATE_ONLINE) ||
4386                             (vv->gv_state == RESTARTER_STATE_DEGRADED))
4387                                 return (B_FALSE);
4388                 } else {
4389                         /*
4390                          * Skip all excluded dependencies and decide whether
4391                          * decide whether to offline the service based on the
4392                          * restart_on attribute.
4393                          */
4394                         if (is_depgrp_bypassed(vv))
4395                                 continue;
4396 
4397                         /*
4398                          * For dependency groups or service vertices, keep
4399                          * traversing to see if instances are running.
4400                          */
4401                         if (insubtree_dependents_down(vv) == B_FALSE)
4402                                 return (B_FALSE);
4403                 }
4404         }
4405 
4406         return (B_TRUE);
4407 }
4408 
4409 /*
4410  * Returns true only if none of this service's dependents are 'up' -- online,
4411  * degraded, or offline.
4412  */


4534                     "the repository is read-only");
4535                 graph_enable_by_vertex(v, 0, 0);
4536                 return (0);
4537 
4538         default:
4539                 bad_error("libscf_set_enable_ovr", r);
4540                 /* NOTREACHED */
4541         }
4542 }
4543 
4544 /*
4545  * Of the transitive instance dependencies of v, offline those which are
4546  * in the subtree and which are leaves (i.e., have no dependents which are
4547  * "up").
4548  */
4549 void
4550 offline_subtree_leaves(graph_vertex_t *v, void *arg)
4551 {
4552         assert(MUTEX_HELD(&dgraph_lock));
4553 
4554         /* If v has up dependents, try to bring them down first. */
4555         if (insubtree_dependents_down(v) == B_FALSE) {
4556                 graph_walk_dependents(v, offline_subtree_leaves, arg);
4557 
4558                 /* If we couldn't bring them down, return. */
4559                 if (insubtree_dependents_down(v) == B_FALSE)
4560                         return;
4561         }
4562 
4563         /* If v isn't an instance, recurse on its dependencies. */
4564         if (v->gv_type != GVT_INST) {
4565                 graph_walk_dependencies(v, offline_subtree_leaves, arg);
4566                 return;
4567         }
4568 
4569         /*
4570          * If v is not in the subtree, so should all of its dependencies,
4571          * so do nothing.
4572          */
4573         if ((v->gv_flags & GV_TOOFFLINE) == 0)
4574                 return;
4575 
4576         /* If v isn't a leaf because it's already down, recurse. */
4577         if (!up_state(v->gv_state)) {
4578                 graph_walk_dependencies(v, offline_subtree_leaves, arg);
4579                 return;
4580         }
4581 
4582         /* if v is a leaf, offline it or disable it if it's the last one */


5442         graph_vertex_t *v;
5443         int r;
5444 
5445         v = e->ge_vertex;
5446 
5447         /* If it's already in the subgraph, skip. */
5448         if (v->gv_flags & GV_TOOFFLINE)
5449                 return (UU_WALK_NEXT);
5450 
5451         switch (v->gv_type) {
5452         case GVT_INST:
5453                 /* If the instance is already disabled, skip it. */
5454                 if (!(v->gv_flags & GV_ENABLED))
5455                         return (UU_WALK_NEXT);
5456 
5457                 v->gv_flags |= GV_TOOFFLINE;
5458                 log_framework(LOG_DEBUG, "%s added to subtree\n", v->gv_name);
5459                 break;
5460         case GVT_GROUP:
5461                 /*
5462                  * Skip all excluded dependencies and decide whether to offline
5463                  * the service based on the restart_on attribute.
5464                  */
5465                 if (is_depgrp_bypassed(v))
5466                         return (UU_WALK_NEXT);
5467                 break;
5468         }
5469 
5470         r = uu_list_walk(v->gv_dependents, (uu_walk_fn_t *)mark_subtree, arg,
5471             0);
5472         assert(r == 0);
5473         return (UU_WALK_NEXT);
5474 }
5475 
5476 static int
5477 mark_subgraph(graph_edge_t *e, void *arg)
5478 {
5479         graph_vertex_t *v;
5480         int r;
5481         int optional = (int)arg;
5482 
5483         v = e->ge_vertex;