Skip site navigation (1)Skip section navigation (2)
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>