diff --git a/sys/conf/files b/sys/conf/files index 36abb5d3a9d6..59640aefe1b9 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 21df95a9948c..2525f297191d 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 000000000000..e9412eb05a28 --- /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 000000000000..83b85478ec02 --- /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_ */