From owner-svn-src-head@FreeBSD.ORG Sun Feb 8 23:51:45 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 059E2106566C; Sun, 8 Feb 2009 23:51:45 +0000 (UTC) (envelope-from marcel@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id E62988FC17; Sun, 8 Feb 2009 23:51:44 +0000 (UTC) (envelope-from marcel@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n18Npiut038554; Sun, 8 Feb 2009 23:51:44 GMT (envelope-from marcel@svn.freebsd.org) Received: (from marcel@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n18Npihc038550; Sun, 8 Feb 2009 23:51:44 GMT (envelope-from marcel@svn.freebsd.org) Message-Id: <200902082351.n18Npihc038550@svn.freebsd.org> From: Marcel Moolenaar Date: Sun, 8 Feb 2009 23:51:44 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r188354 - in head/sys: geom/part modules/geom/geom_part modules/geom/geom_part/geom_part_ebr X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 08 Feb 2009 23:51:45 -0000 Author: marcel Date: Sun Feb 8 23:51:44 2009 New Revision: 188354 URL: http://svn.freebsd.org/changeset/base/188354 Log: Add the EBR scheme. The EBR scheme supports the Extended Boot Records found inside extended partitions and used to create logical partitions. At this time write/modify support is not (yet) present. The EBR and MBR schemes both check the parent scheme. The MBR will back-off when nested under another MBR, whereas the EBR only nests under a MBR. Added: head/sys/geom/part/g_part_ebr.c (contents, props changed) head/sys/modules/geom/geom_part/geom_part_ebr/ head/sys/modules/geom/geom_part/geom_part_ebr/Makefile (contents, props changed) Modified: head/sys/geom/part/g_part_mbr.c head/sys/modules/geom/geom_part/Makefile Added: head/sys/geom/part/g_part_ebr.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/geom/part/g_part_ebr.c Sun Feb 8 23:51:44 2009 (r188354) @@ -0,0 +1,339 @@ +/*- + * Copyright (c) 2007-2009 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 + +#include "g_part_if.h" + +#define EBRSIZE 512 + +struct g_part_ebr_table { + struct g_part_table base; +}; + +struct g_part_ebr_entry { + struct g_part_entry base; + struct dos_partition ent; +}; + +static int g_part_ebr_add(struct g_part_table *, struct g_part_entry *, + struct g_part_parms *); +static int g_part_ebr_create(struct g_part_table *, struct g_part_parms *); +static int g_part_ebr_destroy(struct g_part_table *, struct g_part_parms *); +static void g_part_ebr_dumpconf(struct g_part_table *, struct g_part_entry *, + struct sbuf *, const char *); +static int g_part_ebr_dumpto(struct g_part_table *, struct g_part_entry *); +static int g_part_ebr_modify(struct g_part_table *, struct g_part_entry *, + struct g_part_parms *); +static const char *g_part_ebr_name(struct g_part_table *, struct g_part_entry *, + char *, size_t); +static int g_part_ebr_probe(struct g_part_table *, struct g_consumer *); +static int g_part_ebr_read(struct g_part_table *, struct g_consumer *); +static int g_part_ebr_setunset(struct g_part_table *, struct g_part_entry *, + const char *, unsigned int); +static const char *g_part_ebr_type(struct g_part_table *, struct g_part_entry *, + char *, size_t); +static int g_part_ebr_write(struct g_part_table *, struct g_consumer *); + +static kobj_method_t g_part_ebr_methods[] = { + KOBJMETHOD(g_part_add, g_part_ebr_add), + KOBJMETHOD(g_part_create, g_part_ebr_create), + KOBJMETHOD(g_part_destroy, g_part_ebr_destroy), + KOBJMETHOD(g_part_dumpconf, g_part_ebr_dumpconf), + KOBJMETHOD(g_part_dumpto, g_part_ebr_dumpto), + KOBJMETHOD(g_part_modify, g_part_ebr_modify), + KOBJMETHOD(g_part_name, g_part_ebr_name), + KOBJMETHOD(g_part_probe, g_part_ebr_probe), + KOBJMETHOD(g_part_read, g_part_ebr_read), + KOBJMETHOD(g_part_setunset, g_part_ebr_setunset), + KOBJMETHOD(g_part_type, g_part_ebr_type), + KOBJMETHOD(g_part_write, g_part_ebr_write), + { 0, 0 } +}; + +static struct g_part_scheme g_part_ebr_scheme = { + "EBR", + g_part_ebr_methods, + sizeof(struct g_part_ebr_table), + .gps_entrysz = sizeof(struct g_part_ebr_entry), + .gps_minent = 1, + .gps_maxent = INT_MAX, +}; +G_PART_SCHEME_DECLARE(g_part_ebr); + +static void +ebr_entry_decode(const char *p, struct dos_partition *ent) +{ + ent->dp_flag = p[0]; + ent->dp_shd = p[1]; + ent->dp_ssect = p[2]; + ent->dp_scyl = p[3]; + ent->dp_typ = p[4]; + ent->dp_ehd = p[5]; + ent->dp_esect = p[6]; + ent->dp_ecyl = p[7]; + ent->dp_start = le32dec(p + 8); + ent->dp_size = le32dec(p + 12); +} + +static int +g_part_ebr_add(struct g_part_table *basetable, struct g_part_entry *baseentry, + struct g_part_parms *gpp) +{ + + return (ENOSYS); +} + +static int +g_part_ebr_create(struct g_part_table *basetable, struct g_part_parms *gpp) +{ + + return (ENOSYS); +} + +static int +g_part_ebr_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 void +g_part_ebr_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, + struct sbuf *sb, const char *indent) +{ + struct g_part_ebr_entry *entry; + + entry = (struct g_part_ebr_entry *)baseentry; + if (indent == NULL) { + /* conftxt: libdisk compatibility */ + sbuf_printf(sb, " xs MBREXT xt %u", entry->ent.dp_typ); + } else if (entry != NULL) { + /* confxml: partition entry information */ + sbuf_printf(sb, "%s%u\n", indent, + entry->ent.dp_typ); + if (entry->ent.dp_flag & 0x80) + sbuf_printf(sb, "%sactive\n", indent); + } else { + /* confxml: scheme information */ + } +} + +static int +g_part_ebr_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) +{ + struct g_part_ebr_entry *entry; + + /* Allow dumping to a FreeBSD partition only. */ + entry = (struct g_part_ebr_entry *)baseentry; + return ((entry->ent.dp_typ == DOSPTYP_386BSD) ? 1 : 0); +} + +static int +g_part_ebr_modify(struct g_part_table *basetable, + struct g_part_entry *baseentry, struct g_part_parms *gpp) +{ + + return (ENOSYS); +} + +static const char * +g_part_ebr_name(struct g_part_table *table, struct g_part_entry *entry, + char *buf, size_t bufsz) +{ + + snprintf(buf, bufsz, ".%08u", entry->gpe_index); + return (buf); +} + +static int +g_part_ebr_probe(struct g_part_table *table, struct g_consumer *cp) +{ + char psn[8]; + struct g_provider *pp; + u_char *buf, *p; + int error, index, res, sum; + uint16_t magic; + + pp = cp->provider; + + /* Sanity-check the provider. */ + if (pp->sectorsize < EBRSIZE || pp->mediasize < pp->sectorsize) + return (ENOSPC); + if (pp->sectorsize > 4096) + return (ENXIO); + + /* Check that we have a parent and that it's a MBR. */ + if (table->gpt_depth == 0) + return (ENXIO); + error = g_getattr("PART::scheme", cp, &psn); + if (error) + return (error); + if (strcmp(psn, "MBR")) + return (ENXIO); + + /* Check that there's a EBR. */ + buf = g_read_data(cp, 0L, pp->sectorsize, &error); + if (buf == NULL) + return (error); + + /* We goto out on mismatch. */ + res = ENXIO; + + magic = le16dec(buf + DOSMAGICOFFSET); + if (magic != DOSMAGIC) + goto out; + + /* The sector is all zeroes, except for the partition entries. */ + sum = 0; + for (index = 0; index < DOSPARTOFF; index++) + sum += buf[index]; + if (sum != 0) + goto out; + + for (index = 0; index < NDOSPART; index++) { + p = buf + DOSPARTOFF + index * DOSPARTSIZE; + if (p[0] != 0 && p[0] != 0x80) + goto out; + if (index < 2) + continue; + /* The 3rd & 4th entries are always zero. */ + if ((le64dec(p+0) + le64dec(p+8)) != 0) + goto out; + } + + res = G_PART_PROBE_PRI_HIGH; + + out: + g_free(buf); + return (res); +} + +static int +g_part_ebr_read(struct g_part_table *basetable, struct g_consumer *cp) +{ + struct dos_partition ent[2]; + struct g_provider *pp; + struct g_part_entry *baseentry; + struct g_part_ebr_table *table; + struct g_part_ebr_entry *entry; + u_char *buf; + off_t ofs, msize; + u_int lba; + int error, index; + + pp = cp->provider; + table = (struct g_part_ebr_table *)basetable; + msize = pp->mediasize / pp->sectorsize; + + lba = 0; + while (1) { + ofs = (off_t)lba * pp->sectorsize; + buf = g_read_data(cp, ofs, pp->sectorsize, &error); + if (buf == NULL) + return (error); + + ebr_entry_decode(buf + DOSPARTOFF + 0 * DOSPARTSIZE, ent + 0); + ebr_entry_decode(buf + DOSPARTOFF + 1 * DOSPARTSIZE, ent + 1); + g_free(buf); + + if (ent[0].dp_typ == 0) + break; + + if (ent[0].dp_typ == 5 && ent[1].dp_typ == 0) { + lba = ent[0].dp_start; + continue; + } + + index = (lba / basetable->gpt_sectors) + 1; + baseentry = (struct g_part_entry *)g_part_new_entry(basetable, + index, lba, lba + ent[0].dp_start + ent[0].dp_size - 1); + baseentry->gpe_offset = (off_t)(lba + ent[0].dp_start) * + pp->sectorsize; + entry = (struct g_part_ebr_entry *)baseentry; + entry->ent = ent[0]; + + if (ent[1].dp_typ == 0) + break; + + lba = ent[1].dp_start; + } + + basetable->gpt_entries = msize / basetable->gpt_sectors; + basetable->gpt_first = 0; + basetable->gpt_last = msize - (msize % basetable->gpt_sectors) - 1; + return (0); +} + +static int +g_part_ebr_setunset(struct g_part_table *table, struct g_part_entry *baseentry, + const char *attrib, unsigned int set) +{ + + return (ENOSYS); +} + +static const char * +g_part_ebr_type(struct g_part_table *basetable, struct g_part_entry *baseentry, + char *buf, size_t bufsz) +{ + struct g_part_ebr_entry *entry; + int type; + + entry = (struct g_part_ebr_entry *)baseentry; + type = entry->ent.dp_typ; + if (type == DOSPTYP_386BSD) + return (g_part_alias_name(G_PART_ALIAS_FREEBSD)); + snprintf(buf, bufsz, "!%d", type); + return (buf); +} + +static int +g_part_ebr_write(struct g_part_table *basetable, struct g_consumer *cp) +{ + + return (ENOSYS); +} Modified: head/sys/geom/part/g_part_mbr.c ============================================================================== --- head/sys/geom/part/g_part_mbr.c Sun Feb 8 23:43:36 2009 (r188353) +++ head/sys/geom/part/g_part_mbr.c Sun Feb 8 23:51:44 2009 (r188354) @@ -314,6 +314,7 @@ g_part_mbr_name(struct g_part_table *tab static int g_part_mbr_probe(struct g_part_table *table, struct g_consumer *cp) { + char psn[8]; struct g_provider *pp; u_char *buf, *p; int error, index, res, sum; @@ -327,6 +328,11 @@ g_part_mbr_probe(struct g_part_table *ta if (pp->sectorsize > 4096) return (ENXIO); + /* We don't nest under an MBR (see EBR instead). */ + error = g_getattr("PART::scheme", cp, &psn); + if (error == 0 && strcmp(psn, g_part_mbr_scheme.name) == 0) + return (ELOOP); + /* Check that there's a MBR. */ buf = g_read_data(cp, 0L, pp->sectorsize, &error); if (buf == NULL) Modified: head/sys/modules/geom/geom_part/Makefile ============================================================================== --- head/sys/modules/geom/geom_part/Makefile Sun Feb 8 23:43:36 2009 (r188353) +++ head/sys/modules/geom/geom_part/Makefile Sun Feb 8 23:51:44 2009 (r188354) @@ -2,6 +2,7 @@ SUBDIR= geom_part_apm \ geom_part_bsd \ + geom_part_ebr \ geom_part_gpt \ geom_part_mbr \ geom_part_pc98 \ Added: head/sys/modules/geom/geom_part/geom_part_ebr/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/modules/geom/geom_part/geom_part_ebr/Makefile Sun Feb 8 23:51:44 2009 (r188354) @@ -0,0 +1,12 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../geom/part + +KMOD= geom_part_ebr +SRCS= g_part_ebr.c + +SRCS+= bus_if.h device_if.h g_part_if.h + +MFILES= kern/bus_if.m kern/device_if.m geom/part/g_part_if.m + +.include