Print this page
2594 implement graceful shutdown for local zones in zoneadm

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/zoneadmd/zoneadmd.c
          +++ new/usr/src/cmd/zoneadmd/zoneadmd.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  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) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  24   25   */
  25   26  
  26   27  /*
  27   28   * zoneadmd manages zones; one zoneadmd process is launched for each
  28   29   * non-global zone on the system.  This daemon juggles four jobs:
  29   30   *
  30   31   * - Implement setup and teardown of the zone "virtual platform": mount and
  31   32   *   unmount filesystems; create and destroy network interfaces; communicate
  32   33   *   with devfsadmd to lay out devices for the zone; instantiate the zone
  33   34   *   console device; configure process runtime attributes such as resource
↓ open down ↓ 58 lines elided ↑ open up ↑
  92   93  #include <zone.h>
  93   94  #include <libbrand.h>
  94   95  #include <sys/brand.h>
  95   96  #include <libcontract.h>
  96   97  #include <libcontract_priv.h>
  97   98  #include <sys/brand.h>
  98   99  #include <sys/contract/process.h>
  99  100  #include <sys/ctfs.h>
 100  101  #include <libdladm.h>
 101  102  #include <sys/dls_mgmt.h>
      103 +#include <libscf.h>
 102  104  
 103  105  #include <libzonecfg.h>
 104  106  #include <zonestat_impl.h>
 105  107  #include "zoneadmd.h"
 106  108  
 107  109  static char *progname;
 108  110  char *zone_name;        /* zone which we are managing */
 109  111  char pool_name[MAXNAMELEN];
 110  112  char default_brand[MAXNAMELEN];
 111  113  char brand_name[MAXNAMELEN];
 112  114  boolean_t zone_isnative;
 113  115  boolean_t zone_iscluster;
 114  116  boolean_t zone_islabeled;
      117 +boolean_t shutdown_in_progress;
 115  118  static zoneid_t zone_id;
 116  119  dladm_handle_t dld_handle = NULL;
 117  120  
 118  121  static char pre_statechg_hook[2 * MAXPATHLEN];
 119  122  static char post_statechg_hook[2 * MAXPATHLEN];
 120  123  char query_hook[2 * MAXPATHLEN];
 121  124  
 122  125  zlog_t logsys;
 123  126  
 124  127  mutex_t lock = DEFAULTMUTEX;    /* to serialize stuff */
↓ open down ↓ 12 lines elided ↑ open up ↑
 137  140  #endif
 138  141  
 139  142  #define DEFAULT_LOCALE  "C"
 140  143  
 141  144  static const char *
 142  145  z_cmd_name(zone_cmd_t zcmd)
 143  146  {
 144  147          /* This list needs to match the enum in sys/zone.h */
 145  148          static const char *zcmdstr[] = {
 146  149                  "ready", "boot", "forceboot", "reboot", "halt",
 147      -                "note_uninstalling", "mount", "forcemount", "unmount"
      150 +                "note_uninstalling", "mount", "forcemount", "unmount",
      151 +                "shutdown"
 148  152          };
 149  153  
 150  154          if (zcmd >= sizeof (zcmdstr) / sizeof (*zcmdstr))
 151  155                  return ("unknown");
 152  156          else
 153  157                  return (zcmdstr[(int)zcmd]);
 154  158  }
 155  159  
 156  160  static char *
 157  161  get_execbasename(char *execfullname)
↓ open down ↓ 821 lines elided ↑ open up ↑
 979  983          if ((err = zonecfg_destroy_snapshot(zone_name)) != Z_OK)
 980  984                  zerror(zlogp, B_FALSE, "destroying snapshot: %s",
 981  985                      zonecfg_strerror(err));
 982  986  
 983  987          if (brand_poststatechg(zlogp, zstate, Z_HALT) != 0)
 984  988                  return (-1);
 985  989  
 986  990          return (0);
 987  991  }
 988  992  
      993 +static int
      994 +zone_graceful_shutdown(zlog_t *zlogp)
      995 +{
      996 +        zoneid_t zoneid;
      997 +        pid_t child;
      998 +        char cmdbuf[MAXPATHLEN];
      999 +        brand_handle_t bh = NULL;
     1000 +        char zpath[MAXPATHLEN];
     1001 +        ctid_t ct;
     1002 +        int tmpl_fd;
     1003 +        int child_status;
     1004 +
     1005 +        if (shutdown_in_progress) {
     1006 +                zerror(zlogp, B_FALSE, "shutdown already in progress");
     1007 +                return (-1);
     1008 +        }
     1009 +
     1010 +        if ((zoneid = getzoneidbyname(zone_name)) == -1) {
     1011 +                zerror(zlogp, B_TRUE, "unable to get zoneid");
     1012 +                return (-1);
     1013 +        }
     1014 +
     1015 +        /* Get a handle to the brand info for this zone */
     1016 +        if ((bh = brand_open(brand_name)) == NULL) {
     1017 +                zerror(zlogp, B_FALSE, "unable to determine zone brand");
     1018 +                return (-1);
     1019 +        }
     1020 +
     1021 +        if (zone_get_zonepath(zone_name, zpath, sizeof (zpath)) != Z_OK) {
     1022 +                zerror(zlogp, B_FALSE, "unable to determine zone path");
     1023 +                brand_close(bh);
     1024 +                return (-1);
     1025 +        }
     1026 +
     1027 +        /*
     1028 +         * If there is a brand 'shutdown' callback, execute it now to give the
     1029 +         * brand a chance to cleanup any custom configuration.
     1030 +         */
     1031 +        (void) strcpy(cmdbuf, EXEC_PREFIX);
     1032 +        if (brand_get_shutdown(bh, zone_name, zpath, cmdbuf + EXEC_LEN,
     1033 +            sizeof (cmdbuf) - EXEC_LEN) != 0 || strlen(cmdbuf) <= EXEC_LEN) {
     1034 +                (void) strcat(cmdbuf, SHUTDOWN_DEFAULT);
     1035 +        }
     1036 +        brand_close(bh);
     1037 +
     1038 +        if ((tmpl_fd = init_template()) == -1) {
     1039 +                zerror(zlogp, B_TRUE, "failed to create contract");
     1040 +                return (-1);
     1041 +        }
     1042 +
     1043 +        if ((child = fork()) == -1) {
     1044 +                (void) ct_tmpl_clear(tmpl_fd);
     1045 +                (void) close(tmpl_fd);
     1046 +                zerror(zlogp, B_TRUE, "failed to fork");
     1047 +                return (-1);
     1048 +        } else if (child == 0) {
     1049 +                (void) ct_tmpl_clear(tmpl_fd);
     1050 +                if (zone_enter(zoneid) == -1) {
     1051 +                        _exit(errno);
     1052 +                }
     1053 +                _exit(execl("/bin/sh", "sh", "-c", cmdbuf, (char *)NULL));
     1054 +        }
     1055 +
     1056 +        if (contract_latest(&ct) == -1)
     1057 +                ct = -1;
     1058 +        (void) ct_tmpl_clear(tmpl_fd);
     1059 +        (void) close(tmpl_fd);
     1060 +
     1061 +        if (waitpid(child, &child_status, 0) != child) {
     1062 +                /* unexpected: we must have been signalled */
     1063 +                (void) contract_abandon_id(ct);
     1064 +                return (-1);
     1065 +        }
     1066 +
     1067 +        (void) contract_abandon_id(ct);
     1068 +        if (WEXITSTATUS(child_status) != 0) {
     1069 +                errno = WEXITSTATUS(child_status);
     1070 +                zerror(zlogp, B_FALSE, "unable to shutdown zone");
     1071 +                return (-1);
     1072 +        }
     1073 +
     1074 +        shutdown_in_progress = B_TRUE;
     1075 +
     1076 +        return (0);
     1077 +}
     1078 +
     1079 +static int
     1080 +zone_wait_shutdown(zlog_t *zlogp)
     1081 +{
     1082 +        zone_state_t zstate;
     1083 +        uint64_t *tm = NULL;
     1084 +        scf_simple_prop_t *prop = NULL;
     1085 +        int timeout;
     1086 +        int tries;
     1087 +        int rc = -1;
     1088 +
     1089 +        /* Get default stop timeout from SMF framework */
     1090 +        timeout = SHUTDOWN_WAIT;
     1091 +        if ((prop = scf_simple_prop_get(NULL, SHUTDOWN_FMRI, "stop",
     1092 +            SCF_PROPERTY_TIMEOUT)) != NULL) {
     1093 +                if ((tm = scf_simple_prop_next_count(prop)) != NULL) {
     1094 +                        if (tm != 0)
     1095 +                                timeout = *tm;
     1096 +                }
     1097 +                scf_simple_prop_free(prop);
     1098 +        }
     1099 +
     1100 +        /* allow time for zone to shutdown cleanly */
     1101 +        for (tries = 0; tries < timeout; tries ++) {
     1102 +                (void) sleep(1);
     1103 +                if (zone_get_state(zone_name, &zstate) == Z_OK &&
     1104 +                    zstate == ZONE_STATE_INSTALLED) {
     1105 +                        rc = 0;
     1106 +                        break;
     1107 +                }
     1108 +        }
     1109 +
     1110 +        if (rc != 0)
     1111 +                zerror(zlogp, B_FALSE, "unable to shutdown zone");
     1112 +
     1113 +        shutdown_in_progress = B_FALSE;
     1114 +
     1115 +        return (rc);
     1116 +}
     1117 +
     1118 +
     1119 +
 989 1120  /*
 990 1121   * Generate AUE_zone_state for a command that boots a zone.
 991 1122   */
 992 1123  static void
 993 1124  audit_put_record(zlog_t *zlogp, ucred_t *uc, int return_val,
 994 1125      char *new_state)
 995 1126  {
 996 1127          adt_session_data_t      *ah;
 997 1128          adt_event_data_t        *event;
 998 1129          int                     pass_fail, fail_reason;
↓ open down ↓ 55 lines elided ↑ open up ↑
1054 1185  
1055 1186          int rval = -1;
1056 1187          uint64_t uniqid;
1057 1188          zoneid_t zoneid = -1;
1058 1189          zlog_t zlog;
1059 1190          zlog_t *zlogp;
1060 1191          zone_cmd_rval_t *rvalp;
1061 1192          size_t rlen = getpagesize(); /* conservative */
1062 1193          fs_callback_t cb;
1063 1194          brand_handle_t bh;
     1195 +        boolean_t wait_shut = B_FALSE;
1064 1196  
1065 1197          /* LINTED E_BAD_PTR_CAST_ALIGN */
1066 1198          zargp = (zone_cmd_arg_t *)args;
1067 1199  
1068 1200          /*
1069 1201           * When we get the door unref message, we've fdetach'd the door, and
1070 1202           * it is time for us to shut down zoneadmd.
1071 1203           */
1072 1204          if (zargp == DOOR_UNREF_DATA) {
1073 1205                  /*
↓ open down ↓ 56 lines elided ↑ open up ↑
1130 1262                  (void) mutex_unlock(&lock);
1131 1263                  ucred_free(uc);
1132 1264                  (void) door_return(NULL, 0, 0, 0);
1133 1265                  thr_exit(NULL);
1134 1266          }
1135 1267  
1136 1268          /*
1137 1269           * Check for validity of command.
1138 1270           */
1139 1271          if (cmd != Z_READY && cmd != Z_BOOT && cmd != Z_FORCEBOOT &&
1140      -            cmd != Z_REBOOT && cmd != Z_HALT && cmd != Z_NOTE_UNINSTALLING &&
1141      -            cmd != Z_MOUNT && cmd != Z_FORCEMOUNT && cmd != Z_UNMOUNT) {
     1272 +            cmd != Z_REBOOT && cmd != Z_SHUTDOWN && cmd != Z_HALT &&
     1273 +            cmd != Z_NOTE_UNINSTALLING && cmd != Z_MOUNT &&
     1274 +            cmd != Z_FORCEMOUNT && cmd != Z_UNMOUNT) {
1142 1275                  zerror(&logsys, B_FALSE, "invalid command %d", (int)cmd);
1143 1276                  goto out;
1144 1277          }
1145 1278  
1146 1279          if (kernelcall && (cmd != Z_HALT && cmd != Z_REBOOT)) {
1147 1280                  /*
1148 1281                   * Can't happen
1149 1282                   */
1150 1283                  zerror(&logsys, B_FALSE, "received unexpected kernel upcall %d",
1151 1284                      cmd);
↓ open down ↓ 65 lines elided ↑ open up ↑
1217 1350                                      zstate);
1218 1351                          }
1219 1352                          audit_put_record(zlogp, uc, rval, "boot");
1220 1353                          if (rval != 0) {
1221 1354                                  bringup_failure_recovery = B_TRUE;
1222 1355                                  (void) zone_halt(zlogp, B_FALSE, B_FALSE,
1223 1356                                      zstate);
1224 1357                                  eventstream_write(Z_EVT_ZONE_BOOTFAILED);
1225 1358                          }
1226 1359                          break;
     1360 +                case Z_SHUTDOWN:
1227 1361                  case Z_HALT:
1228 1362                          if (kernelcall) /* Invalid; can't happen */
1229 1363                                  abort();
1230 1364                          /*
1231 1365                           * We could have two clients racing to halt this
1232 1366                           * zone; the second client loses, but his request
1233 1367                           * doesn't fail, since the zone is now in the desired
1234 1368                           * state.
1235 1369                           */
1236 1370                          zerror(zlogp, B_FALSE, "zone is already halted");
↓ open down ↓ 110 lines elided ↑ open up ↑
1347 1481                          boot_args[0] = '\0';
1348 1482                          break;
1349 1483                  case Z_HALT:
1350 1484                          if (kernelcall) /* Invalid; can't happen */
1351 1485                                  abort();
1352 1486                          if ((rval = zone_halt(zlogp, B_FALSE, B_FALSE, zstate))
1353 1487                              != 0)
1354 1488                                  break;
1355 1489                          eventstream_write(Z_EVT_ZONE_HALTED);
1356 1490                          break;
     1491 +                case Z_SHUTDOWN:
1357 1492                  case Z_REBOOT:
1358 1493                  case Z_NOTE_UNINSTALLING:
1359 1494                  case Z_MOUNT:
1360 1495                  case Z_UNMOUNT:
1361 1496                          if (kernelcall) /* Invalid; can't happen */
1362 1497                                  abort();
1363 1498                          zerror(zlogp, B_FALSE, "%s operation is invalid "
1364 1499                              "for zones in state '%s'", z_cmd_name(cmd),
1365 1500                              zone_state_str(zstate));
1366 1501                          rval = -1;
↓ open down ↓ 70 lines elided ↑ open up ↑
1437 1572                          }
1438 1573                          rval = zone_bootup(zlogp, zargp->bootbuf, zstate);
1439 1574                          audit_put_record(zlogp, uc, rval, "reboot");
1440 1575                          if (rval != 0) {
1441 1576                                  (void) zone_halt(zlogp, B_FALSE, B_TRUE,
1442 1577                                      zstate);
1443 1578                                  eventstream_write(Z_EVT_ZONE_BOOTFAILED);
1444 1579                          }
1445 1580                          boot_args[0] = '\0';
1446 1581                          break;
     1582 +                case Z_SHUTDOWN:
     1583 +                        if ((rval = zone_graceful_shutdown(zlogp)) == 0) {
     1584 +                                wait_shut = B_TRUE;
     1585 +                        }
     1586 +                        break;
1447 1587                  case Z_NOTE_UNINSTALLING:
1448 1588                  case Z_MOUNT:
1449 1589                  case Z_UNMOUNT:
1450 1590                          zerror(zlogp, B_FALSE, "%s operation is invalid "
1451 1591                              "for zones in state '%s'", z_cmd_name(cmd),
1452 1592                              zone_state_str(zstate));
1453 1593                          rval = -1;
1454 1594                          break;
1455 1595                  }
1456 1596                  break;
↓ open down ↓ 3 lines elided ↑ open up ↑
1460 1600  
1461 1601          /*
1462 1602           * Because the state of the zone may have changed, we make sure
1463 1603           * to wake the console poller, which is in charge of initiating
1464 1604           * the shutdown procedure as necessary.
1465 1605           */
1466 1606          eventstream_write(Z_EVT_NULL);
1467 1607  
1468 1608  out:
1469 1609          (void) mutex_unlock(&lock);
     1610 +
     1611 +        /* Wait for the Z_SHUTDOWN commands to complete */
     1612 +        if (wait_shut)
     1613 +                rval = zone_wait_shutdown(zlogp);
     1614 +
1470 1615          if (kernelcall) {
1471 1616                  rvalp = NULL;
1472 1617                  rlen = 0;
1473 1618          } else {
1474 1619                  rvalp->rval = rval;
1475 1620          }
1476 1621          if (uc != NULL)
1477 1622                  ucred_free(uc);
1478 1623          (void) door_return((char *)rvalp, rlen, NULL, 0);
1479 1624          thr_exit(NULL);
↓ open down ↓ 657 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX