Date: Sat, 17 Sep 2005 09:46:54 GMT From: Robert Watson <rwatson@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 83777 for review Message-ID: <200509170946.j8H9ksYa012782@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=83777 Change 83777 by rwatson@rwatson_zoo on 2005/09/17 09:45:57 Integrate netsmp branch from FreeBSD CVS: - ATI AGP driver, AGP work generally. - More if_free fixes. - geom_gpt rewrite. - Buffer cache fixes. Affected files ... .. //depot/projects/netsmp/src/sys/conf/files.i386#4 integrate .. //depot/projects/netsmp/src/sys/contrib/dev/oltr/if_oltr.c#4 integrate .. //depot/projects/netsmp/src/sys/dev/fe/if_fe.c#6 integrate .. //depot/projects/netsmp/src/sys/dev/lnc/if_lnc.c#7 integrate .. //depot/projects/netsmp/src/sys/dev/nve/if_nve.c#7 integrate .. //depot/projects/netsmp/src/sys/dev/patm/if_patm_attach.c#2 integrate .. //depot/projects/netsmp/src/sys/dev/ral/if_ral.c#7 integrate .. //depot/projects/netsmp/src/sys/geom/geom_gpt.c#2 integrate .. //depot/projects/netsmp/src/sys/kern/vfs_subr.c#10 integrate .. //depot/projects/netsmp/src/sys/modules/agp/Makefile#2 integrate .. //depot/projects/netsmp/src/sys/net/if_vlan.c#10 integrate .. //depot/projects/netsmp/src/sys/pci/agp_ati.c#1 branch .. //depot/projects/netsmp/src/sys/pci/agp_nvidia.c#2 integrate .. //depot/projects/netsmp/src/sys/pci/agpreg.h#2 integrate .. //depot/projects/netsmp/src/sys/sys/gpt.h#2 integrate Differences ... ==== //depot/projects/netsmp/src/sys/conf/files.i386#4 (text+ko) ==== @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $FreeBSD: src/sys/conf/files.i386,v 1.540 2005/08/26 13:42:03 jhb Exp $ +# $FreeBSD: src/sys/conf/files.i386,v 1.541 2005/09/17 03:36:46 anholt Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -456,6 +456,7 @@ pci/agp_ali.c optional agp pci/agp_amd.c optional agp pci/agp_amd64.c optional agp +pci/agp_ati.c optional agp pci/agp_i810.c optional agp pci/agp_intel.c optional agp pci/agp_nvidia.c optional agp ==== //depot/projects/netsmp/src/sys/contrib/dev/oltr/if_oltr.c#4 (text+ko) ==== @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/contrib/dev/oltr/if_oltr.c,v 1.38 2005/08/09 10:19:41 rwatson Exp $ + * $FreeBSD: src/sys/contrib/dev/oltr/if_oltr.c,v 1.39 2005/09/16 12:49:05 ru Exp $ */ #include <sys/param.h> @@ -152,12 +152,14 @@ RF_ACTIVE | RF_SHAREABLE : RF_ACTIVE); if (sc->irq_res == NULL) { device_printf(dev, "couldn't map interrupt\n"); + if_free(ifp); return (-1); } if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, oltr_intr, sc, &sc-> oltr_intrhand)) { device_printf(dev, "couldn't setup interrupt\n"); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); + if_free(ifp); return (-1); } ==== //depot/projects/netsmp/src/sys/dev/fe/if_fe.c#6 (text+ko) ==== @@ -21,7 +21,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: src/sys/dev/fe/if_fe.c,v 1.93 2005/08/09 10:19:47 rwatson Exp $"); +__FBSDID("$FreeBSD: src/sys/dev/fe/if_fe.c,v 1.94 2005/09/16 12:49:06 ru Exp $"); /* * @@ -743,6 +743,7 @@ error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, fe_intr, sc, &sc->irq_handle); if (error) { + if_free(ifp); fe_release_resource(dev); return ENXIO; } ==== //depot/projects/netsmp/src/sys/dev/lnc/if_lnc.c#7 (text+ko) ==== @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: src/sys/dev/lnc/if_lnc.c,v 1.113 2005/08/09 10:19:50 rwatson Exp $"); +__FBSDID("$FreeBSD: src/sys/dev/lnc/if_lnc.c,v 1.114 2005/09/16 12:49:05 ru Exp $"); /* #define DIAGNOSTIC @@ -212,6 +212,9 @@ } bus_dma_tag_destroy(sc->dmat); } + + if (sc->ifp) + if_free(sc->ifp); } /* @@ -897,7 +900,6 @@ int s = splimp(); ether_ifdetach(sc->ifp); - if_free(sc->ifp); lnc_stop(sc); lnc_release_resources(dev); ==== //depot/projects/netsmp/src/sys/dev/nve/if_nve.c#7 (text+ko) ==== @@ -74,7 +74,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: src/sys/dev/nve/if_nve.c,v 1.10 2005/08/09 10:19:51 rwatson Exp $"); +__FBSDID("$FreeBSD: src/sys/dev/nve/if_nve.c,v 1.11 2005/09/16 12:49:05 ru Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -560,8 +560,10 @@ if (device_is_attached(dev)) { nve_stop(sc); ether_ifdetach(ifp); + } + + if (ifp) if_free(ifp); - } if (sc->miibus) device_delete_child(dev, sc->miibus); ==== //depot/projects/netsmp/src/sys/dev/patm/if_patm_attach.c#2 (text+ko) ==== @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: src/sys/dev/patm/if_patm_attach.c,v 1.11 2005/07/01 10:45:02 harti Exp $"); +__FBSDID("$FreeBSD: src/sys/dev/patm/if_patm_attach.c,v 1.12 2005/09/16 12:49:06 ru Exp $"); #include "opt_inet.h" #include "opt_natm.h" @@ -477,7 +477,6 @@ mtx_unlock(&sc->mtx); atm_ifdetach(sc->ifp); - if_free(sc->ifp); patm_destroy(sc); @@ -562,6 +561,9 @@ cv_destroy(&sc->vcc_cv); mtx_destroy(&sc->tst_lock); mtx_destroy(&sc->mtx); + + if (sc->ifp != NULL) + if_free(sc->ifp); } /* ==== //depot/projects/netsmp/src/sys/dev/ral/if_ral.c#7 (text+ko) ==== @@ -1,4 +1,4 @@ -/* $FreeBSD: src/sys/dev/ral/if_ral.c,v 1.15 2005/08/21 14:16:19 damien Exp $ */ +/* $FreeBSD: src/sys/dev/ral/if_ral.c,v 1.16 2005/09/16 12:17:12 ru Exp $ */ /*- * Copyright (c) 2005 @@ -18,7 +18,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD: src/sys/dev/ral/if_ral.c,v 1.15 2005/08/21 14:16:19 damien Exp $"); +__FBSDID("$FreeBSD: src/sys/dev/ral/if_ral.c,v 1.16 2005/09/16 12:17:12 ru Exp $"); /*- * Ralink Technology RT2500 chipset driver @@ -508,9 +508,8 @@ fail7: bpfdetach(ifp); ieee80211_ifdetach(ic); -fail6: if_free(ifp); - - ral_free_rx_ring(sc, &sc->rxq); + if_free(ifp); +fail6: ral_free_rx_ring(sc, &sc->rxq); fail5: ral_free_tx_ring(sc, &sc->bcnq); fail4: ral_free_tx_ring(sc, &sc->prioq); fail3: ral_free_tx_ring(sc, &sc->atimq); ==== //depot/projects/netsmp/src/sys/geom/geom_gpt.c#2 (text+ko) ==== @@ -1,247 +1,819 @@ /*- - * Copyright (c) 2002 Marcel Moolenaar - * Copyright (c) 2002 Poul-Henning Kamp - * Copyright (c) 2002 Networks Associates Technology, Inc. + * Copyright (c) 2002, 2005 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. - * 3. The names of the authors may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * 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 <sys/cdefs.h> -__FBSDID("$FreeBSD: src/sys/geom/geom_gpt.c,v 1.32 2005/03/18 07:03:56 phk Exp $"); +__FBSDID("$FreeBSD: src/sys/geom/geom_gpt.c,v 1.33 2005/09/17 07:05:17 marcel Exp $"); #include <sys/param.h> -#include <sys/systm.h> +#include <sys/bio.h> +#include <sys/diskmbr.h> +#include <sys/endian.h> +#include <sys/gpt.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/malloc.h> -#include <sys/bio.h> -#include <sys/lock.h> #include <sys/mutex.h> -#include <sys/diskmbr.h> -#include <sys/endian.h> +#include <sys/queue.h> #include <sys/sbuf.h> +#include <sys/systm.h> #include <sys/uuid.h> -#include <sys/gpt.h> #include <geom/geom.h> -#include <geom/geom_slice.h> CTASSERT(offsetof(struct gpt_hdr, padding) == 92); CTASSERT(sizeof(struct gpt_ent) == 128); +#define G_GPT_TRACE(args) /* g_trace args */ + +/* + * The GEOM GPT class. Nothing fancy... + */ +static g_ctl_req_t g_gpt_ctlreq; +static g_ctl_destroy_geom_t g_gpt_destroy_geom; +static g_taste_t g_gpt_taste; + +static g_access_t g_gpt_access; +static g_dumpconf_t g_gpt_dumpconf; +static g_orphan_t g_gpt_orphan; +static g_spoiled_t g_gpt_spoiled; +static g_start_t g_gpt_start; + +static struct g_class g_gpt_class = { + .name = "GPT", + .version = G_VERSION, + /* Class methods. */ + .ctlreq = g_gpt_ctlreq, + .destroy_geom = g_gpt_destroy_geom, + .taste = g_gpt_taste, + /* Geom methods. */ + .access = g_gpt_access, + .dumpconf = g_gpt_dumpconf, + .orphan = g_gpt_orphan, + .spoiled = g_gpt_spoiled, + .start = g_gpt_start, +}; + +DECLARE_GEOM_CLASS(g_gpt_class, g_gpt); + /* - * XXX: GEOM is not dynamic enough. We are forced to use a compile-time - * limit. The minimum number of partitions (128) as required by EFI is - * most of the time just a waste of space. + * The GEOM GPT instance data. */ -#define GPT_MAX_SLICES 128 +struct g_gpt_part { + LIST_ENTRY(g_gpt_part) parts; + struct g_provider *provider; + off_t offset; + struct gpt_ent ent; + int index; +}; + +enum gpt_hdr_type { + GPT_HDR_PRIMARY, + GPT_HDR_SECONDARY, + GPT_HDR_COUNT +}; + +enum gpt_hdr_state { + GPT_HDR_UNKNOWN, + GPT_HDR_MISSING, + GPT_HDR_CORRUPT, + GPT_HDR_INVALID, + GPT_HDR_OK +}; struct g_gpt_softc { - struct gpt_ent *part[GPT_MAX_SLICES]; + LIST_HEAD(, g_gpt_part) parts; + struct gpt_hdr hdr[GPT_HDR_COUNT]; + enum gpt_hdr_state state[GPT_HDR_COUNT]; }; -static int -is_gpt_hdr(struct gpt_hdr *hdr) -{ - uint32_t crc; +static struct uuid g_gpt_freebsd = GPT_ENT_TYPE_FREEBSD; +static struct uuid g_gpt_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; +static struct uuid g_gpt_linux_swap = GPT_ENT_TYPE_LINUX_SWAP; +static struct uuid g_gpt_unused = GPT_ENT_TYPE_UNUSED; - if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig))) - return (0); - crc = le32toh(hdr->hdr_crc_self); - hdr->hdr_crc_self = 0; - if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) - return (0); - hdr->hdr_crc_self = htole32(crc); - /* We're happy... */ - return (1); -} +/* + * Support functions. + */ static int -is_pmbr(char *mbr) +g_gpt_has_pmbr(struct g_consumer *cp, int *error) { struct dos_partition *part; - int i; + char *buf; + int i, pmbr; uint16_t magic; - magic = le16toh(*(uint16_t *)(uintptr_t)(mbr + DOSMAGICOFFSET)); + buf = g_read_data(cp, 0L, cp->provider->sectorsize, error); + if (*error != 0) + return (0); + + pmbr = 0; + + magic = le16toh(*(uint16_t *)(uintptr_t)(buf + DOSMAGICOFFSET)); if (magic != DOSMAGIC) - return (0); + goto out; - part = (struct dos_partition *)(uintptr_t)(mbr + DOSPARTOFF); + part = (struct dos_partition *)(uintptr_t)(buf + DOSPARTOFF); for (i = 0; i < 4; i++) { if (part[i].dp_typ != 0 && part[i].dp_typ != DOSPTYP_PMBR) - return (0); + goto out; } - return (1); + pmbr = 1; + +out: + g_free(buf); + return (pmbr); } -static int -g_gpt_start(struct bio *bp) +static void +g_gpt_load_hdr(struct g_gpt_softc *softc, struct g_provider *pp, + enum gpt_hdr_type type, void *buf) { + struct uuid uuid; + struct gpt_hdr *hdr; + uint64_t lba, last; + uint32_t crc, sz; + + softc->state[type] = GPT_HDR_MISSING; + + hdr = softc->hdr + type; + bcopy(buf, hdr, sizeof(*hdr)); + if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0) + return; + + softc->state[type] = GPT_HDR_CORRUPT; + + sz = le32toh(hdr->hdr_size); + if (sz < 92 || sz > pp->sectorsize) + return; + crc = le32toh(hdr->hdr_crc_self); + hdr->hdr_crc_self = 0; + if (crc32(hdr, sz) != crc) + return; + hdr->hdr_size = sz; + hdr->hdr_crc_self = crc; + + softc->state[type] = GPT_HDR_INVALID; - return (0); + last = (pp->mediasize / pp->sectorsize) - 1; + hdr->hdr_revision = le32toh(hdr->hdr_revision); + if (hdr->hdr_revision < 0x00010000) + return; + hdr->hdr_lba_self = le64toh(hdr->hdr_lba_self); + if (hdr->hdr_lba_self != (type == GPT_HDR_PRIMARY ? 1 : last)) + return; + hdr->hdr_lba_alt = le64toh(hdr->hdr_lba_alt); + if (hdr->hdr_lba_alt != (type == GPT_HDR_PRIMARY ? last : 1)) + return; + + /* Check the managed area. */ + hdr->hdr_lba_start = le64toh(hdr->hdr_lba_start); + if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last) + return; + hdr->hdr_lba_end = le64toh(hdr->hdr_lba_end); + if (hdr->hdr_lba_end < hdr->hdr_lba_start || hdr->hdr_lba_end >= last) + return; + + /* Check the table location and size of the table. */ + hdr->hdr_entries = le32toh(hdr->hdr_entries); + hdr->hdr_entsz = le32toh(hdr->hdr_entsz); + if (hdr->hdr_entries == 0 || hdr->hdr_entsz < 128 || + (hdr->hdr_entsz & 7) != 0) + return; + hdr->hdr_lba_table = le64toh(hdr->hdr_lba_table); + if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last) + return; + if (hdr->hdr_lba_table >= hdr->hdr_lba_start && + hdr->hdr_lba_table <= hdr->hdr_lba_end) + return; + lba = hdr->hdr_lba_table + + (hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) / + pp->sectorsize - 1; + if (lba >= last) + return; + if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end) + return; + + softc->state[type] = GPT_HDR_OK; + + le_uuid_dec(&hdr->hdr_uuid, &uuid); + hdr->hdr_uuid = uuid; + hdr->hdr_crc_table = le32toh(hdr->hdr_crc_table); } static void -g_gpt_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, - struct g_consumer *cp, struct g_provider *pp) +g_gpt_load_tbl(struct g_geom *gp, struct g_provider *pp, struct gpt_hdr *hdr, + char *tbl) { - struct g_slicer *gsp = gp->softc; - struct g_gpt_softc *gs = gsp->softc; struct uuid uuid; + struct gpt_ent *ent; + struct g_gpt_part *last, *part; + struct g_gpt_softc *softc; + uint64_t part_start, part_end; + unsigned int ch, idx; + + softc = gp->softc; - g_slice_dumpconf(sb, indent, gp, cp, pp); + for (idx = 0, last = part = NULL; + idx < hdr->hdr_entries; + idx++, last = part, tbl += hdr->hdr_entsz) { + ent = (struct gpt_ent *)(uintptr_t)tbl; + le_uuid_dec(&ent->ent_type, &uuid); + if (!memcmp(&uuid, &g_gpt_unused, sizeof(struct uuid))) + continue; + part_start = le64toh(ent->ent_lba_start); + part_end = le64toh(ent->ent_lba_end); + if (part_start < hdr->hdr_lba_start || part_start > part_end || + part_end > hdr->hdr_lba_end) { + printf("GEOM: %s: GPT partition %d is invalid -- " + "ignored.\n", gp->name, idx + 1); + continue; + } - if (pp != NULL) { - le_uuid_dec(&gs->part[pp->index]->ent_type, &uuid); - if (indent != NULL) - sbuf_printf(sb, "%s<type>", indent); + part = g_malloc(sizeof(struct g_gpt_part), M_WAITOK | M_ZERO); + part->index = idx; + part->offset = part_start * pp->sectorsize; + if (last == NULL) + LIST_INSERT_HEAD(&softc->parts, part, parts); else - sbuf_printf(sb, " ty "); - sbuf_printf_uuid(sb, &uuid); - if (indent != NULL) - sbuf_printf(sb, "</type>\n"); + LIST_INSERT_AFTER(last, part, parts); + part->ent.ent_type = uuid; + le_uuid_dec(&ent->ent_uuid, &part->ent.ent_uuid); + part->ent.ent_lba_start = part_start; + part->ent.ent_lba_end = part_end; + part->ent.ent_attr = le64toh(ent->ent_attr); + for (ch = 0; ch < sizeof(ent->ent_name)/2; ch++) + part->ent.ent_name[ch] = le16toh(ent->ent_name[ch]); + + g_topology_lock(); + part->provider = g_new_providerf(gp, "%s%c%d", gp->name, + !memcmp(&uuid, &g_gpt_freebsd, sizeof(struct uuid)) + ? 's' : 'p', idx + 1); + part->provider->index = idx; + part->provider->private = part; /* Close the circle. */ + part->provider->mediasize = (part_end - part_start + 1) * + pp->sectorsize; + part->provider->sectorsize = pp->sectorsize; + part->provider->flags = pp->flags & G_PF_CANDELETE; + if (pp->stripesize > 0) { + part->provider->stripesize = pp->stripesize; + part->provider->stripeoffset = + (pp->stripeoffset + part->offset) % pp->stripesize; + } + g_error_provider(part->provider, 0); + g_topology_unlock(); + + if (bootverbose) { + printf("GEOM: %s: partition ", part->provider->name); + printf_uuid(&part->ent.ent_uuid); + printf(".\n"); + } + } +} + +static int +g_gpt_matched_hdrs(struct gpt_hdr *pri, struct gpt_hdr *sec) +{ + + if (memcmp(&pri->hdr_uuid, &sec->hdr_uuid, sizeof(struct uuid)) != 0) + return (0); + return ((pri->hdr_revision == sec->hdr_revision && + pri->hdr_size == sec->hdr_size && + pri->hdr_lba_start == sec->hdr_lba_start && + pri->hdr_lba_end == sec->hdr_lba_end && + pri->hdr_entries == sec->hdr_entries && + pri->hdr_entsz == sec->hdr_entsz && + pri->hdr_crc_table == sec->hdr_crc_table) ? 1 : 0); +} + +static int +g_gpt_tbl_ok(struct gpt_hdr *hdr, char *tbl) +{ + size_t sz; + uint32_t crc; + + crc = hdr->hdr_crc_table; + sz = hdr->hdr_entries * hdr->hdr_entsz; + return ((crc32(tbl, sz) == crc) ? 1 : 0); +} + +static void +g_gpt_to_utf8(struct sbuf *sb, uint16_t *str, size_t len) +{ + u_int bo; + uint32_t ch; + uint16_t c; + + bo = BYTE_ORDER; + while (len > 0 && *str != 0) { + ch = (bo == BIG_ENDIAN) ? be16toh(*str) : le16toh(*str); + str++, len--; + if ((ch & 0xf800) == 0xd800) { + if (len > 0) { + c = (bo == BIG_ENDIAN) ? be16toh(*str) + : le16toh(*str); + str++, len--; + } else + c = 0xfffd; + if ((ch & 0x400) == 0 && (c & 0xfc00) == 0xdc00) { + ch = ((ch & 0x3ff) << 10) + (c & 0x3ff); + ch += 0x10000; + } else + ch = 0xfffd; + } else if (ch == 0xfffe) { /* BOM (U+FEFF) swapped. */ + bo = (bo == BIG_ENDIAN) ? LITTLE_ENDIAN : BIG_ENDIAN; + continue; + } else if (ch == 0xfeff) /* BOM (U+FEFF) unswapped. */ + continue; + + if (ch < 0x80) + sbuf_printf(sb, "%c", ch); + else if (ch < 0x800) + sbuf_printf(sb, "%c%c", 0xc0 | (ch >> 6), + 0x80 | (ch & 0x3f)); + else if (ch < 0x10000) + sbuf_printf(sb, "%c%c%c", 0xe0 | (ch >> 12), + 0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f)); + else if (ch < 0x200000) + sbuf_printf(sb, "%c%c%c%c", 0xf0 | (ch >> 18), + 0x80 | ((ch >> 12) & 0x3f), + 0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f)); + } +} + +static void +g_gpt_wither(struct g_geom *gp, int error) +{ + struct g_gpt_part *part; + struct g_gpt_softc *softc; + + softc = gp->softc; + if (softc != NULL) { + part = LIST_FIRST(&softc->parts); + while (part != NULL) { + LIST_REMOVE(part, parts); + g_free(part); + part = LIST_FIRST(&softc->parts); + } + g_free(softc); + gp->softc = NULL; } + g_wither_geom(gp, error); +} + +/* + * Class methods. + */ + +static void +g_gpt_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) +{ + /* XXX todo */ +} + +static int +g_gpt_destroy_geom(struct gctl_req *req, struct g_class *mp, + struct g_geom *gp) +{ + + G_GPT_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name)); + + g_topology_assert(); + + g_gpt_wither(gp, EINVAL); + return (0); } static struct g_geom * g_gpt_taste(struct g_class *mp, struct g_provider *pp, int insist __unused) { - struct uuid tmp; struct g_consumer *cp; struct g_geom *gp; - struct g_gpt_softc *gs; - u_char *buf, *mbr; - struct gpt_ent *ent, *part; + struct g_gpt_softc *softc; struct gpt_hdr *hdr; - u_int i, secsz, tblsz; - int error, ps; - uint32_t entries, entsz; + void *buf; + off_t ofs; + size_t nbytes; + int error; - g_trace(G_T_TOPOLOGY, "g_gpt_taste(%s,%s)", mp->name, pp->name); + G_GPT_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name)); g_topology_assert(); /* - * XXX: I don't like to hardcode a maximum number of slices, since - * it's wasting space most of the time and insufficient any time. - * It's easier for now... + * Sanity-check the provider. Since the first sector on the provider + * must be a PMBR and a PMBR is 512 bytes large, the sector size must + * be at least 512 bytes. We also require that the sector size is a + * multiple of the GPT entry size (which is 128 bytes). + * Also, since the theoretical minimum number of sectors needed by + * GPT is 6, any medium that has less than 6 sectors is never going + * to hold a GPT. The number 6 comes from: + * 1 sector for the PMBR + * 2 sectors for the GPT headers (each 1 sector) + * 2 sectors for the GPT tables (each 1 sector) + * 1 sector for an actual partition + * It's better to catch this pathological case early than behaving + * pathologically later on by panicing... + */ + if (pp->sectorsize < 512 || + pp->sectorsize % sizeof(struct gpt_ent) != 0 || + pp->mediasize < 6 * pp->sectorsize) + return (NULL); + + /* + * We don't nest. That is, we disallow nesting a GPT inside a GPT + * partition. We check only for direct nesting. Indirect nesting is + * not easy to determine. If you want, you can therefore nest GPT + * partitions by putting a dummy GEOM in between them. But I didn't + * say that... + */ + if (pp->geom->class == &g_gpt_class) + return (NULL); + + /* + * Create a GEOM with consumer and hook it up to the provider. + * With that we become part of the topology. Optain read, write + * and exclusive access to the provider. */ - gp = g_slice_new(mp, GPT_MAX_SLICES, pp, &cp, &gs, sizeof(*gs), - g_gpt_start); - if (gp == NULL) + gp = g_new_geomf(mp, "%s", pp->name); + softc = g_malloc(sizeof(struct g_gpt_softc), M_WAITOK | M_ZERO); + gp->softc = softc; + LIST_INIT(&softc->parts); + cp = g_new_consumer(gp); + error = g_attach(cp, pp); + if (error == 0) + error = g_access(cp, 1, 0, 0); + if (error != 0) { + g_gpt_wither(gp, error); return (NULL); + } g_topology_unlock(); - do { - mbr = NULL; + /* + * Read both the primary and secondary GPT headers. We have all + * the information at our fingertips that way to determine if + * there's a GPT, including whether recovery is appropriate. + */ + buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error); + if (error != 0) + goto fail; + g_gpt_load_hdr(softc, pp, GPT_HDR_PRIMARY, buf); + g_free(buf); + + buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, + &error); + if (error != 0) + goto fail; + g_gpt_load_hdr(softc, pp, GPT_HDR_SECONDARY, buf); + g_free(buf); + + /* Bail out if there are no GPT headers at all. */ + if (softc->state[GPT_HDR_PRIMARY] == GPT_HDR_MISSING && + softc->state[GPT_HDR_SECONDARY] == GPT_HDR_MISSING) { + error = ENXIO; /* Device not configured for GPT. */ + goto fail; + } - secsz = cp->provider->sectorsize; - if (secsz < 512) - break; + /* + * We have at least one GPT header (though that one may be corrupt + * or invalid). This disk supposedly has GPT in some shape or form. + * First check that there's a protective MBR. Complain if there + * is none and fail. + */ + if (!g_gpt_has_pmbr(cp, &error)) { + printf("GEOM: %s: GPT detected, but no protective MBR.\n", + pp->name); + error = ENXIO; + goto fail; + } - /* XXX: we need to get the media size as well. */ + /* + * Now, catch the non-recoverable case where there's no good GPT + * header at all. That is, unrecoverable by us. The user may able + * to fix it up with some magic. + */ + if (softc->state[GPT_HDR_PRIMARY] != GPT_HDR_OK && + softc->state[GPT_HDR_SECONDARY] != GPT_HDR_OK) { + printf("GEOM: %s: corrupt or invalid GPT detected.\n", + pp->name); + printf("GEOM: %s: GPT rejected -- may not be recoverable.\n", + pp->name); + error = EINVAL; /* No valid GPT header exists. */ + goto fail; + } - /* Read both the MBR sector and the GPT sector. */ - mbr = g_read_data(cp, 0, 2 * secsz, &error); - if (mbr == NULL || error != 0) - break; + /* + * Ok, at least one header is good. We can use the GPT. If there's + * a corrupt or invalid header, we'd like to user to know about it. + * Also catch the case where both headers appear to be good but are + * not mirroring each other. We only check superficially for that. + */ + if (softc->state[GPT_HDR_PRIMARY] != GPT_HDR_OK) { + printf("GEOM: %s: the primary GPT header is corrupt or " + "invalid.\n", pp->name); + printf("GEOM: %s: using the secondary instead -- recovery " + "strongly advised.\n", pp->name); + } else if (softc->state[GPT_HDR_SECONDARY] != GPT_HDR_OK) { + printf("GEOM: %s: the secondary GPT header is corrupt or " + "invalid.\n", pp->name); + printf("GEOM: %s: using the primary only -- recovery " + "suggested.\n", pp->name); + } else if (!g_gpt_matched_hdrs(softc->hdr + GPT_HDR_PRIMARY, + softc->hdr + GPT_HDR_SECONDARY)) { + printf("GEOM: %s: the primary and secondary GPT header do " + "not agree.\n", pp->name); + printf("GEOM: %s: GPT rejected -- recovery required.\n", + pp->name); + error = EINVAL; /* No consistent GPT exists. */ + goto fail; + } - if (!is_pmbr(mbr)) - break; + /* Always prefer the primary header. */ + hdr = (softc->state[GPT_HDR_PRIMARY] == GPT_HDR_OK) + ? softc->hdr + GPT_HDR_PRIMARY : softc->hdr + GPT_HDR_SECONDARY; - hdr = (void*)(mbr + secsz); + /* + * Now that we've got a GPT header, we have to deal with the table + * itself. Again there's a primary table and a secondary table and + * either or both may be corrupt or invalid. Redundancy is nice, + * but it's a combinatorial pain in the butt. + */ - /* - * XXX: if we don't have a GPT header at LBA 1, we should - * check if there's a backup GPT at the end of the medium. If - * we have a valid backup GPT, we should restore the primary - * GPT and claim this lunch. - */ - if (!is_gpt_hdr(hdr)) - break; + nbytes = ((hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) / + pp->sectorsize) * pp->sectorsize; - entries = le32toh(hdr->hdr_entries); - entsz = le32toh(hdr->hdr_entsz); - tblsz = (entries * entsz + secsz - 1) & ~(secsz - 1); - buf = g_read_data(cp, le64toh(hdr->hdr_lba_table) * secsz, - tblsz, &error); - if (buf == NULL) - break; + ofs = hdr->hdr_lba_table * pp->sectorsize; + buf = g_read_data(cp, ofs, nbytes, &error); + if (error != 0) + goto fail; - for (i = 0; i < entries; i++) { - struct uuid unused = GPT_ENT_TYPE_UNUSED; - struct uuid freebsd = GPT_ENT_TYPE_FREEBSD; + /* + * If the table is corrupt, check if we can use the other one. + * Complain and bail if not. + */ + if (!g_gpt_tbl_ok(hdr, buf)) { + g_free(buf); + if (hdr != softc->hdr + GPT_HDR_PRIMARY || + softc->state[GPT_HDR_SECONDARY] != GPT_HDR_OK) { + printf("GEOM: %s: the GPT table is corrupt -- " + "may not be recoverable.\n", pp->name); + goto fail; + } + softc->state[GPT_HDR_PRIMARY] = GPT_HDR_CORRUPT; + hdr = softc->hdr + GPT_HDR_SECONDARY; + ofs = hdr->hdr_lba_table * pp->sectorsize; + buf = g_read_data(cp, ofs, nbytes, &error); + if (error != 0) + goto fail; - if (i >= GPT_MAX_SLICES) - break; - ent = (void*)(buf + i * entsz); - le_uuid_dec(&ent->ent_type, &tmp); - if (!memcmp(&tmp, &unused, sizeof(unused))) - continue; - /* XXX: This memory leaks */ - part = gs->part[i] = g_malloc(entsz, M_WAITOK); - if (part == NULL) - break; - part->ent_type = tmp; - le_uuid_dec(&ent->ent_uuid, &part->ent_uuid); - part->ent_lba_start = le64toh(ent->ent_lba_start); - part->ent_lba_end = le64toh(ent->ent_lba_end); - part->ent_attr = le64toh(ent->ent_attr); - /* XXX do we need to byte-swap UNICODE-16? */ - bcopy(ent->ent_name, part->ent_name, - sizeof(part->ent_name)); - ps = (!memcmp(&tmp, &freebsd, sizeof(freebsd))) - ? 's' : 'p'; - g_topology_lock(); - (void)g_slice_config(gp, i, G_SLICE_CONFIG_SET, - part->ent_lba_start * secsz, - (1 + part->ent_lba_end - part->ent_lba_start) * - secsz, secsz, "%s%c%d", gp->name, ps, i + 1); - g_topology_unlock(); + if (!g_gpt_tbl_ok(hdr, buf)) { + g_free(buf); + printf("GEOM: %s: both primary and secondary GPT " + "tables are corrupt.\n", pp->name); + printf("GEOM: %s: GPT rejected -- may not be " + "recoverable.\n", pp->name); + goto fail; } - g_free(buf); - } while (0); + printf("GEOM: %s: the primary GPT table is corrupt.\n", + pp->name); + printf("GEOM: %s: using the secondary table -- recovery " + "strongly advised.\n", pp->name); + } + + if (bootverbose) { + printf("GEOM: %s: GPT ", pp->name); + printf_uuid(&hdr->hdr_uuid); + printf(".\n"); + } - if (mbr != NULL) - g_free(mbr); + g_gpt_load_tbl(gp, pp, hdr, buf); + g_free(buf); + g_topology_lock(); + g_access(cp, -1, 0, 0); + return (gp); + fail: g_topology_lock(); g_access(cp, -1, 0, 0); - if (LIST_EMPTY(&gp->provider)) { - g_slice_spoiled(cp); - return (NULL); + g_gpt_wither(gp, error); + return (NULL); +} + +/* + * Geom methods. + */ + +static int +g_gpt_access(struct g_provider *pp, int dr, int dw, int de) +{ + struct g_consumer *cp; + + G_GPT_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr, + dw, de)); + + cp = LIST_FIRST(&pp->geom->consumer); + + /* We always gain write-exclusive access. */ + return (g_access(cp, dr, dw, dw + de)); +} + >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200509170946.j8H9ksYa012782>