Index: head/sys/geom/geom_aes.c =================================================================== --- head/sys/geom/geom_aes.c (revision 152970) +++ head/sys/geom/geom_aes.c (revision 152971) @@ -1,375 +1,375 @@ /*- * Copyright (c) 2002 Poul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by Poul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the * DARPA CHATS research program. * * 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 method provides AES encryption with a compiled in key (default * all zeroes). * * XXX: This could probably save a lot of code by pretending to be a slicer. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define AES_CLASS_NAME "AES" #define MASTER_KEY_LENGTH (1024/8) static const u_char *aes_magic = "<>"; static const u_char *aes_magic_random = "<>"; static const u_char *aes_magic_test = "<>"; struct g_aes_softc { enum { KEY_ZERO, KEY_RANDOM, KEY_TEST } keying; u_int sectorsize; off_t mediasize; cipherInstance ci; u_char master_key[MASTER_KEY_LENGTH]; }; /* * Generate a sectorkey from the masterkey and the offset position. * * For KEY_ZERO we just return a key of all zeros. * * We feed the sector byte offset, 16 bytes of the master-key and * the sector byte offset once more to MD5. * The sector byte offset is converted to little-endian format first * to support multi-architecture operation. * We use 16 bytes from the master-key starting at the logical sector * number modulus he length of the master-key. If need be we wrap * around to the start of the master-key. */ static void g_aes_makekey(struct g_aes_softc *sc, off_t off, keyInstance *ki, int dir) { MD5_CTX cx; u_int64_t u64; u_int u, u1; u_char *p, buf[16]; if (sc->keying == KEY_ZERO) { rijndael_makeKey(ki, dir, 128, sc->master_key); return; } MD5Init(&cx); u64 = htole64(off); MD5Update(&cx, (u_char *)&u64, sizeof(u64)); u = off / sc->sectorsize; u %= sizeof sc->master_key; p = sc->master_key + u; if (u + 16 <= sizeof(sc->master_key)) { MD5Update(&cx, p, 16); } else { u1 = sizeof sc->master_key - u; MD5Update(&cx, p, u1); MD5Update(&cx, sc->master_key, 16 - u1); u1 = 0; /* destroy evidence */ } u = 0; /* destroy evidence */ MD5Update(&cx, (u_char *)&u64, sizeof(u64)); u64 = 0; /* destroy evidence */ MD5Final(buf, &cx); bzero(&cx, sizeof cx); /* destroy evidence */ rijndael_makeKey(ki, dir, 128, buf); bzero(buf, sizeof buf); /* destroy evidence */ } static void g_aes_read_done(struct bio *bp) { struct g_geom *gp; struct g_aes_softc *sc; u_char *p, *b, *e, *sb; keyInstance dkey; off_t o; gp = bp->bio_from->geom; sc = gp->softc; sb = g_malloc(sc->sectorsize, M_WAITOK); b = bp->bio_data; e = bp->bio_data; e += bp->bio_length; o = bp->bio_offset - sc->sectorsize; for (p = b; p < e; p += sc->sectorsize) { g_aes_makekey(sc, o, &dkey, DIR_DECRYPT); rijndael_blockDecrypt(&sc->ci, &dkey, p, sc->sectorsize * 8, sb); bcopy(sb, p, sc->sectorsize); o += sc->sectorsize; } bzero(&dkey, sizeof dkey); /* destroy evidence */ bzero(sb, sc->sectorsize); /* destroy evidence */ g_free(sb); g_std_done(bp); } static void g_aes_write_done(struct bio *bp) { bzero(bp->bio_data, bp->bio_length); /* destroy evidence */ g_free(bp->bio_data); g_std_done(bp); } static void g_aes_start(struct bio *bp) { struct g_geom *gp; struct g_consumer *cp; struct g_aes_softc *sc; struct bio *bp2; u_char *p1, *p2, *b, *e; keyInstance ekey; off_t o; gp = bp->bio_to->geom; cp = LIST_FIRST(&gp->consumer); sc = gp->softc; switch (bp->bio_cmd) { case BIO_READ: bp2 = g_clone_bio(bp); if (bp2 == NULL) { g_io_deliver(bp, ENOMEM); return; } bp2->bio_done = g_aes_read_done; bp2->bio_offset += sc->sectorsize; g_io_request(bp2, cp); break; case BIO_WRITE: bp2 = g_clone_bio(bp); if (bp2 == NULL) { g_io_deliver(bp, ENOMEM); return; } bp2->bio_done = g_aes_write_done; bp2->bio_offset += sc->sectorsize; bp2->bio_data = g_malloc(bp->bio_length, M_WAITOK); b = bp->bio_data; e = bp->bio_data; e += bp->bio_length; p2 = bp2->bio_data; o = bp->bio_offset; for (p1 = b; p1 < e; p1 += sc->sectorsize) { g_aes_makekey(sc, o, &ekey, DIR_ENCRYPT); rijndael_blockEncrypt(&sc->ci, &ekey, p1, sc->sectorsize * 8, p2); p2 += sc->sectorsize; o += sc->sectorsize; } bzero(&ekey, sizeof ekey); /* destroy evidence */ g_io_request(bp2, cp); break; case BIO_GETATTR: bp2 = g_clone_bio(bp); if (bp2 == NULL) { g_io_deliver(bp, ENOMEM); return; } bp2->bio_done = g_std_done; bp2->bio_offset += sc->sectorsize; g_io_request(bp2, cp); break; default: g_io_deliver(bp, EOPNOTSUPP); return; } return; } static void g_aes_orphan(struct g_consumer *cp) { struct g_geom *gp; struct g_aes_softc *sc; g_trace(G_T_TOPOLOGY, "g_aes_orphan(%p/%s)", cp, cp->provider->name); g_topology_assert(); KASSERT(cp->provider->error != 0, ("g_aes_orphan with error == 0")); gp = cp->geom; sc = gp->softc; g_wither_geom(gp, cp->provider->error); bzero(sc, sizeof(struct g_aes_softc)); /* destroy evidence */ g_free(sc); return; } static int g_aes_access(struct g_provider *pp, int dr, int dw, int de) { struct g_geom *gp; struct g_consumer *cp; gp = pp->geom; cp = LIST_FIRST(&gp->consumer); /* On first open, grab an extra "exclusive" bit */ if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0) de++; /* ... and let go of it on last close */ if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1) de--; return (g_access(cp, dr, dw, de)); } static struct g_geom * g_aes_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) { struct g_geom *gp; struct g_consumer *cp; struct g_aes_softc *sc; int error; u_int sectorsize; off_t mediasize; u_char *buf; g_trace(G_T_TOPOLOGY, "aes_taste(%s,%s)", mp->name, pp->name); g_topology_assert(); gp = g_new_geomf(mp, "%s.aes", pp->name); cp = g_new_consumer(gp); g_attach(cp, pp); error = g_access(cp, 1, 0, 0); if (error) { g_detach(cp); g_destroy_consumer(cp); g_destroy_geom(gp); return (NULL); } buf = NULL; g_topology_unlock(); do { if (gp->rank != 2) break; sectorsize = cp->provider->sectorsize; mediasize = cp->provider->mediasize; - buf = g_read_data(cp, 0, sectorsize, &error); + buf = g_read_data(cp, 0, sectorsize, NULL); if (buf == NULL) { break; } sc = g_malloc(sizeof(struct g_aes_softc), M_WAITOK | M_ZERO); if (!memcmp(buf, aes_magic, strlen(aes_magic))) { sc->keying = KEY_ZERO; } else if (!memcmp(buf, aes_magic_random, strlen(aes_magic_random))) { sc->keying = KEY_RANDOM; } else if (!memcmp(buf, aes_magic_test, strlen(aes_magic_test))) { sc->keying = KEY_TEST; } else { g_free(sc); break; } g_free(buf); gp->softc = sc; sc->sectorsize = sectorsize; sc->mediasize = mediasize - sectorsize; rijndael_cipherInit(&sc->ci, MODE_CBC, NULL); if (sc->keying == KEY_TEST) { int i; u_char *p; p = sc->master_key; for (i = 0; i < (int)sizeof sc->master_key; i ++) *p++ = i; } if (sc->keying == KEY_RANDOM) { int i; u_int32_t u; u_char *p; p = sc->master_key; for (i = 0; i < (int)sizeof sc->master_key; i += sizeof u) { u = arc4random(); *p++ = u; *p++ = u >> 8; *p++ = u >> 16; *p++ = u >> 24; } } g_topology_lock(); pp = g_new_providerf(gp, gp->name); pp->mediasize = mediasize - sectorsize; pp->sectorsize = sectorsize; g_error_provider(pp, 0); g_topology_unlock(); } while(0); g_topology_lock(); if (buf) g_free(buf); g_access(cp, -1, 0, 0); if (gp->softc != NULL) return (gp); g_detach(cp); g_destroy_consumer(cp); g_destroy_geom(gp); return (NULL); } static struct g_class g_aes_class = { .name = AES_CLASS_NAME, .version = G_VERSION, .taste = g_aes_taste, .start = g_aes_start, .orphan = g_aes_orphan, .spoiled = g_std_spoiled, .access = g_aes_access, }; DECLARE_GEOM_CLASS(g_aes_class, g_aes); Index: head/sys/geom/geom_apple.c =================================================================== --- head/sys/geom/geom_apple.c (revision 152970) +++ head/sys/geom/geom_apple.c (revision 152971) @@ -1,263 +1,263 @@ /*- * Copyright (c) 2002 Peter Grehan. * 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 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. */ /* * GEOM module for Apple Partition Maps * As described in 'Inside Macintosh Vol 3: About the SCSI Manager - * The Structure of Block Devices" */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #define APPLE_CLASS_NAME "APPLE" #define NAPMPART 16 /* Max partitions */ struct apm_partition { char am_sig[2]; u_int32_t am_mapcnt; u_int32_t am_start; u_int32_t am_partcnt; char am_name[32]; char am_type[32]; }; struct g_apple_softc { u_int16_t dd_bsiz; u_int32_t dd_blkcnt; u_int16_t dd_drvrcnt; u_int32_t am_mapcnt0; struct apm_partition apmpart[NAPMPART]; }; static void g_dec_drvrdesc(u_char *ptr, struct g_apple_softc *sc) { sc->dd_bsiz = be16dec(ptr + 2); sc->dd_blkcnt = be32dec(ptr + 4); sc->dd_drvrcnt = be32dec(ptr + 16); } static void g_dec_apple_partition(u_char *ptr, struct apm_partition *d) { d->am_sig[0] = ptr[0]; d->am_sig[1] = ptr[1]; d->am_mapcnt = be32dec(ptr + 4); d->am_start = be32dec(ptr + 8); d->am_partcnt = be32dec(ptr + 12); memcpy(d->am_name, ptr + 16, 32); memcpy(d->am_type, ptr + 48, 32); } static int g_apple_start(struct bio *bp) { struct g_provider *pp; struct g_geom *gp; struct g_slicer *gsp; pp = bp->bio_to; gp = pp->geom; gsp = gp->softc; if (bp->bio_cmd == BIO_GETATTR) { if (g_handleattr_off_t(bp, "APM::offset", gsp->slices[pp->index].offset)) return (1); } return (0); } static void g_apple_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp) { struct g_apple_softc *mp; struct g_slicer *gsp; gsp = gp->softc; mp = gsp->softc; g_slice_dumpconf(sb, indent, gp, cp, pp); if (pp != NULL) { if (indent == NULL) { sbuf_printf(sb, " ty %s", mp->apmpart[pp->index].am_type); if (*mp->apmpart[pp->index].am_name) sbuf_printf(sb, " sn %s", mp->apmpart[pp->index].am_name); } else { sbuf_printf(sb, "%s%s\n", indent, mp->apmpart[pp->index].am_name); sbuf_printf(sb, "%s%s\n", indent, mp->apmpart[pp->index].am_type); } } } #if 0 static void g_apple_print() { /* XXX */ } #endif static struct g_geom * g_apple_taste(struct g_class *mp, struct g_provider *pp, int insist) { struct g_geom *gp; struct g_consumer *cp; - int error, i; + int i; struct g_apple_softc *ms; struct apm_partition *apm; u_int sectorsize; u_char *buf; g_trace(G_T_TOPOLOGY, "apple_taste(%s,%s)", mp->name, pp->name); g_topology_assert(); gp = g_slice_new(mp, NAPMPART, pp, &cp, &ms, sizeof *ms, g_apple_start); if (gp == NULL) return (NULL); g_topology_unlock(); do { if (gp->rank != 2 && insist == 0) break; sectorsize = cp->provider->sectorsize; if (sectorsize != 512) break; - buf = g_read_data(cp, 0, sectorsize, &error); + buf = g_read_data(cp, 0, sectorsize, NULL); if (buf == NULL) break; /* * Test for the sector 0 driver record signature, and * validate sector and disk size */ if (buf[0] != 'E' && buf[1] != 'R') { g_free(buf); break; } g_dec_drvrdesc(buf, ms); g_free(buf); if (ms->dd_bsiz != 512) { break; } /* * Read in the first partition map */ - buf = g_read_data(cp, sectorsize, sectorsize, &error); + buf = g_read_data(cp, sectorsize, sectorsize, NULL); if (buf == NULL) break; /* * Decode the first partition: it's another indication of * validity, as well as giving the size of the partition * map */ apm = &ms->apmpart[0]; g_dec_apple_partition(buf, apm); g_free(buf); if (apm->am_sig[0] != 'P' || apm->am_sig[1] != 'M') break; ms->am_mapcnt0 = apm->am_mapcnt; buf = g_read_data(cp, 2 * sectorsize, - (NAPMPART - 1) * sectorsize, &error); + (NAPMPART - 1) * sectorsize, NULL); if (buf == NULL) break; for (i = 1; i < NAPMPART; i++) { g_dec_apple_partition(buf + ((i - 1) * sectorsize), &ms->apmpart[i]); } for (i = 0; i < NAPMPART; i++) { apm = &ms->apmpart[i]; /* * Validate partition sig and global mapcount */ if (apm->am_sig[0] != 'P' || apm->am_sig[1] != 'M') continue; if (apm->am_mapcnt != ms->am_mapcnt0) continue; if (bootverbose) { printf("APM Slice %d (%s/%s) on %s:\n", i + 1, apm->am_name, apm->am_type, gp->name); /* g_apple_print(i, dp + i); */ } g_topology_lock(); g_slice_config(gp, i, G_SLICE_CONFIG_SET, (off_t)apm->am_start << 9ULL, (off_t)apm->am_partcnt << 9ULL, sectorsize, "%ss%d", gp->name, i + 1); g_topology_unlock(); } g_free(buf); break; } while(0); g_topology_lock(); g_access(cp, -1, 0, 0); if (LIST_EMPTY(&gp->provider)) { g_slice_spoiled(cp); return (NULL); } return (gp); } static struct g_class g_apple_class = { .name = APPLE_CLASS_NAME, .version = G_VERSION, .taste = g_apple_taste, .dumpconf = g_apple_dumpconf, }; DECLARE_GEOM_CLASS(g_apple_class, g_apple); Index: head/sys/geom/geom_bsd.c =================================================================== --- head/sys/geom/geom_bsd.c (revision 152970) +++ head/sys/geom/geom_bsd.c (revision 152971) @@ -1,678 +1,677 @@ /*- * Copyright (c) 2002 Poul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by Poul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the * DARPA CHATS research program. * * 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 is the method for dealing with BSD disklabels. It has been * extensively (by my standards at least) commented, in the vain hope that * it will serve as the source in future copy&paste operations. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BSD_CLASS_NAME "BSD" #define ALPHA_LABEL_OFFSET 64 #define LABELSIZE (148 + 16 * MAXPARTITIONS) static void g_bsd_hotwrite(void *arg, int flag); /* * Our private data about one instance. All the rest is handled by the * slice code and stored in its softc, so this is just the stuff * specific to BSD disklabels. */ struct g_bsd_softc { off_t labeloffset; off_t mbroffset; off_t rawoffset; struct disklabel ondisk; u_char label[LABELSIZE]; u_char labelsum[16]; }; /* * Modify our slicer to match proposed disklabel, if possible. * This is where we make sure we don't do something stupid. */ static int g_bsd_modify(struct g_geom *gp, u_char *label) { int i, error; struct partition *ppp; struct g_slicer *gsp; struct g_consumer *cp; struct g_bsd_softc *ms; u_int secsize, u; off_t rawoffset, o; struct disklabel dl; MD5_CTX md5sum; g_topology_assert(); gsp = gp->softc; ms = gsp->softc; error = bsd_disklabel_le_dec(label, &dl, MAXPARTITIONS); if (error) { return (error); } /* Get dimensions of our device. */ cp = LIST_FIRST(&gp->consumer); secsize = cp->provider->sectorsize; /* ... or a smaller sector size. */ if (dl.d_secsize < secsize) { return (EINVAL); } /* ... or a non-multiple sector size. */ if (dl.d_secsize % secsize != 0) { return (EINVAL); } /* Historical braindamage... */ rawoffset = (off_t)dl.d_partitions[RAW_PART].p_offset * dl.d_secsize; for (i = 0; i < dl.d_npartitions; i++) { ppp = &dl.d_partitions[i]; if (ppp->p_size == 0) continue; o = (off_t)ppp->p_offset * dl.d_secsize; if (o < rawoffset) rawoffset = 0; } if (rawoffset != 0 && (off_t)rawoffset != ms->mbroffset) printf("WARNING: Expected rawoffset %jd, found %jd\n", (intmax_t)ms->mbroffset/dl.d_secsize, (intmax_t)rawoffset/dl.d_secsize); /* Don't munge open partitions. */ for (i = 0; i < dl.d_npartitions; i++) { ppp = &dl.d_partitions[i]; o = (off_t)ppp->p_offset * dl.d_secsize; if (o == 0) o = rawoffset; error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, o - rawoffset, (off_t)ppp->p_size * dl.d_secsize, dl.d_secsize, "%s%c", gp->name, 'a' + i); if (error) return (error); } /* Look good, go for it... */ for (u = 0; u < gsp->nslice; u++) { ppp = &dl.d_partitions[u]; o = (off_t)ppp->p_offset * dl.d_secsize; if (o == 0) o = rawoffset; g_slice_config(gp, u, G_SLICE_CONFIG_SET, o - rawoffset, (off_t)ppp->p_size * dl.d_secsize, dl.d_secsize, "%s%c", gp->name, 'a' + u); } /* Update our softc */ ms->ondisk = dl; if (label != ms->label) bcopy(label, ms->label, LABELSIZE); ms->rawoffset = rawoffset; /* * In order to avoid recursively attaching to the same * on-disk label (it's usually visible through the 'c' * partition) we calculate an MD5 and ask if other BSD's * below us love that label. If they do, we don't. */ MD5Init(&md5sum); MD5Update(&md5sum, ms->label, sizeof(ms->label)); MD5Final(ms->labelsum, &md5sum); return (0); } /* * This is an internal helper function, called multiple times from the taste * function to try to locate a disklabel on the disk. More civilized formats * will not need this, as there is only one possible place on disk to look * for the magic spot. */ static int g_bsd_try(struct g_geom *gp, struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset) { int error; u_char *buf; struct disklabel *dl; off_t secoff; /* * We need to read entire aligned sectors, and we assume that the * disklabel does not span sectors, so one sector is enough. */ - error = 0; secoff = offset % secsize; - buf = g_read_data(cp, offset - secoff, secsize, &error); + buf = g_read_data(cp, offset - secoff, secsize, NULL); if (buf == NULL) return (ENOENT); /* Decode into our native format. */ dl = &ms->ondisk; error = bsd_disklabel_le_dec(buf + secoff, dl, MAXPARTITIONS); if (!error) bcopy(buf + secoff, ms->label, LABELSIZE); /* Remember to free the buffer g_read_data() gave us. */ g_free(buf); ms->labeloffset = offset; return (error); } /* * This function writes the current label to disk, possibly updating * the alpha SRM checksum. */ static int g_bsd_writelabel(struct g_geom *gp, u_char *bootcode) { off_t secoff; u_int secsize; struct g_consumer *cp; struct g_slicer *gsp; struct g_bsd_softc *ms; u_char *buf; uint64_t sum; int error, i; gsp = gp->softc; ms = gsp->softc; cp = LIST_FIRST(&gp->consumer); /* Get sector size, we need it to read data. */ secsize = cp->provider->sectorsize; secoff = ms->labeloffset % secsize; if (bootcode == NULL) { buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error); if (buf == NULL) return (error); bcopy(ms->label, buf + secoff, sizeof(ms->label)); } else { buf = bootcode; bcopy(ms->label, buf + ms->labeloffset, sizeof(ms->label)); } if (ms->labeloffset == ALPHA_LABEL_OFFSET) { sum = 0; for (i = 0; i < 63; i++) sum += le64dec(buf + i * 8); le64enc(buf + 504, sum); } if (bootcode == NULL) { error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize); g_free(buf); } else { error = g_write_data(cp, 0, bootcode, BBSIZE); } return(error); } /* * If the user tries to overwrite our disklabel through an open partition * or via a magicwrite config call, we end up here and try to prevent * footshooting as best we can. */ static void g_bsd_hotwrite(void *arg, int flag) { struct bio *bp; struct g_geom *gp; struct g_slicer *gsp; struct g_slice *gsl; struct g_bsd_softc *ms; u_char *p; int error; g_topology_assert(); /* * We should never get canceled, because that would amount to a removal * of the geom while there was outstanding I/O requests. */ KASSERT(flag != EV_CANCEL, ("g_bsd_hotwrite cancelled")); bp = arg; gp = bp->bio_to->geom; gsp = gp->softc; ms = gsp->softc; gsl = &gsp->slices[bp->bio_to->index]; p = (u_char*)bp->bio_data + ms->labeloffset - (bp->bio_offset + gsl->offset); error = g_bsd_modify(gp, p); if (error) { g_io_deliver(bp, EPERM); return; } g_slice_finish_hot(bp); } /*- * This start routine is only called for non-trivial requests, all the * trivial ones are handled autonomously by the slice code. * For requests we handle here, we must call the g_io_deliver() on the * bio, and return non-zero to indicate to the slice code that we did so. * This code executes in the "DOWN" I/O path, this means: * * No sleeping. * * Don't grab the topology lock. * * Don't call biowait, g_getattr(), g_setattr() or g_read_data() */ static int g_bsd_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td) { struct g_geom *gp; struct g_bsd_softc *ms; struct g_slicer *gsp; u_char *label; int error; gp = pp->geom; gsp = gp->softc; ms = gsp->softc; switch(cmd) { case DIOCGDINFO: /* Return a copy of the disklabel to userland. */ bsd_disklabel_le_dec(ms->label, data, MAXPARTITIONS); return(0); case DIOCBSDBB: { struct g_consumer *cp; u_char *buf; void *p; int error, i; uint64_t sum; if (!(fflag & FWRITE)) return (EPERM); /* The disklabel to set is the ioctl argument. */ buf = g_malloc(BBSIZE, M_WAITOK); p = *(void **)data; error = copyin(p, buf, BBSIZE); if (!error) { /* XXX: Rude, but supposedly safe */ DROP_GIANT(); g_topology_lock(); /* Validate and modify our slice instance to match. */ error = g_bsd_modify(gp, buf + ms->labeloffset); if (!error) { cp = LIST_FIRST(&gp->consumer); if (ms->labeloffset == ALPHA_LABEL_OFFSET) { sum = 0; for (i = 0; i < 63; i++) sum += le64dec(buf + i * 8); le64enc(buf + 504, sum); } error = g_write_data(cp, 0, buf, BBSIZE); } g_topology_unlock(); PICKUP_GIANT(); } g_free(buf); return (error); } case DIOCSDINFO: case DIOCWDINFO: { if (!(fflag & FWRITE)) return (EPERM); label = g_malloc(LABELSIZE, M_WAITOK); /* The disklabel to set is the ioctl argument. */ bsd_disklabel_le_enc(label, data); DROP_GIANT(); g_topology_lock(); /* Validate and modify our slice instance to match. */ error = g_bsd_modify(gp, label); if (error == 0 && cmd == DIOCWDINFO) error = g_bsd_writelabel(gp, NULL); g_topology_unlock(); PICKUP_GIANT(); g_free(label); return(error); } default: return (ENOIOCTL); } } static int g_bsd_start(struct bio *bp) { struct g_geom *gp; struct g_bsd_softc *ms; struct g_slicer *gsp; gp = bp->bio_to->geom; gsp = gp->softc; ms = gsp->softc; if (bp->bio_cmd == BIO_GETATTR) { if (g_handleattr(bp, "BSD::labelsum", ms->labelsum, sizeof(ms->labelsum))) return (1); } return (0); } /* * Dump configuration information in XML format. * Notice that the function is called once for the geom and once for each * consumer and provider. We let g_slice_dumpconf() do most of the work. */ static void g_bsd_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp) { struct g_bsd_softc *ms; struct g_slicer *gsp; gsp = gp->softc; ms = gsp->softc; g_slice_dumpconf(sb, indent, gp, cp, pp); if (indent != NULL && pp == NULL && cp == NULL) { sbuf_printf(sb, "%s%jd\n", indent, (intmax_t)ms->labeloffset); sbuf_printf(sb, "%s%jd\n", indent, (intmax_t)ms->rawoffset); sbuf_printf(sb, "%s%jd\n", indent, (intmax_t)ms->mbroffset); } else if (pp != NULL) { if (indent == NULL) sbuf_printf(sb, " ty %d", ms->ondisk.d_partitions[pp->index].p_fstype); else sbuf_printf(sb, "%s%d\n", indent, ms->ondisk.d_partitions[pp->index].p_fstype); } } /* * The taste function is called from the event-handler, with the topology * lock already held and a provider to examine. The flags are unused. * * If flags == G_TF_NORMAL, the idea is to take a bite of the provider and * if we find valid, consistent magic on it, build a geom on it. * any magic bits which indicate that we should automatically put a BSD * geom on it. * * There may be cases where the operator would like to put a BSD-geom on * providers which do not meet all of the requirements. This can be done * by instead passing the G_TF_INSIST flag, which will override these * checks. * * The final flags value is G_TF_TRANSPARENT, which instructs the method * to put a geom on top of the provider and configure it to be as transparent * as possible. This is not really relevant to the BSD method and therefore * not implemented here. */ static struct g_geom * g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags) { struct g_geom *gp; struct g_consumer *cp; int error, i; struct g_bsd_softc *ms; u_int secsize; struct g_slicer *gsp; u_char hash[16]; MD5_CTX md5sum; g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name); g_topology_assert(); /* We don't implement transparent inserts. */ if (flags == G_TF_TRANSPARENT) return (NULL); /* * BSD labels are a subclass of the general "slicing" topology so * a lot of the work can be done by the common "slice" code. * Create a geom with space for MAXPARTITIONS providers, one consumer * and a softc structure for us. Specify the provider to attach * the consumer to and our "start" routine for special requests. * The provider is opened with mode (1,0,0) so we can do reads * from it. */ gp = g_slice_new(mp, MAXPARTITIONS, pp, &cp, &ms, sizeof(*ms), g_bsd_start); if (gp == NULL) return (NULL); /* Get the geom_slicer softc from the geom. */ gsp = gp->softc; /* * The do...while loop here allows us to have multiple escapes * using a simple "break". This improves code clarity without * ending up in deep nesting and without using goto or come from. */ do { /* * If the provider is an MBR we will only auto attach * to type 165 slices in the G_TF_NORMAL case. We will * attach to any other type. */ error = g_getattr("MBR::type", cp, &i); if (!error) { if (i != 165 && flags == G_TF_NORMAL) break; error = g_getattr("MBR::offset", cp, &ms->mbroffset); if (error) break; } /* Same thing if we are inside a PC98 */ error = g_getattr("PC98::type", cp, &i); if (!error) { if (i != 0xc494 && flags == G_TF_NORMAL) break; error = g_getattr("PC98::offset", cp, &ms->mbroffset); if (error) break; } /* Get sector size, we need it to read data. */ secsize = cp->provider->sectorsize; if (secsize < 512) break; /* First look for a label at the start of the second sector. */ error = g_bsd_try(gp, gsp, cp, secsize, ms, secsize); /* Next, look for alpha labels */ if (error) error = g_bsd_try(gp, gsp, cp, secsize, ms, ALPHA_LABEL_OFFSET); /* If we didn't find a label, punt. */ if (error) break; /* * In order to avoid recursively attaching to the same * on-disk label (it's usually visible through the 'c' * partition) we calculate an MD5 and ask if other BSD's * below us love that label. If they do, we don't. */ MD5Init(&md5sum); MD5Update(&md5sum, ms->label, sizeof(ms->label)); MD5Final(ms->labelsum, &md5sum); error = g_getattr("BSD::labelsum", cp, &hash); if (!error && !bcmp(ms->labelsum, hash, sizeof(hash))) break; /* * Process the found disklabel, and modify our "slice" * instance to match it, if possible. */ error = g_bsd_modify(gp, ms->label); } while (0); /* Success or failure, we can close our provider now. */ g_access(cp, -1, 0, 0); /* If we have configured any providers, return the new geom. */ if (gsp->nprovider > 0) { g_slice_conf_hot(gp, 0, ms->labeloffset, LABELSIZE, G_SLICE_HOT_ALLOW, G_SLICE_HOT_DENY, G_SLICE_HOT_CALL); gsp->hot = g_bsd_hotwrite; return (gp); } /* * ...else push the "self-destruct" button, by spoiling our own * consumer. This triggers a call to g_slice_spoiled which will * dismantle what was setup. */ g_slice_spoiled(cp); return (NULL); } struct h0h0 { struct g_geom *gp; struct g_bsd_softc *ms; u_char *label; int error; }; static void g_bsd_callconfig(void *arg, int flag) { struct h0h0 *hp; hp = arg; hp->error = g_bsd_modify(hp->gp, hp->label); if (!hp->error) hp->error = g_bsd_writelabel(hp->gp, NULL); } /* * NB! curthread is user process which GCTL'ed. */ static void g_bsd_config(struct gctl_req *req, struct g_class *mp, char const *verb) { u_char *label; int error; struct h0h0 h0h0; struct g_geom *gp; struct g_slicer *gsp; struct g_consumer *cp; struct g_bsd_softc *ms; g_topology_assert(); gp = gctl_get_geom(req, mp, "geom"); if (gp == NULL) return; cp = LIST_FIRST(&gp->consumer); gsp = gp->softc; ms = gsp->softc; if (!strcmp(verb, "read mbroffset")) { gctl_set_param(req, "mbroffset", &ms->mbroffset, sizeof(ms->mbroffset)); return; } else if (!strcmp(verb, "write label")) { label = gctl_get_paraml(req, "label", LABELSIZE); if (label == NULL) return; h0h0.gp = gp; h0h0.ms = gsp->softc; h0h0.label = label; h0h0.error = -1; /* XXX: Does this reference register with our selfdestruct code ? */ error = g_access(cp, 1, 1, 1); if (error) { gctl_error(req, "could not access consumer"); return; } g_bsd_callconfig(&h0h0, 0); error = h0h0.error; g_access(cp, -1, -1, -1); } else if (!strcmp(verb, "write bootcode")) { label = gctl_get_paraml(req, "bootcode", BBSIZE); if (label == NULL) return; /* XXX: Does this reference register with our selfdestruct code ? */ error = g_access(cp, 1, 1, 1); if (error) { gctl_error(req, "could not access consumer"); return; } error = g_bsd_writelabel(gp, label); g_access(cp, -1, -1, -1); } else { gctl_error(req, "Unknown verb parameter"); } return; } /* Finally, register with GEOM infrastructure. */ static struct g_class g_bsd_class = { .name = BSD_CLASS_NAME, .version = G_VERSION, .taste = g_bsd_taste, .ctlreq = g_bsd_config, .dumpconf = g_bsd_dumpconf, .ioctl = g_bsd_ioctl, }; DECLARE_GEOM_CLASS(g_bsd_class, g_bsd); Index: head/sys/geom/geom_fox.c =================================================================== --- head/sys/geom/geom_fox.c (revision 152970) +++ head/sys/geom/geom_fox.c (revision 152971) @@ -1,473 +1,473 @@ /*- * Copyright (c) 2003 Poul-Henning Kamp * 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. * * $FreeBSD$ */ /* This is a GEOM module for handling path selection for multi-path * storage devices. It is named "fox" because it, like they, prefer * to have multiple exits to choose from. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define FOX_CLASS_NAME "FOX" #define FOX_MAGIC "GEOM::FOX" struct g_fox_softc { off_t mediasize; u_int sectorsize; TAILQ_HEAD(, bio) queue; struct mtx lock; u_char magic[16]; struct g_consumer *path; struct g_consumer *opath; int waiting; int cr, cw, ce; }; /* * This function is called whenever we need to select a new path. */ static void g_fox_select_path(void *arg, int flag) { struct g_geom *gp; struct g_fox_softc *sc; struct g_consumer *cp1; struct bio *bp; int error; g_topology_assert(); if (flag == EV_CANCEL) return; gp = arg; sc = gp->softc; if (sc->opath != NULL) { /* * First, close the old path entirely. */ printf("Closing old path (%s) on fox (%s)\n", sc->opath->provider->name, gp->name); cp1 = LIST_NEXT(sc->opath, consumer); g_access(sc->opath, -sc->cr, -sc->cw, -(sc->ce + 1)); /* * The attempt to reopen it with a exclusive count */ error = g_access(sc->opath, 0, 0, 1); if (error) { /* * Ok, ditch this consumer, we can't use it. */ printf("Drop old path (%s) on fox (%s)\n", sc->opath->provider->name, gp->name); g_detach(sc->opath); g_destroy_consumer(sc->opath); if (LIST_EMPTY(&gp->consumer)) { /* No consumers left */ g_wither_geom(gp, ENXIO); for (;;) { bp = TAILQ_FIRST(&sc->queue); if (bp == NULL) break; TAILQ_REMOVE(&sc->queue, bp, bio_queue); bp->bio_error = ENXIO; g_std_done(bp); } return; } } else { printf("Got e-bit on old path (%s) on fox (%s)\n", sc->opath->provider->name, gp->name); } sc->opath = NULL; } else { cp1 = LIST_FIRST(&gp->consumer); } if (cp1 == NULL) cp1 = LIST_FIRST(&gp->consumer); printf("Open new path (%s) on fox (%s)\n", cp1->provider->name, gp->name); error = g_access(cp1, sc->cr, sc->cw, sc->ce); if (error) { /* * If we failed, we take another trip through here */ printf("Open new path (%s) on fox (%s) failed, reselect.\n", cp1->provider->name, gp->name); sc->opath = cp1; g_post_event(g_fox_select_path, gp, M_WAITOK, gp, NULL); } else { printf("Open new path (%s) on fox (%s) succeeded\n", cp1->provider->name, gp->name); mtx_lock(&sc->lock); sc->path = cp1; sc->waiting = 0; for (;;) { bp = TAILQ_FIRST(&sc->queue); if (bp == NULL) break; TAILQ_REMOVE(&sc->queue, bp, bio_queue); g_io_request(bp, sc->path); } mtx_unlock(&sc->lock); } } static void g_fox_orphan(struct g_consumer *cp) { struct g_geom *gp; struct g_fox_softc *sc; int error, mark; g_topology_assert(); gp = cp->geom; sc = gp->softc; printf("Removing path (%s) from fox (%s)\n", cp->provider->name, gp->name); mtx_lock(&sc->lock); if (cp == sc->path) { sc->opath = NULL; sc->path = NULL; sc->waiting = 1; mark = 1; } else { mark = 0; } mtx_unlock(&sc->lock); g_access(cp, -cp->acr, -cp->acw, -cp->ace); error = cp->provider->error; g_detach(cp); g_destroy_consumer(cp); if (!LIST_EMPTY(&gp->consumer)) { if (mark) g_post_event(g_fox_select_path, gp, M_WAITOK, gp, NULL); return; } mtx_destroy(&sc->lock); g_free(gp->softc); gp->softc = NULL; g_wither_geom(gp, ENXIO); } static void g_fox_done(struct bio *bp) { struct g_geom *gp; struct g_fox_softc *sc; int error; if (bp->bio_error == 0) { g_std_done(bp); return; } gp = bp->bio_from->geom; sc = gp->softc; if (bp->bio_from != sc->path) { g_io_request(bp, sc->path); return; } mtx_lock(&sc->lock); sc->opath = sc->path; sc->path = NULL; error = g_post_event(g_fox_select_path, gp, M_NOWAIT, gp, NULL); if (error) { bp->bio_error = ENOMEM; g_std_done(bp); } else { sc->waiting = 1; TAILQ_INSERT_TAIL(&sc->queue, bp, bio_queue); } mtx_unlock(&sc->lock); } static void g_fox_start(struct bio *bp) { struct g_geom *gp; struct bio *bp2; struct g_fox_softc *sc; int error; gp = bp->bio_to->geom; sc = gp->softc; if (sc == NULL) { g_io_deliver(bp, ENXIO); return; } switch(bp->bio_cmd) { case BIO_READ: case BIO_WRITE: case BIO_DELETE: bp2 = g_clone_bio(bp); if (bp2 == NULL) { g_io_deliver(bp, ENOMEM); break; } bp2->bio_offset += sc->sectorsize; bp2->bio_done = g_fox_done; mtx_lock(&sc->lock); if (sc->path == NULL || !TAILQ_EMPTY(&sc->queue)) { if (sc->waiting == 0) { error = g_post_event(g_fox_select_path, gp, M_NOWAIT, gp, NULL); if (error) { g_destroy_bio(bp2); bp2 = NULL; g_io_deliver(bp, error); } else { sc->waiting = 1; } } if (bp2 != NULL) TAILQ_INSERT_TAIL(&sc->queue, bp2, bio_queue); } else { g_io_request(bp2, sc->path); } mtx_unlock(&sc->lock); break; default: g_io_deliver(bp, EOPNOTSUPP); break; } return; } static int g_fox_access(struct g_provider *pp, int dr, int dw, int de) { struct g_geom *gp; struct g_fox_softc *sc; struct g_consumer *cp1; int error; g_topology_assert(); gp = pp->geom; sc = gp->softc; if (sc == NULL) { if (dr <= 0 && dw <= 0 && de <= 0) return (0); else return (ENXIO); } if (sc->cr == 0 && sc->cw == 0 && sc->ce == 0) { /* * First open, open all consumers with an exclusive bit */ error = 0; LIST_FOREACH(cp1, &gp->consumer, consumer) { error = g_access(cp1, 0, 0, 1); if (error) { printf("FOX: access(%s,0,0,1) = %d\n", cp1->provider->name, error); break; } } if (error) { LIST_FOREACH(cp1, &gp->consumer, consumer) { if (cp1->ace) g_access(cp1, 0, 0, -1); } return (error); } } if (sc->path == NULL) g_fox_select_path(gp, 0); if (sc->path == NULL) error = ENXIO; else error = g_access(sc->path, dr, dw, de); if (error == 0) { sc->cr += dr; sc->cw += dw; sc->ce += de; if (sc->cr == 0 && sc->cw == 0 && sc->ce == 0) { /* * Last close, remove e-bit on all consumers */ LIST_FOREACH(cp1, &gp->consumer, consumer) g_access(cp1, 0, 0, -1); } } return (error); } static struct g_geom * g_fox_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) { struct g_geom *gp, *gp2; struct g_provider *pp2; struct g_consumer *cp, *cp2; struct g_fox_softc *sc, *sc2; int error; u_int sectorsize; u_char *buf; g_trace(G_T_TOPOLOGY, "fox_taste(%s, %s)", mp->name, pp->name); g_topology_assert(); if (!strcmp(pp->geom->class->name, mp->name)) return (NULL); gp = g_new_geomf(mp, "%s.fox", pp->name); gp->softc = g_malloc(sizeof(struct g_fox_softc), M_WAITOK | M_ZERO); sc = gp->softc; cp = g_new_consumer(gp); g_attach(cp, pp); error = g_access(cp, 1, 0, 0); if (error) { g_free(sc); g_detach(cp); g_destroy_consumer(cp); g_destroy_geom(gp); return(NULL); } do { sectorsize = cp->provider->sectorsize; g_topology_unlock(); - buf = g_read_data(cp, 0, sectorsize, &error); + buf = g_read_data(cp, 0, sectorsize, NULL); g_topology_lock(); if (buf == NULL) break; if (memcmp(buf, FOX_MAGIC, strlen(FOX_MAGIC))) break; /* * First we need to see if this a new path for an existing fox. */ LIST_FOREACH(gp2, &mp->geom, geom) { sc2 = gp2->softc; if (sc2 == NULL) continue; if (memcmp(buf + 16, sc2->magic, sizeof sc2->magic)) continue; break; } if (gp2 != NULL) { /* * It was. Create a new consumer for that fox, * attach it, and if the fox is open, open this * path with an exclusive count of one. */ printf("Adding path (%s) to fox (%s)\n", pp->name, gp2->name); cp2 = g_new_consumer(gp2); g_attach(cp2, pp); pp2 = LIST_FIRST(&gp2->provider); if (pp2->acr > 0 || pp2->acw > 0 || pp2->ace > 0) { error = g_access(cp2, 0, 0, 1); if (error) { /* * This is bad, or more likely, * the user is doing something stupid */ printf( "WARNING: New path (%s) to fox(%s) not added: %s\n%s", cp2->provider->name, gp2->name, "Could not get exclusive bit.", "WARNING: This indicates a risk of data inconsistency." ); g_detach(cp2); g_destroy_consumer(cp2); } } break; } printf("Creating new fox (%s)\n", pp->name); sc->path = cp; memcpy(sc->magic, buf + 16, sizeof sc->magic); pp2 = g_new_providerf(gp, "%s", gp->name); pp2->mediasize = sc->mediasize = pp->mediasize - pp->sectorsize; pp2->sectorsize = sc->sectorsize = pp->sectorsize; printf("fox %s lock %p\n", gp->name, &sc->lock); mtx_init(&sc->lock, "fox queue", NULL, MTX_DEF); TAILQ_INIT(&sc->queue); g_error_provider(pp2, 0); } while (0); if (buf != NULL) g_free(buf); g_access(cp, -1, 0, 0); if (!LIST_EMPTY(&gp->provider)) return (gp); g_free(gp->softc); g_detach(cp); g_destroy_consumer(cp); g_destroy_geom(gp); return (NULL); } static int g_fox_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) { struct g_fox_softc *sc; g_topology_assert(); sc = gp->softc; mtx_destroy(&sc->lock); g_free(gp->softc); gp->softc = NULL; g_wither_geom(gp, ENXIO); return (0); } static struct g_class g_fox_class = { .name = FOX_CLASS_NAME, .version = G_VERSION, .taste = g_fox_taste, .destroy_geom = g_fox_destroy_geom, .start = g_fox_start, .spoiled = g_fox_orphan, .orphan = g_fox_orphan, .access= g_fox_access, }; DECLARE_GEOM_CLASS(g_fox_class, g_fox); Index: head/sys/geom/geom_mbr.c =================================================================== --- head/sys/geom/geom_mbr.c (revision 152970) +++ head/sys/geom/geom_mbr.c (revision 152971) @@ -1,518 +1,518 @@ /*- * Copyright (c) 2002 Poul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by Poul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the * DARPA CHATS research program. * * 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 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MBR_CLASS_NAME "MBR" #define MBREXT_CLASS_NAME "MBREXT" static struct dos_partition historical_bogus_partition_table[NDOSPART] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, { 0x80, 0, 1, 0, DOSPTYP_386BSD, 255, 255, 255, 0, 50000, }, }; static struct dos_partition historical_bogus_partition_table_fixed[NDOSPART] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, { 0x80, 0, 1, 0, DOSPTYP_386BSD, 254, 255, 255, 0, 50000, }, }; static void g_mbr_print(int i, struct dos_partition *dp) { printf("[%d] f:%02x typ:%d", i, dp->dp_flag, dp->dp_typ); printf(" s(CHS):%d/%d/%d", DPCYL(dp->dp_scyl, dp->dp_ssect), dp->dp_shd, DPSECT(dp->dp_ssect)); printf(" e(CHS):%d/%d/%d", DPCYL(dp->dp_ecyl, dp->dp_esect), dp->dp_ehd, DPSECT(dp->dp_esect)); printf(" s:%d l:%d\n", dp->dp_start, dp->dp_size); } struct g_mbr_softc { int type [NDOSPART]; u_int sectorsize; u_char sec0[512]; u_char slicesum[16]; }; /* * XXX: Add gctl_req arg and give good error msgs. * XXX: Check that length argument does not bring boot code inside any slice. */ static int g_mbr_modify(struct g_geom *gp, struct g_mbr_softc *ms, u_char *sec0, int len __unused) { int i, error; off_t l[NDOSPART]; struct dos_partition ndp[NDOSPART], *dp; MD5_CTX md5sum; g_topology_assert(); if (sec0[0x1fe] != 0x55 && sec0[0x1ff] != 0xaa) return (EBUSY); dp = ndp; for (i = 0; i < NDOSPART; i++) { dos_partition_dec( sec0 + DOSPARTOFF + i * sizeof(struct dos_partition), dp + i); } if ((!bcmp(dp, historical_bogus_partition_table, sizeof historical_bogus_partition_table)) || (!bcmp(dp, historical_bogus_partition_table_fixed, sizeof historical_bogus_partition_table_fixed))) { /* * We will not allow people to write these from "the inside", * Since properly selfdestructing takes too much code. If * people really want to do this, they cannot have any * providers of this geom open, and in that case they can just * as easily overwrite the MBR in the parent device. */ return(EBUSY); } for (i = 0; i < NDOSPART; i++) { /* * A Protective MBR (PMBR) has a single partition of * type 0xEE spanning the whole disk. Such a MBR * protects a GPT on the disk from MBR tools that * don't know anything about GPT. We're interpreting * it a bit more loosely: any partition of type 0xEE * is to be skipped as it doesn't contain any data * that we should care about. We still allow other * partitions to be present in the MBR. A PMBR will * be handled correctly anyway. */ if (dp[i].dp_typ == DOSPTYP_PMBR) l[i] = 0; else if (dp[i].dp_flag != 0 && dp[i].dp_flag != 0x80) l[i] = 0; else if (dp[i].dp_typ == 0) l[i] = 0; else l[i] = (off_t)dp[i].dp_size * ms->sectorsize; error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, (off_t)dp[i].dp_start * ms->sectorsize, l[i], ms->sectorsize, "%ss%d", gp->name, 1 + i); if (error) return (error); } for (i = 0; i < NDOSPART; i++) { ms->type[i] = dp[i].dp_typ; g_slice_config(gp, i, G_SLICE_CONFIG_SET, (off_t)dp[i].dp_start * ms->sectorsize, l[i], ms->sectorsize, "%ss%d", gp->name, 1 + i); } bcopy(sec0, ms->sec0, 512); /* * Calculate MD5 from the first sector and use it for avoiding * recursive slices creation. */ MD5Init(&md5sum); MD5Update(&md5sum, ms->sec0, sizeof(ms->sec0)); MD5Final(ms->slicesum, &md5sum); return (0); } static int g_mbr_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td) { struct g_geom *gp; struct g_mbr_softc *ms; struct g_slicer *gsp; struct g_consumer *cp; int error, opened; gp = pp->geom; gsp = gp->softc; ms = gsp->softc; opened = 0; error = 0; switch(cmd) { case DIOCSMBR: { if (!(fflag & FWRITE)) return (EPERM); DROP_GIANT(); g_topology_lock(); cp = LIST_FIRST(&gp->consumer); if (cp->acw == 0) { error = g_access(cp, 0, 1, 0); if (error == 0) opened = 1; } if (!error) error = g_mbr_modify(gp, ms, data, 512); if (!error) error = g_write_data(cp, 0, data, 512); if (opened) g_access(cp, 0, -1 , 0); g_topology_unlock(); PICKUP_GIANT(); return(error); } default: return (ENOIOCTL); } } static int g_mbr_start(struct bio *bp) { struct g_provider *pp; struct g_geom *gp; struct g_mbr_softc *mp; struct g_slicer *gsp; int idx; pp = bp->bio_to; idx = pp->index; gp = pp->geom; gsp = gp->softc; mp = gsp->softc; if (bp->bio_cmd == BIO_GETATTR) { if (g_handleattr_int(bp, "MBR::type", mp->type[idx])) return (1); if (g_handleattr_off_t(bp, "MBR::offset", gsp->slices[idx].offset)) return (1); if (g_handleattr(bp, "MBR::slicesum", mp->slicesum, sizeof(mp->slicesum))) return (1); } return (0); } static void g_mbr_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp) { struct g_mbr_softc *mp; struct g_slicer *gsp; gsp = gp->softc; mp = gsp->softc; g_slice_dumpconf(sb, indent, gp, cp, pp); if (pp != NULL) { if (indent == NULL) sbuf_printf(sb, " ty %d", mp->type[pp->index]); else sbuf_printf(sb, "%s%d\n", indent, mp->type[pp->index]); } } static struct g_geom * g_mbr_taste(struct g_class *mp, struct g_provider *pp, int insist) { struct g_geom *gp; struct g_consumer *cp; int error; struct g_mbr_softc *ms; u_int fwsectors, sectorsize; u_char *buf; u_char hash[16]; MD5_CTX md5sum; g_trace(G_T_TOPOLOGY, "mbr_taste(%s,%s)", mp->name, pp->name); g_topology_assert(); if (!strcmp(pp->geom->class->name, MBR_CLASS_NAME)) return (NULL); gp = g_slice_new(mp, NDOSPART, pp, &cp, &ms, sizeof *ms, g_mbr_start); if (gp == NULL) return (NULL); g_topology_unlock(); do { error = g_getattr("GEOM::fwsectors", cp, &fwsectors); if (error) fwsectors = 17; sectorsize = cp->provider->sectorsize; if (sectorsize < 512) break; ms->sectorsize = sectorsize; - buf = g_read_data(cp, 0, sectorsize, &error); + buf = g_read_data(cp, 0, sectorsize, NULL); if (buf == NULL) break; /* * Calculate MD5 from the first sector and use it for avoiding * recursive slices creation. */ bcopy(buf, ms->sec0, 512); MD5Init(&md5sum); MD5Update(&md5sum, ms->sec0, sizeof(ms->sec0)); MD5Final(ms->slicesum, &md5sum); error = g_getattr("MBR::slicesum", cp, &hash); if (!error && !bcmp(ms->slicesum, hash, sizeof(hash))) { g_free(buf); break; } g_topology_lock(); g_mbr_modify(gp, ms, buf, 512); g_topology_unlock(); g_free(buf); break; } while (0); g_topology_lock(); g_access(cp, -1, 0, 0); if (LIST_EMPTY(&gp->provider)) { g_slice_spoiled(cp); return (NULL); } return (gp); } static void g_mbr_config(struct gctl_req *req, struct g_class *mp, const char *verb) { struct g_geom *gp; struct g_consumer *cp; struct g_mbr_softc *ms; struct g_slicer *gsp; int opened = 0, error = 0; void *data; int len; g_topology_assert(); gp = gctl_get_geom(req, mp, "geom"); if (gp == NULL) return; if (strcmp(verb, "write MBR")) { gctl_error(req, "Unknown verb"); return; } gsp = gp->softc; ms = gsp->softc; data = gctl_get_param(req, "data", &len); if (data == NULL) return; if (len < 512 || (len % 512)) { gctl_error(req, "Wrong request length"); return; } cp = LIST_FIRST(&gp->consumer); if (cp->acw == 0) { error = g_access(cp, 0, 1, 0); if (error == 0) opened = 1; } if (!error) error = g_mbr_modify(gp, ms, data, len); if (error) gctl_error(req, "conflict with open slices"); if (!error) error = g_write_data(cp, 0, data, len); if (error) gctl_error(req, "sector zero write failed"); if (opened) g_access(cp, 0, -1 , 0); return; } static struct g_class g_mbr_class = { .name = MBR_CLASS_NAME, .version = G_VERSION, .taste = g_mbr_taste, .dumpconf = g_mbr_dumpconf, .ctlreq = g_mbr_config, .ioctl = g_mbr_ioctl, }; DECLARE_GEOM_CLASS(g_mbr_class, g_mbr); #define NDOSEXTPART 32 struct g_mbrext_softc { int type [NDOSEXTPART]; }; static int g_mbrext_start(struct bio *bp) { struct g_provider *pp; struct g_geom *gp; struct g_mbrext_softc *mp; struct g_slicer *gsp; int idx; pp = bp->bio_to; idx = pp->index; gp = pp->geom; gsp = gp->softc; mp = gsp->softc; if (bp->bio_cmd == BIO_GETATTR) { if (g_handleattr_int(bp, "MBR::type", mp->type[idx])) return (1); } return (0); } static void g_mbrext_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp) { struct g_mbrext_softc *mp; struct g_slicer *gsp; g_slice_dumpconf(sb, indent, gp, cp, pp); gsp = gp->softc; mp = gsp->softc; if (pp != NULL) { if (indent == NULL) sbuf_printf(sb, " ty %d", mp->type[pp->index]); else sbuf_printf(sb, "%s%d\n", indent, mp->type[pp->index]); } } static struct g_geom * g_mbrext_taste(struct g_class *mp, struct g_provider *pp, int insist __unused) { struct g_geom *gp; struct g_consumer *cp; int error, i, slice; struct g_mbrext_softc *ms; off_t off; u_char *buf; struct dos_partition dp[4]; u_int fwsectors, sectorsize; g_trace(G_T_TOPOLOGY, "g_mbrext_taste(%s,%s)", mp->name, pp->name); g_topology_assert(); if (strcmp(pp->geom->class->name, MBR_CLASS_NAME)) return (NULL); gp = g_slice_new(mp, NDOSEXTPART, pp, &cp, &ms, sizeof *ms, g_mbrext_start); if (gp == NULL) return (NULL); g_topology_unlock(); off = 0; slice = 0; do { error = g_getattr("MBR::type", cp, &i); if (error || (i != DOSPTYP_EXT && i != DOSPTYP_EXTLBA)) break; error = g_getattr("GEOM::fwsectors", cp, &fwsectors); if (error) fwsectors = 17; sectorsize = cp->provider->sectorsize; if (sectorsize != 512) break; for (;;) { - buf = g_read_data(cp, off, sectorsize, &error); + buf = g_read_data(cp, off, sectorsize, NULL); if (buf == NULL) break; if (buf[0x1fe] != 0x55 && buf[0x1ff] != 0xaa) { g_free(buf); break; } for (i = 0; i < NDOSPART; i++) dos_partition_dec( buf + DOSPARTOFF + i * sizeof(struct dos_partition), dp + i); g_free(buf); if (0 && bootverbose) { printf("MBREXT Slice %d on %s:\n", slice + 5, gp->name); g_mbr_print(0, dp); g_mbr_print(1, dp + 1); } if ((dp[0].dp_flag & 0x7f) == 0 && dp[0].dp_size != 0 && dp[0].dp_typ != 0) { g_topology_lock(); g_slice_config(gp, slice, G_SLICE_CONFIG_SET, (((off_t)dp[0].dp_start) << 9ULL) + off, ((off_t)dp[0].dp_size) << 9ULL, sectorsize, "%*.*s%d", strlen(gp->name) - 1, strlen(gp->name) - 1, gp->name, slice + 5); g_topology_unlock(); ms->type[slice] = dp[0].dp_typ; slice++; } if (dp[1].dp_flag != 0) break; if (dp[1].dp_typ != DOSPTYP_EXT && dp[1].dp_typ != DOSPTYP_EXTLBA) break; if (dp[1].dp_size == 0) break; off = ((off_t)dp[1].dp_start) << 9ULL; } break; } while (0); g_topology_lock(); g_access(cp, -1, 0, 0); if (LIST_EMPTY(&gp->provider)) { g_slice_spoiled(cp); return (NULL); } return (gp); } static struct g_class g_mbrext_class = { .name = MBREXT_CLASS_NAME, .version = G_VERSION, .taste = g_mbrext_taste, .dumpconf = g_mbrext_dumpconf, }; DECLARE_GEOM_CLASS(g_mbrext_class, g_mbrext); Index: head/sys/geom/geom_pc98.c =================================================================== --- head/sys/geom/geom_pc98.c (revision 152970) +++ head/sys/geom/geom_pc98.c (revision 152971) @@ -1,368 +1,368 @@ /*- * Copyright (c) 2002 Poul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by Poul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the * DARPA CHATS research program. * * 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 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #define PC98_CLASS_NAME "PC98" struct g_pc98_softc { u_int fwsectors, fwheads, sectorsize; int type[NDOSPART]; u_char sec[8192]; }; static void g_pc98_print(int i, struct pc98_partition *dp) { char sname[17]; strncpy(sname, dp->dp_name, 16); sname[16] = '\0'; hexdump(dp, sizeof(dp[0]), NULL, 0); printf("[%d] mid:%d(0x%x) sid:%d(0x%x)", i, dp->dp_mid, dp->dp_mid, dp->dp_sid, dp->dp_sid); printf(" s:%d/%d/%d", dp->dp_scyl, dp->dp_shd, dp->dp_ssect); printf(" e:%d/%d/%d", dp->dp_ecyl, dp->dp_ehd, dp->dp_esect); printf(" sname:%s\n", sname); } /* * XXX: Add gctl_req arg and give good error msgs. * XXX: Check that length argument does not bring boot code inside any slice. */ static int g_pc98_modify(struct g_geom *gp, struct g_pc98_softc *ms, u_char *sec, int len __unused) { int i, error; off_t s[NDOSPART], l[NDOSPART]; struct pc98_partition dp[NDOSPART]; g_topology_assert(); if (sec[0x1fe] != 0x55 || sec[0x1ff] != 0xaa) return (EBUSY); #if 0 /* * By convetion, it seems that the ipl program has a jump at location * 0 to the real start of the boot loader. By convetion, it appears * that after this jump, there's a string, terminated by at last one, * if not more, zeros, followed by the target of the jump. FreeBSD's * pc98 boot0 uses 'IPL1' followed by 3 zeros here, likely for * compatibility with some older boot loader. Linux98's boot loader * appears to use 'Linux 98' followed by only two. GRUB/98 appears to * use 'GRUB/98 ' followed by none. These last two appear to be * ported from the ia32 versions, but appear to show similar * convention. Grub/98 has an additional NOP after the jmp, which * isn't present in others. * * The following test was inspired by looking only at partitions * with FreeBSD's boot0 (or one that it is compatible with). As * such, if failed when other IPL programs were used. */ if (sec[4] != 'I' || sec[5] != 'P' || sec[6] != 'L' || sec[7] != '1') return (EBUSY); #endif for (i = 0; i < NDOSPART; i++) pc98_partition_dec( sec + 512 + i * sizeof(struct pc98_partition), &dp[i]); for (i = 0; i < NDOSPART; i++) { /* If start and end are identical it's bogus */ if (dp[i].dp_ssect == dp[i].dp_esect && dp[i].dp_shd == dp[i].dp_ehd && dp[i].dp_scyl == dp[i].dp_ecyl) s[i] = l[i] = 0; else if (dp[i].dp_ecyl == 0) s[i] = l[i] = 0; else { s[i] = (off_t)dp[i].dp_scyl * ms->fwsectors * ms->fwheads * ms->sectorsize; l[i] = (off_t)(dp[i].dp_ecyl - dp[i].dp_scyl + 1) * ms->fwsectors * ms->fwheads * ms->sectorsize; } if (bootverbose) { printf("PC98 Slice %d on %s:\n", i + 1, gp->name); g_pc98_print(i, dp + i); } if (s[i] < 0 || l[i] < 0) error = EBUSY; else error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, s[i], l[i], ms->sectorsize, "%ss%d", gp->name, i + 1); if (error) return (error); } for (i = 0; i < NDOSPART; i++) { ms->type[i] = (dp[i].dp_sid << 8) | dp[i].dp_mid; g_slice_config(gp, i, G_SLICE_CONFIG_SET, s[i], l[i], ms->sectorsize, "%ss%d", gp->name, i + 1); } bcopy(sec, ms->sec, sizeof (ms->sec)); return (0); } static int g_pc98_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td) { struct g_geom *gp; struct g_pc98_softc *ms; struct g_slicer *gsp; struct g_consumer *cp; int error, opened; gp = pp->geom; gsp = gp->softc; ms = gsp->softc; opened = 0; error = 0; switch(cmd) { case DIOCSPC98: { if (!(fflag & FWRITE)) return (EPERM); DROP_GIANT(); g_topology_lock(); cp = LIST_FIRST(&gp->consumer); if (cp->acw == 0) { error = g_access(cp, 0, 1, 0); if (error == 0) opened = 1; } if (!error) error = g_pc98_modify(gp, ms, data, 8192); if (!error) error = g_write_data(cp, 0, data, 8192); if (opened) g_access(cp, 0, -1 , 0); g_topology_unlock(); PICKUP_GIANT(); return(error); } default: return (ENOIOCTL); } } static int g_pc98_start(struct bio *bp) { struct g_provider *pp; struct g_geom *gp; struct g_pc98_softc *mp; struct g_slicer *gsp; int idx; pp = bp->bio_to; idx = pp->index; gp = pp->geom; gsp = gp->softc; mp = gsp->softc; if (bp->bio_cmd == BIO_GETATTR) { if (g_handleattr_int(bp, "PC98::type", mp->type[idx])) return (1); if (g_handleattr_off_t(bp, "PC98::offset", gsp->slices[idx].offset)) return (1); } return (0); } static void g_pc98_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp) { struct g_pc98_softc *mp; struct g_slicer *gsp; struct pc98_partition dp; char sname[17]; gsp = gp->softc; mp = gsp->softc; g_slice_dumpconf(sb, indent, gp, cp, pp); if (pp != NULL) { pc98_partition_dec( mp->sec + 512 + pp->index * sizeof(struct pc98_partition), &dp); strncpy(sname, dp.dp_name, 16); sname[16] = '\0'; if (indent == NULL) { sbuf_printf(sb, " ty %d", mp->type[pp->index]); sbuf_printf(sb, " sn %s", sname); } else { sbuf_printf(sb, "%s%d\n", indent, mp->type[pp->index]); sbuf_printf(sb, "%s%s\n", indent, sname); } } } static struct g_geom * g_pc98_taste(struct g_class *mp, struct g_provider *pp, int flags) { struct g_geom *gp; struct g_consumer *cp; int error; struct g_pc98_softc *ms; u_int fwsectors, fwheads, sectorsize; u_char *buf; g_trace(G_T_TOPOLOGY, "g_pc98_taste(%s,%s)", mp->name, pp->name); g_topology_assert(); if (flags == G_TF_NORMAL && !strcmp(pp->geom->class->name, PC98_CLASS_NAME)) return (NULL); gp = g_slice_new(mp, NDOSPART, pp, &cp, &ms, sizeof *ms, g_pc98_start); if (gp == NULL) return (NULL); g_topology_unlock(); do { if (gp->rank != 2 && flags == G_TF_NORMAL) break; error = g_getattr("GEOM::fwsectors", cp, &fwsectors); if (error || fwsectors == 0) { fwsectors = 17; if (bootverbose) printf("g_pc98_taste: guessing %d sectors\n", fwsectors); } error = g_getattr("GEOM::fwheads", cp, &fwheads); if (error || fwheads == 0) { fwheads = 8; if (bootverbose) printf("g_pc98_taste: guessing %d heads\n", fwheads); } sectorsize = cp->provider->sectorsize; if (sectorsize % 512 != 0) break; - buf = g_read_data(cp, 0, 8192, &error); + buf = g_read_data(cp, 0, 8192, NULL); if (buf == NULL) break; ms->fwsectors = fwsectors; ms->fwheads = fwheads; ms->sectorsize = sectorsize; g_topology_lock(); g_pc98_modify(gp, ms, buf, 8192); g_topology_unlock(); g_free(buf); break; } while (0); g_topology_lock(); g_access(cp, -1, 0, 0); if (LIST_EMPTY(&gp->provider)) { g_slice_spoiled(cp); return (NULL); } return (gp); } static void g_pc98_config(struct gctl_req *req, struct g_class *mp, const char *verb) { struct g_geom *gp; struct g_consumer *cp; struct g_pc98_softc *ms; struct g_slicer *gsp; int opened = 0, error = 0; void *data; int len; g_topology_assert(); gp = gctl_get_geom(req, mp, "geom"); if (gp == NULL) return; if (strcmp(verb, "write PC98")) { gctl_error(req, "Unknown verb"); return; } gsp = gp->softc; ms = gsp->softc; data = gctl_get_param(req, "data", &len); if (data == NULL) return; if (len < 8192 || (len % 512)) { gctl_error(req, "Wrong request length"); return; } cp = LIST_FIRST(&gp->consumer); if (cp->acw == 0) { error = g_access(cp, 0, 1, 0); if (error == 0) opened = 1; } if (!error) error = g_pc98_modify(gp, ms, data, len); if (error) gctl_error(req, "conflict with open slices"); if (!error) error = g_write_data(cp, 0, data, len); if (error) gctl_error(req, "sector zero write failed"); if (opened) g_access(cp, 0, -1 , 0); return; } static struct g_class g_pc98_class = { .name = PC98_CLASS_NAME, .version = G_VERSION, .taste = g_pc98_taste, .dumpconf = g_pc98_dumpconf, .ctlreq = g_pc98_config, .ioctl = g_pc98_ioctl, }; DECLARE_GEOM_CLASS(g_pc98_class, g_pc98); Index: head/sys/geom/geom_sunlabel.c =================================================================== --- head/sys/geom/geom_sunlabel.c (revision 152970) +++ head/sys/geom/geom_sunlabel.c (revision 152971) @@ -1,322 +1,322 @@ /*- * Copyright (c) 2002 Poul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by Poul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the * DARPA CHATS research program. * * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SUNLABEL_CLASS_NAME "SUN" struct g_sunlabel_softc { int sectorsize; int nheads; int nsects; int nalt; u_char labelsum[16]; }; static int g_sunlabel_modify(struct g_geom *gp, struct g_sunlabel_softc *ms, u_char *sec0) { int i, error; u_int u, v, csize; struct sun_disklabel sl; MD5_CTX md5sum; error = sunlabel_dec(sec0, &sl); if (error) return (error); csize = sl.sl_ntracks * sl.sl_nsectors; for (i = 0; i < SUN_NPART; i++) { v = sl.sl_part[i].sdkp_cyloffset; u = sl.sl_part[i].sdkp_nsectors; error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, ((off_t)v * csize) << 9ULL, ((off_t)u) << 9ULL, ms->sectorsize, "%s%c", gp->name, 'a' + i); if (error) return (error); } for (i = 0; i < SUN_NPART; i++) { v = sl.sl_part[i].sdkp_cyloffset; u = sl.sl_part[i].sdkp_nsectors; g_slice_config(gp, i, G_SLICE_CONFIG_SET, ((off_t)v * csize) << 9ULL, ((off_t)u) << 9ULL, ms->sectorsize, "%s%c", gp->name, 'a' + i); } ms->nalt = sl.sl_acylinders; ms->nheads = sl.sl_ntracks; ms->nsects = sl.sl_nsectors; /* * Calculate MD5 from the first sector and use it for avoiding * recursive labels creation. */ MD5Init(&md5sum); MD5Update(&md5sum, sec0, ms->sectorsize); MD5Final(ms->labelsum, &md5sum); return (0); } static void g_sunlabel_hotwrite(void *arg, int flag) { struct bio *bp; struct g_geom *gp; struct g_slicer *gsp; struct g_slice *gsl; struct g_sunlabel_softc *ms; u_char *p; int error; KASSERT(flag != EV_CANCEL, ("g_sunlabel_hotwrite cancelled")); bp = arg; gp = bp->bio_to->geom; gsp = gp->softc; ms = gsp->softc; gsl = &gsp->slices[bp->bio_to->index]; /* * XXX: For all practical purposes, this whould be equvivalent to * XXX: "p = (u_char *)bp->bio_data;" because the label is always * XXX: in the first sector and we refuse sectors smaller than the * XXX: label. */ p = (u_char *)bp->bio_data - (bp->bio_offset + gsl->offset); error = g_sunlabel_modify(gp, ms, p); if (error) { g_io_deliver(bp, EPERM); return; } g_slice_finish_hot(bp); } static void g_sunlabel_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp) { struct g_slicer *gsp; struct g_sunlabel_softc *ms; gsp = gp->softc; ms = gsp->softc; g_slice_dumpconf(sb, indent, gp, cp, pp); if (indent == NULL) { sbuf_printf(sb, " sc %u hd %u alt %u", ms->nsects, ms->nheads, ms->nalt); } } struct g_hh01 { struct g_geom *gp; struct g_sunlabel_softc *ms; u_char *label; int error; }; static void g_sunlabel_callconfig(void *arg, int flag) { struct g_hh01 *hp; hp = arg; hp->error = g_sunlabel_modify(hp->gp, hp->ms, hp->label); if (!hp->error) hp->error = g_write_data(LIST_FIRST(&hp->gp->consumer), 0, hp->label, SUN_SIZE); } /* * NB! curthread is user process which GCTL'ed. */ static void g_sunlabel_config(struct gctl_req *req, struct g_class *mp, const char *verb) { u_char *label; int error, i; struct g_hh01 h0h0; struct g_slicer *gsp; struct g_geom *gp; struct g_consumer *cp; g_topology_assert(); gp = gctl_get_geom(req, mp, "geom"); if (gp == NULL) return; cp = LIST_FIRST(&gp->consumer); gsp = gp->softc; if (!strcmp(verb, "write label")) { label = gctl_get_paraml(req, "label", SUN_SIZE); if (label == NULL) return; h0h0.gp = gp; h0h0.ms = gsp->softc; h0h0.label = label; h0h0.error = -1; /* XXX: Does this reference register with our selfdestruct code ? */ error = g_access(cp, 1, 1, 1); if (error) { gctl_error(req, "could not access consumer"); return; } g_sunlabel_callconfig(&h0h0, 0); g_access(cp, -1, -1, -1); } else if (!strcmp(verb, "write bootcode")) { label = gctl_get_paraml(req, "bootcode", SUN_BOOTSIZE); if (label == NULL) return; /* XXX: Does this reference register with our selfdestruct code ? */ error = g_access(cp, 1, 1, 1); if (error) { gctl_error(req, "could not access consumer"); return; } for (i = 0; i < SUN_NPART; i++) { if (gsp->slices[i].length <= SUN_BOOTSIZE) continue; g_write_data(cp, gsp->slices[i].offset + SUN_SIZE, label + SUN_SIZE, SUN_BOOTSIZE - SUN_SIZE); } g_access(cp, -1, -1, -1); } else { gctl_error(req, "Unknown verb parameter"); } } static int g_sunlabel_start(struct bio *bp) { struct g_sunlabel_softc *mp; struct g_slicer *gsp; gsp = bp->bio_to->geom->softc; mp = gsp->softc; if (bp->bio_cmd == BIO_GETATTR) { if (g_handleattr(bp, "SUN::labelsum", mp->labelsum, sizeof(mp->labelsum))) return (1); } return (0); } static struct g_geom * g_sunlabel_taste(struct g_class *mp, struct g_provider *pp, int flags) { struct g_geom *gp; struct g_consumer *cp; struct g_sunlabel_softc *ms; struct g_slicer *gsp; u_char *buf, hash[16]; MD5_CTX md5sum; int error; g_trace(G_T_TOPOLOGY, "g_sunlabel_taste(%s,%s)", mp->name, pp->name); g_topology_assert(); if (flags == G_TF_NORMAL && !strcmp(pp->geom->class->name, SUNLABEL_CLASS_NAME)) return (NULL); gp = g_slice_new(mp, 8, pp, &cp, &ms, sizeof *ms, g_sunlabel_start); if (gp == NULL) return (NULL); gsp = gp->softc; do { ms->sectorsize = cp->provider->sectorsize; if (ms->sectorsize < 512) break; g_topology_unlock(); - buf = g_read_data(cp, 0, ms->sectorsize, &error); + buf = g_read_data(cp, 0, ms->sectorsize, NULL); g_topology_lock(); if (buf == NULL) break; /* * Calculate MD5 from the first sector and use it for avoiding * recursive labels creation. */ MD5Init(&md5sum); MD5Update(&md5sum, buf, ms->sectorsize); MD5Final(ms->labelsum, &md5sum); error = g_getattr("SUN::labelsum", cp, &hash); if (!error && !bcmp(ms->labelsum, hash, sizeof(hash))) { g_free(buf); break; } g_sunlabel_modify(gp, ms, buf); g_free(buf); break; } while (0); g_access(cp, -1, 0, 0); if (LIST_EMPTY(&gp->provider)) { g_slice_spoiled(cp); return (NULL); } g_slice_conf_hot(gp, 0, 0, SUN_SIZE, G_SLICE_HOT_ALLOW, G_SLICE_HOT_DENY, G_SLICE_HOT_CALL); gsp->hot = g_sunlabel_hotwrite; return (gp); } static struct g_class g_sunlabel_class = { .name = SUNLABEL_CLASS_NAME, .version = G_VERSION, .taste = g_sunlabel_taste, .ctlreq = g_sunlabel_config, .dumpconf = g_sunlabel_dumpconf, }; DECLARE_GEOM_CLASS(g_sunlabel_class, g_sunlabel); Index: head/sys/geom/geom_vol_ffs.c =================================================================== --- head/sys/geom/geom_vol_ffs.c (revision 152970) +++ head/sys/geom/geom_vol_ffs.c (revision 152971) @@ -1,154 +1,154 @@ /*- * Copyright (c) 2002, 2003 Gordon Tetlow * 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 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #define VOL_FFS_CLASS_NAME "VOL_FFS" static int superblocks[] = SBLOCKSEARCH; struct g_vol_ffs_softc { char * vol; }; static int g_vol_ffs_start(struct bio *bp __unused) { return(0); } static struct g_geom * g_vol_ffs_taste(struct g_class *mp, struct g_provider *pp, int flags) { struct g_geom *gp; struct g_consumer *cp; struct g_vol_ffs_softc *ms; - int error, sb, superblock; + int sb, superblock; struct fs *fs; g_trace(G_T_TOPOLOGY, "vol_taste(%s,%s)", mp->name, pp->name); g_topology_assert(); /* * XXX This is a really weak way to make sure we don't recurse. * Probably ought to use BIO_GETATTR to check for this. */ if (flags == G_TF_NORMAL && !strcmp(pp->geom->class->name, VOL_FFS_CLASS_NAME)) return (NULL); gp = g_slice_new(mp, 1, pp, &cp, &ms, sizeof(*ms), g_vol_ffs_start); if (gp == NULL) return (NULL); g_topology_unlock(); /* * Walk through the standard places that superblocks hide and look * for UFS magic. If we find magic, then check that the size in the * superblock corresponds to the size of the underlying provider. * Finally, look for a volume label and create an appropriate * provider based on that. */ for (sb=0; (superblock = superblocks[sb]) != -1; sb++) { /* * Take care not to issue an invalid I/O request. The * offset and size of the superblock candidate must be * multiples of the provider's sector size, otherwise an * FFS can't exist on the provider anyway. */ if (superblock % cp->provider->sectorsize != 0 || SBLOCKSIZE % cp->provider->sectorsize != 0) continue; fs = (struct fs *) g_read_data(cp, superblock, - SBLOCKSIZE, &error); + SBLOCKSIZE, NULL); if (fs == NULL) continue; /* Check for magic and make sure things are the right size */ if (fs->fs_magic == FS_UFS1_MAGIC) { if (fs->fs_old_size * fs->fs_fsize != (int32_t) pp->mediasize) { g_free(fs); continue; } } else if (fs->fs_magic == FS_UFS2_MAGIC) { if (fs->fs_size * fs->fs_fsize != (int64_t) pp->mediasize) { g_free(fs); continue; } } else { g_free(fs); continue; } /* Check for volume label */ if (fs->fs_volname[0] == '\0') { g_free(fs); continue; } /* XXX We need to check for namespace conflicts. */ /* XXX How do you handle a mirror set? */ /* XXX We don't validate the volume name. */ g_topology_lock(); /* Alright, we have a label and a volume name, reconfig. */ g_slice_config(gp, 0, G_SLICE_CONFIG_SET, (off_t) 0, pp->mediasize, pp->sectorsize, "vol/%s", fs->fs_volname); g_free(fs); g_topology_unlock(); break; } g_topology_lock(); g_access(cp, -1, 0, 0); if (LIST_EMPTY(&gp->provider)) { g_slice_spoiled(cp); return (NULL); } return (gp); } static struct g_class g_vol_ffs_class = { .name = VOL_FFS_CLASS_NAME, .version = G_VERSION, .taste = g_vol_ffs_taste, }; DECLARE_GEOM_CLASS(g_vol_ffs_class, g_vol_ffs); Index: head/sys/geom/label/g_label_iso9660.c =================================================================== --- head/sys/geom/label/g_label_iso9660.c (revision 152970) +++ head/sys/geom/label/g_label_iso9660.c (revision 152971) @@ -1,84 +1,84 @@ /*- * Copyright (c) 2004 Pawel Jakub Dawidek * 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 AUTHORS 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 AUTHORS 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #define G_LABEL_ISO9660_DIR "iso9660" #define ISO9660_MAGIC "\x01" "CD001" "\x01\x00" #define ISO9660_OFFSET 0x8000 #define VOLUME_LEN 32 static void g_label_iso9660_taste(struct g_consumer *cp, char *label, size_t size) { struct g_provider *pp; char *sector, *volume; - int i, error; + int i; g_topology_assert_not(); pp = cp->provider; label[0] = '\0'; if ((ISO9660_OFFSET % pp->sectorsize) != 0) return; sector = (char *)g_read_data(cp, ISO9660_OFFSET, pp->sectorsize, - &error); + NULL); if (sector == NULL) return; if (bcmp(sector, ISO9660_MAGIC, sizeof(ISO9660_MAGIC) - 1) != 0) { g_free(sector); return; } G_LABEL_DEBUG(1, "ISO9660 file system detected on %s.", pp->name); volume = sector + 0x28; bzero(label, size); strlcpy(label, volume, MIN(size, VOLUME_LEN)); g_free(sector); for (i = size - 1; i > 0; i--) { if (label[i] == '\0') continue; else if (label[i] == ' ') label[i] = '\0'; else break; } } const struct g_label_desc g_label_iso9660 = { .ld_taste = g_label_iso9660_taste, .ld_dir = G_LABEL_ISO9660_DIR }; Index: head/sys/geom/label/g_label_msdosfs.c =================================================================== --- head/sys/geom/label/g_label_msdosfs.c (revision 152970) +++ head/sys/geom/label/g_label_msdosfs.c (revision 152971) @@ -1,101 +1,101 @@ /*- * Copyright (c) 2004 Pawel Jakub Dawidek * 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 AUTHORS 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 AUTHORS 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #define G_LABEL_MSDOSFS_DIR "msdosfs" #define FAT12 "FAT12 " #define FAT16 "FAT16 " #define FAT32 "FAT32 " #define VOLUME_LEN 11 #define NO_NAME "NO NAME " static void g_label_msdosfs_taste(struct g_consumer *cp, char *label, size_t size) { struct g_provider *pp; char *sector, *volume; - int i, error; + int i; g_topology_assert_not(); pp = cp->provider; label[0] = '\0'; - sector = (char *)g_read_data(cp, 0, pp->sectorsize, &error); + sector = (char *)g_read_data(cp, 0, pp->sectorsize, NULL); if (sector == NULL) return; if (strncmp(sector + 0x36, FAT12, strlen(FAT12)) == 0) { G_LABEL_DEBUG(1, "MSDOS (FAT12) file system detected on %s.", pp->name); volume = sector + 0x2b; } else if (strncmp(sector + 0x36, FAT16, strlen(FAT16)) == 0) { G_LABEL_DEBUG(1, "MSDOS (FAT16) file system detected on %s.", pp->name); volume = sector + 0x2b; } else if (strncmp(sector + 0x52, FAT32, strlen(FAT32)) == 0) { G_LABEL_DEBUG(1, "MSDOS (FAT32) file system detected on %s.", pp->name); volume = sector + 0x47; } else { g_free(sector); return; } if (strncmp(volume, NO_NAME, VOLUME_LEN) == 0) { g_free(sector); return; } if (volume[0] == '\0') { g_free(sector); return; } bzero(label, size); strlcpy(label, volume, MIN(size, VOLUME_LEN)); g_free(sector); for (i = size - 1; i > 0; i--) { if (label[i] == '\0') continue; else if (label[i] == ' ') label[i] = '\0'; else break; } } const struct g_label_desc g_label_msdosfs = { .ld_taste = g_label_msdosfs_taste, .ld_dir = G_LABEL_MSDOSFS_DIR }; Index: head/sys/geom/label/g_label_ufs.c =================================================================== --- head/sys/geom/label/g_label_ufs.c (revision 152970) +++ head/sys/geom/label/g_label_ufs.c (revision 152971) @@ -1,112 +1,112 @@ /*- * Copyright (c) 2002, 2003 Gordon Tetlow * 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 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #define G_LABEL_UFS_DIR "ufs" static const int superblocks[] = SBLOCKSEARCH; static void g_label_ufs_taste(struct g_consumer *cp, char *label, size_t size) { struct g_provider *pp; - int error, sb, superblock; + int sb, superblock; struct fs *fs; g_topology_assert_not(); pp = cp->provider; label[0] = '\0'; /* * Walk through the standard places that superblocks hide and look * for UFS magic. If we find magic, then check that the size in the * superblock corresponds to the size of the underlying provider. * Finally, look for a volume label and create an appropriate * provider based on that. */ for (sb = 0; (superblock = superblocks[sb]) != -1; sb++) { /* * Take care not to issue an invalid I/O request. The * offset and size of the superblock candidate must be * multiples of the provider's sector size, otherwise an * FFS can't exist on the provider anyway. */ if (superblock % cp->provider->sectorsize != 0 || SBLOCKSIZE % cp->provider->sectorsize != 0) continue; fs = (struct fs *)g_read_data(cp, superblock, SBLOCKSIZE, - &error); + NULL); if (fs == NULL) continue; /* Check for magic and make sure things are the right size */ if (fs->fs_magic == FS_UFS1_MAGIC) { G_LABEL_DEBUG(1, "UFS1 file system detected on %s.", pp->name); if (fs->fs_old_size * fs->fs_fsize != (int32_t)pp->mediasize) { g_free(fs); continue; } } else if (fs->fs_magic == FS_UFS2_MAGIC) { G_LABEL_DEBUG(1, "UFS2 file system detected on %s.", pp->name); if (fs->fs_fsize <= 0 || pp->mediasize / fs->fs_fsize != fs->fs_size) { g_free(fs); continue; } } else { g_free(fs); continue; } /* Check for volume label */ if (fs->fs_volname[0] == '\0') { g_free(fs); continue; } strlcpy(label, fs->fs_volname, size); g_free(fs); break; } } const struct g_label_desc g_label_ufs = { .ld_taste = g_label_ufs_taste, .ld_dir = G_LABEL_UFS_DIR }; Index: head/sys/geom/uzip/g_uzip.c =================================================================== --- head/sys/geom/uzip/g_uzip.c (revision 152970) +++ head/sys/geom/uzip/g_uzip.c (revision 152971) @@ -1,525 +1,525 @@ /*- * Copyright (c) 2004 Max Khon * 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 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #undef GEOM_UZIP_DEBUG #ifdef GEOM_UZIP_DEBUG #define DPRINTF(a) printf a #else #define DPRINTF(a) #endif MALLOC_DEFINE(M_GEOM_UZIP, "geom_uzip", "GEOM UZIP data structures"); #define UZIP_CLASS_NAME "UZIP" /* * Maximum allowed valid block size (to prevent foot-shooting) */ #define MAX_BLKSZ (MAXPHYS - MAXPHYS / 1000 - 12) /* * Integer values (block size, number of blocks, offsets) * are stored in big-endian (network) order on disk and struct cloop_header * and in native order in struct g_uzip_softc */ #define CLOOP_MAGIC_LEN 128 static char CLOOP_MAGIC_START[] = "#!/bin/sh\n"; struct cloop_header { char magic[CLOOP_MAGIC_LEN]; /* cloop magic */ uint32_t blksz; /* block size */ uint32_t nblocks; /* number of blocks */ }; struct g_uzip_softc { uint32_t blksz; /* block size */ uint32_t nblocks; /* number of blocks */ uint64_t *offsets; struct mtx last_mtx; uint32_t last_blk; /* last blk no */ char *last_buf; /* last blk data */ int req_total; /* total requests */ int req_cached; /* cached requests */ }; static void g_uzip_softc_free(struct g_uzip_softc *sc, struct g_geom *gp) { if (gp != NULL) { printf("%s: %d requests, %d cached\n", gp->name, sc->req_total, sc->req_cached); } if (sc->offsets != NULL) free(sc->offsets, M_GEOM_UZIP); mtx_destroy(&sc->last_mtx); free(sc->last_buf, M_GEOM_UZIP); free(sc, M_GEOM_UZIP); } static void * z_alloc(void *nil, u_int type, u_int size) { void *ptr; ptr = malloc(type * size, M_GEOM_UZIP, M_NOWAIT); return ptr; } static void z_free(void *nil, void *ptr) { free(ptr, M_GEOM_UZIP); } static void g_uzip_done(struct bio *bp) { int err; struct bio *bp2; z_stream zs; struct g_provider *pp, *pp2; struct g_consumer *cp; struct g_geom *gp; struct g_uzip_softc *sc; off_t pos, upos; uint32_t start_blk, i; size_t bsize; bp2 = bp->bio_parent; pp = bp2->bio_to; gp = pp->geom; cp = LIST_FIRST(&gp->consumer); pp2 = cp->provider; sc = gp->softc; DPRINTF(("%s: done\n", gp->name)); bp2->bio_error = bp->bio_error; if (bp2->bio_error != 0) goto done; /* * Uncompress data. */ zs.zalloc = z_alloc; zs.zfree = z_free; err = inflateInit(&zs); if (err != Z_OK) { bp2->bio_error = EIO; goto done; } start_blk = bp2->bio_offset / sc->blksz; bsize = pp2->sectorsize; pos = sc->offsets[start_blk] % bsize; upos = 0; DPRINTF(("%s: done: start_blk %d, pos %lld, upos %lld (%lld, %d, %d)\n", gp->name, start_blk, pos, upos, bp2->bio_offset, sc->blksz, bsize)); for (i = start_blk; upos < bp2->bio_length; i++) { off_t len, ulen, uoff; uoff = i == start_blk ? bp2->bio_offset % sc->blksz : 0; ulen = MIN(sc->blksz - uoff, bp2->bio_length - upos); len = sc->offsets[i + 1] - sc->offsets[i]; zs.next_in = bp->bio_data + pos; zs.avail_in = len; zs.next_out = sc->last_buf; zs.avail_out = sc->blksz; mtx_lock(&sc->last_mtx); err = inflate(&zs, Z_FINISH); if (err != Z_STREAM_END) { sc->last_blk = -1; mtx_unlock(&sc->last_mtx); DPRINTF(("%s: done: inflate failed (%lld + %lld -> %lld + %lld + %lld)\n", gp->name, pos, len, uoff, upos, ulen)); inflateEnd(&zs); bp2->bio_error = EIO; goto done; } sc->last_blk = i; DPRINTF(("%s: done: inflated %lld + %lld -> %lld + %lld + %lld\n", gp->name, pos, len, uoff, upos, ulen)); memcpy(bp2->bio_data + upos, sc->last_buf + uoff, ulen); mtx_unlock(&sc->last_mtx); pos += len; upos += ulen; bp2->bio_completed += ulen; err = inflateReset(&zs); if (err != Z_OK) { inflateEnd(&zs); bp2->bio_error = EIO; goto done; } } err = inflateEnd(&zs); if (err != Z_OK) { bp2->bio_error = EIO; goto done; } done: /* * Finish processing the request. */ DPRINTF(("%s: done: (%d, %lld, %ld)\n", gp->name, bp2->bio_error, bp2->bio_completed, bp2->bio_resid)); free(bp->bio_data, M_GEOM_UZIP); g_destroy_bio(bp); g_io_deliver(bp2, bp2->bio_error); } static void g_uzip_start(struct bio *bp) { struct bio *bp2; struct g_provider *pp, *pp2; struct g_geom *gp; struct g_consumer *cp; struct g_uzip_softc *sc; uint32_t start_blk, end_blk; size_t bsize; pp = bp->bio_to; gp = pp->geom; DPRINTF(("%s: start (%d)\n", gp->name, bp->bio_cmd)); if (bp->bio_cmd != BIO_READ) { g_io_deliver(bp, EOPNOTSUPP); return; } cp = LIST_FIRST(&gp->consumer); pp2 = cp->provider; sc = gp->softc; start_blk = bp->bio_offset / sc->blksz; end_blk = (bp->bio_offset + bp->bio_length + sc->blksz - 1) / sc->blksz; KASSERT(start_blk < sc->nblocks, ("start_blk out of range")); KASSERT(end_blk <= sc->nblocks, ("end_blk out of range")); sc->req_total++; if (start_blk + 1 == end_blk) { mtx_lock(&sc->last_mtx); if (start_blk == sc->last_blk) { off_t uoff; uoff = bp->bio_offset % sc->blksz; KASSERT(bp->bio_length <= sc->blksz - uoff, ("cached data error")); memcpy(bp->bio_data, sc->last_buf + uoff, bp->bio_length); sc->req_cached++; mtx_unlock(&sc->last_mtx); DPRINTF(("%s: start: cached 0 + %lld, %lld + 0 + %lld\n", gp->name, bp->bio_length, uoff, bp->bio_length)); bp->bio_completed = bp->bio_length; g_io_deliver(bp, 0); return; } mtx_unlock(&sc->last_mtx); } bp2 = g_clone_bio(bp); if (bp2 == NULL) { g_io_deliver(bp, ENOMEM); return; } bp2->bio_done = g_uzip_done; DPRINTF(("%s: start (%d..%d), %s: %d + %lld, %s: %d + %lld\n", gp->name, start_blk, end_blk, pp->name, pp->sectorsize, pp->mediasize, pp2->name, pp2->sectorsize, pp2->mediasize)); bsize = pp2->sectorsize; bp2->bio_offset = sc->offsets[start_blk] - sc->offsets[start_blk] % bsize; bp2->bio_length = sc->offsets[end_blk] - bp2->bio_offset; bp2->bio_length = (bp2->bio_length + bsize - 1) / bsize * bsize; DPRINTF(("%s: start %lld + %lld -> %lld + %lld -> %lld + %lld\n", gp->name, bp->bio_offset, bp->bio_length, sc->offsets[start_blk], sc->offsets[end_blk] - sc->offsets[start_blk], bp2->bio_offset, bp2->bio_length)); bp2->bio_data = malloc(bp2->bio_length, M_GEOM_UZIP, M_NOWAIT); if (bp2->bio_data == NULL) { g_io_deliver(bp, ENOMEM); return; } g_io_request(bp2, cp); DPRINTF(("%s: start ok\n", gp->name)); } static void g_uzip_orphan(struct g_consumer *cp) { struct g_geom *gp; g_trace(G_T_TOPOLOGY, "g_uzip_orphan(%p/%s)", cp, cp->provider->name); g_topology_assert(); KASSERT(cp->provider->error != 0, ("g_uzip_orphan with error == 0")); gp = cp->geom; g_uzip_softc_free(gp->softc, gp); gp->softc = NULL; g_wither_geom(gp, cp->provider->error); } static int g_uzip_access(struct g_provider *pp, int dr, int dw, int de) { struct g_geom *gp; struct g_consumer *cp; gp = pp->geom; cp = LIST_FIRST(&gp->consumer); KASSERT (cp != NULL, ("g_uzip_access but no consumer")); if (cp->acw + dw > 0) return EROFS; return (g_access(cp, dr, dw, de)); } static void g_uzip_spoiled(struct g_consumer *cp) { struct g_geom *gp; gp = cp->geom; g_trace(G_T_TOPOLOGY, "g_uzip_spoiled(%p/%s)", cp, gp->name); g_topology_assert(); g_uzip_softc_free(gp->softc, gp); gp->softc = NULL; g_wither_geom(gp, ENXIO); } static struct g_geom * g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags) { int error; uint32_t i, total_offsets, offsets_read, blk; void *buf; struct cloop_header *header; struct g_consumer *cp; struct g_geom *gp; struct g_provider *pp2; struct g_uzip_softc *sc; g_trace(G_T_TOPOLOGY, "g_uzip_taste(%s,%s)", mp->name, pp->name); g_topology_assert(); buf = NULL; /* * Create geom instance. */ gp = g_new_geomf(mp, "%s.uzip", pp->name); cp = g_new_consumer(gp); error = g_attach(cp, pp); if (error == 0) error = g_access(cp, 1, 0, 0); if (error) { g_detach(cp); g_destroy_consumer(cp); g_destroy_geom(gp); return (NULL); } g_topology_unlock(); /* * Read cloop header, look for CLOOP magic, perform * other validity checks. */ DPRINTF(("%s: media sectorsize %u, mediasize %lld\n", gp->name, pp->sectorsize, pp->mediasize)); - buf = g_read_data(cp, 0, pp->sectorsize, &error); + buf = g_read_data(cp, 0, pp->sectorsize, NULL); if (buf == NULL) goto err; header = (struct cloop_header *) buf; if (strncmp(header->magic, CLOOP_MAGIC_START, sizeof(CLOOP_MAGIC_START) - 1) != 0) { DPRINTF(("%s: no CLOOP magic\n", gp->name)); goto err; } if (header->magic[0x0b] != 'V' || header->magic[0x0c] < '2') { DPRINTF(("%s: image version too old\n", gp->name)); goto err; } /* * Initialize softc and read offsets. */ sc = malloc(sizeof(*sc), M_GEOM_UZIP, M_WAITOK | M_ZERO); gp->softc = sc; sc->blksz = ntohl(header->blksz); sc->nblocks = ntohl(header->nblocks); if (sc->blksz % 512 != 0) { printf("%s: block size (%u) should be multiple of 512.\n", gp->name, sc->blksz); goto err; } if (sc->blksz > MAX_BLKSZ) { printf("%s: block size (%u) should not be larger than %d.\n", gp->name, sc->blksz, MAX_BLKSZ); } total_offsets = sc->nblocks + 1; if (sizeof(struct cloop_header) + total_offsets * sizeof(uint64_t) > pp->mediasize) { printf("%s: media too small for %u blocks\n", gp->name, sc->nblocks); goto err; } sc->offsets = malloc( total_offsets * sizeof(uint64_t), M_GEOM_UZIP, M_WAITOK); offsets_read = MIN(total_offsets, (pp->sectorsize - sizeof(*header)) / sizeof(uint64_t)); for (i = 0; i < offsets_read; i++) sc->offsets[i] = be64toh(((uint64_t *) (header + 1))[i]); DPRINTF(("%s: %u offsets in the first sector\n", gp->name, offsets_read)); for (blk = 1; offsets_read < total_offsets; blk++) { uint32_t nread; free(buf, M_GEOM); buf = g_read_data( - cp, blk * pp->sectorsize, pp->sectorsize, &error); + cp, blk * pp->sectorsize, pp->sectorsize, NULL); if (buf == NULL) goto err; nread = MIN(total_offsets - offsets_read, pp->sectorsize / sizeof(uint64_t)); DPRINTF(("%s: %u offsets read from sector %d\n", gp->name, nread, blk)); for (i = 0; i < nread; i++) { sc->offsets[offsets_read + i] = be64toh(((uint64_t *) buf)[i]); } offsets_read += nread; } DPRINTF(("%s: done reading offsets\n", gp->name)); mtx_init(&sc->last_mtx, "geom_uzip cache", NULL, MTX_DEF); sc->last_blk = -1; sc->last_buf = malloc(sc->blksz, M_GEOM_UZIP, M_WAITOK); sc->req_total = 0; sc->req_cached = 0; g_topology_lock(); pp2 = g_new_providerf(gp, "%s", gp->name); pp2->sectorsize = 512; pp2->mediasize = sc->nblocks * sc->blksz; pp2->flags = pp->flags & G_PF_CANDELETE; if (pp->stripesize > 0) { pp2->stripesize = pp->stripesize; pp2->stripeoffset = pp->stripeoffset; } g_error_provider(pp2, 0); g_access(cp, -1, 0, 0); DPRINTF(("%s: taste ok (%d, %lld), (%d, %d), %x\n", gp->name, pp2->sectorsize, pp2->mediasize, pp2->stripeoffset, pp2->stripesize, pp2->flags)); printf("%s: %u x %u blocks\n", gp->name, sc->nblocks, sc->blksz); return (gp); err: g_topology_lock(); g_access(cp, -1, 0, 0); if (buf != NULL) free(buf, M_GEOM); if (gp->softc != NULL) { g_uzip_softc_free(gp->softc, NULL); gp->softc = NULL; } g_detach(cp); g_destroy_consumer(cp); g_destroy_geom(gp); return (NULL); } static int g_uzip_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) { struct g_provider *pp; g_trace(G_T_TOPOLOGY, "g_uzip_destroy_geom(%s, %s)", mp->name, gp->name); g_topology_assert(); if (gp->softc == NULL) { printf("%s(%s): gp->softc == NULL\n", __func__, gp->name); return (ENXIO); } KASSERT(gp != NULL, ("NULL geom")); pp = LIST_FIRST(&gp->provider); KASSERT(pp != NULL, ("NULL provider")); if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) return (EBUSY); g_uzip_softc_free(gp->softc, gp); gp->softc = NULL; g_wither_geom(gp, ENXIO); return (0); } static struct g_class g_uzip_class = { .name = UZIP_CLASS_NAME, .version = G_VERSION, .taste = g_uzip_taste, .destroy_geom = g_uzip_destroy_geom, .start = g_uzip_start, .orphan = g_uzip_orphan, .access = g_uzip_access, .spoiled = g_uzip_spoiled, }; DECLARE_GEOM_CLASS(g_uzip_class, geom_uzip); MODULE_DEPEND(geom_uzip, zlib, 1, 1, 1); Index: head/sys/geom/vinum/geom_vinum_drive.c =================================================================== --- head/sys/geom/vinum/geom_vinum_drive.c (revision 152970) +++ head/sys/geom/vinum/geom_vinum_drive.c (revision 152971) @@ -1,674 +1,674 @@ /*- * Copyright (c) 2004, 2005 Lukas Ertl * 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 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void gv_drive_dead(void *, int); static void gv_drive_worker(void *); void gv_config_new_drive(struct gv_drive *d) { struct gv_hdr *vhdr; struct gv_freelist *fl; KASSERT(d != NULL, ("config_new_drive: NULL d")); vhdr = g_malloc(sizeof(*vhdr), M_WAITOK | M_ZERO); vhdr->magic = GV_MAGIC; vhdr->config_length = GV_CFG_LEN; bcopy(hostname, vhdr->label.sysname, GV_HOSTNAME_LEN); strncpy(vhdr->label.name, d->name, GV_MAXDRIVENAME); microtime(&vhdr->label.date_of_birth); d->hdr = vhdr; LIST_INIT(&d->subdisks); LIST_INIT(&d->freelist); fl = g_malloc(sizeof(struct gv_freelist), M_WAITOK | M_ZERO); fl->offset = GV_DATA_START; fl->size = d->avail; LIST_INSERT_HEAD(&d->freelist, fl, freelist); d->freelist_entries = 1; TAILQ_INIT(&d->bqueue); mtx_init(&d->bqueue_mtx, "gv_drive", NULL, MTX_DEF); kthread_create(gv_drive_worker, d, NULL, 0, 0, "gv_d %s", d->name); d->flags |= GV_DRIVE_THREAD_ACTIVE; } void gv_save_config_all(struct gv_softc *sc) { struct gv_drive *d; g_topology_assert(); LIST_FOREACH(d, &sc->drives, drive) { if (d->geom == NULL) continue; gv_save_config(NULL, d, sc); } } /* Save the vinum configuration back to disk. */ void gv_save_config(struct g_consumer *cp, struct gv_drive *d, struct gv_softc *sc) { struct g_geom *gp; struct g_consumer *cp2; struct gv_hdr *vhdr, *hdr; struct sbuf *sb; int error; g_topology_assert(); KASSERT(d != NULL, ("gv_save_config: null d")); KASSERT(sc != NULL, ("gv_save_config: null sc")); /* * We can't save the config on a drive that isn't up, but drives that * were just created aren't officially up yet, so we check a special * flag. */ if ((d->state != GV_DRIVE_UP) && !(d->flags && GV_DRIVE_NEWBORN)) return; if (cp == NULL) { gp = d->geom; KASSERT(gp != NULL, ("gv_save_config: null gp")); cp2 = LIST_FIRST(&gp->consumer); KASSERT(cp2 != NULL, ("gv_save_config: null cp2")); } else cp2 = cp; vhdr = g_malloc(GV_HDR_LEN, M_WAITOK | M_ZERO); vhdr->magic = GV_MAGIC; vhdr->config_length = GV_CFG_LEN; hdr = d->hdr; if (hdr == NULL) { printf("GEOM_VINUM: drive %s has NULL hdr\n", d->name); g_free(vhdr); return; } microtime(&hdr->label.last_update); bcopy(&hdr->label, &vhdr->label, sizeof(struct gv_label)); sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN); gv_format_config(sc, sb, 1, NULL); sbuf_finish(sb); error = g_access(cp2, 0, 1, 0); if (error) { printf("GEOM_VINUM: g_access failed on drive %s, errno %d\n", d->name, error); sbuf_delete(sb); g_free(vhdr); return; } g_topology_unlock(); do { error = g_write_data(cp2, GV_HDR_OFFSET, vhdr, GV_HDR_LEN); if (error) { printf("GEOM_VINUM: writing vhdr failed on drive %s, " "errno %d", d->name, error); break; } error = g_write_data(cp2, GV_CFG_OFFSET, sbuf_data(sb), GV_CFG_LEN); if (error) { printf("GEOM_VINUM: writing first config copy failed " "on drive %s, errno %d", d->name, error); break; } error = g_write_data(cp2, GV_CFG_OFFSET + GV_CFG_LEN, sbuf_data(sb), GV_CFG_LEN); if (error) printf("GEOM_VINUM: writing second config copy failed " "on drive %s, errno %d", d->name, error); } while (0); g_topology_lock(); g_access(cp2, 0, -1, 0); sbuf_delete(sb); g_free(vhdr); if (d->geom != NULL) gv_drive_modify(d); } /* This resembles g_slice_access(). */ static int gv_drive_access(struct g_provider *pp, int dr, int dw, int de) { struct g_geom *gp; struct g_consumer *cp; struct g_provider *pp2; struct gv_drive *d; struct gv_sd *s, *s2; int error; gp = pp->geom; cp = LIST_FIRST(&gp->consumer); if (cp == NULL) return (0); d = gp->softc; if (d == NULL) return (0); s = pp->private; KASSERT(s != NULL, ("gv_drive_access: NULL s")); LIST_FOREACH(s2, &d->subdisks, from_drive) { if (s == s2) continue; if (s->drive_offset + s->size <= s2->drive_offset) continue; if (s2->drive_offset + s2->size <= s->drive_offset) continue; /* Overlap. */ pp2 = s2->provider; KASSERT(s2 != NULL, ("gv_drive_access: NULL s2")); if ((pp->acw + dw) > 0 && pp2->ace > 0) return (EPERM); if ((pp->ace + de) > 0 && pp2->acw > 0) return (EPERM); } error = g_access(cp, dr, dw, de); return (error); } static void gv_drive_done(struct bio *bp) { struct gv_drive *d; struct gv_bioq *bq; /* Put the BIO on the worker queue again. */ d = bp->bio_from->geom->softc; bp->bio_cflags |= GV_BIO_DONE; bq = g_malloc(sizeof(*bq), M_NOWAIT | M_ZERO); bq->bp = bp; mtx_lock(&d->bqueue_mtx); TAILQ_INSERT_TAIL(&d->bqueue, bq, queue); wakeup(d); mtx_unlock(&d->bqueue_mtx); } static void gv_drive_start(struct bio *bp) { struct gv_drive *d; struct gv_sd *s; struct gv_bioq *bq; switch (bp->bio_cmd) { case BIO_READ: case BIO_WRITE: case BIO_DELETE: break; case BIO_GETATTR: default: g_io_deliver(bp, EOPNOTSUPP); return; } s = bp->bio_to->private; if ((s->state == GV_SD_DOWN) || (s->state == GV_SD_STALE)) { g_io_deliver(bp, ENXIO); return; } d = bp->bio_to->geom->softc; /* * Put the BIO on the worker queue, where the worker thread will pick * it up. */ bq = g_malloc(sizeof(*bq), M_NOWAIT | M_ZERO); bq->bp = bp; mtx_lock(&d->bqueue_mtx); TAILQ_INSERT_TAIL(&d->bqueue, bq, queue); wakeup(d); mtx_unlock(&d->bqueue_mtx); } static void gv_drive_worker(void *arg) { struct bio *bp, *cbp; struct g_geom *gp; struct g_provider *pp; struct gv_drive *d; struct gv_sd *s; struct gv_bioq *bq, *bq2; int error; d = arg; mtx_lock(&d->bqueue_mtx); for (;;) { /* We were signaled to exit. */ if (d->flags & GV_DRIVE_THREAD_DIE) break; /* Take the first BIO from out queue. */ bq = TAILQ_FIRST(&d->bqueue); if (bq == NULL) { msleep(d, &d->bqueue_mtx, PRIBIO, "-", hz/10); continue; } TAILQ_REMOVE(&d->bqueue, bq, queue); mtx_unlock(&d->bqueue_mtx); bp = bq->bp; g_free(bq); pp = bp->bio_to; gp = pp->geom; /* Completed request. */ if (bp->bio_cflags & GV_BIO_DONE) { error = bp->bio_error; /* Deliver the original request. */ g_std_done(bp); /* The request had an error, we need to clean up. */ if (error != 0) { g_topology_lock(); gv_set_drive_state(d, GV_DRIVE_DOWN, GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG); g_topology_unlock(); g_post_event(gv_drive_dead, d, M_WAITOK, d, NULL); } /* New request, needs to be sent downwards. */ } else { s = pp->private; if ((s->state == GV_SD_DOWN) || (s->state == GV_SD_STALE)) { g_io_deliver(bp, ENXIO); mtx_lock(&d->bqueue_mtx); continue; } if (bp->bio_offset > s->size) { g_io_deliver(bp, EINVAL); mtx_lock(&d->bqueue_mtx); continue; } cbp = g_clone_bio(bp); if (cbp == NULL) { g_io_deliver(bp, ENOMEM); mtx_lock(&d->bqueue_mtx); continue; } if (cbp->bio_offset + cbp->bio_length > s->size) cbp->bio_length = s->size - cbp->bio_offset; cbp->bio_done = gv_drive_done; cbp->bio_offset += s->drive_offset; g_io_request(cbp, LIST_FIRST(&gp->consumer)); } mtx_lock(&d->bqueue_mtx); } TAILQ_FOREACH_SAFE(bq, &d->bqueue, queue, bq2) { TAILQ_REMOVE(&d->bqueue, bq, queue); mtx_unlock(&d->bqueue_mtx); bp = bq->bp; g_free(bq); if (bp->bio_cflags & GV_BIO_DONE) g_std_done(bp); else g_io_deliver(bp, ENXIO); mtx_lock(&d->bqueue_mtx); } mtx_unlock(&d->bqueue_mtx); d->flags |= GV_DRIVE_THREAD_DEAD; kthread_exit(ENXIO); } static void gv_drive_orphan(struct g_consumer *cp) { struct g_geom *gp; struct gv_drive *d; g_topology_assert(); gp = cp->geom; g_trace(G_T_TOPOLOGY, "gv_drive_orphan(%s)", gp->name); d = gp->softc; if (d != NULL) { gv_set_drive_state(d, GV_DRIVE_DOWN, GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG); g_post_event(gv_drive_dead, d, M_WAITOK, d, NULL); } else g_wither_geom(gp, ENXIO); } static struct g_geom * gv_drive_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) { struct g_geom *gp, *gp2; struct g_consumer *cp; struct gv_drive *d; struct gv_sd *s; struct gv_softc *sc; struct gv_freelist *fl; struct gv_hdr *vhdr; int error; char *buf, errstr[ERRBUFSIZ]; vhdr = NULL; d = NULL; g_trace(G_T_TOPOLOGY, "gv_drive_taste(%s, %s)", mp->name, pp->name); g_topology_assert(); /* Find the VINUM class and its associated geom. */ gp2 = find_vinum_geom(); if (gp2 == NULL) return (NULL); sc = gp2->softc; gp = g_new_geomf(mp, "%s.vinumdrive", pp->name); gp->start = gv_drive_start; gp->orphan = gv_drive_orphan; gp->access = gv_drive_access; gp->start = gv_drive_start; cp = g_new_consumer(gp); g_attach(cp, pp); error = g_access(cp, 1, 0, 0); if (error) { g_detach(cp); g_destroy_consumer(cp); g_destroy_geom(gp); return (NULL); } g_topology_unlock(); /* Now check if the provided slice is a valid vinum drive. */ do { - vhdr = g_read_data(cp, GV_HDR_OFFSET, pp->sectorsize, &error); + vhdr = g_read_data(cp, GV_HDR_OFFSET, pp->sectorsize, NULL); if (vhdr == NULL) break; if (vhdr->magic != GV_MAGIC) { g_free(vhdr); break; } /* A valid vinum drive, let's parse the on-disk information. */ - buf = g_read_data(cp, GV_CFG_OFFSET, GV_CFG_LEN, &error); - if (buf == NULL || error != 0) { + buf = g_read_data(cp, GV_CFG_OFFSET, GV_CFG_LEN, NULL); + if (buf == NULL) { g_free(vhdr); break; } g_topology_lock(); gv_parse_config(sc, buf, 1); g_free(buf); /* * Let's see if this drive is already known in the * configuration. */ d = gv_find_drive(sc, vhdr->label.name); /* We already know about this drive. */ if (d != NULL) { /* Check if this drive already has a geom. */ if (d->geom != NULL) { g_topology_unlock(); break; } bcopy(vhdr, d->hdr, sizeof(*vhdr)); /* This is a new drive. */ } else { d = g_malloc(sizeof(*d), M_WAITOK | M_ZERO); /* Initialize all needed variables. */ d->size = pp->mediasize - GV_DATA_START; d->avail = d->size; d->hdr = vhdr; strncpy(d->name, vhdr->label.name, GV_MAXDRIVENAME); LIST_INIT(&d->subdisks); LIST_INIT(&d->freelist); /* We also need a freelist entry. */ fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO); fl->offset = GV_DATA_START; fl->size = d->avail; LIST_INSERT_HEAD(&d->freelist, fl, freelist); d->freelist_entries = 1; TAILQ_INIT(&d->bqueue); /* Save it into the main configuration. */ LIST_INSERT_HEAD(&sc->drives, d, drive); } /* * Create a bio queue mutex and a worker thread, if necessary. */ if (mtx_initialized(&d->bqueue_mtx) == 0) mtx_init(&d->bqueue_mtx, "gv_drive", NULL, MTX_DEF); if (!(d->flags & GV_DRIVE_THREAD_ACTIVE)) { kthread_create(gv_drive_worker, d, NULL, 0, 0, "gv_d %s", d->name); d->flags |= GV_DRIVE_THREAD_ACTIVE; } g_access(cp, -1, 0, 0); gp->softc = d; d->geom = gp; d->vinumconf = sc; strncpy(d->device, pp->name, GV_MAXDRIVENAME); /* * Find out which subdisks belong to this drive and crosslink * them. */ LIST_FOREACH(s, &sc->subdisks, sd) { if (!strncmp(s->drive, d->name, GV_MAXDRIVENAME)) /* XXX: errors ignored */ gv_sd_to_drive(sc, d, s, errstr, sizeof(errstr)); } /* This drive is now up for sure. */ gv_set_drive_state(d, GV_DRIVE_UP, 0); /* * If there are subdisks on this drive, we need to create * providers for them. */ if (d->sdcount) gv_drive_modify(d); return (gp); } while (0); g_topology_lock(); g_access(cp, -1, 0, 0); g_detach(cp); g_destroy_consumer(cp); g_destroy_geom(gp); return (NULL); } /* * Modify the providers for the given drive 'd'. It is assumed that the * subdisk list of 'd' is already correctly set up. */ void gv_drive_modify(struct gv_drive *d) { struct g_geom *gp; struct g_consumer *cp; struct g_provider *pp, *pp2; struct gv_sd *s; KASSERT(d != NULL, ("gv_drive_modify: null d")); gp = d->geom; KASSERT(gp != NULL, ("gv_drive_modify: null gp")); cp = LIST_FIRST(&gp->consumer); KASSERT(cp != NULL, ("gv_drive_modify: null cp")); pp = cp->provider; KASSERT(pp != NULL, ("gv_drive_modify: null pp")); g_topology_assert(); LIST_FOREACH(s, &d->subdisks, from_drive) { /* This subdisk already has a provider. */ if (s->provider != NULL) continue; pp2 = g_new_providerf(gp, "gvinum/sd/%s", s->name); pp2->mediasize = s->size; pp2->sectorsize = pp->sectorsize; g_error_provider(pp2, 0); s->provider = pp2; pp2->private = s; } } static void gv_drive_dead(void *arg, int flag) { struct g_geom *gp; struct g_consumer *cp; struct gv_drive *d; struct gv_sd *s; g_topology_assert(); KASSERT(arg != NULL, ("gv_drive_dead: NULL arg")); if (flag == EV_CANCEL) return; d = arg; if (d->state != GV_DRIVE_DOWN) return; g_trace(G_T_TOPOLOGY, "gv_drive_dead(%s)", d->name); gp = d->geom; if (gp == NULL) return; LIST_FOREACH(cp, &gp->consumer, consumer) { if (cp->nstart != cp->nend) { printf("GEOM_VINUM: dead drive '%s' has still " "active requests, can't detach consumer\n", d->name); g_post_event(gv_drive_dead, d, M_WAITOK, d, NULL); return; } if (cp->acr != 0 || cp->acw != 0 || cp->ace != 0) g_access(cp, -cp->acr, -cp->acw, -cp->ace); } printf("GEOM_VINUM: lost drive '%s'\n", d->name); d->geom = NULL; LIST_FOREACH(s, &d->subdisks, from_drive) { s->provider = NULL; s->consumer = NULL; } gv_kill_drive_thread(d); gp->softc = NULL; g_wither_geom(gp, ENXIO); } static int gv_drive_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) { struct gv_drive *d; g_trace(G_T_TOPOLOGY, "gv_drive_destroy_geom: %s", gp->name); g_topology_assert(); d = gp->softc; gv_kill_drive_thread(d); g_wither_geom(gp, ENXIO); return (0); } #define VINUMDRIVE_CLASS_NAME "VINUMDRIVE" static struct g_class g_vinum_drive_class = { .name = VINUMDRIVE_CLASS_NAME, .version = G_VERSION, .taste = gv_drive_taste, .destroy_geom = gv_drive_destroy_geom }; DECLARE_GEOM_CLASS(g_vinum_drive_class, g_vinum_drive);