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

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 ↓ 77 lines elided ↑ open up ↑
 298  298  /* These are for seed repository magic.  See can_come_up(). */
 299  299  static const char * const manifest_import = SCF_INSTANCE_MI;
 300  300  static graph_vertex_t *manifest_import_p = NULL;
 301  301  
 302  302  
 303  303  static char target_milestone_as_runlevel(void);
 304  304  static void graph_runlevel_changed(char rl, int online);
 305  305  static int dgraph_set_milestone(const char *, scf_handle_t *, boolean_t);
 306  306  static boolean_t should_be_in_subgraph(graph_vertex_t *v);
 307  307  static int mark_subtree(graph_edge_t *, void *);
 308      -static boolean_t insubtree_dependents_down(graph_vertex_t *);
 309  308  
 310  309  /*
 311  310   * graph_vertex_compare()
 312  311   *      This function can compare either int *id or * graph_vertex_t *gv
 313  312   *      values, as the vertex id is always the first element of a
 314  313   *      graph_vertex structure.
 315  314   */
 316  315  /* ARGSUSED */
 317  316  static int
 318  317  graph_vertex_compare(const void *lc_arg, const void *rc_arg, void *private)
↓ open down ↓ 1002 lines elided ↑ open up ↑
1321 1320          any_qualified = B_FALSE;
1322 1321          any_unsatisfied = B_FALSE;
1323 1322  
1324 1323          for (edge = uu_list_first(groupv->gv_dependencies);
1325 1324              edge != NULL;
1326 1325              edge = uu_list_next(groupv->gv_dependencies, edge)) {
1327 1326                  v = edge->ge_vertex;
1328 1327  
1329 1328                  switch (v->gv_type) {
1330 1329                  case GVT_INST:
1331      -                        /* Skip missing or disabled instances */
1332      -                        if ((v->gv_flags & (GV_CONFIGURED | GV_ENABLED)) !=
1333      -                            (GV_CONFIGURED | GV_ENABLED))
     1330 +                        /* Skip missing instances */
     1331 +                        if ((v->gv_flags & GV_CONFIGURED) == 0)
1334 1332                                  continue;
1335 1333  
1336 1334                          if (v->gv_state == RESTARTER_STATE_MAINT)
1337 1335                                  continue;
1338 1336  
1339      -                        if (v->gv_flags & GV_TOOFFLINE)
1340      -                                continue;
1341      -
1342 1337                          any_qualified = B_TRUE;
1343 1338                          if (v->gv_state == RESTARTER_STATE_OFFLINE) {
1344 1339                                  /*
1345 1340                                   * For offline dependencies, treat unsatisfiable
1346 1341                                   * as satisfied.
1347 1342                                   */
1348 1343                                  i = dependency_satisfied(v, B_TRUE);
1349 1344                                  if (i == -1)
1350 1345                                          i = 1;
1351 1346                          } else if (v->gv_state == RESTARTER_STATE_DISABLED) {
1352 1347                                  /*
1353 1348                                   * The service is enabled, but hasn't
1354 1349                                   * transitioned out of disabled yet.  Treat it
1355 1350                                   * as unsatisfied (not unsatisfiable).
1356 1351                                   */
1357      -                                i = 0;
     1352 +                                i = v->gv_flags & GV_ENABLED ? 0 : 1;
1358 1353                          } else {
1359 1354                                  i = dependency_satisfied(v, satbility);
1360 1355                          }
1361 1356                          break;
1362 1357  
1363 1358                  case GVT_FILE:
1364 1359                          any_qualified = B_TRUE;
1365 1360                          i = dependency_satisfied(v, satbility);
1366 1361  
1367 1362                          break;
↓ open down ↓ 8 lines elided ↑ open up ↑
1376 1371                          svc_any_qualified = B_FALSE;
1377 1372                          svc_satisfied = B_FALSE;
1378 1373                          svc_satisfiable = B_FALSE;
1379 1374  
1380 1375                          for (e2 = uu_list_first(v->gv_dependencies);
1381 1376                              e2 != NULL;
1382 1377                              e2 = uu_list_next(v->gv_dependencies, e2)) {
1383 1378                                  v2 = e2->ge_vertex;
1384 1379                                  assert(v2->gv_type == GVT_INST);
1385 1380  
1386      -                                if ((v2->gv_flags &
1387      -                                    (GV_CONFIGURED | GV_ENABLED)) !=
1388      -                                    (GV_CONFIGURED | GV_ENABLED))
     1381 +                                if ((v2->gv_flags & GV_CONFIGURED) == 0)
1389 1382                                          continue;
1390 1383  
1391 1384                                  if (v2->gv_state == RESTARTER_STATE_MAINT)
1392 1385                                          continue;
1393 1386  
1394      -                                if (v2->gv_flags & GV_TOOFFLINE)
1395      -                                        continue;
1396      -
1397 1387                                  svc_any_qualified = B_TRUE;
1398      -
1399 1388                                  if (v2->gv_state == RESTARTER_STATE_OFFLINE) {
1400 1389                                          /*
1401 1390                                           * For offline dependencies, treat
1402 1391                                           * unsatisfiable as satisfied.
1403 1392                                           */
1404 1393                                          i = dependency_satisfied(v2, B_TRUE);
1405 1394                                          if (i == -1)
1406 1395                                                  i = 1;
1407 1396                                  } else if (v2->gv_state ==
1408 1397                                      RESTARTER_STATE_DISABLED) {
1409      -                                        i = 0;
     1398 +                                        i = v2->gv_flags & GV_ENABLED ? 0 : 1;
1410 1399                                  } else {
1411 1400                                          i = dependency_satisfied(v2, satbility);
1412 1401                                  }
1413 1402  
1414 1403                                  if (i == 1) {
1415 1404                                          svc_satisfied = B_TRUE;
1416 1405                                          break;
1417 1406                                  }
1418 1407                                  if (i == 0)
1419 1408                                          svc_satisfiable = B_TRUE;
↓ open down ↓ 2948 lines elided ↑ open up ↑
4368 4357          if (r != 0 && r != ECONNABORTED)
4369 4358                  bad_error("refresh_vertex", r);
4370 4359          return (r);
4371 4360  }
4372 4361  
4373 4362  /*
4374 4363   * Returns true only if none of this service's dependents are 'up' -- online
4375 4364   * or degraded (offline is considered down in this situation). This function
4376 4365   * is somehow similar to is_nonsubgraph_leaf() but works on subtrees.
4377 4366   */
4378      -static boolean_t
     4367 +boolean_t
4379 4368  insubtree_dependents_down(graph_vertex_t *v)
4380 4369  {
4381 4370          graph_vertex_t *vv;
4382 4371          graph_edge_t *e;
4383 4372  
4384 4373          assert(MUTEX_HELD(&dgraph_lock));
4385 4374  
4386 4375          for (e = uu_list_first(v->gv_dependents); e != NULL;
4387 4376              e = uu_list_next(v->gv_dependents, e)) {
4388 4377                  vv = e->ge_vertex;
4389 4378                  if (vv->gv_type == GVT_INST) {
4390 4379                          if ((vv->gv_flags & GV_CONFIGURED) == 0)
4391 4380                                  continue;
4392 4381  
4393 4382                          if ((vv->gv_flags & GV_TOOFFLINE) == 0)
4394      -                                continue;
     4383 +                                return (B_FALSE);
4395 4384  
4396 4385                          if ((vv->gv_state == RESTARTER_STATE_ONLINE) ||
4397 4386                              (vv->gv_state == RESTARTER_STATE_DEGRADED))
4398 4387                                  return (B_FALSE);
4399 4388                  } else {
4400 4389                          /*
4401      -                         * Skip all excluded and optional_all dependencies
4402      -                         * and decide whether to offline the service based
4403      -                         * on restart_on attribute.
     4390 +                         * Skip all excluded dependencies and decide whether
     4391 +                         * decide whether to offline the service based on the
     4392 +                         * restart_on attribute.
4404 4393                           */
4405 4394                          if (is_depgrp_bypassed(vv))
4406 4395                                  continue;
4407 4396  
4408 4397                          /*
4409 4398                           * For dependency groups or service vertices, keep
4410 4399                           * traversing to see if instances are running.
4411 4400                           */
4412 4401                          if (insubtree_dependents_down(vv) == B_FALSE)
4413 4402                                  return (B_FALSE);
↓ open down ↓ 141 lines elided ↑ open up ↑
4555 4544  /*
4556 4545   * Of the transitive instance dependencies of v, offline those which are
4557 4546   * in the subtree and which are leaves (i.e., have no dependents which are
4558 4547   * "up").
4559 4548   */
4560 4549  void
4561 4550  offline_subtree_leaves(graph_vertex_t *v, void *arg)
4562 4551  {
4563 4552          assert(MUTEX_HELD(&dgraph_lock));
4564 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 +
4565 4563          /* If v isn't an instance, recurse on its dependencies. */
4566 4564          if (v->gv_type != GVT_INST) {
4567 4565                  graph_walk_dependencies(v, offline_subtree_leaves, arg);
4568 4566                  return;
4569 4567          }
4570 4568  
4571 4569          /*
4572 4570           * If v is not in the subtree, so should all of its dependencies,
4573 4571           * so do nothing.
4574 4572           */
↓ open down ↓ 879 lines elided ↑ open up ↑
5454 5452          case GVT_INST:
5455 5453                  /* If the instance is already disabled, skip it. */
5456 5454                  if (!(v->gv_flags & GV_ENABLED))
5457 5455                          return (UU_WALK_NEXT);
5458 5456  
5459 5457                  v->gv_flags |= GV_TOOFFLINE;
5460 5458                  log_framework(LOG_DEBUG, "%s added to subtree\n", v->gv_name);
5461 5459                  break;
5462 5460          case GVT_GROUP:
5463 5461                  /*
5464      -                 * Skip all excluded and optional_all dependencies and decide
5465      -                 * whether to offline the service based on restart_on attribute.
     5462 +                 * Skip all excluded dependencies and decide whether to offline
     5463 +                 * the service based on the restart_on attribute.
5466 5464                   */
5467 5465                  if (is_depgrp_bypassed(v))
5468 5466                          return (UU_WALK_NEXT);
5469 5467                  break;
5470 5468          }
5471 5469  
5472 5470          r = uu_list_walk(v->gv_dependents, (uu_walk_fn_t *)mark_subtree, arg,
5473 5471              0);
5474 5472          assert(r == 0);
5475 5473          return (UU_WALK_NEXT);
↓ open down ↓ 1457 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX