summaryrefslogtreecommitdiffstats
path: root/sys/geom/geom_gpt.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/geom/geom_gpt.c')
-rw-r--r--sys/geom/geom_gpt.c1356
1 files changed, 0 insertions, 1356 deletions
diff --git a/sys/geom/geom_gpt.c b/sys/geom/geom_gpt.c
deleted file mode 100644
index bea8c7b..0000000
--- a/sys/geom/geom_gpt.c
+++ /dev/null
@@ -1,1356 +0,0 @@
-/*-
- * Copyright (c) 2002, 2005, 2006 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 <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.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/mutex.h>
-#include <sys/queue.h>
-#include <sys/sbuf.h>
-#include <sys/systm.h>
-#include <sys/uuid.h>
-#include <geom/geom.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);
-
-/*
- * The GEOM GPT instance data.
- */
-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 {
- LIST_HEAD(, g_gpt_part) parts;
- struct gpt_hdr hdr[GPT_HDR_COUNT];
- enum gpt_hdr_state state[GPT_HDR_COUNT];
-};
-
-enum g_gpt_ctl {
- G_GPT_CTL_NONE,
- G_GPT_CTL_ADD,
- G_GPT_CTL_CREATE,
- G_GPT_CTL_DESTROY,
- G_GPT_CTL_MODIFY,
- G_GPT_CTL_RECOVER,
- G_GPT_CTL_REMOVE
-};
-
-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;
-
-/*
- * Support functions.
- */
-
-static void g_gpt_wither(struct g_geom *, int);
-
-static void
-g_gpt_ctl_add(struct gctl_req *req, const char *flags, struct g_geom *gp,
- struct uuid *type, uint64_t start, uint64_t end, long entry)
-{
- char buf[16];
- struct g_provider *pp;
- struct g_gpt_softc *softc;
- struct g_gpt_part *last, *part;
- u_int idx;
-
- G_GPT_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
- g_topology_assert();
-
- pp = LIST_FIRST(&gp->consumer)->provider;
- softc = gp->softc;
-
- last = NULL;
- idx = (entry > 0) ? (u_int)(entry - 1) : 0;
- LIST_FOREACH(part, &softc->parts, parts) {
- if (part->index == idx) {
- idx = part->index + 1;
- last = part;
- }
- if ((start >= part->ent.ent_lba_start &&
- start <= part->ent.ent_lba_end) ||
- (end >= part->ent.ent_lba_start &&
- end <= part->ent.ent_lba_end) ||
- (start < part->ent.ent_lba_start &&
- end > part->ent.ent_lba_end)) {
- gctl_error(req, "%d start/end %jd/%jd", ENOSPC,
- (intmax_t)start, (intmax_t)end);
- return;
- }
- }
- if (entry > 0 && (long)idx != entry - 1) {
- gctl_error(req, "%d entry %ld", EEXIST, entry);
- return;
- }
- snprintf(buf, sizeof(buf), "%u", idx + 1);
- gctl_set_param(req, "entry", buf, strlen(buf) + 1);
-
- part = g_malloc(sizeof(struct g_gpt_part), M_WAITOK | M_ZERO);
- part->index = idx;
- part->offset = start * pp->sectorsize;
- if (last == NULL)
- LIST_INSERT_HEAD(&softc->parts, part, parts);
- else
- LIST_INSERT_AFTER(last, part, parts);
- part->ent.ent_type = *type;
- kern_uuidgen(&part->ent.ent_uuid, 1);
- part->ent.ent_lba_start = start;
- part->ent.ent_lba_end = end;
-
- /* XXX ent_attr */
- /* XXX ent_name */
-
- part->provider = g_new_providerf(gp, "%s%c%d", gp->name,
- !memcmp(type, &g_gpt_freebsd, sizeof(struct uuid)) ? 's' : 'p',
- idx + 1);
- part->provider->index = idx;
- part->provider->private = part; /* Close the circle. */
- part->provider->mediasize = (end - 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);
-
- if (bootverbose) {
- printf("GEOM: %s: partition ", part->provider->name);
- printf_uuid(&part->ent.ent_uuid);
- printf(".\n");
- }
-}
-
-static struct g_geom *
-g_gpt_ctl_create(struct gctl_req *req, const char *flags, struct g_class *mp,
- struct g_provider *pp, uint32_t entries)
-{
- struct uuid uuid;
- struct g_consumer *cp;
- struct g_geom *gp;
- struct g_gpt_softc *softc;
- struct gpt_hdr *hdr;
- uint64_t last;
- size_t tblsz;
- int error, i;
-
- G_GPT_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name));
- g_topology_assert();
-
- tblsz = (entries * sizeof(struct gpt_ent) + pp->sectorsize - 1) /
- pp->sectorsize;
-
- /*
- * Sanity-check the size of the provider. This test is very similar
- * to the one in g_gpt_taste(). Here we want to make sure that the
- * size of the provider is large enough to hold a GPT that has the
- * requested number of entries, plus as many available sectors for
- * partitions of minimal size. The latter test is not exactly needed
- * but it helps keep the table size proportional to the media size.
- * Thus, a GPT with 128 entries must at least have 128 sectors of
- * usable partition space. Therefore, the absolute minimal size we
- * allow is (1 + 2 * (1 + 32) + 128) = 195 sectors. This is more
- * restrictive than what g_gpt_taste() requires.
- */
- if (pp->sectorsize < 512 ||
- pp->sectorsize % sizeof(struct gpt_ent) != 0 ||
- pp->mediasize < (3 + 2 * tblsz + entries) * pp->sectorsize) {
- gctl_error(req, "%d provider", ENOSPC);
- return (NULL);
- }
-
- /* We don't nest. See also g_gpt_taste(). */
- if (pp->geom->class == &g_gpt_class) {
- gctl_error(req, "%d provider", ENODEV);
- return (NULL);
- }
-
- /* Create a GEOM. */
- 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);
- gctl_error(req, "%d geom '%s'", error, pp->name);
- return (NULL);
- }
-
- last = (pp->mediasize / pp->sectorsize) - 1;
- kern_uuidgen(&uuid, 1);
-
- /* Construct an in-memory GPT. */
- for (i = GPT_HDR_PRIMARY; i < GPT_HDR_COUNT; i++) {
- hdr = softc->hdr + i;
- bcopy(GPT_HDR_SIG, hdr->hdr_sig, sizeof(hdr->hdr_sig));
- hdr->hdr_revision = GPT_HDR_REVISION;
- hdr->hdr_size = offsetof(struct gpt_hdr, padding);
- hdr->hdr_lba_self = (i == GPT_HDR_PRIMARY) ? 1 : last;
- hdr->hdr_lba_alt = (i == GPT_HDR_PRIMARY) ? last : 1;
- hdr->hdr_lba_start = 2 + tblsz;
- hdr->hdr_lba_end = last - (1 + tblsz);
- hdr->hdr_uuid = uuid;
- hdr->hdr_lba_table = (i == GPT_HDR_PRIMARY) ? 2 : last - tblsz;
- hdr->hdr_entries = entries;
- hdr->hdr_entsz = sizeof(struct gpt_ent);
- softc->state[i] = GPT_HDR_OK;
- }
-
- if (0)
- goto fail;
-
- if (bootverbose) {
- printf("GEOM: %s: GPT ", pp->name);
- printf_uuid(&softc->hdr[GPT_HDR_PRIMARY].hdr_uuid);
- printf(".\n");
- }
-
- g_access(cp, -1, 0, 0);
- return (gp);
-
-fail:
- g_access(cp, -1, 0, 0);
- g_gpt_wither(gp, error);
- gctl_error(req, "%d geom '%s'", error, pp->name);
- return (NULL);
-}
-
-static void
-g_gpt_ctl_destroy(struct gctl_req *req, const char *flags, struct g_geom *gp)
-{
-}
-
-static void
-g_gpt_ctl_modify(struct gctl_req *req, const char *flags, struct g_geom *gp,
- long entry)
-{
-}
-
-static void
-g_gpt_ctl_recover(struct gctl_req *req, const char *flags, struct g_geom *gp)
-{
-}
-
-static void
-g_gpt_ctl_remove(struct gctl_req *req, const char *flags, struct g_geom *gp,
- long entry)
-{
- struct g_provider *pp;
- struct g_gpt_softc *softc;
- struct g_gpt_part *part;
-
- G_GPT_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
- g_topology_assert();
-
- softc = gp->softc;
-
- LIST_FOREACH(part, &softc->parts, parts) {
- if ((long)part->index == entry - 1)
- break;
- }
- if (part == NULL) {
- gctl_error(req, "%d entry %ld", ENOENT, entry);
- return;
- }
-
- pp = part->provider;
- if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) {
- gctl_error(req, "%d", EBUSY);
- return;
- }
-
- LIST_REMOVE(part, parts);
- pp->private = NULL;
- g_wither_provider(pp, ENXIO);
- g_free(part);
-}
-
-static int
-g_gpt_has_pmbr(struct g_consumer *cp, int *error)
-{
- char *buf;
- uint8_t *typ;
- uint64_t mediasize;
- int i, pmbr, parts;
- uint32_t dp_start, dp_size;
- uint16_t magic;
-
- buf = g_read_data(cp, 0L, cp->provider->sectorsize, error);
- if (buf == NULL)
- return (0);
-
- pmbr = 0;
- *error = 0;
-
- magic = le16toh(*(uint16_t *)(uintptr_t)(buf + DOSMAGICOFFSET));
- if (magic != DOSMAGIC)
- goto out;
-
- /*
- * Check that there are at least one partition of type
- * DOSPTYP_PMBR that covers the whole unit.
- */
- parts = 0;
- mediasize = cp->provider->mediasize / cp->provider->sectorsize;
- for (i = 0; i < 4; i++) {
- typ = buf + DOSPARTOFF + i * sizeof(struct dos_partition) +
- offsetof(struct dos_partition, dp_typ);
- if (*typ != 0)
- parts++;
- if (*typ != DOSPTYP_PMBR)
- continue;
-
- bcopy(buf + DOSPARTOFF + i * sizeof(struct dos_partition) +
- offsetof(struct dos_partition, dp_start), &dp_start,
- sizeof(dp_start));
- if (le32toh(dp_start) != 1)
- break;
-
- bcopy(buf + DOSPARTOFF + i * sizeof(struct dos_partition) +
- offsetof(struct dos_partition, dp_size), &dp_size,
- sizeof(dp_size));
- if (le32toh(dp_size) != ~0U &&
- le32toh(dp_size) != mediasize - 1 &&
- /* Catch old FreeBSD bug for backward compatibility. */
- le32toh(dp_size) != mediasize)
- break;
-
- pmbr = 1;
- }
-
- /*
- * Treat empty MBRs as PMBRs for increased flexibility. Note that an
- * invalid entry of type DOSPTYP_PMBR counts towards the number of
- * partitions and will prevent the MBR from being treated as a PMBR.
- */
- if (!pmbr && parts == 0)
- pmbr = 1;
-
-out:
- g_free(buf);
- return (pmbr);
-}
-
-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;
-
- 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_load_tbl(struct g_geom *gp, struct g_provider *pp, struct gpt_hdr *hdr,
- char *tbl)
-{
- 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;
-
- 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;
- }
-
- 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
- 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)
-{
- struct uuid type;
- struct g_geom *gp;
- struct g_provider *pp;
- struct g_gpt_softc *softc;
- const char *flags;
- char const *s;
- uint64_t start, end;
- long entry, entries;
- enum g_gpt_ctl ctlreq;
- int error;
-
- G_GPT_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb));
- g_topology_assert();
-
- /*
- * Improve error reporting by first checking if the verb is
- * a valid one. It also allows us to make assumptions down-
- * stream about the validity of the verb.
- */
- ctlreq = G_GPT_CTL_NONE;
- switch (*verb) {
- case 'a':
- if (!strcmp(verb, "add"))
- ctlreq = G_GPT_CTL_ADD;
- break;
- case 'c':
- if (!strcmp(verb, "create"))
- ctlreq = G_GPT_CTL_CREATE;
- break;
- case 'd':
- if (!strcmp(verb, "destroy"))
- ctlreq = G_GPT_CTL_DESTROY;
- break;
- case 'm':
- if (!strcmp(verb, "modify"))
- ctlreq = G_GPT_CTL_MODIFY;
- break;
- case 'r':
- if (!strcmp(verb, "recover"))
- ctlreq = G_GPT_CTL_RECOVER;
- else if (!strcmp(verb, "remove"))
- ctlreq = G_GPT_CTL_REMOVE;
- break;
- }
- if (ctlreq == G_GPT_CTL_NONE) {
- gctl_error(req, "%d verb '%s'", EINVAL, verb);
- return;
- }
-
- /*
- * All verbs take an optional flags parameter. The flags parameter
- * is a string with each letter an independent flag. Each verb has
- * it's own set of valid flags and the meaning of the flags is
- * specific to the verb. Typically the presence of a letter (=flag)
- * in the string means true and the absence means false.
- */
- s = gctl_get_asciiparam(req, "flags");
- flags = (s == NULL) ? "" : s;
-
- /*
- * Only the create verb takes a provider parameter. Make this a
- * special case so that more code sharing is possible for the
- * common case.
- */
- if (ctlreq == G_GPT_CTL_CREATE) {
- /*
- * Create a GPT on a pristine disk-like provider.
- * Required parameters/attributes:
- * provider
- * Optional parameters/attributes:
- * entries
- */
- s = gctl_get_asciiparam(req, "provider");
- if (s == NULL) {
- gctl_error(req, "%d provider", ENOATTR);
- return;
- }
- pp = g_provider_by_name(s);
- if (pp == NULL) {
- gctl_error(req, "%d provider '%s'", EINVAL, s);
- return;
- }
- /* Check that there isn't already a GPT on the provider. */
- LIST_FOREACH(gp, &mp->geom, geom) {
- if (!strcmp(s, gp->name)) {
- gctl_error(req, "%d geom '%s'", EEXIST, s);
- return;
- }
- }
- s = gctl_get_asciiparam(req, "entries");
- if (s != NULL) {
- entries = strtol(s, (char **)(uintptr_t)&s, 0);
- if (entries < 128 || *s != '\0') {
- gctl_error(req, "%d entries %ld", EINVAL,
- entries);
- return;
- }
- } else
- entries = 128; /* Documented mininum */
- gp = g_gpt_ctl_create(req, flags, mp, pp, entries);
- return;
- }
-
- /*
- * All but the create verb, which is handled above, operate on an
- * existing GPT geom. The geom parameter is non-optional, so get
- * it here first.
- */
- s = gctl_get_asciiparam(req, "geom");
- if (s == NULL) {
- gctl_error(req, "%d geom", ENOATTR);
- return;
- }
- /* Get the GPT geom with the given name. */
- LIST_FOREACH(gp, &mp->geom, geom) {
- if (!strcmp(s, gp->name))
- break;
- }
- if (gp == NULL) {
- gctl_error(req, "%d geom '%s'", EINVAL, s);
- return;
- }
- softc = gp->softc;
-
- /*
- * Now handle the verbs that can operate on a downgraded or
- * partially corrupted GPT. In particular these are the verbs
- * that don't deal with the table entries. We implement the
- * policy that all table entry related requests require a
- * valid GPT.
- */
- if (ctlreq == G_GPT_CTL_DESTROY) {
- /*
- * Destroy a GPT completely.
- */
- g_gpt_ctl_destroy(req, flags, gp);
- return;
- }
- if (ctlreq == G_GPT_CTL_RECOVER) {
- /*
- * Recover a downgraded GPT.
- */
- g_gpt_ctl_recover(req, flags, gp);
- return;
- }
-
- /*
- * Check that the GPT is complete and valid before we make changes
- * to the table entries.
- */
- if (softc->state[GPT_HDR_PRIMARY] != GPT_HDR_OK ||
- softc->state[GPT_HDR_SECONDARY] != GPT_HDR_OK) {
- gctl_error(req, "%d geom '%s'", ENXIO, s);
- return;
- }
-
- /*
- * The add verb is the only table entry related verb that doesn't
- * require the entry parameter. All other verbs identify the table
- * entry by the entry number. Handle the add here.
- */
- if (ctlreq == G_GPT_CTL_ADD) {
- /*
- * Add a partition entry to a GPT.
- * Required parameters/attributes:
- * type
- * start
- * end
- * Optional parameters/attributes:
- * entry (read/write)
- * label
- */
- s = gctl_get_asciiparam(req, "type");
- if (s == NULL) {
- gctl_error(req, "%d type", ENOATTR);
- return;
- }
- error = parse_uuid(s, &type);
- if (error != 0) {
- gctl_error(req, "%d type '%s'", error, s);
- return;
- }
- s = gctl_get_asciiparam(req, "start");
- if (s == NULL) {
- gctl_error(req, "%d start", ENOATTR);
- return;
- }
- start = strtoq(s, (char **)(uintptr_t)&s, 0);
- if (start < softc->hdr[GPT_HDR_PRIMARY].hdr_lba_start ||
- start > softc->hdr[GPT_HDR_PRIMARY].hdr_lba_end ||
- *s != '\0') {
- gctl_error(req, "%d start %jd", EINVAL,
- (intmax_t)start);
- return;
- }
- s = gctl_get_asciiparam(req, "end");
- if (s == NULL) {
- gctl_error(req, "%d end", ENOATTR);
- return;
- }
- end = strtoq(s, (char **)(uintptr_t)&s, 0);
- if (end < start ||
- end > softc->hdr[GPT_HDR_PRIMARY].hdr_lba_end ||
- *s != '\0') {
- gctl_error(req, "%d end %jd", EINVAL,
- (intmax_t)end);
- return;
- }
- entry = 0;
- s = gctl_get_asciiparam(req, "entry");
- if (s != NULL && *s != '\0') {
- entry = strtol(s, (char **)(uintptr_t)&s, 0);
- if (*s != '\0' || entry <= 0 ||
- entry > softc->hdr[GPT_HDR_PRIMARY].hdr_entries) {
- gctl_error(req, "%d entry %ld", EINVAL, entry);
- return;
- }
- }
- g_gpt_ctl_add(req, flags, gp, &type, start, end, entry);
- return;
- }
-
- /*
- * Get the table entry number. Entry numbers run from 1 to the
- * number of entries in the table.
- */
- s = gctl_get_asciiparam(req, "entry");
- if (s == NULL) {
- gctl_error(req, "%d entry", ENOATTR);
- return;
- }
- entry = strtol(s, (char **)(uintptr_t)&s, 0);
- if (*s != '\0' || entry <= 0 ||
- entry > softc->hdr[GPT_HDR_PRIMARY].hdr_entries) {
- gctl_error(req, "%d entry %ld", EINVAL, entry);
- return;
- }
-
- if (ctlreq == G_GPT_CTL_MODIFY) {
- /*
- * Modify a partition entry.
- */
- g_gpt_ctl_modify(req, flags, gp, entry);
- return;
- }
- if (ctlreq == G_GPT_CTL_REMOVE) {
- /*
- * Remove a partition entry.
- */
- g_gpt_ctl_remove(req, flags, gp, entry);
- return;
- }
-}
-
-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 g_consumer *cp;
- struct g_geom *gp;
- struct g_gpt_softc *softc;
- struct gpt_hdr *hdr;
- void *buf;
- off_t ofs;
- size_t nbytes;
- int error;
-
- G_GPT_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name));
- g_topology_assert();
-
- /*
- * 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_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();
-
- /*
- * Now that we have access permissions, we can 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). Lastly, since the
- * theoretical minimum number of sectors needed by GPT is 6, any
- * medium that has less than 6 sectors is never going to be able
- * 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)
- goto fail;
-
- /*
- * 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 (buf == NULL)
- 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 (buf == NULL)
- 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;
- }
-
- /*
- * 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)) {
- if (error != 0)
- goto fail;
- printf("GEOM: %s: GPT detected, but no protective MBR.\n",
- pp->name);
- error = ENXIO;
- goto fail;
- }
-
- /*
- * 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;
- }
-
- /*
- * 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;
- }
-
- /* Always prefer the primary header. */
- hdr = (softc->state[GPT_HDR_PRIMARY] == GPT_HDR_OK)
- ? softc->hdr + GPT_HDR_PRIMARY : softc->hdr + GPT_HDR_SECONDARY;
-
- /*
- * 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.
- */
-
- nbytes = ((hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) /
- pp->sectorsize) * pp->sectorsize;
-
- ofs = hdr->hdr_lba_table * pp->sectorsize;
- buf = g_read_data(cp, ofs, nbytes, &error);
- if (buf == NULL)
- goto fail;
-
- /*
- * 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 (buf == NULL)
- goto fail;
-
- 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;
- }
- 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");
- }
-
- 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);
- 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));
-}
-
-static void
-g_gpt_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
- struct g_consumer *cp, struct g_provider *pp)
-{
- static char *status[5] = {
- "unknown", "missing", "corrupt", "invalid", "ok"
- };
- struct g_gpt_part *part;
- struct g_gpt_softc *softc;
- struct gpt_hdr *hdr;
-
- KASSERT(sb != NULL && gp != NULL, (__func__));
-
- if (indent == NULL) {
- KASSERT(cp == NULL && pp != NULL, (__func__));
- part = pp->private;
- if (part == NULL)
- return;
- sbuf_printf(sb, " i %u o %ju ty ", pp->index,
- (uintmax_t)part->offset);
- sbuf_printf_uuid(sb, &part->ent.ent_type);
- } else if (cp != NULL) { /* Consumer configuration. */
- KASSERT(pp == NULL, (__func__));
- /* none */
- } else if (pp != NULL) { /* Provider configuration. */
- part = pp->private;
- if (part == NULL)
- return;
- sbuf_printf(sb, "%s<index>%u</index>\n", indent, pp->index);
- sbuf_printf(sb, "%s<type>", indent);
- sbuf_printf_uuid(sb, &part->ent.ent_type);
- sbuf_printf(sb, "</type>\n");
- sbuf_printf(sb, "%s<uuid>", indent);
- sbuf_printf_uuid(sb, &part->ent.ent_uuid);
- sbuf_printf(sb, "</uuid>\n");
- sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent,
- (uintmax_t)part->offset);
- sbuf_printf(sb, "%s<length>%ju</length>\n", indent,
- (uintmax_t)pp->mediasize);
- sbuf_printf(sb, "%s<attr>%ju</attr>\n", indent,
- (uintmax_t)part->ent.ent_attr);
- sbuf_printf(sb, "%s<label>", indent);
- g_gpt_to_utf8(sb, part->ent.ent_name,
- sizeof(part->ent.ent_name)/2);
- sbuf_printf(sb, "</label>\n");
- } else { /* Geom configuration. */
- softc = gp->softc;
- hdr = (softc->state[GPT_HDR_PRIMARY] == GPT_HDR_OK)
- ? softc->hdr + GPT_HDR_PRIMARY
- : softc->hdr + GPT_HDR_SECONDARY;
- sbuf_printf(sb, "%s<uuid>", indent);
- sbuf_printf_uuid(sb, &hdr->hdr_uuid);
- sbuf_printf(sb, "</uuid>\n");
- sbuf_printf(sb, "%s<primary>%s</primary>\n", indent,
- status[softc->state[GPT_HDR_PRIMARY]]);
- sbuf_printf(sb, "%s<secondary>%s</secondary>\n", indent,
- status[softc->state[GPT_HDR_SECONDARY]]);
- sbuf_printf(sb, "%s<selected>%s</selected>\n", indent,
- (hdr == softc->hdr + GPT_HDR_PRIMARY) ? "primary" :
- "secondary");
- sbuf_printf(sb, "%s<revision>%u</revision>\n", indent,
- hdr->hdr_revision);
- sbuf_printf(sb, "%s<header_size>%u</header_size>\n", indent,
- hdr->hdr_size);
- sbuf_printf(sb, "%s<crc_self>%u</crc_self>\n", indent,
- hdr->hdr_crc_self);
- sbuf_printf(sb, "%s<lba_self>%ju</lba_self>\n", indent,
- (uintmax_t)hdr->hdr_lba_self);
- sbuf_printf(sb, "%s<lba_other>%ju</lba_other>\n", indent,
- (uintmax_t)hdr->hdr_lba_alt);
- sbuf_printf(sb, "%s<lba_start>%ju</lba_start>\n", indent,
- (uintmax_t)hdr->hdr_lba_start);
- sbuf_printf(sb, "%s<lba_end>%ju</lba_end>\n", indent,
- (uintmax_t)hdr->hdr_lba_end);
- sbuf_printf(sb, "%s<lba_table>%ju</lba_table>\n", indent,
- (uintmax_t)hdr->hdr_lba_table);
- sbuf_printf(sb, "%s<crc_table>%u</crc_table>\n", indent,
- hdr->hdr_crc_table);
- sbuf_printf(sb, "%s<entries>%u</entries>\n", indent,
- hdr->hdr_entries);
- sbuf_printf(sb, "%s<entry_size>%u</entry_size>\n", indent,
- hdr->hdr_entsz);
- }
-}
-
-static void
-g_gpt_orphan(struct g_consumer *cp)
-{
- struct g_provider *pp;
-
- pp = cp->provider;
- KASSERT(pp != NULL, (__func__));
- G_GPT_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name));
- g_topology_assert();
-
- KASSERT(pp->error != 0, (__func__));
- g_gpt_wither(cp->geom, pp->error);
-}
-
-static void
-g_gpt_spoiled(struct g_consumer *cp)
-{
-
- G_GPT_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name));
- g_topology_assert();
-
- g_gpt_wither(cp->geom, ENXIO);
-}
-
-static void
-g_gpt_start(struct bio *bp)
-{
- struct bio *bp2;
- struct g_consumer *cp;
- struct g_geom *gp;
- struct g_gpt_part *part;
- struct g_kerneldump *gkd;
- struct g_provider *pp;
-
- pp = bp->bio_to;
- gp = pp->geom;
- cp = LIST_FIRST(&gp->consumer);
-
- G_GPT_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd,
- pp->name));
-
- part = pp->private;
- if (part == NULL) {
- g_io_deliver(bp, ENXIO);
- return;
- }
-
- switch(bp->bio_cmd) {
- case BIO_READ:
- case BIO_WRITE:
- case BIO_DELETE:
- if (bp->bio_offset >= pp->mediasize) {
- g_io_deliver(bp, EIO);
- break;
- }
- bp2 = g_clone_bio(bp);
- if (bp2 == NULL) {
- g_io_deliver(bp, ENOMEM);
- break;
- }
- if (bp2->bio_offset + bp2->bio_length > pp->mediasize)
- bp2->bio_length = pp->mediasize - bp2->bio_offset;
- bp2->bio_done = g_std_done;
- bp2->bio_offset += part->offset;
- g_io_request(bp2, cp);
- break;
- case BIO_GETATTR:
- if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) {
- /*
- * Refuse non-swap partitions to be used as kernel
- * dumps.
- */
- if (memcmp(&part->ent.ent_type, &g_gpt_freebsd_swap,
- sizeof(struct uuid)) && memcmp(&part->ent.ent_type,
- &g_gpt_linux_swap, sizeof(struct uuid))) {
- g_io_deliver(bp, ENXIO);
- break;
- }
- gkd = (struct g_kerneldump *)bp->bio_data;
- if (gkd->offset >= pp->mediasize) {
- g_io_deliver(bp, EIO);
- break;
- }
- if (gkd->offset + gkd->length > pp->mediasize)
- gkd->length = pp->mediasize - gkd->offset;
- gkd->offset += part->offset;
- /* FALLTHROUGH */
- }
- /* FALLTHROUGH */
- case BIO_FLUSH:
- bp2 = g_clone_bio(bp);
- if (bp2 == NULL) {
- g_io_deliver(bp, ENOMEM);
- break;
- }
- bp2->bio_done = g_std_done;
- g_io_request(bp2, cp);
- break;
- default:
- g_io_deliver(bp, EOPNOTSUPP);
- break;
- }
-}
OpenPOWER on IntegriCloud