From dd3a7906ab066bb6da5ec7f1fcf0fbe6d1ddc268 Mon Sep 17 00:00:00 2001 From: marcel Date: Sun, 2 Mar 2008 00:52:49 +0000 Subject: [PATCH] Add support for VTOC8 labels (aka sun disk labels). When a label does not have VTOC information about the partitions, it will be created. This is because the VTOC information is used for the partition type and FreeBSD's sunlabel(8) does not create nor use VTOC information. For this purpose, new tags have been added to support FreeBSD's partition types. --- sys/conf/files | 1 + sys/conf/options | 1 + sys/geom/part/g_part_vtoc8.c | 480 +++++++++++++++++++++++++++++++++++ sys/sys/vtoc.h | 106 ++++++++ 4 files changed, 588 insertions(+) create mode 100644 sys/geom/part/g_part_vtoc8.c create mode 100644 sys/sys/vtoc.h diff --git a/sys/conf/files b/sys/conf/files index 36abb5d3a9d..59640aefe1b 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1322,6 +1322,7 @@ geom/part/g_part_apm.c optional geom_part_apm geom/part/g_part_bsd.c optional geom_part_bsd geom/part/g_part_gpt.c optional geom_part_gpt geom/part/g_part_mbr.c optional geom_part_mbr +geom/part/g_part_vtoc8.c optional geom_part_vtoc8 geom/raid3/g_raid3.c optional geom_raid3 geom/raid3/g_raid3_ctl.c optional geom_raid3 geom/shsec/g_shsec.c optional geom_shsec diff --git a/sys/conf/options b/sys/conf/options index 21df95a9948..2525f297191 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -94,6 +94,7 @@ GEOM_PART_APM opt_geom.h GEOM_PART_BSD opt_geom.h GEOM_PART_GPT opt_geom.h GEOM_PART_MBR opt_geom.h +GEOM_PART_VTOC8 opt_geom.h GEOM_PC98 opt_geom.h GEOM_RAID3 opt_geom.h GEOM_SHSEC opt_geom.h diff --git a/sys/geom/part/g_part_vtoc8.c b/sys/geom/part/g_part_vtoc8.c new file mode 100644 index 00000000000..e9412eb05a2 --- /dev/null +++ b/sys/geom/part/g_part_vtoc8.c @@ -0,0 +1,480 @@ +/*- + * Copyright (c) 2008 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "g_part_if.h" + +struct g_part_vtoc8_table { + struct g_part_table base; + struct vtoc8 vtoc; + uint32_t secpercyl; +}; + +static int g_part_vtoc8_add(struct g_part_table *, struct g_part_entry *, + struct g_part_parms *); +static int g_part_vtoc8_create(struct g_part_table *, struct g_part_parms *); +static int g_part_vtoc8_destroy(struct g_part_table *, struct g_part_parms *); +static int g_part_vtoc8_dumpto(struct g_part_table *, struct g_part_entry *); +static int g_part_vtoc8_modify(struct g_part_table *, struct g_part_entry *, + struct g_part_parms *); +static char *g_part_vtoc8_name(struct g_part_table *, struct g_part_entry *, + char *, size_t); +static int g_part_vtoc8_probe(struct g_part_table *, struct g_consumer *); +static int g_part_vtoc8_read(struct g_part_table *, struct g_consumer *); +static const char *g_part_vtoc8_type(struct g_part_table *, struct g_part_entry *, + char *, size_t); +static int g_part_vtoc8_write(struct g_part_table *, struct g_consumer *); + +static kobj_method_t g_part_vtoc8_methods[] = { + KOBJMETHOD(g_part_add, g_part_vtoc8_add), + KOBJMETHOD(g_part_create, g_part_vtoc8_create), + KOBJMETHOD(g_part_destroy, g_part_vtoc8_destroy), + KOBJMETHOD(g_part_dumpto, g_part_vtoc8_dumpto), + KOBJMETHOD(g_part_modify, g_part_vtoc8_modify), + KOBJMETHOD(g_part_name, g_part_vtoc8_name), + KOBJMETHOD(g_part_probe, g_part_vtoc8_probe), + KOBJMETHOD(g_part_read, g_part_vtoc8_read), + KOBJMETHOD(g_part_type, g_part_vtoc8_type), + KOBJMETHOD(g_part_write, g_part_vtoc8_write), + { 0, 0 } +}; + +static struct g_part_scheme g_part_vtoc8_scheme = { + "VTOC8", + g_part_vtoc8_methods, + sizeof(struct g_part_vtoc8_table), + .gps_entrysz = sizeof(struct g_part_entry), + .gps_minent = VTOC8_NPARTS, + .gps_maxent = VTOC8_NPARTS, +}; +G_PART_SCHEME_DECLARE(g_part_vtoc8_scheme); + +static int +vtoc8_parse_type(const char *type, uint16_t *tag) +{ + const char *alias; + char *endp; + long lt; + + if (type[0] == '!') { + lt = strtol(type + 1, &endp, 0); + if (type[1] == '\0' || *endp != '\0' || lt <= 0 || + lt >= 65536) + return (EINVAL); + *tag = (uint16_t)lt; + return (0); + } + alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP); + if (!strcasecmp(type, alias)) { + *tag = VTOC_TAG_FREEBSD_SWAP; + return (0); + } + alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS); + if (!strcasecmp(type, alias)) { + *tag = VTOC_TAG_FREEBSD_UFS; + return (0); + } + alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM); + if (!strcasecmp(type, alias)) { + *tag = VTOC_TAG_FREEBSD_VINUM; + return (0); + } + alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS); + if (!strcasecmp(type, alias)) { + *tag = VTOC_TAG_FREEBSD_ZFS; + return (0); + } + return (EINVAL); +} + +static int +g_part_vtoc8_add(struct g_part_table *basetable, struct g_part_entry *entry, + struct g_part_parms *gpp) +{ + struct g_part_vtoc8_table *table; + int error, index; + uint64_t start, size; + uint16_t tag; + + if (gpp->gpp_parms & G_PART_PARM_LABEL) + return (EINVAL); + + error = vtoc8_parse_type(gpp->gpp_type, &tag); + if (error) + return (error); + + table = (struct g_part_vtoc8_table *)basetable; + index = entry->gpe_index - 1; + + start = gpp->gpp_start; + size = gpp->gpp_size; + if (start % table->secpercyl) { + size = size - table->secpercyl + (start % table->secpercyl); + start = start - (start % table->secpercyl) + table->secpercyl; + } + if (size % table->secpercyl) + size = size - (size % table->secpercyl); + if (size < table->secpercyl) + return (EINVAL); + + KASSERT(entry->gpe_start <= start, (__func__)); + KASSERT(entry->gpe_end >= start + size - 1, (__func__)); + entry->gpe_start = start; + entry->gpe_end = start + size - 1; + + be16enc(&table->vtoc.part[index].tag, tag); + be16enc(&table->vtoc.part[index].flag, 0); + be32enc(&table->vtoc.timestamp[index], 0); + be32enc(&table->vtoc.map[index].cyl, start / table->secpercyl); + be32enc(&table->vtoc.map[index].nblks, size); + return (0); +} + +static int +g_part_vtoc8_create(struct g_part_table *basetable, struct g_part_parms *gpp) +{ + struct g_consumer *cp; + struct g_provider *pp; + struct g_part_entry *entry; + struct g_part_vtoc8_table *table; + uint64_t msize; + uint32_t acyls, ncyls, pcyls; + + pp = gpp->gpp_provider; + cp = LIST_FIRST(&pp->consumers); + + if (pp->sectorsize < sizeof(struct vtoc8)) + return (ENOSPC); + if (pp->sectorsize > sizeof(struct vtoc8)) + return (ENXIO); + + table = (struct g_part_vtoc8_table *)basetable; + + msize = pp->mediasize / pp->sectorsize; + if (msize > 0xffffffffu) + msize = 0xffffffffu; + table->secpercyl = basetable->gpt_sectors * basetable->gpt_heads; + pcyls = msize / table->secpercyl; + acyls = 2; + ncyls = pcyls - acyls; + msize = ncyls * table->secpercyl; + + sprintf(table->vtoc.ascii, "FreeBSD%lldM cyl %u alt %u hd %u sec %u", + (long long)(msize / 2048), ncyls, acyls, basetable->gpt_heads, + basetable->gpt_sectors); + be32enc(&table->vtoc.version, VTOC_VERSION); + be16enc(&table->vtoc.nparts, VTOC8_NPARTS); + be32enc(&table->vtoc.sanity, VTOC_SANITY); + be16enc(&table->vtoc.rpm, 3600); + be16enc(&table->vtoc.physcyls, pcyls); + be16enc(&table->vtoc.ncyls, ncyls); + be16enc(&table->vtoc.altcyls, acyls); + be16enc(&table->vtoc.nheads, basetable->gpt_heads); + be16enc(&table->vtoc.nsecs, basetable->gpt_sectors); + be16enc(&table->vtoc.magic, VTOC_MAGIC); + + basetable->gpt_first = 0; + basetable->gpt_last = msize - 1; + basetable->gpt_isleaf = 1; + + entry = g_part_new_entry(basetable, VTOC_RAW_PART + 1, + basetable->gpt_first, basetable->gpt_last); + entry->gpe_internal = 1; + be16enc(&table->vtoc.part[VTOC_RAW_PART].tag, VTOC_TAG_BACKUP); + be32enc(&table->vtoc.map[VTOC_RAW_PART].nblks, msize); + return (0); +} + +static int +g_part_vtoc8_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) +{ + + /* Wipe the first sector to clear the partitioning. */ + basetable->gpt_smhead |= 1; + return (0); +} + +static int +g_part_vtoc8_dumpto(struct g_part_table *basetable, struct g_part_entry *entry) +{ + struct g_part_vtoc8_table *table; + uint16_t tag; + + /* Allow dumping to a swap partition only. */ + table = (struct g_part_vtoc8_table *)basetable; + tag = be16dec(&table->vtoc.part[entry->gpe_index - 1].tag); + return ((tag == VTOC_TAG_FREEBSD_SWAP) ? 1 : 0); +} + +static int +g_part_vtoc8_modify(struct g_part_table *basetable, + struct g_part_entry *entry, struct g_part_parms *gpp) +{ + struct g_part_vtoc8_table *table; + int error; + uint16_t tag; + + if (gpp->gpp_parms & G_PART_PARM_LABEL) + return (EINVAL); + + table = (struct g_part_vtoc8_table *)basetable; + if (gpp->gpp_parms & G_PART_PARM_TYPE) { + error = vtoc8_parse_type(gpp->gpp_type, &tag); + if (error) + return(error); + + be16enc(&table->vtoc.part[entry->gpe_index - 1].tag, tag); + } + return (0); +} + +static char * +g_part_vtoc8_name(struct g_part_table *table, struct g_part_entry *baseentry, + char *buf, size_t bufsz) +{ + + snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1); + return (buf); +} + +static int +g_part_vtoc8_probe(struct g_part_table *table, struct g_consumer *cp) +{ + struct g_provider *pp; + u_char *buf; + int error, ofs, res; + uint16_t cksum, magic; + + pp = cp->provider; + + /* Sanity-check the provider. */ + if (pp->sectorsize != sizeof(struct vtoc8)) + return (ENOSPC); + + /* Check that there's a disklabel. */ + buf = g_read_data(cp, 0, pp->sectorsize, &error); + if (buf == NULL) + return (error); + + res = ENXIO; /* Assume mismatch */ + + /* Check the magic */ + magic = be16dec(buf + offsetof(struct vtoc8, magic)); + if (magic != VTOC_MAGIC) + goto out; + + /* Check the sum */ + cksum = 0; + for (ofs = 0; ofs < sizeof(struct vtoc8); ofs += 2) + cksum ^= be16dec(buf + ofs); + if (cksum != 0) + goto out; + + res = G_PART_PROBE_PRI_NORM; + + out: + g_free(buf); + return (res); +} + +static int +g_part_vtoc8_read(struct g_part_table *basetable, struct g_consumer *cp) +{ + struct g_provider *pp; + struct g_part_vtoc8_table *table; + struct g_part_entry *entry; + u_char *buf; + off_t chs, msize; + uint64_t offset, size; + u_int cyls, heads, sectors; + int error, index, withtags; + uint16_t tag; + + pp = cp->provider; + buf = g_read_data(cp, 0, pp->sectorsize, &error); + if (buf == NULL) + return (error); + + table = (struct g_part_vtoc8_table *)basetable; + bcopy(buf, &table->vtoc, sizeof(table->vtoc)); + g_free(buf); + + msize = pp->mediasize / pp->sectorsize; + + sectors = be16dec(&table->vtoc.nsecs); + if (sectors < 1 || sectors > 63) + goto invalid_label; + if (sectors != basetable->gpt_sectors && !basetable->gpt_fixgeom) { + g_part_geometry_heads(msize, sectors, &chs, &heads); + if (chs != 0) { + basetable->gpt_sectors = sectors; + basetable->gpt_heads = heads; + } + } + + heads = be16dec(&table->vtoc.nheads); + if (heads < 1 || heads > 255) + goto invalid_label; + if (heads != basetable->gpt_heads && !basetable->gpt_fixgeom) + basetable->gpt_heads = heads; + if (sectors != basetable->gpt_sectors || + heads != basetable->gpt_heads) + printf("GEOM: %s: geometry does not match label.\n", pp->name); + + table->secpercyl = heads * sectors; + cyls = be16dec(&table->vtoc.ncyls); + chs = cyls * table->secpercyl; + if (chs < 1 || chs > msize) + goto invalid_label; + + basetable->gpt_first = 0; + basetable->gpt_last = chs - 1; + basetable->gpt_isleaf = 1; + + withtags = (be32dec(&table->vtoc.sanity) == VTOC_SANITY) ? 1 : 0; + if (!withtags) { + printf("GEOM: %s: adding VTOC information.\n", pp->name); + be32enc(&table->vtoc.version, VTOC_VERSION); + bzero(&table->vtoc.volume, VTOC_VOLUME_LEN); + be16enc(&table->vtoc.nparts, VTOC8_NPARTS); + bzero(&table->vtoc.part, sizeof(table->vtoc.part)); + be32enc(&table->vtoc.sanity, VTOC_SANITY); + } + + basetable->gpt_entries = be16dec(&table->vtoc.nparts); + if (basetable->gpt_entries < g_part_vtoc8_scheme.gps_minent || + basetable->gpt_entries > g_part_vtoc8_scheme.gps_maxent) + goto invalid_label; + + for (index = basetable->gpt_entries - 1; index >= 0; index--) { + offset = be32dec(&table->vtoc.map[index].cyl) * + table->secpercyl; + size = be32dec(&table->vtoc.map[index].nblks); + if (size == 0) + continue; + if (withtags) + tag = be16dec(&table->vtoc.part[index].tag); + else + tag = (index == VTOC_RAW_PART) + ? VTOC_TAG_BACKUP + : VTOC_TAG_UNASSIGNED; + + if (index == VTOC_RAW_PART && tag != VTOC_TAG_BACKUP) + continue; + if (index != VTOC_RAW_PART && tag == VTOC_TAG_BACKUP) + continue; + entry = g_part_new_entry(basetable, index + 1, offset, + offset + size - 1); + if (tag == VTOC_TAG_BACKUP) + entry->gpe_internal = 1; + + if (!withtags) + be16enc(&table->vtoc.part[index].tag, tag); + } + + return (0); + + invalid_label: + printf("GEOM: %s: invalid disklabel.\n", pp->name); + return (EINVAL); +} + +static const char * +g_part_vtoc8_type(struct g_part_table *basetable, struct g_part_entry *entry, + char *buf, size_t bufsz) +{ + struct g_part_vtoc8_table *table; + uint16_t tag; + + table = (struct g_part_vtoc8_table *)basetable; + tag = be16dec(&table->vtoc.part[entry->gpe_index - 1].tag); + if (tag == VTOC_TAG_FREEBSD_SWAP) + return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP)); + if (tag == VTOC_TAG_FREEBSD_UFS) + return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS)); + if (tag == VTOC_TAG_FREEBSD_VINUM) + return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM)); + if (tag == VTOC_TAG_FREEBSD_ZFS) + return (g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS)); + snprintf(buf, bufsz, "!%d", tag); + return (buf); +} + +static int +g_part_vtoc8_write(struct g_part_table *basetable, struct g_consumer *cp) +{ + struct g_provider *pp; + struct g_part_entry *entry; + struct g_part_vtoc8_table *table; + uint16_t sum; + u_char *p; + int error, index, match, offset; + + pp = cp->provider; + table = (struct g_part_vtoc8_table *)basetable; + entry = LIST_FIRST(&basetable->gpt_entry); + for (index = 0; index < basetable->gpt_entries; index++) { + match = (entry != NULL && index == entry->gpe_index - 1) + ? 1 : 0; + if (match) { + if (entry->gpe_deleted) { + be16enc(&table->vtoc.part[index].tag, 0); + be16enc(&table->vtoc.part[index].flag, 0); + be32enc(&table->vtoc.map[index].cyl, 0); + be32enc(&table->vtoc.map[index].nblks, 0); + } + entry = LIST_NEXT(entry, gpe_entry); + } + } + + /* Calculate checksum. */ + sum = 0; + p = (void *)&table->vtoc; + for (offset = 0; offset < sizeof(table->vtoc) - 2; offset += 2) + sum ^= be16dec(p + offset); + be16enc(&table->vtoc.cksum, sum); + + error = g_write_data(cp, 0, p, pp->sectorsize); + return (error); +} diff --git a/sys/sys/vtoc.h b/sys/sys/vtoc.h new file mode 100644 index 00000000000..83b85478ec0 --- /dev/null +++ b/sys/sys/vtoc.h @@ -0,0 +1,106 @@ +/*- + * Copyright (c) 2008 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_VTOC_H_ +#define _SYS_VTOC_H_ + +#define VTOC_TAG_UNASSIGNED 0x00 +#define VTOC_TAG_BOOT 0x01 +#define VTOC_TAG_ROOT 0x02 +#define VTOC_TAG_SWAP 0x03 +#define VTOC_TAG_USR 0x04 +#define VTOC_TAG_BACKUP 0x05 /* "c" partition */ +#define VTOC_TAG_STAND 0x06 +#define VTOC_TAG_VAR 0x07 +#define VTOC_TAG_HOME 0x08 +#define VTOC_TAG_ALTSCTR 0x09 /* alternate sector partition */ +#define VTOC_TAG_CACHE 0x0a /* Solaris cachefs partition */ +#define VTOC_TAG_VXVM_PUB 0x0e /* VxVM public region */ +#define VTOC_TAG_VXVM_PRIV 0x0f /* VxVM private region */ + +/* NetBSD/mips defines this */ +#define VTOC_TAG_NETBSD_FFS 0xff + +/* FreeBSD tags: the high byte equals ELFOSABI_FREEBSD */ +#define VTOC_TAG_FREEBSD_SWAP 0x0901 +#define VTOC_TAG_FREEBSD_UFS 0x0902 +#define VTOC_TAG_FREEBSD_VINUM 0x0903 +#define VTOC_TAG_FREEBSD_ZFS 0x0904 + +#define VTOC_FLAG_UNMNT 0x01 /* unmountable partition */ +#define VTOC_FLAG_RDONLY 0x10 /* partition is read/only */ + +#define VTOC_ASCII_LEN 128 +#define VTOC_MAGIC 0xdabe +#define VTOC_RAW_PART 2 +#define VTOC_SANITY 0x600ddeee +#define VTOC_VERSION 1 +#define VTOC_VOLUME_LEN 8 + +#define VTOC8_NPARTS 8 + +struct vtoc8 { + char ascii[VTOC_ASCII_LEN]; + uint32_t version; + char volume[VTOC_VOLUME_LEN]; + uint16_t nparts; + struct { + uint16_t tag; + uint16_t flag; + } part[VTOC8_NPARTS]; + uint16_t __alignment; + uint32_t bootinfo[3]; + uint32_t sanity; + uint32_t reserved[10]; + uint32_t timestamp[VTOC8_NPARTS]; + uint16_t wskip; + uint16_t rskip; + char padding[152]; + uint16_t rpm; + uint16_t physcyls; + uint16_t sparesecs; + uint16_t spare1[2]; + uint16_t interleave; + uint16_t ncyls; + uint16_t altcyls; + uint16_t nheads; + uint16_t nsecs; + uint16_t spare2[2]; + struct { + uint32_t cyl; + uint32_t nblks; + } map[VTOC8_NPARTS]; + uint16_t magic; + uint16_t cksum; +}; + +#ifdef CTASSERT +CTASSERT(sizeof(struct vtoc8) == 512); +#endif + +#endif /* _SYS_VTOC_H_ */ -- 2.45.0