PERFORCE change 83777 for review
Robert Watson
rwatson at FreeBSD.org
Sat Sep 17 02:46:56 PDT 2005
http://perforce.freebsd.org/chv.cgi?CH=83777
Change 83777 by rwatson at 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) <<<
More information about the p4-projects
mailing list