/* * init_zfd_devs() drives the device-tree configuration of the zone fd devices. * The general strategy is to use the libdevice (devctl) interfaces to * instantiate 3 new zone fd nodes. We do a lot of sanity checking, and * are careful to reuse a dev if one exists. * * Once the devices are in the device tree, we kick devfsadm via * di_devlink_init() to ensure that the appropriate symlinks (to the master and * slave fd devices) are placed in /dev in the global zone. */ static int init_zfd_dev(zlog_t *zlogp, devctl_hdl_t bus_hdl, int id) { int rv = -1; devctl_ddef_t ddef_hdl = NULL; devctl_hdl_t dev_hdl = NULL; if ((ddef_hdl = devctl_ddef_alloc("zfd", 0)) == NULL) { zerror(zlogp, B_TRUE, "failed to allocate ddef handle"); goto error; } /* * Set four properties on this node; the first is the name of the * zone; the second is a flag which lets pseudo know that it is * OK to automatically allocate an instance # for this device; * the third tells the device framework not to auto-detach this * node-- we need the node to still be there when we ask devfsadmd * to make links, and when we need to open it. */ if (devctl_ddef_string(ddef_hdl, "zfd_zname", zone_name) == -1) { zerror(zlogp, B_TRUE, "failed to create zfd_zname property"); goto error; } if (devctl_ddef_int(ddef_hdl, "zfd_id", id) == -1) { zerror(zlogp, B_TRUE, "failed to create zfd_id property"); goto error; } if (devctl_ddef_int(ddef_hdl, "auto-assign-instance", 1) == -1) { zerror(zlogp, B_TRUE, "failed to create auto-assign-instance " "property"); goto error; } if (devctl_ddef_int(ddef_hdl, "ddi-no-autodetach", 1) == -1) { zerror(zlogp, B_TRUE, "failed to create ddi-no-auto-detach " "property"); goto error; } if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl) == -1) { zerror(zlogp, B_TRUE, "failed to create zfd node"); goto error; } rv = 0; error: if (ddef_hdl) devctl_ddef_free(ddef_hdl); if (dev_hdl) devctl_release(dev_hdl); return (rv); }
/* * init_console_dev() drives the device-tree configuration of the zone * console device. The general strategy is to use the libdevice (devctl) * interfaces to instantiate a new zone console node. We do a lot of * sanity checking, and are careful to reuse a console if one exists. * * Once the device is in the device tree, we kick devfsadm via di_devlink_init() * to ensure that the appropriate symlinks (to the master and slave console * devices) are placed in /dev in the global zone. */ static int init_console_dev(zlog_t *zlogp) { char conspath[MAXPATHLEN]; devctl_hdl_t bus_hdl = NULL; devctl_hdl_t dev_hdl = NULL; devctl_ddef_t ddef_hdl = NULL; di_devlink_handle_t dl = NULL; int rv = -1; int ndevs; int masterfd; int slavefd; int i; /* * Don't re-setup console if it is working and ready already; just * skip ahead to making devlinks, which we do for sanity's sake. */ ndevs = count_console_devs(zlogp); if (ndevs == 1) { goto devlinks; } else if (ndevs > 1 || ndevs == -1) { /* * For now, this seems like a reasonable but harsh punishment. * If needed, we could try to get clever and delete all but * the console which is pointed at by the current symlink. */ if (destroy_console_devs(zlogp) == -1) { goto error; } } /* * Time to make the consoles! */ if ((bus_hdl = devctl_bus_acquire(ZCONSNEX_FILEPATH, 0)) == NULL) { zerror(zlogp, B_TRUE, "%s failed", "devctl_bus_acquire"); goto error; } if ((ddef_hdl = devctl_ddef_alloc("zcons", 0)) == NULL) { zerror(zlogp, B_TRUE, "failed to allocate ddef handle"); goto error; } /* * Set three properties on this node; the first is the name of the * zone; the second is a flag which lets pseudo know that it is * OK to automatically allocate an instance # for this device; * the third tells the device framework not to auto-detach this * node-- we need the node to still be there when we ask devfsadmd * to make links, and when we need to open it. */ if (devctl_ddef_string(ddef_hdl, "zonename", zone_name) == -1) { zerror(zlogp, B_TRUE, "failed to create zonename property"); goto error; } if (devctl_ddef_int(ddef_hdl, "auto-assign-instance", 1) == -1) { zerror(zlogp, B_TRUE, "failed to create auto-assign-instance " "property"); goto error; } if (devctl_ddef_int(ddef_hdl, "ddi-no-autodetach", 1) == -1) { zerror(zlogp, B_TRUE, "failed to create ddi-no-auto-detach " "property"); goto error; } if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl) == -1) { zerror(zlogp, B_TRUE, "failed to create console node"); goto error; } devlinks: if ((dl = di_devlink_init("zcons", DI_MAKE_LINK)) != NULL) { (void) di_devlink_fini(&dl); } else { zerror(zlogp, B_TRUE, "failed to create devlinks"); goto error; } /* * Open the master side of the console and issue the ZC_HOLDSLAVE ioctl, * which will cause the master to retain a reference to the slave. * This prevents ttymon from blowing through the slave's STREAMS anchor. * * In very rare cases the open returns ENOENT if devfs doesn't have * everything setup yet due to heavy zone startup load. Wait for * 1 sec. and retry a few times. Even if we can't setup the zone's * console, we still go ahead and boot the zone. */ (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s", zone_name, ZCONS_MASTER_NAME); for (i = 0; i < ZCONS_RETRY; i++) { masterfd = open(conspath, O_RDWR | O_NOCTTY); if (masterfd >= 0 || errno != ENOENT) break; (void) sleep(1); } if (masterfd == -1) { zerror(zlogp, B_TRUE, "ERROR: could not open master side of " "zone console for %s to acquire slave handle", zone_name); master_zcons_failed = B_TRUE; } (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s", zone_name, ZCONS_SLAVE_NAME); for (i = 0; i < ZCONS_RETRY; i++) { slavefd = open(conspath, O_RDWR | O_NOCTTY); if (slavefd >= 0 || errno != ENOENT) break; (void) sleep(1); } if (slavefd == -1) zerror(zlogp, B_TRUE, "ERROR: could not open slave side of zone" " console for %s to acquire slave handle", zone_name); /* * This ioctl can occasionally return ENXIO if devfs doesn't have * everything plumbed up yet due to heavy zone startup load. Wait for * 1 sec. and retry a few times before we fail to boot the zone. */ if (masterfd != -1 && slavefd != -1) { for (i = 0; i < ZCONS_RETRY; i++) { if (ioctl(masterfd, ZC_HOLDSLAVE, (caddr_t)(intptr_t)slavefd) == 0) { rv = 0; break; } else if (errno != ENXIO) { break; } (void) sleep(1); } if (rv != 0) zerror(zlogp, B_TRUE, "ERROR: error while acquiring " "slave handle of zone console for %s", zone_name); } if (slavefd != -1) (void) close(slavefd); if (masterfd != -1) (void) close(masterfd); error: if (ddef_hdl) devctl_ddef_free(ddef_hdl); if (bus_hdl) devctl_release(bus_hdl); if (dev_hdl) devctl_release(dev_hdl); return (rv); }