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;
|