Print this page
Merge cleanup from previous six commits
OS-2564 zone boot failed: could not start zoneadmd

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/zoneadmd/zcons.c
          +++ new/usr/src/cmd/zoneadmd/zcons.c
↓ open down ↓ 110 lines elided ↑ open up ↑
 111  111  #include <syslog.h>
 112  112  #include <sys/modctl.h>
 113  113  
 114  114  #include "zoneadmd.h"
 115  115  
 116  116  #define ZCONSNEX_DEVTREEPATH    "/pseudo/zconsnex@1"
 117  117  #define ZCONSNEX_FILEPATH       "/devices/pseudo/zconsnex@1"
 118  118  
 119  119  #define CONSOLE_SOCKPATH        ZONES_TMPDIR "/%s.console_sock"
 120  120  
      121 +#define ZCONS_RETRY             10
      122 +
 121  123  static int      serverfd = -1;  /* console server unix domain socket fd */
 122  124  char boot_args[BOOTARGS_MAX];
 123  125  
 124  126  /*
 125  127   * The eventstream is a simple one-directional flow of messages from the
 126  128   * door server to the console subsystem, implemented with a pipe.
 127  129   * It is used to wake up the console poller when it needs to take action,
 128  130   * message the user, die off, etc.
 129  131   */
 130  132  static int eventstream[2];
 131  133  
      134 +/* flag used to cope with race creating master zcons devlink */
      135 +static boolean_t master_zcons_failed = B_FALSE;
      136 +/* flag to track if we've seen a state change when there is no master zcons */
      137 +static boolean_t state_changed = B_FALSE;
 132  138  
 133      -
 134  139  int
 135  140  eventstream_init()
 136  141  {
 137  142          if (pipe(eventstream) == -1)
 138  143                  return (-1);
 139  144          return (0);
 140  145  }
 141  146  
 142  147  void
 143  148  eventstream_write(zone_evt_t evt)
↓ open down ↓ 256 lines elided ↑ open up ↑
 400  405                  (void) di_devlink_fini(&dl);
 401  406          } else {
 402  407                  zerror(zlogp, B_TRUE, "failed to create devlinks");
 403  408                  goto error;
 404  409          }
 405  410  
 406  411          /*
 407  412           * Open the master side of the console and issue the ZC_HOLDSLAVE ioctl,
 408  413           * which will cause the master to retain a reference to the slave.
 409  414           * This prevents ttymon from blowing through the slave's STREAMS anchor.
      415 +         *
      416 +         * In very rare cases the open returns ENOENT if devfs doesn't have
      417 +         * everything setup yet due to heavy zone startup load. Wait for
      418 +         * 1 sec. and retry a few times. Even if we can't setup the zone's
      419 +         * console, we still go ahead and boot the zone.
 410  420           */
 411  421          (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
 412  422              zone_name, ZCONS_MASTER_NAME);
 413  423          if ((masterfd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
 414  424                  zerror(zlogp, B_TRUE, "ERROR: could not open master side of "
 415  425                      "zone console for %s to acquire slave handle", zone_name);
 416      -                goto error;
      426 +                master_zcons_failed = B_TRUE;
 417  427          }
 418  428          (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
 419  429              zone_name, ZCONS_SLAVE_NAME);
 420      -        if ((slavefd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
      430 +        for (i = 0; i < ZCONS_RETRY; i++) {
      431 +                slavefd = open(conspath, O_RDWR | O_NOCTTY);
      432 +                if (slavefd >= 0 || errno != ENOENT)
      433 +                        break;
      434 +                (void) sleep(1);
      435 +        }
      436 +        if (slavefd == -1)
 421  437                  zerror(zlogp, B_TRUE, "ERROR: could not open slave side of zone"
 422  438                      " console for %s to acquire slave handle", zone_name);
 423      -                (void) close(masterfd);
 424      -                goto error;
 425      -        }
      439 +
 426  440          /*
 427  441           * This ioctl can occasionally return ENXIO if devfs doesn't have
 428  442           * everything plumbed up yet due to heavy zone startup load. Wait for
 429  443           * 1 sec. and retry a few times before we fail to boot the zone.
 430  444           */
 431      -        for (i = 0; i < 5; i++) {
 432      -                if (ioctl(masterfd, ZC_HOLDSLAVE, (caddr_t)(intptr_t)slavefd)
 433      -                    == 0) {
 434      -                        rv = 0;
 435      -                        break;
 436      -                } else if (errno != ENXIO) {
 437      -                        break;
      445 +        if (masterfd != -1 && slavefd != -1) {
      446 +                for (i = 0; i < ZCONS_RETRY; i++) {
      447 +                        if (ioctl(masterfd, ZC_HOLDSLAVE,
      448 +                            (caddr_t)(intptr_t)slavefd) == 0) {
      449 +                                rv = 0;
      450 +                                break;
      451 +                        } else if (errno != ENXIO) {
      452 +                                break;
      453 +                        }
      454 +                        (void) sleep(1);
 438  455                  }
 439      -                (void) sleep(1);
      456 +                if (rv != 0)
      457 +                        zerror(zlogp, B_TRUE, "ERROR: error while acquiring "
      458 +                            "slave handle of zone console for %s", zone_name);
 440  459          }
 441      -        if (rv != 0)
 442      -                zerror(zlogp, B_TRUE, "ERROR: error while acquiring slave "
 443      -                    "handle of zone console for %s", zone_name);
 444  460  
 445      -        (void) close(slavefd);
 446      -        (void) close(masterfd);
      461 +        if (slavefd != -1)
      462 +                (void) close(slavefd);
      463 +        if (masterfd != -1)
      464 +                (void) close(masterfd);
 447  465  
 448  466  error:
 449  467          if (ddef_hdl)
 450  468                  devctl_ddef_free(ddef_hdl);
 451  469          if (bus_hdl)
 452  470                  devctl_release(bus_hdl);
 453  471          if (dev_hdl)
 454  472                  devctl_release(dev_hdl);
 455  473          return (rv);
 456  474  }
↓ open down ↓ 410 lines elided ↑ open up ↑
 867  885                  (void) close(clifd);
 868  886          }
 869  887  }
 870  888  
 871  889  int
 872  890  init_console(zlog_t *zlogp)
 873  891  {
 874  892          if (init_console_dev(zlogp) == -1) {
 875  893                  zerror(zlogp, B_FALSE,
 876  894                      "console setup: device initialization failed");
 877      -                return (-1);
 878  895          }
 879  896  
 880  897          if ((serverfd = init_console_sock(zlogp)) == -1) {
 881  898                  zerror(zlogp, B_FALSE,
 882  899                      "console setup: socket initialization failed");
 883  900                  return (-1);
 884  901          }
 885  902          return (0);
 886  903  }
 887  904  
 888  905  /*
      906 + * Maintain a simple flag that tracks if we have seen at least one state
      907 + * change. This is currently only used to handle the special case where we are
      908 + * running without a console device, which is what normally drives shutdown.
      909 + */
      910 +void
      911 +zcons_statechanged()
      912 +{
      913 +        state_changed = B_TRUE;
      914 +}
      915 +
      916 +/*
 889  917   * serve_console() is the master loop for driving console I/O.  It is also the
 890  918   * routine which is ultimately responsible for "pulling the plug" on zoneadmd
 891  919   * when it realizes that the daemon should shut down.
 892  920   *
 893  921   * The rules for shutdown are: there must be no console client, and the zone
 894  922   * state must be < ready.  However, we need to give things a chance to actually
 895  923   * get going when the daemon starts up-- otherwise the daemon would immediately
 896  924   * exit on startup if the zone was in the installed state, so we first drop
 897  925   * into the do_console_io() loop in order to give *something* a chance to
 898  926   * happen.
 899  927   */
 900  928  void
 901  929  serve_console(zlog_t *zlogp)
 902  930  {
 903  931          int masterfd;
 904  932          zone_state_t zstate;
 905  933          char conspath[MAXPATHLEN];
      934 +        static boolean_t cons_warned = B_FALSE;
 906  935  
 907  936          (void) snprintf(conspath, sizeof (conspath),
 908  937              "/dev/zcons/%s/%s", zone_name, ZCONS_MASTER_NAME);
 909  938  
 910  939          for (;;) {
 911  940                  masterfd = open(conspath, O_RDWR|O_NONBLOCK|O_NOCTTY);
 912  941                  if (masterfd == -1) {
      942 +                        if (master_zcons_failed) {
      943 +                                /*
      944 +                                 * If we don't have a console and the zone is
      945 +                                 * not shutting down, there may have been a
      946 +                                 * race/failure with devfs while creating the
      947 +                                 * console. In this case we want to leave the
      948 +                                 * zone up, even without a console, so
      949 +                                 * periodically recheck.
      950 +                                 */
      951 +                                int i;
      952 +
      953 +                                /*
      954 +                                 * In the normal flow of this loop, we use
      955 +                                 * do_console_io to give things a chance to get
      956 +                                 * going first. However, in this case we can't
      957 +                                 * use that, so we have to wait for at least
      958 +                                 * one state change before checking the state.
      959 +                                 */
      960 +                                for (i = 0; i < 60; i++) {
      961 +                                        if (state_changed)
      962 +                                                break;
      963 +                                        (void) sleep(1);
      964 +                                }
      965 +
      966 +                                if (i < 60 && zone_get_state(zone_name,
      967 +                                    &zstate) == Z_OK &&
      968 +                                    (zstate == ZONE_STATE_READY ||
      969 +                                    zstate == ZONE_STATE_RUNNING)) {
      970 +                                        if (!cons_warned) {
      971 +                                                zerror(zlogp, B_FALSE,
      972 +                                                    "WARNING: missing zone "
      973 +                                                    "console for %s",
      974 +                                                    zone_name);
      975 +                                                cons_warned = B_TRUE;
      976 +                                        }
      977 +                                        (void) sleep(ZCONS_RETRY);
      978 +                                        continue;
      979 +                                }
      980 +                        }
      981 +
 913  982                          zerror(zlogp, B_TRUE, "failed to open console master");
 914  983                          (void) mutex_lock(&lock);
 915  984                          goto death;
 916  985                  }
 917  986  
 918  987                  /*
 919  988                   * Setting RPROTDIS on the stream means that the control
 920  989                   * portion of messages received (which we don't care about)
 921  990                   * will be discarded by the stream head.  If we allowed such
 922  991                   * messages, we wouldn't be able to use read(2), as it fails
↓ open down ↓ 51 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX