diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2011-02-07 12:02:10 -0700 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2011-02-07 12:02:10 -0700 |
commit | 0f446d5563ab9ed4b3de1b7b5ac44ee01ed62b58 (patch) | |
tree | bfb08e3c186bc4cd16395734b649d9e4e6de245c | |
parent | 4c78616eafcd9f9c2c9f9327da1b97025c9854e9 (diff) | |
download | illumos-joyent-0f446d5563ab9ed4b3de1b7b5ac44ee01ed62b58.tar.gz |
OS-200 need a better mechanism for storing persistent zone_did
-rw-r--r-- | usr/src/cmd/zoneadm/zoneadm.c | 104 | ||||
-rw-r--r-- | usr/src/cmd/zoneadmd/zoneadmd.c | 51 | ||||
-rw-r--r-- | usr/src/cmd/zonecfg/zonecfg.c | 6 | ||||
-rw-r--r-- | usr/src/head/libzonecfg.h | 3 | ||||
-rw-r--r-- | usr/src/lib/libzonecfg/common/libzonecfg.c | 161 | ||||
-rw-r--r-- | usr/src/lib/libzonecfg/common/mapfile-vers | 4 | ||||
-rw-r--r-- | usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 | 2 |
7 files changed, 274 insertions, 57 deletions
diff --git a/usr/src/cmd/zoneadm/zoneadm.c b/usr/src/cmd/zoneadm/zoneadm.c index d0305b48a8..9931505a10 100644 --- a/usr/src/cmd/zoneadm/zoneadm.c +++ b/usr/src/cmd/zoneadm/zoneadm.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 201l, Joyent Inc. All rights reserved. */ /* @@ -99,6 +100,7 @@ typedef struct zone_entry { char zroot[MAXPATHLEN]; char zuuid[UUID_PRINTABLE_STRING_LENGTH]; zone_iptype_t ziptype; + zoneid_t zdid; } zone_entry_t; #define CLUSTER_BRAND_NAME "cluster" @@ -434,6 +436,7 @@ zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable) } if (!verbose) { char *cp, *clim; + char zdid[80]; if (!parsable) { (void) printf("%s\n", zent->zname); @@ -449,8 +452,12 @@ zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable) (void) printf("%.*s\\:", clim - cp, cp); cp = clim + 1; } - (void) printf("%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand, - ip_type_str); + if (zent->zdid == -1) + zdid[0] = '\0'; + else + (void) snprintf(zdid, sizeof (zdid), "%d", zent->zdid); + (void) printf("%s:%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand, + ip_type_str, zdid); return; } if (zent->zstate_str != NULL) { @@ -545,6 +552,22 @@ lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent) return (Z_OK); } + if ((handle = zonecfg_init_handle()) == NULL) { + zperror2(zent->zname, gettext("could not init handle")); + return (Z_ERR); + } + if ((err = zonecfg_get_handle(zent->zname, handle)) != Z_OK) { + zperror2(zent->zname, gettext("could not get handle")); + zonecfg_fini_handle(handle); + return (Z_ERR); + } + + if ((err = zonecfg_get_iptype(handle, &zent->ziptype)) != Z_OK) { + zperror2(zent->zname, gettext("could not get ip-type")); + zonecfg_fini_handle(handle); + return (Z_ERR); + } + /* * There is a race condition where the zone could boot while * we're walking the index file. In this case the zone state @@ -565,25 +588,11 @@ lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent) zent->ziptype = ZS_EXCLUSIVE; else zent->ziptype = ZS_SHARED; - return (Z_OK); } } - if ((handle = zonecfg_init_handle()) == NULL) { - zperror2(zent->zname, gettext("could not init handle")); - return (Z_ERR); - } - if ((err = zonecfg_get_handle(zent->zname, handle)) != Z_OK) { - zperror2(zent->zname, gettext("could not get handle")); - zonecfg_fini_handle(handle); - return (Z_ERR); - } + zent->zdid = zonecfg_get_did(handle); - if ((err = zonecfg_get_iptype(handle, &zent->ziptype)) != Z_OK) { - zperror2(zent->zname, gettext("could not get ip-type")); - zonecfg_fini_handle(handle); - return (Z_ERR); - } zonecfg_fini_handle(handle); return (Z_OK); @@ -2677,6 +2686,61 @@ no_net: return (return_code); } +/* + * Called when readying or booting a zone. We double check that the zone's + * debug ID is set and is unique. This covers the case of pre-existing zones + * with no ID. Also, its possible that a zone was migrated to this host + * and as a result it has a duplicate ID. In this case we preserve the ID + * of the first zone we match on in the index file (since it was there before + * the current zone) and we assign a new unique ID to the current zone. + * Return true if we assigned a new ID, indicating that the zone configuration + * needs to be saved. + */ +static boolean_t +verify_fix_did(zone_dochandle_t handle) +{ + zoneid_t mydid; + zone_entry_t zent; + FILE *cookie; + char *name; + boolean_t fix = B_FALSE; + + mydid = zonecfg_get_did(handle); + if (mydid == -1) { + zonecfg_set_did(handle); + return (B_TRUE); + } + + /* Get the full list of zones from the configuration. */ + cookie = setzoneent(); + while ((name = getzoneent(cookie)) != NULL) { + if (strcmp(target_zone, name) == 0) { + free(name); + break; /* Once we find our entry, stop. */ + } + + if (strcmp(name, "global") == 0 || + lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) { + free(name); + continue; + } + + free(name); + if (zent.zdid == mydid) { + fix = B_TRUE; + break; + } + } + endzoneent(cookie); + + if (fix) { + zonecfg_set_did(handle); + return (B_TRUE); + } + + return (B_FALSE); +} + static int verify_details(int cmd_num, char *argv[]) { @@ -2736,6 +2800,12 @@ verify_details(int cmd_num, char *argv[]) if (verify_handle(cmd_num, handle, argv) != Z_OK) return_code = Z_ERR; + if (cmd_num == CMD_READY || cmd_num == CMD_BOOT) + if (verify_fix_did(handle)) + if (zonecfg_save(handle) != Z_OK) + (void) fprintf(stderr, gettext("Could not save " + "debug ID.\n")); + zonecfg_fini_handle(handle); if (return_code == Z_ERR) (void) fprintf(stderr, diff --git a/usr/src/cmd/zoneadmd/zoneadmd.c b/usr/src/cmd/zoneadmd/zoneadmd.c index eb00aad1bb..9b7c1247d8 100644 --- a/usr/src/cmd/zoneadmd/zoneadmd.c +++ b/usr/src/cmd/zoneadmd/zoneadmd.c @@ -531,7 +531,7 @@ notify_zonestatd(zoneid_t zoneid) * subcommand. */ static int -zone_ready(zlog_t *zlogp, zone_mnt_t mount_cmd, int zstate, zoneid_t zone_did) +zone_ready(zlog_t *zlogp, zone_mnt_t mount_cmd, int zstate) { int err; @@ -544,6 +544,9 @@ zone_ready(zlog_t *zlogp, zone_mnt_t mount_cmd, int zstate, zoneid_t zone_did) goto bad; } + if (zone_did == 0) + zone_did = zone_get_did(zone_name); + if ((zone_id = vplat_create(zlogp, mount_cmd, zone_did)) == -1) { if ((err = zonecfg_destroy_snapshot(zone_name)) != Z_OK) zerror(zlogp, B_FALSE, "destroying snapshot: %s", @@ -1037,34 +1040,6 @@ audit_put_record(zlog_t *zlogp, ucred_t *uc, int return_val, (void) adt_end_session(ah); } -static zoneid_t -getzone_did(char *zonename) -{ - int len; - FILE *fp; - char buf[256]; - char pat[ZONENAME_MAX + 2]; - int id = 1; - - (void) snprintf(pat, sizeof (pat), "%s:", zonename); - len = strlen(pat); - if ((fp = fopen("/etc/zones/index", "r")) == NULL) - return (getpid()); - - while (fgets(buf, sizeof (buf), fp) != NULL) { - if (strncmp(buf, pat, len) == 0) { - fclose(fp); - return (id); - } - - if (isalpha(buf[0]) && strncmp(buf, "global:", 7) != 0) - id++; - } - - fclose(fp); - return (getpid()); -} - /* * The main routine for the door server that deals with zone state transitions. */ @@ -1193,9 +1168,6 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp, goto out; } - if (zone_did == 0) - zone_did = getzone_did(zone_name); - if (kernelcall) { /* * Kernel-initiated requests may lose their validity if the @@ -1237,15 +1209,15 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp, case ZONE_STATE_INSTALLED: switch (cmd) { case Z_READY: - rval = zone_ready(zlogp, Z_MNT_BOOT, zstate, zone_did); + rval = zone_ready(zlogp, Z_MNT_BOOT, zstate); if (rval == 0) eventstream_write(Z_EVT_ZONE_READIED); break; case Z_BOOT: case Z_FORCEBOOT: eventstream_write(Z_EVT_ZONE_BOOTING); - if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate, - zone_did)) == 0) { + if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate)) + == 0) { rval = zone_bootup(zlogp, zargp->bootbuf, zstate); } @@ -1304,7 +1276,7 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp, rval = zone_ready(zlogp, strcmp(zargp->bootbuf, "-U") == 0 ? - Z_MNT_UPDATE : Z_MNT_SCRATCH, zstate, zone_did); + Z_MNT_UPDATE : Z_MNT_SCRATCH, zstate); if (rval != 0) break; @@ -1431,8 +1403,7 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp, if ((rval = zone_halt(zlogp, B_FALSE, B_TRUE, zstate)) != 0) break; - if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate, - zone_did)) == 0) + if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate)) == 0) eventstream_write(Z_EVT_ZONE_READIED); else eventstream_write(Z_EVT_ZONE_HALTED); @@ -1463,8 +1434,8 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp, boot_args[0] = '\0'; break; } - if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate, - zone_did)) != 0) { + if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate)) + != 0) { eventstream_write(Z_EVT_ZONE_BOOTFAILED); boot_args[0] = '\0'; break; diff --git a/usr/src/cmd/zonecfg/zonecfg.c b/usr/src/cmd/zonecfg/zonecfg.c index 5015c03955..1b93148548 100644 --- a/usr/src/cmd/zonecfg/zonecfg.c +++ b/usr/src/cmd/zonecfg/zonecfg.c @@ -6034,6 +6034,12 @@ verify_func(cmd_t *cmd) if (save) { if (ret_val == Z_OK) { + /* + * If the zone doesn't yet have a debug ID, set one now. + */ + if (zonecfg_get_did(handle) == -1) + zonecfg_set_did(handle); + if ((ret_val = zonecfg_save(handle)) == Z_OK) { need_to_commit = B_FALSE; (void) strlcpy(revert_zone, zone, diff --git a/usr/src/head/libzonecfg.h b/usr/src/head/libzonecfg.h index db3390dab1..44456e6631 100644 --- a/usr/src/head/libzonecfg.h +++ b/usr/src/head/libzonecfg.h @@ -319,6 +319,8 @@ extern int zonecfg_set_bootargs(zone_dochandle_t, char *); extern int zonecfg_get_sched_class(zone_dochandle_t, char *, size_t); extern int zonecfg_set_sched(zone_dochandle_t, char *); extern int zonecfg_get_dflt_sched_class(zone_dochandle_t, char *, int); +extern zoneid_t zonecfg_get_did(zone_dochandle_t); +extern void zonecfg_set_did(zone_dochandle_t); /* * Set/retrieve the brand for the zone @@ -511,6 +513,7 @@ extern int zonecfg_set_limitpriv(zone_dochandle_t, char *); * Higher-level routines. */ extern int zone_get_brand(char *, char *, size_t); +extern zoneid_t zone_get_did(char *); extern int zone_get_rootpath(char *, char *, size_t); extern int zone_get_devroot(char *, char *, size_t); extern int zone_get_zonepath(char *, char *, size_t); diff --git a/usr/src/lib/libzonecfg/common/libzonecfg.c b/usr/src/lib/libzonecfg/common/libzonecfg.c index 40d2c36aaa..0843119058 100644 --- a/usr/src/lib/libzonecfg/common/libzonecfg.c +++ b/usr/src/lib/libzonecfg/common/libzonecfg.c @@ -78,6 +78,8 @@ #define ZONE_EVENT_PING_SUBCLASS "ping" #define ZONE_EVENT_PING_PUBLISHER "solaris" +#define DEBUGID_FILE "/etc/zones/did.txt" + /* Hard-code the DTD element/attribute/entity names just once, here. */ #define DTD_ELEM_ATTR (const xmlChar *) "attr" #define DTD_ELEM_COMMENT (const xmlChar *) "comment" @@ -129,6 +131,7 @@ #define DTD_ATTR_MODE (const xmlChar *) "mode" #define DTD_ATTR_ACL (const xmlChar *) "acl" #define DTD_ATTR_BRAND (const xmlChar *) "brand" +#define DTD_ATTR_DID (const xmlChar *) "debugid" #define DTD_ATTR_HOSTID (const xmlChar *) "hostid" #define DTD_ATTR_USER (const xmlChar *) "user" #define DTD_ATTR_AUTHS (const xmlChar *) "auths" @@ -5525,6 +5528,164 @@ zone_get_brand(char *zone_name, char *brandname, size_t rp_sz) } /* + * Atomically get a new zone_did value. The currently allocated value + * is stored in /etc/zones/did.txt. Lock the file, read the current value, + * increment, save the new value and unlock the file. Return the new value + * or -1 if there was an error. The ID namespace is large enough that we + * don't worry about recycling an ID when a zone is deleted. + */ +static zoneid_t +new_zone_did() +{ + int fd; + int len; + int val; + struct flock lck; + char buf[80]; + + if ((fd = open(DEBUGID_FILE, O_RDWR | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { + perror("new_zone_did open failed"); + return (-1); + } + + /* Initialize the lock. */ + lck.l_whence = SEEK_SET; + lck.l_start = 0; + lck.l_len = 0; + + /* Wait until we acquire an exclusive lock on the file. */ + lck.l_type = F_WRLCK; + if (fcntl(fd, F_SETLKW, &lck) == -1) { + perror("new_zone_did lock failed"); + (void) close(fd); + return (-1); + } + + /* Get currently allocated value */ + len = read(fd, buf, sizeof (buf)); + if (len == -1) { + perror("new_zone_did read failed"); + val = -1; + } else { + if (lseek(fd, 0L, SEEK_SET) == -1) { + perror("new_zone_did seek failed"); + val = -1; + } else { + if (len == 0) { + /* Just created the file, initialize at 1 */ + val = 1; + } else { + val = atoi(buf); + val++; + } + + (void) snprintf(buf, sizeof (buf), "%d\n", val); + len = strlen(buf); + + /* Save newly allocated value */ + if (write(fd, buf, len) == -1) { + perror("new_zone_did write failed"); + val = -1; + } + } + } + + /* Release the file lock. */ + lck.l_type = F_UNLCK; + if (fcntl(fd, F_SETLK, &lck) == -1) { + perror("new_zone_did unlock failed"); + val = -1; + } + + if (close(fd) != 0) + perror("new_zone_did close failed"); + + return (val); +} + +/* + * Called by zoneadmd to get the zone's debug ID. + * If the zone doesn't already have an ID, a new one is generated and + * persistently saved onto the zone. Normally either zoneadm or zonecfg + * will assign a new ID for the zone, so zoneadmd should never have to + * generate one, but we also handle that here just to be paranoid. + */ +zoneid_t +zone_get_did(char *zone_name) +{ + int res; + zoneid_t new_did; + zone_dochandle_t handle; + char did_str[80]; + + if ((handle = zonecfg_init_handle()) == NULL) + return (getpid()); + + if (zonecfg_get_handle((char *)zone_name, handle) != Z_OK) + return (getpid()); + + res = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str)); + + /* If the zone already has an assigned debug ID, return it. */ + if (res == Z_OK && did_str[0] != '\0') { + zonecfg_fini_handle(handle); + return (atoi(did_str)); + } + + /* + * The zone doesn't have an assigned debug ID yet, generate one and + * save it as part of the zone definition. + */ + if ((new_did = new_zone_did()) == -1) { + /* + * We should really never hit this block of code. + * Generating a new ID failed for some reason. Use the current + * pid as a temporary ID so that the zone can continue to boot + * but we don't persistently save this temporary ID on the zone. + */ + zonecfg_fini_handle(handle); + return (getpid()); + } + + /* Now persistently save this new ID onto the zone. */ + (void) snprintf(did_str, sizeof (did_str), "%d", new_did); + (void) setrootattr(handle, DTD_ATTR_DID, did_str); + (void) zonecfg_save(handle); + + zonecfg_fini_handle(handle); + return (new_did); +} + +zoneid_t +zonecfg_get_did(zone_dochandle_t handle) +{ + char did_str[80]; + int err; + zoneid_t did; + + err = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str)); + if (err == Z_OK && did_str[0] != '\0') + did = atoi(did_str); + else + did = -1; + + return (did); +} + +void +zonecfg_set_did(zone_dochandle_t handle) +{ + zoneid_t new_did; + char did_str[80]; + + if ((new_did = new_zone_did()) == -1) + return; + (void) snprintf(did_str, sizeof (did_str), "%d", new_did); + (void) setrootattr(handle, DTD_ATTR_DID, did_str); +} + +/* * Return the appropriate root for the active /dev. * For normal zone, the path is $ZONEPATH/root; * for scratch zone, the dev path is $ZONEPATH/lu. diff --git a/usr/src/lib/libzonecfg/common/mapfile-vers b/usr/src/lib/libzonecfg/common/mapfile-vers index b908a28174..0f3e1bdd31 100644 --- a/usr/src/lib/libzonecfg/common/mapfile-vers +++ b/usr/src/lib/libzonecfg/common/mapfile-vers @@ -20,6 +20,7 @@ # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, Joyent Inc. All rights reserved. # # @@ -118,6 +119,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { zonecfg_get_bootargs; zonecfg_get_brand; zonecfg_get_dflt_sched_class; + zonecfg_get_did; zonecfg_getdevent; zonecfg_getdevperment; zonecfg_getdsent; @@ -196,6 +198,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { zonecfg_set_autoboot; zonecfg_set_bootargs; zonecfg_set_brand; + zonecfg_set_did; zonecfg_setdevent; zonecfg_setdevperment; zonecfg_setdsent; @@ -229,6 +232,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { zonecfg_verify_save; zonecfg_warn_poold; zone_get_brand; + zone_get_did; zone_get_devroot; zone_get_id; zone_get_rootpath; diff --git a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 index d94bb09c5f..1eff52beb9 100644 --- a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 +++ b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 @@ -21,6 +21,7 @@ CDDL HEADER END Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, Joyent Inc. All rights reserved. --> @@ -156,6 +157,7 @@ limitpriv CDATA "" bootargs CDATA "" brand CDATA "" + debugid CDATA "" scheduling-class CDATA "" fs-allowed CDATA "" version NMTOKEN #FIXED '1'> |