Index: sys/geom/vinum/geom_vinum.h =================================================================== RCS file: /srv/ncvs/src/sys/geom/vinum/geom_vinum.h,v retrieving revision 1.13 diff -u -r1.13 geom_vinum.h --- sys/geom/vinum/geom_vinum.h 12 Apr 2007 17:54:35 -0000 1.13 +++ sys/geom/vinum/geom_vinum.h 27 Apr 2008 14:11:11 -0000 @@ -34,9 +34,11 @@ /* geom_vinum_drive.c */ void gv_config_new_drive(struct gv_drive *); void gv_drive_modify(struct gv_drive *); +int gv_read_header(struct g_consumer *, struct gv_hdr *); void gv_save_config_all(struct gv_softc *); void gv_save_config(struct g_consumer *, struct gv_drive *, struct gv_softc *); +int gv_write_header(struct g_consumer *, struct gv_hdr *); /* geom_vinum_init.c */ void gv_parityop(struct g_geom *, struct gctl_req *); Index: sys/geom/vinum/geom_vinum_drive.c =================================================================== RCS file: /srv/ncvs/src/sys/geom/vinum/geom_vinum_drive.c,v retrieving revision 1.27 diff -u -r1.27 geom_vinum_drive.c --- sys/geom/vinum/geom_vinum_drive.c 18 Mar 2008 08:48:51 -0000 1.27 +++ sys/geom/vinum/geom_vinum_drive.c 27 Apr 2008 14:11:11 -0000 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -47,8 +48,173 @@ #include #include +#define GV_LEGACY_I386 0 +#define GV_LEGACY_AMD64 1 + static void gv_drive_dead(void *, int); static void gv_drive_worker(void *); +static int gv_legacy_header_type(uint8_t *); + +/* + * Here are the "offset (size)" for the various struct gv_hdr fields, + * for the legacy i386, legacy amd64, and current (cpu & endian agnostic) + * versions of the on-disk format of the vinum header structure: + * + * i386 amd64 current field + * -------- -------- -------- ----- + * 0 ( 8) 0 ( 8) 0 ( 8) magic + * 8 ( 4) 8 ( 8) 8 ( 4) config_length + * 12 (32) 16 (32) 16 (32) label.sysname + * 44 (32) 48 (32) 48 (32) label.name + * 76 ( 4) 80 ( 8) 80 ( 8) label.date_of_birth.tv_sec + * 80 ( 4) 88 ( 8) 88 ( 8) label.date_of_birth.tv_usec + * 84 ( 4) 96 ( 8) 96 ( 8) label.last_update.tv_sec + * 88 ( 4) 104 ( 8) 104 ( 8) label.last_update.tv_usec + * 92 ( 8) 112 ( 8) 112 ( 8) label.drive_size + * ======== ======== ======== + * 100 120 120 total size + * + * NOTE: i386 and amd64 formats are stored as little-endian; the current + * format uses big-endian (network order). + */ + + +/* Checks for legacy format depending on platform. */ +static int +gv_legacy_header_type(uint8_t *hdr) +{ + uint32_t *i32; + int i; + + /* if non-empty hostname overlaps amd64 config_length */ + i32 = (uint32_t *)(hdr + 12); + if (*i32 != 0) + return (GV_LEGACY_I386); + /* check for non-empty hostname */ + if (hdr[16] != 0) + return (GV_LEGACY_AMD64); + /* check bytes past i386 structure */ + for (i = 100; i < 120; i++) + if (hdr[i] != 0) + return (GV_LEGACY_I386); + /* check for overlapping timestamp */ + i32 = (uint32_t *)(hdr + 84); + + if (*i32 == 0) + return (GV_LEGACY_AMD64); + return (GV_LEGACY_I386); +} + +/* + * Read the header while taking magic number into account, and write it to + * destination pointer. + */ +int +gv_read_header(struct g_consumer *cp, struct gv_hdr *m_hdr) +{ + uint8_t *d_hdr; + int off; + +#define GV_GET32(endian) \ + endian##32toh(*((uint32_t *)&d_hdr[off])); \ + off += 4 +#define GV_GET64(endian) \ + endian##64toh(*((uint64_t *)&d_hdr[off])); \ + off += 8 + + KASSERT(m_hdr != NULL, ("gv_read_header: null m_hdr")); + + d_hdr = g_read_data(cp, GV_HDR_OFFSET, GV_HDR_LEN, NULL); + if (d_hdr == NULL) + return (-1); +/* m_hdr = g_malloc(GV_HDR_LEN, M_WAITOK | M_ZERO);*/ + off = 0; + m_hdr->magic = GV_GET64(be); + if (m_hdr->magic == GV_MAGIC) { + m_hdr->config_length = GV_GET32(be); + off = 16; + bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN); + off += GV_HOSTNAME_LEN; + bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME); + off += GV_MAXDRIVENAME; + m_hdr->label.date_of_birth.tv_sec = GV_GET64(be); + m_hdr->label.date_of_birth.tv_usec = GV_GET64(be); + m_hdr->label.last_update.tv_sec = GV_GET64(be); + m_hdr->label.last_update.tv_usec = GV_GET64(be); + m_hdr->label.drive_size = GV_GET64(be); + } else if (m_hdr->magic != GV_OLD_MAGIC) { + /* Shouldn't happen. */ + g_free(d_hdr); + return (-1); + } else if (gv_legacy_header_type(d_hdr) == GV_LEGACY_I386) { + m_hdr->magic = GV_MAGIC; + /* legacy i386 on-disk header */ + m_hdr->config_length = GV_GET32(le); + bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN); + off += GV_HOSTNAME_LEN; + bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME); + off += GV_MAXDRIVENAME; + m_hdr->label.date_of_birth.tv_sec = GV_GET32(le); + m_hdr->label.date_of_birth.tv_usec = GV_GET32(le); + m_hdr->label.last_update.tv_sec = GV_GET32(le); + m_hdr->label.last_update.tv_usec = GV_GET32(le); + m_hdr->label.drive_size = GV_GET64(le); + } else { + m_hdr->magic = GV_MAGIC; + /* legacy amd64 on-disk header */ + m_hdr->config_length = GV_GET64(le); + bcopy(d_hdr + 16, m_hdr->label.sysname, GV_HOSTNAME_LEN); + off += GV_HOSTNAME_LEN; + bcopy(d_hdr + 48, m_hdr->label.name, GV_MAXDRIVENAME); + off += GV_MAXDRIVENAME; + m_hdr->label.date_of_birth.tv_sec = GV_GET64(le); + m_hdr->label.date_of_birth.tv_usec = GV_GET64(le); + m_hdr->label.last_update.tv_sec = GV_GET64(le); + m_hdr->label.last_update.tv_usec = GV_GET64(le); + m_hdr->label.drive_size = GV_GET64(le); + } + + g_free(d_hdr); + return (0); +} + +/* Write out the gvinum header. */ +int +gv_write_header(struct g_consumer *cp, struct gv_hdr *m_hdr) +{ + uint8_t d_hdr[GV_HDR_LEN]; + int off, ret; + +#define GV_SET32BE(field) \ + do { \ + *((uint32_t *)&d_hdr[off]) = htobe32(field); \ + off += 4; \ + } while (0) +#define GV_SET64BE(field) \ + do { \ + *((uint64_t *)&d_hdr[off]) = htobe64(field); \ + off += 8; \ + } while (0) + + KASSERT(m_hdr != NULL, ("gv_write_header: null m_hdr")); + + off = 0; + GV_SET64BE(m_hdr->magic); + GV_SET32BE(m_hdr->config_length); + off = 16; + bcopy(m_hdr->label.sysname, d_hdr + off, GV_HOSTNAME_LEN); + off += GV_HOSTNAME_LEN; + bcopy(m_hdr->label.name, d_hdr + off, GV_MAXDRIVENAME); + off += GV_MAXDRIVENAME; + GV_SET64BE(m_hdr->label.date_of_birth.tv_sec); + GV_SET64BE(m_hdr->label.date_of_birth.tv_usec); + GV_SET64BE(m_hdr->label.last_update.tv_sec); + GV_SET64BE(m_hdr->label.last_update.tv_usec); + GV_SET64BE(m_hdr->label.drive_size); + + ret = g_write_data(cp, GV_HDR_OFFSET, d_hdr, GV_HDR_LEN); + return (ret); +} void gv_config_new_drive(struct gv_drive *d) @@ -157,7 +323,7 @@ g_topology_unlock(); do { - error = g_write_data(cp2, GV_HDR_OFFSET, vhdr, GV_HDR_LEN); + error = gv_write_header(cp2, vhdr); if (error) { printf("GEOM_VINUM: writing vhdr failed on drive %s, " "errno %d", d->name, error); @@ -440,10 +606,9 @@ /* Now check if the provided slice is a valid vinum drive. */ do { - vhdr = g_read_data(cp, GV_HDR_OFFSET, pp->sectorsize, NULL); - if (vhdr == NULL) - break; - if (vhdr->magic != GV_MAGIC) { + vhdr = g_malloc(GV_HDR_LEN, M_WAITOK | M_ZERO); + error = gv_read_header(cp, vhdr); + if (error) { g_free(vhdr); break; } Index: sys/geom/vinum/geom_vinum_var.h =================================================================== RCS file: /srv/ncvs/src/sys/geom/vinum/geom_vinum_var.h,v retrieving revision 1.11 diff -u -r1.11 geom_vinum_var.h --- sys/geom/vinum/geom_vinum_var.h 6 Jan 2006 18:03:17 -0000 1.11 +++ sys/geom/vinum/geom_vinum_var.h 27 Apr 2008 14:11:11 -0000 @@ -136,10 +136,12 @@ /* The 'header' of each valid vinum drive. */ struct gv_hdr { uint64_t magic; -#define GV_MAGIC 22322600044678729LL -#define GV_NOMAGIC 22322600044678990LL +#define GV_OLD_MAGIC 0x494E2056494E4F00LL +#define GV_OLD_NOMAGIC 0x4E4F2056494E4F00LL +#define GV_MAGIC 0x56494E554D2D3100LL +#define GV_NOMAGIC 0x56494E554D2D2D00LL - int config_length; + uint64_t config_length; struct gv_label label; };