summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/geom/geom.h290
-rw-r--r--sys/geom/geom_bsd.c257
-rw-r--r--sys/geom/geom_dev.c382
-rw-r--r--sys/geom/geom_disk.c232
-rw-r--r--sys/geom/geom_dump.c275
-rw-r--r--sys/geom/geom_event.c299
-rw-r--r--sys/geom/geom_io.c375
-rw-r--r--sys/geom/geom_kern.c192
-rw-r--r--sys/geom/geom_mbr.c211
-rw-r--r--sys/geom/geom_mbrext.c200
-rw-r--r--sys/geom/geom_slice.c278
-rw-r--r--sys/geom/geom_slice.h60
-rw-r--r--sys/geom/geom_subr.c639
13 files changed, 3690 insertions, 0 deletions
diff --git a/sys/geom/geom.h b/sys/geom/geom.h
new file mode 100644
index 0000000..0a3f4807
--- /dev/null
+++ b/sys/geom/geom.h
@@ -0,0 +1,290 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sx.h>
+#include <sys/queue.h>
+
+#ifndef _KERNEL
+/*
+ * The GEOM subsystem makes a few concessions in order to be able to run as a
+ * user-land simulation as well as a kernel component.
+ */
+#include <geom/geom_sim.h>
+#endif
+
+struct g_method;
+struct g_geom;
+struct g_consumer;
+struct g_provider;
+struct g_event;
+struct thread;
+struct bio;
+struct sbuf;
+
+LIST_HEAD(method_list_head, g_method);
+TAILQ_HEAD(g_tailq_head, g_geom);
+TAILQ_HEAD(event_tailq_head, g_event);
+
+extern struct g_tailq_head geoms;
+extern struct event_tailq_head events;
+extern int g_debugflags;
+
+
+#define G_METHOD_INITSTUFF { 0, 0 }, { 0 }, 0
+
+typedef struct g_geom * g_create_geom_t (struct g_method *mp,
+ struct g_provider *pp, char *name);
+typedef struct g_geom * g_taste_t (struct g_method *, struct g_provider *,
+ struct thread *tp, int flags);
+#define G_TF_NORMAL 0
+#define G_TF_INSIST 1
+#define G_TF_TRANSPARENT 2
+typedef int g_access_t (struct g_provider *, int, int, int);
+/* XXX: not sure about the thread arg */
+typedef void g_orphan_t (struct g_consumer *, struct thread *);
+
+typedef void g_start_t (struct bio *);
+typedef void g_spoiled_t (struct g_consumer *);
+typedef void g_dumpconf_t (struct sbuf *, char *indent, struct g_geom *,
+ struct g_consumer *, struct g_provider *);
+
+/*
+ * The g_method structure describes a transformation method. In other words
+ * all BSD disklabel handlers share one g_method, all MBR handlers share
+ * one common g_method and so on.
+ * Certain operations are instantiated on the method, most notably the
+ * taste and create_geom functions.
+ * XXX: should access and orphan go into g_geom ?
+ * XXX: would g_class be a better and less confusing name ?
+ */
+struct g_method {
+ char *name;
+ g_taste_t *taste;
+ g_access_t *access;
+ g_orphan_t *orphan;
+ g_create_geom_t *create_geom;
+ LIST_ENTRY(g_method) method;
+ LIST_HEAD(,g_geom) geom;
+ struct g_event *event;
+};
+
+/*
+ * The g_geom is an instance of a g_method.
+ */
+struct g_geom {
+ char *name;
+ struct g_method *method;
+ LIST_ENTRY(g_geom) geom;
+ LIST_HEAD(,g_consumer) consumer;
+ LIST_HEAD(,g_provider) provider;
+ TAILQ_ENTRY(g_geom) geoms; /* XXX: better name */
+ int rank;
+ g_start_t *start;
+ g_spoiled_t *spoiled;
+ g_dumpconf_t *dumpconf;
+ void *softc;
+ struct g_event *event;
+ unsigned flags;
+#define G_GEOM_WITHER 1
+};
+
+/*
+ * The g_bioq is a queue of struct bio's.
+ * XXX: possibly collection point for statistics.
+ * XXX: should (possibly) be collapsed with sys/bio.h::bio_queue_head.
+ */
+struct g_bioq {
+ TAILQ_HEAD(, bio) bio_queue;
+ struct mtx bio_queue_lock;
+ int bio_queue_length;
+};
+
+/*
+ * A g_consumer is an attachment point for a g_provider. One g_consumer
+ * can only be attached to one g_provider, but multiple g_consumers
+ * can be attached to one g_provider.
+ */
+
+struct g_consumer {
+ struct g_geom *geom;
+ LIST_ENTRY(g_consumer) consumer;
+ struct g_provider *provider;
+ LIST_ENTRY(g_consumer) consumers; /* XXX: better name */
+ int acr, acw, ace;
+ struct g_event *event;
+
+ int biocount;
+ int spoiled;
+};
+
+/*
+ * A g_provider is a "logical disk".
+ */
+struct g_provider {
+ char *name;
+ LIST_ENTRY(g_provider) provider;
+ struct g_geom *geom;
+ LIST_HEAD(,g_consumer) consumers;
+ int acr, acw, ace;
+ int error;
+ struct g_event *event;
+ TAILQ_ENTRY(g_provider) orphan;
+ int index;
+};
+
+/*
+ * Various internal actions are tracked by tagging g_event[s] onto
+ * an internal eventqueue.
+ */
+enum g_events {
+ EV_NEW_METHOD, /* method */
+ EV_NEW_PROVIDER, /* provider */
+ EV_SPOILED, /* provider, consumer */
+ EV_LAST
+};
+
+struct g_event {
+ enum g_events event;
+ TAILQ_ENTRY(g_event) events;
+ struct g_method *method;
+ struct g_geom *geom;
+ struct g_provider *provider;
+ struct g_consumer *consumer;
+};
+
+/* geom_dump.c */
+struct sbuf * g_conf(void);
+struct sbuf * g_conf_specific(struct g_method *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp);
+struct sbuf * g_confdot(void);
+void g_hexdump(void *ptr, int length);
+void g_trace(int level, char *, ...);
+# define G_T_TOPOLOGY 1
+# define G_T_BIO 2
+# define G_T_ACCESS 4
+
+/* geom_event.c */
+void g_event_init(void);
+void g_orphan_provider(struct g_provider *pp, int error);
+void g_post_event(enum g_events ev, struct g_method *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp);
+void g_rattle(void);
+void g_run_events(struct thread *tp);
+void g_silence(void);
+
+/* geom_subr.c */
+int g_access_abs(struct g_consumer *cp, int read, int write, int exclusive);
+int g_access_rel(struct g_consumer *cp, int read, int write, int exclusive);
+void g_add_method(struct g_method *mp);
+int g_attach(struct g_consumer *cp, struct g_provider *pp);
+struct g_geom *g_create_geomf(char *method, struct g_provider *, char *fmt, ...);
+void g_destroy_consumer(struct g_consumer *cp);
+void g_destroy_geom(struct g_geom *pp);
+void g_destroy_provider(struct g_provider *pp);
+void g_dettach(struct g_consumer *cp);
+void g_error_provider(struct g_provider *pp, int error);
+int g_haveattr(struct bio *bp, char *attribute, void *val, int len);
+int g_haveattr_int(struct bio *bp, char *attribute, int val);
+int g_haveattr_off_t(struct bio *bp, char *attribute, off_t val);
+struct g_geom * g_insert_geom(char *method, struct g_consumer *cp);
+extern struct method_list_head g_methods;
+struct g_consumer * g_new_consumer(struct g_geom *gp);
+struct g_geom * g_new_geomf(struct g_method *mp, char *fmt, ...);
+struct g_provider * g_new_providerf(struct g_geom *gp, char *fmt, ...);
+void g_spoil(struct g_provider *pp, struct g_consumer *cp);
+int g_std_access(struct g_provider *pp, int dr, int dw, int de);
+void g_std_done(struct bio *bp);
+void g_std_spoiled(struct g_consumer *cp);
+extern char *g_wait_event, *g_wait_sim, *g_wait_up, *g_wait_down;
+
+/* geom_io.c */
+struct bio * g_clone_bio(struct bio *);
+void g_destroy_bio(struct bio *);
+void g_io_deliver(struct bio *bp);
+int g_io_getattr(char *attr, struct g_consumer *cp, int *len, void *ptr, struct thread *tp);
+void g_io_init(void);
+void g_io_request(struct bio *bp, struct g_consumer *cp);
+void g_io_schedule_down(struct thread *tp);
+void g_io_schedule_up(struct thread *tp);
+int g_io_setattr(char *attr, struct g_consumer *cp, int len, void *ptr, struct thread *tp);
+struct bio *g_new_bio(void);
+void * g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error);
+
+/* geom_kern.c / geom_kernsim.c */
+void g_init(void);
+
+
+#ifdef _KERNEL
+
+MALLOC_DECLARE(M_GEOM);
+
+static __inline void *
+g_malloc(int size, int flags)
+{
+ void *p;
+
+ mtx_lock(&Giant);
+ p = malloc(size, M_GEOM, flags);
+ mtx_unlock(&Giant);
+ return (p);
+}
+
+static __inline void
+g_free(void *ptr)
+{
+ mtx_lock(&Giant);
+ free(ptr, M_GEOM);
+ mtx_unlock(&Giant);
+}
+
+extern struct sx topology_lock;
+#define g_topology_lock() sx_xlock(&topology_lock)
+#define g_topology_unlock() sx_xunlock(&topology_lock)
+#define g_topology_assert() sx_assert(&topology_lock, SX_XLOCKED)
+
+#define DECLARE_GEOM_METHOD(method, name) \
+ static void \
+ name##init(void) \
+ { \
+ mtx_unlock(&Giant); \
+ g_add_method(&method); \
+ mtx_lock(&Giant); \
+ } \
+ SYSINIT(name, SI_SUB_PSEUDO, SI_ORDER_FIRST, name##init, NULL);
+
+#endif
+
diff --git a/sys/geom/geom_bsd.c b/sys/geom/geom_bsd.c
new file mode 100644
index 0000000..47e601d
--- /dev/null
+++ b/sys/geom/geom_bsd.c
@@ -0,0 +1,257 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+
+#include <sys/param.h>
+#ifndef _KERNEL
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <err.h>
+#else
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/bio.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#endif
+#include <sys/errno.h>
+#include <sys/disklabel.h>
+#include <geom/geom.h>
+#include <geom/geom_slice.h>
+
+#define BSD_METHOD_NAME "BSD-method"
+
+struct g_bsd_softc {
+ struct disklabel ondisk;
+ struct disklabel inram;
+};
+
+static void
+ondisk2inram(struct g_bsd_softc *sc)
+{
+ struct partition *ppp;
+ unsigned offset;
+ int i;
+
+ sc->inram = sc->ondisk;
+ offset = sc->inram.d_partitions[RAW_PART].p_offset;
+ for (i = 0; i < 8; i++) {
+ ppp = &sc->inram.d_partitions[i];
+ if (ppp->p_offset >= offset)
+ ppp->p_offset -= offset;
+ }
+ sc->inram.d_checksum = 0;
+ sc->inram.d_checksum = dkcksum(&sc->inram);
+}
+
+static int
+g_bsd_start(struct bio *bp)
+{
+ struct g_geom *gp;
+ struct g_bsd_softc *ms;
+ struct g_slicer *gsp;
+ struct partinfo pi;
+
+ gp = bp->bio_to->geom;
+ gsp = gp->softc;
+ ms = gsp->softc;
+ if (g_haveattr(bp, "IOCTL::DIOCGDINFO",
+ &ms->inram,
+ sizeof ms->inram))
+ return (1);
+ if (!strcmp(bp->bio_attribute, "IOCTL::DIOCGPART")) {
+ pi.disklab = &ms->inram;
+ pi.part = &ms->inram.d_partitions[bp->bio_to->index];
+ if (g_haveattr(bp, "IOCTL::DIOCGPART", &pi, sizeof pi))
+ return (1);
+ }
+ return (0);
+}
+
+static void
+g_bsd_dumpconf(struct sbuf *sb, char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp)
+{
+#if 0
+ struct g_mbr_softc *ms;
+ struct g_slicer *gsp;
+
+ gsp = gp->softc;
+ ms = gsp->softc;
+ if (pp != NULL) {
+ sbuf_printf(sb, "%s<type>%d</type>\n",
+ indent, ms->type[pp->index]);
+ }
+#endif
+ g_slice_dumpconf(sb, indent, gp, cp, pp);
+}
+
+static struct g_geom *
+g_bsd_taste(struct g_method *mp, struct g_provider *pp, struct thread *tp, int flags)
+{
+ struct g_geom *gp;
+ struct g_consumer *cp;
+ struct g_provider *pp2;
+ int error, i, j, npart;
+ u_char *buf;
+ struct g_bsd_softc *ms;
+ struct disklabel *dl;
+ u_int secsize;
+ u_int fwsectors, fwheads;
+ off_t mediasize;
+ struct partition *ppp, *ppr;
+
+ g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name);
+ g_topology_assert();
+ if (flags == G_TF_NORMAL &&
+ !strcmp(pp->geom->method->name, BSD_METHOD_NAME))
+ return (NULL);
+ gp = g_slice_new(mp, 8, pp, &cp, &ms, sizeof *ms, g_bsd_start);
+ if (gp == NULL)
+ return (NULL);
+ g_topology_unlock();
+ gp->dumpconf = g_bsd_dumpconf;
+ npart = 0;
+ while (1) { /* a trick to allow us to use break */
+ j = sizeof i;
+ error = g_io_getattr("MBR::type", cp, &j, &i, tp);
+ if (!error && i != 165 && flags == G_TF_NORMAL)
+ break;
+ j = sizeof secsize;
+ error = g_io_getattr("GEOM::sectorsize", cp, &j, &secsize, tp);
+ if (error) {
+ secsize = 512;
+ printf("g_bsd_taste: error %d Sectors are %d bytes\n",
+ error, secsize);
+ }
+ j = sizeof mediasize;
+ error = g_io_getattr("GEOM::mediasize", cp, &j, &mediasize, tp);
+ if (error) {
+ mediasize = 0;
+ printf("g_error %d Mediasize is %lld bytes\n",
+ error, mediasize);
+ }
+ buf = g_read_data(cp, secsize * LABELSECTOR, secsize, &error);
+ if (buf == NULL || error != 0)
+ break;
+ bcopy(buf, &ms->ondisk, sizeof(ms->ondisk));
+ dl = &ms->ondisk;
+ g_free(buf);
+ if (dl->d_magic != DISKMAGIC)
+ break;
+ if (dl->d_magic2 != DISKMAGIC)
+ break;
+ if (dkcksum(dl) != 0)
+ break;
+ if (bootverbose)
+ g_hexdump(dl, sizeof(*dl));
+ if (dl->d_secsize < secsize)
+ break;
+ if (dl->d_secsize > secsize)
+ secsize = dl->d_secsize;
+ ppr = &dl->d_partitions[2];
+ for (i = 0; i < 8; i++) {
+ ppp = &dl->d_partitions[i];
+ if (ppp->p_size == 0)
+ continue;
+ npart++;
+ pp2 = g_slice_addslice(gp, i,
+ ((off_t)(ppp->p_offset - ppr->p_offset)) << 9ULL,
+ ((off_t)ppp->p_size) << 9ULL,
+ "%s%c", pp->name, 'a' + i);
+ g_error_provider(pp2, 0);
+ }
+ ondisk2inram(ms);
+ break;
+ }
+ if (npart == 0 && (
+ (flags == G_TF_INSIST && mediasize != 0) ||
+ (flags == G_TF_TRANSPARENT))) {
+ dl = &ms->ondisk;
+ bzero(dl, sizeof *dl);
+ dl->d_magic = DISKMAGIC;
+ dl->d_magic2 = DISKMAGIC;
+ ppp = &dl->d_partitions[RAW_PART];
+ ppp->p_offset = 0;
+ ppp->p_size = mediasize / secsize;
+ dl->d_npartitions = MAXPARTITIONS;
+ dl->d_interleave = 1;
+ dl->d_secsize = secsize;
+ dl->d_rpm = 3600;
+ j = sizeof fwsectors;
+ error = g_io_getattr("GEOM::fwsectors", cp, &j, &fwsectors, tp);
+ if (error)
+ dl->d_nsectors = 32;
+ else
+ dl->d_nsectors = fwsectors;
+ error = g_io_getattr("GEOM::fwheads", cp, &j, &fwheads, tp);
+ if (error)
+ dl->d_ntracks = 64;
+ else
+ dl->d_ntracks = fwheads;
+ dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
+ dl->d_ncylinders = ppp->p_size / dl->d_secpercyl;
+ dl->d_secperunit = ppp->p_size;
+ dl->d_checksum = 0;
+ dl->d_checksum = dkcksum(dl);
+ ms->inram = ms->ondisk;
+ pp2 = g_slice_addslice(gp, RAW_PART,
+ 0, mediasize, "%s%c", pp->name, 'a' + RAW_PART);
+ g_error_provider(pp2, 0);
+ npart = 1;
+ }
+ g_topology_lock();
+ error = g_access_rel(cp, -1, 0, 0);
+ if (npart > 0)
+ return (gp);
+ g_std_spoiled(cp);
+ return (NULL);
+}
+
+static struct g_method g_bsd_method = {
+ BSD_METHOD_NAME,
+ g_bsd_taste,
+ g_slice_access,
+ g_slice_orphan,
+ NULL,
+ G_METHOD_INITSTUFF
+};
+
+DECLARE_GEOM_METHOD(g_bsd_method, g_bsd);
diff --git a/sys/geom/geom_dev.c b/sys/geom/geom_dev.c
new file mode 100644
index 0000000..16f4ad5
--- /dev/null
+++ b/sys/geom/geom_dev.c
@@ -0,0 +1,382 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/bio.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/disk.h>
+#include <sys/fcntl.h>
+#include <geom/geom.h>
+
+
+#define CDEV_MAJOR 4
+
+static d_open_t g_dev_open;
+static d_close_t g_dev_close;
+static d_strategy_t g_dev_strategy;
+static d_ioctl_t g_dev_ioctl;
+static d_psize_t g_dev_psize;
+
+static struct cdevsw g_dev_cdevsw = {
+ /* open */ g_dev_open,
+ /* close */ g_dev_close,
+ /* read */ physread,
+ /* write */ physwrite,
+ /* ioctl */ g_dev_ioctl,
+ /* poll */ nopoll,
+ /* mmap */ nommap,
+ /* strategy */ g_dev_strategy,
+ /* name */ "g_dev",
+ /* maj */ CDEV_MAJOR,
+ /* dump */ nodump,
+ /* psize */ g_dev_psize,
+ /* flags */ D_DISK | D_CANFREE | D_TRACKCLOSE,
+};
+
+static g_taste_t g_dev_taste;
+static g_orphan_t g_dev_orphan;
+
+static struct g_method g_dev_method = {
+ "DEV-method",
+ g_dev_taste,
+ NULL,
+ g_dev_orphan,
+ NULL,
+ G_METHOD_INITSTUFF
+};
+
+static void
+g_dev_clone(void *arg, char *name, int namelen, dev_t *dev)
+{
+ struct g_geom *gp;
+
+ if (*dev != NODEV)
+ return;
+
+ g_trace(G_T_TOPOLOGY, "g_dev_clone(%s)", name);
+ g_rattle();
+
+ /* XXX: can I drop Giant here ??? */
+ /* g_topology_lock(); */
+ LIST_FOREACH(gp, &g_dev_method.geom, geom) {
+ if (strcmp(gp->name, name))
+ continue;
+ *dev = gp->softc;
+ g_trace(G_T_TOPOLOGY, "g_dev_clone(%s) = %p", name, *dev);
+ return;
+ }
+ /* g_topology_unlock(); */
+ return;
+}
+
+static void
+g_dev_register_cloner(void *foo __unused)
+{
+ static int once;
+
+ if (!once) {
+ if (!once)
+ EVENTHANDLER_REGISTER(dev_clone, g_dev_clone, 0, 1000);
+ once++;
+ }
+}
+
+SYSINIT(geomdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,g_dev_register_cloner,NULL);
+
+static struct g_geom *
+g_dev_taste(struct g_method *mp, struct g_provider *pp, struct thread *tp __unused, int insist __unused)
+{
+ struct g_geom *gp;
+ struct g_consumer *cp;
+ static int unit;
+#if 1
+ u_int secsize;
+ off_t mediasize;
+ int error, j;
+#endif
+ dev_t dev;
+
+ g_trace(G_T_TOPOLOGY, "dev_taste(%s,%s)", mp->name, pp->name);
+ g_topology_assert();
+ LIST_FOREACH(cp, &pp->consumers, consumers)
+ if (cp->geom->method == mp)
+ return (NULL);
+ gp = g_new_geomf(mp, pp->name);
+ cp = g_new_consumer(gp);
+ g_attach(cp, pp);
+#if 1
+ error = g_access_rel(cp, 1, 0, 0);
+ g_topology_unlock();
+ if (!error) {
+ j = sizeof secsize;
+ error = g_io_getattr("GEOM::sectorsize", cp, &j, &secsize, tp);
+ if (error) {
+ secsize = 512;
+ printf("g_bsd_taste: error %d Sectors are %d bytes\n",
+ error, secsize);
+ }
+ j = sizeof mediasize;
+ error = g_io_getattr("GEOM::mediasize", cp, &j, &mediasize, tp);
+ if (error) {
+ mediasize = 0;
+ printf("g_error %d Mediasize is %lld bytes\n",
+ error, mediasize);
+ }
+ g_topology_lock();
+ g_access_rel(cp, -1, 0, 0);
+ g_topology_unlock();
+ } else {
+ secsize = 512;
+ mediasize = 0;
+ }
+#else
+ g_topology_unlock();
+#endif
+ mtx_lock(&Giant);
+#if 1
+ if (mediasize != 0)
+ printf("GEOM: \"%s\" %lld bytes in %lld sectors of %u bytes\n",
+ pp->name, mediasize, mediasize / secsize, secsize);
+ else
+ printf("GEOM: \"%s\" (size unavailable)\n", pp->name);
+#endif
+ dev = make_dev(&g_dev_cdevsw, unit++,
+ UID_ROOT, GID_WHEEL, 0600, gp->name);
+ gp->softc = dev;
+ dev->si_drv1 = gp;
+ dev->si_drv2 = cp;
+ mtx_unlock(&Giant);
+ g_topology_lock();
+ return (gp);
+}
+
+static int
+g_dev_open(dev_t dev, int flags, int fmt, struct thread *td)
+{
+ struct g_geom *gp;
+ struct g_consumer *cp;
+ int error, r, w, e;
+
+ gp = dev->si_drv1;
+ cp = dev->si_drv2;
+ if (gp == NULL || cp == NULL)
+ return(ENXIO);
+ g_trace(G_T_ACCESS, "g_dev_open(%s, %d, %d, %p)",
+ gp->name, flags, fmt, td);
+ mtx_unlock(&Giant);
+ g_topology_lock();
+ g_silence();
+ r = flags & FREAD ? 1 : 0;
+ w = flags & FWRITE ? 1 : 0;
+ e = flags & O_EXCL ? 1 : 0;
+ error = g_access_rel(cp, r, w, e);
+ g_topology_unlock();
+ mtx_lock(&Giant);
+ g_rattle();
+ return(error);
+}
+
+static int
+g_dev_close(dev_t dev, int flags, int fmt, struct thread *td)
+{
+ struct g_geom *gp;
+ struct g_consumer *cp;
+ int error, r, w, e;
+
+ gp = dev->si_drv1;
+ cp = dev->si_drv2;
+ if (gp == NULL || cp == NULL)
+ return(ENXIO);
+ g_trace(G_T_ACCESS, "g_dev_close(%s, %d, %d, %p)",
+ gp->name, flags, fmt, td);
+ mtx_unlock(&Giant);
+ g_topology_lock();
+ g_silence();
+ r = flags & FREAD ? -1 : 0;
+ w = flags & FWRITE ? -1 : 0;
+ e = flags & O_EXCL ? -1 : 0;
+ error = g_access_rel(cp, r, w, e);
+ g_topology_unlock();
+ mtx_lock(&Giant);
+ g_rattle();
+ return (error);
+}
+
+static int
+g_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
+{
+ struct g_geom *gp;
+ struct g_consumer *cp;
+ char *nm;
+ int i, error;
+
+ gp = dev->si_drv1;
+ cp = dev->si_drv2;
+
+ error = 0;
+ mtx_unlock(&Giant);
+ switch (cmd) {
+ case DIOCGDINFO: nm = "IOCTL::DIOCGDINFO"; break;
+ case DIOCGDVIRGIN: nm = "IOCTL::DIOCGDVIRGIN"; break;
+ case DIOCGPART: nm = "IOCTL::DIOCGPART"; break;
+ default: nm = "?"; break;
+ }
+ i = IOCGROUP(cmd);
+ if (*nm == '?') {
+ printf("IOCTL(0x%lx) \"%s\"", cmd, gp->name);
+ if (i > ' ' && i <= '~')
+ printf(" '%c'", (int)IOCGROUP(cmd));
+ else
+ printf(" 0x%lx", IOCGROUP(cmd));
+ printf("/%ld ", cmd & 0xff);
+ if (cmd & IOC_IN)
+ printf("I");
+ if (cmd & IOC_OUT)
+ printf("O");
+ printf("(%ld)", IOCPARM_LEN(cmd));
+ printf(" \"%s\"\n", nm);
+ error = ENOIOCTL;
+ }
+ if (error == 0) {
+ i = IOCPARM_LEN(cmd);
+ error = g_io_getattr(nm, cp, &i, data, td);
+ if (error != 0 && cmd == DIOCGDVIRGIN) {
+ g_topology_lock();
+ gp = g_create_geomf("BSD-method", cp->provider, NULL);
+ g_topology_unlock();
+ }
+ }
+ mtx_lock(&Giant);
+ g_rattle();
+ if (error == ENOIOCTL)
+ error = ENOTTY;
+ return (error);
+}
+
+static int
+g_dev_psize(dev_t dev)
+{
+ struct g_consumer *cp;
+ int i, error;
+ off_t mediasize;
+
+ cp = dev->si_drv2;
+
+ i = sizeof mediasize;
+ error = g_io_getattr("GEOM::mediasize", cp, &i, &mediasize, NULL);
+ if (error)
+ return (-1);
+ return (mediasize >> DEV_BSHIFT);
+}
+
+static void
+g_dev_done(struct bio *bp2)
+{
+ struct bio *bp;
+
+ bp = bp2->bio_linkage;
+ bp->bio_error = bp2->bio_error;
+ if (bp->bio_error != 0) {
+ g_trace(G_T_BIO, "g_dev_done(%p) had error %d",
+ bp2, bp->bio_error);
+ bp->bio_flags |= BIO_ERROR;
+ } else {
+ g_trace(G_T_BIO, "g_dev_done(%p/%p) resid %ld completed %lld",
+ bp2, bp, bp->bio_resid, bp2->bio_completed);
+ }
+ bp->bio_resid = bp->bio_bcount - bp2->bio_completed;
+ g_destroy_bio(bp2);
+ mtx_lock(&Giant);
+ biodone(bp);
+ mtx_unlock(&Giant);
+}
+
+static void
+g_dev_strategy(struct bio *bp)
+{
+ struct g_geom *gp;
+ struct g_consumer *cp;
+ struct bio *bp2;
+ dev_t dev;
+
+ mtx_unlock(&Giant);
+ dev = bp->bio_dev;
+ gp = dev->si_drv1;
+ cp = dev->si_drv2;
+ bp2 = g_clone_bio(bp);
+ bp2->bio_offset = (off_t)bp->bio_blkno << DEV_BSHIFT;
+ bp2->bio_length = (off_t)bp->bio_bcount;
+ bp2->bio_done = g_dev_done;
+ g_trace(G_T_BIO,
+ "g_dev_strategy(%p/%p) offset %lld length %lld data %p cmd %d",
+ bp, bp2, bp->bio_offset, bp2->bio_length, bp2->bio_data,
+ bp2->bio_cmd);
+ g_io_request(bp2, cp);
+ mtx_lock(&Giant);
+}
+
+
+static void
+g_dev_orphan(struct g_consumer *cp, struct thread *tp)
+{
+ struct g_geom *gp;
+ dev_t dev;
+
+ gp = cp->geom;
+ g_trace(G_T_TOPOLOGY, "g_dev_orphan(%p(%s))", cp, gp->name);
+ g_topology_assert();
+ if (cp->biocount > 0)
+ return;
+ dev = gp->softc;
+ destroy_dev(dev);
+ if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
+ g_access_rel(cp, -cp->acr, -cp->acw, -cp->ace);
+ g_dettach(cp);
+ g_destroy_consumer(cp);
+ g_destroy_geom(gp);
+}
+
+DECLARE_GEOM_METHOD(g_dev_method, g_dev)
+
diff --git a/sys/geom/geom_disk.c b/sys/geom/geom_disk.c
new file mode 100644
index 0000000..62da840
--- /dev/null
+++ b/sys/geom/geom_disk.c
@@ -0,0 +1,232 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_geom.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/bio.h>
+#include <sys/conf.h>
+#include <sys/disk.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <machine/md_var.h>
+#include <sys/ctype.h>
+
+
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <geom/geom.h>
+
+static g_access_t g_disk_access;
+
+struct g_method g_disk_method = {
+ "DISK-method",
+ NULL,
+ g_disk_access,
+ NULL,
+ NULL,
+ { 0, 0 },
+ { 0 }
+};
+
+static int
+g_disk_access(struct g_provider *pp, int r, int w, int e)
+{
+ struct disk *dp;
+ dev_t dev;
+ int error;
+
+ g_trace(G_T_ACCESS, "g_disk_access(%s, %d, %d, %d)",
+ pp->name, r, w, e);
+ g_topology_assert();
+ r += pp->acr;
+ w += pp->acw;
+ e += pp->ace;
+ dp = pp->geom->softc;
+ dev = dp->d_dev;
+ if ((pp->acr + pp->acw + pp->ace) == 0 && (r + w + e) > 0) {
+ mtx_lock(&Giant);
+ error = devsw(dev)->d_open(dev, 3, 0, NULL);
+ if (error != 0)
+ printf("Opened disk %s -> %d\n", pp->name, error);
+ mtx_unlock(&Giant);
+ } else if ((pp->acr + pp->acw + pp->ace) > 0 && (r + w + e) == 0) {
+ mtx_lock(&Giant);
+ error = devsw(dev)->d_close(dev, 3, 0, NULL);
+ if (error != 0)
+ printf("Closed disk %s -> %d\n", pp->name, error);
+ mtx_unlock(&Giant);
+ } else {
+ error = 0;
+ }
+ return (error);
+}
+
+static void
+g_disk_done(struct bio *bp)
+{
+
+ mtx_unlock(&Giant);
+ bp->bio_completed = bp->bio_length - bp->bio_resid;
+ g_std_done(bp);
+ mtx_lock(&Giant);
+}
+
+static void
+g_disk_start(struct bio *bp)
+{
+ struct bio *bp2;
+ dev_t dev;
+ struct disk *dp;
+
+ dp = bp->bio_to->geom->softc;
+ dev = dp->d_dev;
+ switch(bp->bio_cmd) {
+ case BIO_READ:
+ case BIO_WRITE:
+ bp2 = g_clone_bio(bp);
+ bp2->bio_done = g_disk_done;
+ bp2->bio_blkno = bp2->bio_offset >> DEV_BSHIFT;
+ bp2->bio_pblkno = bp2->bio_blkno;
+ bp2->bio_bcount = bp2->bio_length;
+ bp2->bio_dev = dev;
+ mtx_lock(&Giant);
+ devsw(dev)->d_strategy(bp2);
+ mtx_unlock(&Giant);
+ break;
+ case BIO_GETATTR:
+ if (g_haveattr_int(bp, "GEOM::sectorsize",
+ dp->d_label.d_secsize))
+ return;
+ if (g_haveattr_int(bp, "GEOM::fwsectors",
+ dp->d_label.d_nsectors))
+ return;
+ if (g_haveattr_int(bp, "GEOM::fwheads",
+ dp->d_label.d_ntracks))
+ return;
+ if (g_haveattr_int(bp, "GEOM::fwcylinders",
+ dp->d_label.d_ncylinders))
+ return;
+ if (g_haveattr_off_t(bp, "GEOM::mediasize",
+ dp->d_label.d_secsize * (off_t)dp->d_label.d_secperunit))
+ return;
+ bp->bio_error = ENOIOCTL;
+ g_io_deliver(bp);
+ return;
+ default:
+ bp->bio_error = EOPNOTSUPP;
+ g_io_deliver(bp);
+ return;
+ }
+}
+
+dev_t
+disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
+{
+ static int once;
+ struct g_geom *gp;
+ struct g_provider *pp;
+ dev_t dev;
+
+ mtx_unlock(&Giant);
+ if (!once) {
+ g_add_method(&g_disk_method);
+ once++;
+ }
+ dev = g_malloc(sizeof *dev, M_WAITOK | M_ZERO);
+ dp->d_dev = dev;
+ dev->si_devsw = cdevsw;
+ dev->si_disk = dp;
+ dev->si_udev = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART);
+ g_topology_lock();
+ gp = g_new_geomf(&g_disk_method, "%s%d", cdevsw->d_name, unit);
+ gp->start = g_disk_start;
+ gp->softc = dp;
+ dp->d_softc = gp;
+ pp = g_new_providerf(gp, "%s", gp->name);
+ g_error_provider(pp, 0);
+ g_topology_unlock();
+ mtx_lock(&Giant);
+ return (dev);
+}
+
+void disk_dev_synth(dev_t dev);
+
+void
+disk_dev_synth(dev_t dev)
+{
+
+ return;
+}
+
+void
+disk_destroy(dev_t dev)
+{
+ struct disk *dp;
+ struct g_geom *gp;
+
+ dp = dev->si_disk;
+ gp = dp->d_softc;
+ g_free(dev);
+ gp->flags |= G_GEOM_WITHER;
+ g_orphan_provider(LIST_FIRST(&gp->provider), ENXIO);
+}
+
+void
+disk_invalidate (struct disk *disk)
+{
+}
+
+int
+disk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize)
+{
+
+ return (ENXIO);
+}
+
+
+SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD,
+ 0, sizeof(struct disklabel), "sizeof(struct disklabel)");
+
+SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD,
+ 0, sizeof(struct diskslices), "sizeof(struct diskslices)");
+
+SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD,
+ 0, sizeof(struct disk), "sizeof(struct disk)");
diff --git a/sys/geom/geom_dump.c b/sys/geom/geom_dump.c
new file mode 100644
index 0000000..7ea0697
--- /dev/null
+++ b/sys/geom/geom_dump.c
@@ -0,0 +1,275 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+
+#include <sys/param.h>
+#include <sys/sbuf.h>
+#ifndef _KERNEL
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <err.h>
+#else
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#endif
+#include <machine/stdarg.h>
+
+#include <geom/geom.h>
+
+
+static void
+g_confdot_consumer(struct sbuf *sb, struct g_consumer *cp)
+{
+
+ sbuf_printf(sb, "z%p [label=\"r%dw%de%d\\nbio #%d\"];\n",
+ cp, cp->acr, cp->acw, cp->ace, cp->biocount);
+ if (cp->provider)
+ sbuf_printf(sb, "z%p -> z%p;\n", cp, cp->provider);
+}
+
+static void
+g_confdot_provider(struct sbuf *sb, struct g_provider *pp)
+{
+
+ sbuf_printf(sb, "z%p [shape=hexagon,label=\"%s\\nr%dw%de%d\\nerr#%d\"];\n",
+ pp, pp->name, pp->acr, pp->acw, pp->ace, pp->error);
+}
+
+static void
+g_confdot_geom(struct sbuf *sb, struct g_geom *gp)
+{
+ struct g_consumer *cp;
+ struct g_provider *pp;
+
+ sbuf_printf(sb, "z%p [shape=box,label=\"%s\\n%s\\nr#%d\"];\n",
+ gp, gp->method->name, gp->name, gp->rank);
+ LIST_FOREACH(cp, &gp->consumer, consumer) {
+ g_confdot_consumer(sb, cp);
+ sbuf_printf(sb, "z%p -> z%p;\n", gp, cp);
+ }
+
+ LIST_FOREACH(pp, &gp->provider, provider) {
+ g_confdot_provider(sb, pp);
+ sbuf_printf(sb, "z%p -> z%p;\n", pp, gp);
+ }
+}
+
+static void
+g_confdot_method(struct sbuf *sb, struct g_method *mp)
+{
+ struct g_geom *gp;
+
+ LIST_FOREACH(gp, &mp->geom, geom)
+ g_confdot_geom(sb, gp);
+}
+
+struct sbuf *
+g_confdot(void)
+{
+ struct g_method *mp;
+ struct sbuf *sb;
+
+ sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ sbuf_clear(sb);
+ sbuf_printf(sb, "digraph geom {\n");
+ LIST_FOREACH(mp, &g_methods, method)
+ g_confdot_method(sb, mp);
+ sbuf_printf(sb, "};\n");
+ sbuf_finish(sb);
+ return (sb);
+}
+
+
+static void
+g_conf_consumer(struct sbuf *sb, struct g_consumer *cp)
+{
+
+ sbuf_printf(sb, "\t<consumer>\n");
+ sbuf_printf(sb, "\t <ref>%p</ref>\n", cp);
+ sbuf_printf(sb, "\t <geom><ref>%p</ref></geom>\n", cp->geom);
+ sbuf_printf(sb, "\t <provider><ref>%p</ref></provider>\n", cp->provider);
+ sbuf_printf(sb, "\t <mode>r%dw%de%d</mode>\n",
+ cp->acr, cp->acw, cp->ace);
+ if (cp->geom->dumpconf) {
+ sbuf_printf(sb, "\t <config>\n");
+ cp->geom->dumpconf(sb, "\t ", cp->geom, cp, NULL);
+ sbuf_printf(sb, "\t </config>\n");
+ }
+ sbuf_printf(sb, "\t</consumer>\n");
+}
+
+static void
+g_conf_provider(struct sbuf *sb, struct g_provider *pp)
+{
+
+ sbuf_printf(sb, "\t<provider>\n", pp);
+ sbuf_printf(sb, "\t <ref>%p</ref>\n", pp);
+ sbuf_printf(sb, "\t <geom><ref>%p</ref></geom>\n", pp->geom);
+ sbuf_printf(sb, "\t <mode>r%dw%de%d</mode>\n",
+ pp->acr, pp->acw, pp->ace);
+ sbuf_printf(sb, "\t <name>%s</name>\n", pp->name);
+ if (pp->geom->dumpconf) {
+ sbuf_printf(sb, "\t <config>\n");
+ pp->geom->dumpconf(sb, "\t ", pp->geom, NULL, pp);
+ sbuf_printf(sb, "\t </config>\n");
+ }
+ sbuf_printf(sb, "\t</provider>\n");
+}
+
+
+static void
+g_conf_geom(struct sbuf *sb, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp)
+{
+ struct g_consumer *cp2;
+ struct g_provider *pp2;
+
+ sbuf_printf(sb, " <geom>\n");
+ sbuf_printf(sb, " <ref>%p</ref>\n", gp);
+ sbuf_printf(sb, " <method><ref>%p</ref></method>\n", gp->method);
+ sbuf_printf(sb, " <name>%s</name>\n", gp->name);
+ sbuf_printf(sb, " <rank>%d</rank>\n", gp->rank);
+ if (gp->dumpconf) {
+ sbuf_printf(sb, " <config>\n");
+ gp->dumpconf(sb, "\t", gp, NULL, NULL);
+ sbuf_printf(sb, " </config>\n");
+ }
+ LIST_FOREACH(cp2, &gp->consumer, consumer) {
+ if (cp != NULL && cp != cp2)
+ continue;
+ g_conf_consumer(sb, cp2);
+ }
+
+ LIST_FOREACH(pp2, &gp->provider, provider) {
+ if (pp != NULL && pp != pp2)
+ continue;
+ g_conf_provider(sb, pp2);
+ }
+ sbuf_printf(sb, " </geom>\n");
+}
+
+static void
+g_conf_method(struct sbuf *sb, struct g_method *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp)
+{
+ struct g_geom *gp2;
+
+ sbuf_printf(sb, " <method>\n");
+ sbuf_printf(sb, " <ref>%p</ref>\n", mp);
+ sbuf_printf(sb, " <name>%s</name>\n", mp->name);
+ LIST_FOREACH(gp2, &mp->geom, geom) {
+ if (gp != NULL && gp != gp2)
+ continue;
+ g_conf_geom(sb, gp2, pp, cp);
+ }
+ sbuf_printf(sb, " </method>\n");
+}
+
+struct sbuf *
+g_conf_specific(struct g_method *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp)
+{
+ struct g_method *mp2;
+ struct sbuf *sb;
+
+ sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ sbuf_clear(sb);
+ sbuf_printf(sb, "<mesh>\n");
+ LIST_FOREACH(mp2, &g_methods, method) {
+ if (mp != NULL && mp != mp2)
+ continue;
+ g_conf_method(sb, mp2, gp, pp, cp);
+ }
+ sbuf_printf(sb, "</mesh>\n");
+ sbuf_finish(sb);
+ return (sb);
+}
+
+struct sbuf *
+g_conf()
+{
+
+ return (g_conf_specific(NULL, NULL, NULL, NULL));
+}
+
+
+void
+g_trace(int level, char *fmt, ...)
+{
+ va_list ap;
+ struct sbuf *sb;
+
+ if (!(g_debugflags & level))
+ return;
+ va_start(ap, fmt);
+ mtx_lock(&Giant);
+ sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ sbuf_vprintf(sb, fmt, ap);
+ sbuf_finish(sb);
+ mtx_unlock(&Giant);
+ printf("%s\n", sbuf_data(sb));
+ sbuf_delete(sb);
+}
+
+void
+g_hexdump(void *ptr, int length)
+{
+ int i, j, k;
+ unsigned char *cp;
+
+ cp = ptr;
+ for (i = 0; i < length; i+= 16) {
+ printf("%04x ", i);
+ for (j = 0; j < 16; j++) {
+ k = i + j;
+ if (k < length)
+ printf(" %02x", cp[k]);
+ else
+ printf(" ");
+ }
+ printf(" |");
+ for (j = 0; j < 16; j++) {
+ k = i + j;
+ if (k >= length)
+ printf(" ");
+ else if (cp[k] >= ' ' && cp[k] <= '~')
+ printf("%c", cp[k]);
+ else
+ printf(".");
+ }
+ printf("|\n");
+ }
+}
+
diff --git a/sys/geom/geom_event.c b/sys/geom/geom_event.c
new file mode 100644
index 0000000..ac89c23
--- /dev/null
+++ b/sys/geom/geom_event.c
@@ -0,0 +1,299 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * XXX: How do we in general know that objects referenced in events
+ * have not been destroyed before we get around to handle the event ?
+ */
+
+#include <sys/param.h>
+#ifndef _KERNEL
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <err.h>
+#else
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#endif
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <geom/geom.h>
+
+static struct event_tailq_head g_events = TAILQ_HEAD_INITIALIZER(g_events);
+static u_int g_pending_events, g_silence_events;
+static void g_do_event(struct g_event *ep, struct thread *tp);
+static TAILQ_HEAD(,g_provider) g_doorstep = TAILQ_HEAD_INITIALIZER(g_doorstep);
+static struct mtx g_doorlock;
+
+void
+g_silence(void)
+{
+
+ g_silence_events = 1;
+}
+
+void
+g_rattle(void)
+{
+
+ g_silence_events = 0;
+ mtx_lock(&Giant);
+ wakeup(&g_silence_events);
+ while (g_pending_events)
+ tsleep(&g_pending_events, PPAUSE, "g_rattle", hz/5);
+ mtx_unlock(&Giant);
+}
+
+void
+g_orphan_provider(struct g_provider *pp, int error)
+{
+
+ g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)",
+ pp, pp->name, error);
+ KASSERT(error != 0,
+ ("g_orphan_provider(%p(%s), 0) error must be non-zero\n",
+ pp, pp->name));
+ pp->error = error;
+ mtx_lock(&g_doorlock);
+ TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan);
+ mtx_unlock(&g_doorlock);
+ mtx_lock(&Giant);
+ wakeup(&g_wait_event);
+ mtx_unlock(&Giant);
+}
+
+/*
+ * This function is called once on each provider which the event handler
+ * finds on its g_doorstep.
+ */
+
+static void
+g_orphan_register(struct g_provider *pp, struct thread *tp)
+{
+ struct g_consumer *cp, *cp2;
+
+ g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name);
+ g_topology_assert();
+
+ /*
+ * Tell all consumers the bad news.
+ * Don't get surprised if they self-destruct.
+ */
+ cp = LIST_FIRST(&pp->consumers);
+ while (cp != NULL) {
+ cp2 = LIST_NEXT(cp, consumers);
+ KASSERT(cp->geom->method->orphan != NULL,
+ ("method %s has no orphan, geom %s",
+ cp->geom->method->name, cp->geom->name));
+ cp->geom->method->orphan(cp, tp);
+ cp = cp2;
+ }
+}
+
+static void
+g_destroy_event(struct g_event *ep)
+{
+
+ g_free(ep);
+}
+
+static void
+g_do_event(struct g_event *ep, struct thread *tp)
+{
+ struct g_method *mp, *mp2;
+ struct g_geom *gp;
+ struct g_consumer *cp, *cp2;
+ struct g_provider *pp;
+ int i;
+
+ g_trace(G_T_TOPOLOGY, "g_do_event(%p) %d m:%p g:%p p:%p c:%p - ",
+ ep, ep->event, ep->method, ep->geom, ep->provider, ep->consumer);
+ g_topology_assert();
+ switch (ep->event) {
+ case EV_NEW_METHOD:
+ mp2 = ep->method;
+ if (mp2->taste == NULL)
+ break;
+ LIST_FOREACH(mp, &g_methods, method) {
+ if (mp2 == mp)
+ continue;
+ LIST_FOREACH(gp, &mp->geom, geom) {
+ LIST_FOREACH(pp, &gp->provider, provider) {
+ mp2->taste(ep->method, pp, tp, 0);
+ g_topology_assert();
+ }
+ }
+ }
+ break;
+ case EV_NEW_PROVIDER:
+ g_trace(G_T_TOPOLOGY, "EV_NEW_PROVIDER(%s)",
+ ep->provider->name);
+ LIST_FOREACH(mp, &g_methods, method) {
+ if (mp->taste == NULL)
+ continue;
+ i = 1;
+ LIST_FOREACH(cp, &ep->provider->consumers, consumers)
+ if(cp->geom->method == mp)
+ i = 0;
+ if (i) {
+ mp->taste(mp, ep->provider, tp, 0);
+ g_topology_assert();
+ }
+ }
+ break;
+ case EV_SPOILED:
+ g_trace(G_T_TOPOLOGY, "EV_SPOILED(%p(%s),%p)",
+ ep->provider, ep->provider->name, ep->consumer);
+ cp = LIST_FIRST(&ep->provider->consumers);
+ while (cp != NULL) {
+ cp2 = LIST_NEXT(cp, consumers);
+ if (cp->spoiled) {
+ g_trace(G_T_TOPOLOGY, "spoiling %p (%s) (%p)",
+ cp, cp->geom->name, cp->geom->spoiled);
+ if (cp->geom->spoiled != NULL)
+ cp->geom->spoiled(cp);
+ cp->spoiled = 0;
+ }
+ cp = cp2;
+ }
+ break;
+ case EV_LAST:
+ default:
+ KASSERT(1 == 0, ("Unknown event %d", ep->event));
+ }
+}
+
+static int
+one_event(struct thread *tp)
+{
+ struct g_event *ep;
+ struct g_provider *pp;
+
+ g_topology_lock();
+ for (;;) {
+ mtx_lock(&g_doorlock);
+ pp = TAILQ_FIRST(&g_doorstep);
+ if (pp != NULL)
+ TAILQ_REMOVE(&g_doorstep, pp, orphan);
+ mtx_unlock(&g_doorlock);
+ if (pp == NULL)
+ break;
+ g_orphan_register(pp, tp);
+ }
+ ep = TAILQ_FIRST(&g_events);
+ if (ep == NULL) {
+ g_topology_unlock();
+ return (0);
+ }
+ TAILQ_REMOVE(&g_events, ep, events);
+ if (ep->method != NULL)
+ ep->method->event = NULL;
+ if (ep->geom != NULL)
+ ep->geom->event = NULL;
+ if (ep->provider != NULL)
+ ep->provider->event = NULL;
+ if (ep->consumer != NULL)
+ ep->consumer->event = NULL;
+ g_do_event(ep, tp);
+ g_pending_events--;
+ if (g_pending_events == 0) {
+ mtx_lock(&Giant);
+ wakeup(&g_pending_events);
+ mtx_unlock(&Giant);
+ }
+ g_topology_unlock();
+ g_destroy_event(ep);
+ return (1);
+}
+
+void
+g_run_events(struct thread *tp)
+{
+
+ while (one_event(tp))
+ ;
+}
+
+void
+g_post_event(enum g_events ev, struct g_method *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp)
+{
+ struct g_event *ep;
+
+ g_trace(G_T_TOPOLOGY, "g_post_event(%d, %p, %p, %p, %p)",
+ ev, mp, gp, pp, cp);
+ g_topology_assert();
+ ep = g_malloc(sizeof *ep, M_WAITOK | M_ZERO);
+ ep->event = ev;
+ if (mp != NULL) {
+ ep->method = mp;
+ KASSERT(mp->event == NULL, ("Double event on method"));
+ mp->event = ep;
+ }
+ if (gp != NULL) {
+ ep->geom = gp;
+ KASSERT(gp->event == NULL, ("Double event on geom"));
+ gp->event = ep;
+ }
+ if (pp != NULL) {
+ ep->provider = pp;
+ KASSERT(pp->event == NULL, ("Double event on provider"));
+ pp->event = ep;
+ }
+ if (cp != NULL) {
+ ep->consumer = cp;
+ KASSERT(cp->event == NULL, ("Double event on consumer"));
+ cp->event = ep;
+ }
+ g_pending_events++;
+ TAILQ_INSERT_TAIL(&g_events, ep, events);
+ mtx_lock(&Giant);
+ wakeup(&g_wait_event);
+ mtx_unlock(&Giant);
+}
+
+void
+g_event_init()
+{
+
+ mtx_init(&g_doorlock, "GEOM orphanage", MTX_DEF);
+}
diff --git a/sys/geom/geom_io.c b/sys/geom/geom_io.c
new file mode 100644
index 0000000..c43e568
--- /dev/null
+++ b/sys/geom/geom_io.c
@@ -0,0 +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.
+ *
+ * $FreeBSD$
+ */
+
+
+#include <sys/param.h>
+#ifndef _KERNEL
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <err.h>
+#include <sched.h>
+#else
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bio.h>
+#endif
+
+#include <sys/errno.h>
+#include <geom/geom.h>
+
+static struct g_bioq g_bio_run_down;
+static struct g_bioq g_bio_run_up;
+static struct g_bioq g_bio_idle;
+
+#include <machine/atomic.h>
+
+static void
+g_bioq_lock(struct g_bioq *bq)
+{
+
+ mtx_lock(&bq->bio_queue_lock);
+}
+
+static void
+g_bioq_unlock(struct g_bioq *bq)
+{
+
+ mtx_unlock(&bq->bio_queue_lock);
+}
+
+#if 0
+static void
+g_bioq_destroy(struct g_bioq *bq)
+{
+
+ mtx_destroy(&bq->bio_queue_lock);
+}
+#endif
+
+static void
+g_bioq_init(struct g_bioq *bq)
+{
+
+ TAILQ_INIT(&bq->bio_queue);
+ mtx_init(&bq->bio_queue_lock, "bio queue", MTX_DEF);
+}
+
+static struct bio *
+g_bioq_first(struct g_bioq *bq)
+{
+ struct bio *bp;
+
+ g_bioq_lock(bq);
+ bp = TAILQ_FIRST(&bq->bio_queue);
+ if (bp != NULL) {
+ TAILQ_REMOVE(&bq->bio_queue, bp, bio_queue);
+ bq->bio_queue_length--;
+ }
+ g_bioq_unlock(bq);
+ return (bp);
+}
+
+static void
+g_bioq_enqueue_tail(struct bio *bp, struct g_bioq *rq)
+{
+
+ g_bioq_lock(rq);
+ TAILQ_INSERT_TAIL(&rq->bio_queue, bp, bio_queue);
+ rq->bio_queue_length++;
+ g_bioq_unlock(rq);
+}
+
+struct bio *
+g_new_bio(void)
+{
+ struct bio *bp;
+
+ bp = g_bioq_first(&g_bio_idle);
+ if (bp == NULL)
+ bp = g_malloc(sizeof *bp, M_WAITOK | M_ZERO);
+ g_trace(G_T_BIO, "g_new_bio() = %p", bp);
+ return (bp);
+}
+
+void
+g_destroy_bio(struct bio *bp)
+{
+
+ g_trace(G_T_BIO, "g_destroy_bio(%p)", bp);
+ bzero(bp, sizeof *bp);
+ g_bioq_enqueue_tail(bp, &g_bio_idle);
+}
+
+struct bio *
+g_clone_bio(struct bio *bp)
+{
+ struct bio *bp2;
+
+ bp2 = g_new_bio();
+ bp2->bio_linkage = bp;
+ bp2->bio_cmd = bp->bio_cmd;
+ bp2->bio_length = bp->bio_length;
+ bp2->bio_offset = bp->bio_offset;
+ bp2->bio_data = bp->bio_data;
+ bp2->bio_attribute = bp->bio_attribute;
+ g_trace(G_T_BIO, "g_clone_bio(%p) = %p", bp, bp2);
+ return(bp2);
+}
+
+void
+g_io_init()
+{
+
+ g_bioq_init(&g_bio_run_down);
+ g_bioq_init(&g_bio_run_up);
+ g_bioq_init(&g_bio_idle);
+}
+
+int
+g_io_setattr(char *attr, struct g_consumer *cp, int len, void *ptr, struct thread *tp __unused)
+{
+ struct bio *bp;
+ int error;
+
+ g_trace(G_T_BIO, "bio_setattr(%s)", attr);
+ do {
+ bp = g_new_bio();
+ bp->bio_cmd = BIO_SETATTR;
+ bp->bio_done = NULL;
+ bp->bio_attribute = attr;
+ bp->bio_length = len;
+ bp->bio_data = ptr;
+ g_io_request(bp, cp);
+ while ((bp->bio_flags & BIO_DONE) == 0) {
+ mtx_lock(&Giant);
+ tsleep(bp, 0, "setattr", hz / 10);
+ mtx_unlock(&Giant);
+ }
+ error = bp->bio_error;
+ g_destroy_bio(bp);
+ if (error == EBUSY)
+ tsleep(&error, 0, "setattr_busy", hz);
+ } while(error == EBUSY);
+ return (error);
+}
+
+
+int
+g_io_getattr(char *attr, struct g_consumer *cp, int *len, void *ptr, struct thread *tp __unused)
+{
+ struct bio *bp;
+ int error;
+
+ g_trace(G_T_BIO, "bio_getattr(%s)", attr);
+ do {
+ bp = g_new_bio();
+ bp->bio_cmd = BIO_GETATTR;
+ bp->bio_done = NULL;
+ bp->bio_attribute = attr;
+ bp->bio_length = *len;
+ bp->bio_data = ptr;
+ g_io_request(bp, cp);
+ while ((bp->bio_flags & BIO_DONE) == 0) {
+ mtx_lock(&Giant);
+ tsleep(bp, 0, "getattr", hz / 10);
+ mtx_unlock(&Giant);
+ }
+ *len = bp->bio_completed;
+ error = bp->bio_error;
+ g_destroy_bio(bp);
+ if (error == EBUSY)
+ tsleep(&error, 0, "getattr_busy", hz);
+
+ } while(error == EBUSY);
+ return (error);
+}
+
+void
+g_io_request(struct bio *bp, struct g_consumer *cp)
+{
+ int error;
+
+ KASSERT(cp != NULL, ("bio_request on thin air"));
+ error = 0;
+ bp->bio_from = cp;
+ bp->bio_to = cp->provider;
+
+ /* begin_stats(&bp->stats); */
+
+ atomic_add_int(&cp->biocount, 1);
+ if (bp->bio_to == NULL)
+ error = ENXIO;
+ if (!error) {
+ switch(bp->bio_cmd) {
+ case BIO_READ:
+ case BIO_GETATTR:
+ if (cp->acr == 0)
+ error = EPERM;
+ break;
+ case BIO_WRITE:
+ if (cp->acw == 0)
+ error = EPERM;
+ break;
+ case BIO_SETATTR:
+ case BIO_DELETE:
+ case BIO_FORMAT:
+ if ((cp->acw == 0) || (cp->ace == 0))
+ error = EPERM;
+ break;
+ default:
+ error = EPERM;
+ break;
+ }
+ }
+ /* if provider is marked for error, don't disturb */
+ if (!error)
+ error = bp->bio_to->error;
+ if (error) {
+ bp->bio_error = error;
+ /* finish_stats(&bp->stats); */
+
+ g_trace(G_T_BIO,
+ "bio_request(%p) from %p(%s) to %p(%s) cmd %d error %d\n",
+ bp, bp->bio_from, bp->bio_from->geom->name,
+ bp->bio_to, bp->bio_to->name, bp->bio_cmd, bp->bio_error);
+ g_bioq_enqueue_tail(bp, &g_bio_run_up);
+ mtx_lock(&Giant);
+ wakeup(&g_wait_up);
+ mtx_unlock(&Giant);
+ } else {
+ g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d",
+ bp, bp->bio_from, bp->bio_from->geom->name,
+ bp->bio_to, bp->bio_to->name, bp->bio_cmd);
+ g_bioq_enqueue_tail(bp, &g_bio_run_down);
+ mtx_lock(&Giant);
+ wakeup(&g_wait_down);
+ mtx_unlock(&Giant);
+ }
+}
+
+void
+g_io_deliver(struct bio *bp)
+{
+
+ g_trace(G_T_BIO,
+ "g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d",
+ bp, bp->bio_from, bp->bio_from->geom->name,
+ bp->bio_to, bp->bio_to->name, bp->bio_cmd, bp->bio_error);
+ /* finish_stats(&bp->stats); */
+
+ g_bioq_enqueue_tail(bp, &g_bio_run_up);
+
+ mtx_lock(&Giant);
+ wakeup(&g_wait_up);
+ mtx_unlock(&Giant);
+}
+
+void
+g_io_schedule_down(struct thread *tp __unused)
+{
+ struct bio *bp;
+
+ for(;;) {
+ bp = g_bioq_first(&g_bio_run_down);
+ if (bp == NULL)
+ break;
+ bp->bio_to->geom->start(bp);
+ }
+}
+
+void
+g_io_schedule_up(struct thread *tp __unused)
+{
+ struct bio *bp;
+ struct g_consumer *cp;
+
+ for(;;) {
+ bp = g_bioq_first(&g_bio_run_up);
+ if (bp == NULL)
+ break;
+
+ cp = bp->bio_from;
+
+ bp->bio_flags |= BIO_DONE;
+ atomic_add_int(&cp->biocount, -1);
+ if (bp->bio_done != NULL) {
+ bp->bio_done(bp);
+ } else {
+ mtx_lock(&Giant);
+ wakeup(bp);
+ mtx_unlock(&Giant);
+ }
+ }
+}
+
+void *
+g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error)
+{
+ struct bio *bp;
+ void *ptr;
+ int errorc;
+
+ do {
+ bp = g_new_bio();
+ bp->bio_cmd = BIO_READ;
+ bp->bio_done = NULL;
+ bp->bio_offset = offset;
+ bp->bio_length = length;
+ ptr = g_malloc(length, M_WAITOK);
+ bp->bio_data = ptr;
+ g_io_request(bp, cp);
+ while ((bp->bio_flags & BIO_DONE) == 0) {
+ mtx_lock(&Giant);
+ tsleep(bp, 0, "g_read_data", hz / 10);
+ mtx_unlock(&Giant);
+ }
+ errorc = bp->bio_error;
+ if (error != NULL)
+ *error = errorc;
+ g_destroy_bio(bp);
+ if (errorc) {
+ g_free(ptr);
+ ptr = NULL;
+ }
+ if (errorc == EBUSY)
+ tsleep(&errorc, 0, "g_read_data_busy", hz);
+ } while (errorc == EBUSY);
+ return (ptr);
+}
diff --git a/sys/geom/geom_kern.c b/sys/geom/geom_kern.c
new file mode 100644
index 0000000..e25ac01
--- /dev/null
+++ b/sys/geom/geom_kern.c
@@ -0,0 +1,192 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bio.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sx.h>
+#include <sys/sbuf.h>
+#include <sys/errno.h>
+#include <geom/geom.h>
+
+MALLOC_DEFINE(M_GEOM, "GEOM", "Geom data structures");
+
+struct sx topology_lock;
+
+static struct proc *g_up_proc;
+
+int g_debugflags;
+
+static void
+g_up_procbody(void)
+{
+ struct proc *p = g_up_proc;
+ struct thread *tp = &p->p_xxthread;
+
+ curthread->td_base_pri = PRIBIO;
+ for(;;) {
+ g_io_schedule_up(tp);
+ mtx_lock(&Giant);
+ tsleep(&g_wait_up, PRIBIO, "g_up", hz/10);
+ mtx_unlock(&Giant);
+ }
+}
+
+struct kproc_desc g_up_kp = {
+ "g_up",
+ g_up_procbody,
+ &g_up_proc,
+};
+
+static struct proc *g_down_proc;
+
+static void
+g_down_procbody(void)
+{
+ struct proc *p = g_down_proc;
+ struct thread *tp = &p->p_xxthread;
+
+ curthread->td_base_pri = PRIBIO;
+ for(;;) {
+ g_io_schedule_down(tp);
+ mtx_lock(&Giant);
+ tsleep(&g_wait_down, PRIBIO, "g_down", hz/10);
+ mtx_unlock(&Giant);
+ }
+}
+
+struct kproc_desc g_down_kp = {
+ "g_down",
+ g_down_procbody,
+ &g_down_proc,
+};
+
+static struct proc *g_event_proc;
+
+static void
+g_event_procbody(void)
+{
+ struct proc *p = g_event_proc;
+ struct thread *tp = &p->p_xxthread;
+
+ curthread->td_base_pri = PRIBIO;
+ for(;;) {
+ g_run_events(tp);
+ mtx_lock(&Giant);
+ tsleep(&g_wait_event, PRIBIO, "g_events", hz/10);
+ mtx_unlock(&Giant);
+ }
+}
+
+struct kproc_desc g_event_kp = {
+ "g_event",
+ g_event_procbody,
+ &g_event_proc,
+};
+
+void
+g_init(void)
+{
+ printf("Initializing GEOMetry subsystem\n");
+ if (bootverbose)
+ g_debugflags |= G_T_TOPOLOGY;
+ sx_init(&topology_lock, "GEOM topology");
+ g_io_init();
+ g_event_init();
+ mtx_lock(&Giant);
+ kproc_start(&g_event_kp);
+ kproc_start(&g_up_kp);
+ kproc_start(&g_down_kp);
+ mtx_unlock(&Giant);
+}
+
+static int
+sysctl_debug_geomdot(SYSCTL_HANDLER_ARGS)
+{
+ int i, error;
+ struct sbuf *sb;
+
+ i = 0;
+ sb = g_confdot();
+ error = sysctl_handle_opaque(oidp, sbuf_data(sb), sbuf_len(sb), req);
+ sbuf_delete(sb);
+ return (error);
+}
+
+SYSCTL_PROC(_debug, OID_AUTO, geomdot, CTLTYPE_STRING|CTLFLAG_RD,
+ 0, 0, sysctl_debug_geomdot, "A",
+ "Dump the GEOM config");
+
+static int
+sysctl_debug_geomconf(SYSCTL_HANDLER_ARGS)
+{
+ int i, error;
+ struct sbuf *sb;
+
+ i = 0;
+ sb = g_conf();
+ error = sysctl_handle_opaque(oidp, sbuf_data(sb), sbuf_len(sb), req);
+ sbuf_delete(sb);
+ return (error);
+}
+
+SYSCTL_PROC(_debug, OID_AUTO, geomconf, CTLTYPE_STRING|CTLFLAG_RD,
+ 0, 0, sysctl_debug_geomconf, "A",
+ "Dump the GEOM config");
+
+SYSCTL_INT(_debug, OID_AUTO, geomdebugflags, CTLTYPE_INT|CTLFLAG_RW,
+ &g_debugflags, 0, "");
+
+SYSCTL_INT(_debug_sizeof, OID_AUTO, g_method, CTLTYPE_INT|CTLFLAG_RD,
+ 0, sizeof(struct g_method), "");
+SYSCTL_INT(_debug_sizeof, OID_AUTO, g_geom, CTLTYPE_INT|CTLFLAG_RD,
+ 0, sizeof(struct g_geom), "");
+SYSCTL_INT(_debug_sizeof, OID_AUTO, g_provider, CTLTYPE_INT|CTLFLAG_RD,
+ 0, sizeof(struct g_provider), "");
+SYSCTL_INT(_debug_sizeof, OID_AUTO, g_consumer, CTLTYPE_INT|CTLFLAG_RD,
+ 0, sizeof(struct g_consumer), "");
+SYSCTL_INT(_debug_sizeof, OID_AUTO, g_bioq, CTLTYPE_INT|CTLFLAG_RD,
+ 0, sizeof(struct g_bioq), "");
+SYSCTL_INT(_debug_sizeof, OID_AUTO, g_event, CTLTYPE_INT|CTLFLAG_RD,
+ 0, sizeof(struct g_event), "");
diff --git a/sys/geom/geom_mbr.c b/sys/geom/geom_mbr.c
new file mode 100644
index 0000000..17788f3
--- /dev/null
+++ b/sys/geom/geom_mbr.c
@@ -0,0 +1,211 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+
+#include <sys/param.h>
+#ifndef _KERNEL
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <err.h>
+#else
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bio.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#endif
+
+#include <sys/errno.h>
+#include <sys/disklabel.h>
+#include <sys/sbuf.h>
+#include <geom/geom.h>
+#include <geom/geom_slice.h>
+
+#define MBR_METHOD_NAME "MBR-method"
+
+struct g_mbr_softc {
+ int type [NDOSPART];
+ struct dos_partition dospart[NDOSPART];
+};
+
+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 index;
+
+ pp = bp->bio_to;
+ index = pp->index;
+ gp = pp->geom;
+ gsp = gp->softc;
+ mp = gsp->softc;
+ if (bp->bio_cmd == BIO_GETATTR) {
+ if (g_haveattr_int(bp, "MBR::type", mp->type[index]))
+ return (1);
+ }
+ return (0);
+}
+
+static void
+g_mbr_dumpconf(struct sbuf *sb, char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp)
+{
+ struct g_mbr_softc *mp;
+ struct g_slicer *gsp;
+
+ g_slice_dumpconf(sb, indent, gp, cp, pp);
+ gsp = gp->softc;
+ mp = gsp->softc;
+ if (pp != NULL) {
+ sbuf_printf(sb, "%s<type>%d</type>\n",
+ indent, mp->type[pp->index]);
+ }
+}
+
+
+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 __unused, struct dos_partition *dp __unused)
+{
+
+#if 0
+ g_hexdump(dp, sizeof(dp[0]));
+ printf("[%d] f:%02x typ:%d", i, dp->dp_flag, dp->dp_typ);
+ printf(" s(CHS):%d/%d/%d", dp->dp_scyl, dp->dp_shd, dp->dp_ssect);
+ printf(" e(CHS):%d/%d/%d", dp->dp_ecyl, dp->dp_ehd, dp->dp_esect);
+ printf(" s:%d l:%d\n", dp->dp_start, dp->dp_size);
+#endif
+}
+
+static struct g_geom *
+g_mbr_taste(struct g_method *mp, struct g_provider *pp, struct thread *tp, int insist)
+{
+ struct g_geom *gp;
+ struct g_consumer *cp;
+ struct g_provider *pp2;
+ int error, i, j, npart;
+ struct dos_partition dp[NDOSPART];
+ struct g_mbr_softc *ms;
+ u_char *buf;
+
+ g_trace(G_T_TOPOLOGY, "mbr_taste(%s,%s)", mp->name, pp->name);
+ g_topology_assert();
+ gp = g_slice_new(mp, NDOSPART, pp, &cp, &ms, sizeof *ms, g_mbr_start);
+ if (gp == NULL)
+ return (NULL);
+ g_topology_unlock();
+ gp->dumpconf = g_mbr_dumpconf;
+ npart = 0;
+ while (1) { /* a trick to allow us to use break */
+ if (gp->rank != 2 && insist == 0)
+ break;
+ j = sizeof i;
+ /* For now we only support 512 bytes sectors */
+ error = g_io_getattr("GEOM::sectorsize", cp, &j, &i, tp);
+ if (!error && i != 512)
+ break;
+ buf = g_read_data(cp, 0, 512, &error);
+ if (buf == NULL || error != 0)
+ break;
+ if (buf[0x1fe] != 0x55 && buf[0x1ff] != 0xaa) {
+ g_free(buf);
+ break;
+ }
+ bcopy(buf + DOSPARTOFF, dp, sizeof(dp));
+ g_free(buf);
+ if (bcmp(dp, historical_bogus_partition_table,
+ sizeof historical_bogus_partition_table) == 0)
+ break;
+ if (bcmp(dp, historical_bogus_partition_table_fixed,
+ sizeof historical_bogus_partition_table_fixed) == 0)
+ break;
+ npart = 0;
+ for (i = 0; i < NDOSPART; i++) {
+ if (dp[i].dp_flag != 0 && dp[i].dp_flag != 0x80)
+ continue;
+ if (dp[i].dp_size == 0)
+ continue;
+ g_mbr_print(i, dp + i);
+ npart++;
+ ms->type[i] = dp[i].dp_typ;
+ pp2 = g_slice_addslice(gp, i,
+ ((off_t)dp[i].dp_start) << 9ULL,
+ ((off_t)dp[i].dp_size) << 9ULL,
+ "%ss%d", gp->name, i + 1);
+ }
+ break;
+ }
+ g_topology_lock();
+ error = g_access_rel(cp, -1, 0, 0);
+ if (npart > 0) {
+ LIST_FOREACH(pp, &gp->provider, provider)
+ g_error_provider(pp, 0);
+ return (gp);
+ }
+ g_std_spoiled(cp);
+ return (NULL);
+}
+
+
+static struct g_method g_mbr_method = {
+ MBR_METHOD_NAME,
+ g_mbr_taste,
+ g_slice_access,
+ g_slice_orphan,
+ NULL,
+ G_METHOD_INITSTUFF
+};
+
+DECLARE_GEOM_METHOD(g_mbr_method, g_mbr);
diff --git a/sys/geom/geom_mbrext.c b/sys/geom/geom_mbrext.c
new file mode 100644
index 0000000..ada6d23
--- /dev/null
+++ b/sys/geom/geom_mbrext.c
@@ -0,0 +1,200 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _KERNEL
+
+#include <sys/param.h>
+#ifndef _KERNEL
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <err.h>
+#else
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bio.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#endif
+
+#include <sys/errno.h>
+#include <sys/disklabel.h>
+#include <sys/sbuf.h>
+#include <geom/geom.h>
+#include <geom/geom_slice.h>
+
+#define MBR_METHOD_NAME "MBR-method"
+#define MBREXT_METHOD_NAME "MBREXT-method"
+
+#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 index;
+
+ pp = bp->bio_to;
+ index = pp->index;
+ gp = pp->geom;
+ gsp = gp->softc;
+ mp = gsp->softc;
+ if (bp->bio_cmd == BIO_GETATTR) {
+ if (g_haveattr_int(bp, "MBR::type", mp->type[index]))
+ return (1);
+ }
+ return (0);
+}
+
+static void
+g_mbrext_dumpconf(struct sbuf *sb, 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) {
+ sbuf_printf(sb, "%s<type>%d</type>\n",
+ indent, mp->type[pp->index]);
+ }
+}
+
+static void
+g_mbrext_print(int i, struct dos_partition *dp)
+{
+ g_hexdump(dp, sizeof(dp[0]));
+ printf("[%d] f:%02x typ:%d", i, dp->dp_flag, dp->dp_typ);
+ printf(" s(CHS):%d/%d/%d", dp->dp_scyl, dp->dp_shd, dp->dp_ssect);
+ printf(" e(CHS):%d/%d/%d", dp->dp_ecyl, dp->dp_ehd, dp->dp_esect);
+ printf(" s:%d l:%d\n", dp->dp_start, dp->dp_size);
+}
+
+static struct g_geom *
+g_mbrext_taste(struct g_method *mp, struct g_provider *pp, struct thread *tp __unused, int insist __unused)
+{
+ struct g_geom *gp;
+ struct g_consumer *cp;
+ struct g_provider *pp2;
+ int error, i, j, slice;
+ struct g_mbrext_softc *ms;
+ off_t off;
+ u_char *buf;
+ struct dos_partition dp[4];
+
+ g_trace(G_T_TOPOLOGY, "g_mbrext_taste(%s,%s)", mp->name, pp->name);
+ g_topology_assert();
+ if (strcmp(pp->geom->method->name, MBR_METHOD_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();
+ gp->dumpconf = g_mbrext_dumpconf;
+ off = 0;
+ slice = 0;
+ while (1) { /* a trick to allow us to use break */
+ j = sizeof i;
+ error = g_io_getattr("MBR::type", cp, &j, &i, tp);
+ if (error || i != DOSPTYP_EXT)
+ break;
+ for (;;) {
+ buf = g_read_data(cp, off, DEV_BSIZE, &error);
+ if (buf == NULL || error != 0)
+ break;
+ if (buf[0x1fe] != 0x55 && buf[0x1ff] != 0xaa)
+ break;
+ bcopy(buf + DOSPARTOFF, dp, sizeof(dp));
+ g_free(buf);
+ g_mbrext_print(0, dp);
+ g_mbrext_print(1, dp + 1);
+ if (dp[0].dp_flag == 0 && dp[0].dp_size != 0) {
+ pp2 = g_slice_addslice(gp, slice,
+ (((off_t)dp[0].dp_start) << 9ULL) + off,
+ ((off_t)dp[0].dp_size) << 9ULL,
+ "%*.*s%d",
+ strlen(gp->name) - 1,
+ strlen(gp->name) - 1,
+ gp->name,
+ slice + 5);
+ ms->type[slice] = dp[0].dp_typ;
+ slice++;
+ g_error_provider(pp2, 0);
+ }
+ if (dp[1].dp_flag != 0)
+ break;
+ if (dp[1].dp_typ != DOSPTYP_EXT)
+ break;
+ if (dp[1].dp_size == 0)
+ break;
+ off = ((off_t)dp[1].dp_start) << 9ULL;
+ }
+ break;
+ }
+ g_topology_lock();
+ error = g_access_rel(cp, -1, 0, 0);
+ if (slice > 0)
+ return (gp);
+
+ g_topology_assert();
+ g_std_spoiled(cp);
+ g_topology_assert();
+ return (NULL);
+}
+
+
+static struct g_method g_mbrext_method = {
+ MBREXT_METHOD_NAME,
+ g_mbrext_taste,
+ g_slice_access,
+ g_slice_orphan,
+ NULL,
+ G_METHOD_INITSTUFF
+};
+
+DECLARE_GEOM_METHOD(g_mbrext_method, g_mbrext);
+#endif
diff --git a/sys/geom/geom_slice.c b/sys/geom/geom_slice.c
new file mode 100644
index 0000000..36b0bd4
--- /dev/null
+++ b/sys/geom/geom_slice.c
@@ -0,0 +1,278 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+
+#include <sys/param.h>
+#ifndef _KERNEL
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <err.h>
+#else
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bio.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#endif
+#include <sys/errno.h>
+#include <sys/sbuf.h>
+#include <geom/geom.h>
+#include <geom/geom_slice.h>
+#include <machine/stdarg.h>
+
+struct g_slicer *
+g_slice_init(unsigned nslice, unsigned scsize)
+{
+ struct g_slicer *gsp;
+
+ gsp = g_malloc(sizeof *gsp + nslice * sizeof(struct g_slice) + scsize,
+ M_WAITOK | M_ZERO);
+ gsp->softc = gsp + 1;
+ gsp->slices = (struct g_slice *)((u_char *)gsp->softc + scsize);
+ gsp->nslice = nslice;
+ return (gsp);
+}
+
+int
+g_slice_access(struct g_provider *pp, int dr, int dw, int de)
+{
+ int error, i;
+ struct g_geom *gp;
+ struct g_consumer *cp;
+ struct g_provider *pp2;
+ struct g_slicer *gsp;
+ struct g_slice *gsl, *gsl2;
+
+ gp = pp->geom;
+ cp = LIST_FIRST(&gp->consumer);
+ KASSERT (cp != NULL, ("g_slice_access but no consumer"));
+ gsp = gp->softc;
+ gsl = &gsp->slices[pp->index];
+ for (i = 0; i < gsp->nslice; i++) {
+ gsl2 = &gsp->slices[i];
+ if (gsl2->length == 0)
+ continue;
+ if (i == pp->index)
+ continue;
+ if (gsl->offset + gsl->length <= gsl2->offset)
+ continue;
+ if (gsl2->offset + gsl2->length <= gsl->offset)
+ continue;
+ /* overlap */
+ pp2 = gsl2->provider;
+ if ((pp->acw + dw) > 0 && pp2->ace > 0)
+ return (EPERM);
+ if ((pp->ace + de) > 0 && pp2->acw > 0)
+ return (EPERM);
+ }
+ /* 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--;
+ error = g_access_rel(cp, dr, dw, de);
+ return (error);
+}
+
+void
+g_slice_start(struct bio *bp)
+{
+ struct bio *bp2;
+ struct g_provider *pp;
+ struct g_geom *gp;
+ struct g_consumer *cp;
+ struct g_slicer *gsp;
+ struct g_slice *gsl;
+ int index;
+
+ pp = bp->bio_to;
+ gp = pp->geom;
+ gsp = gp->softc;
+ cp = LIST_FIRST(&gp->consumer);
+ index = pp->index;
+ switch(bp->bio_cmd) {
+ case BIO_READ:
+ case BIO_WRITE:
+ case BIO_DELETE:
+ gsl = &gsp->slices[index];
+ if (bp->bio_offset > gsl->length) {
+ bp->bio_error = EINVAL; /* XXX: EWHAT ? */
+ g_io_deliver(bp);
+ return;
+ }
+ bp2 = g_clone_bio(bp);
+ if (bp2->bio_offset + bp2->bio_length > gsl->length)
+ bp2->bio_length = gsl->length - bp2->bio_offset;
+ bp2->bio_done = g_std_done;
+ bp2->bio_offset += gsl->offset;
+ g_io_request(bp2, cp);
+ return;
+ case BIO_GETATTR:
+ case BIO_SETATTR:
+ if (g_haveattr_off_t(bp, "GEOM::mediasize",
+ gsp->slices[index].length))
+ return;
+ if (gsp->start(bp))
+ return;
+ bp2 = g_clone_bio(bp);
+ bp2->bio_done = g_std_done;
+ g_io_request(bp2, cp);
+ break;
+ default:
+ bp->bio_error = EOPNOTSUPP;
+ g_io_deliver(bp);
+ return;
+ }
+}
+
+void
+g_slice_dumpconf(struct sbuf *sb, 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;
+ if (pp != NULL) {
+ sbuf_printf(sb, "%s<index>%u</index>\n", indent, pp->index);
+ sbuf_printf(sb, "%s<length>%llu</length>\n",
+ indent, gsp->slices[pp->index].length);
+ sbuf_printf(sb, "%s<seclength>%llu</seclength>\n",
+ indent, gsp->slices[pp->index].length / 512);
+ sbuf_printf(sb, "%s<offset>%llu</offset>\n",
+ indent, gsp->slices[pp->index].offset);
+ sbuf_printf(sb, "%s<secoffset>%llu</secoffset>\n",
+ indent, gsp->slices[pp->index].offset / 512);
+ }
+}
+
+struct g_provider *
+g_slice_addslice(struct g_geom *gp, int index, off_t offset, off_t length, char *fmt, ...)
+{
+ struct g_provider *pp;
+ struct g_slicer *gsp;
+ va_list ap;
+ struct sbuf *sb;
+
+ g_trace(G_T_TOPOLOGY, "g_slice_addslice()");
+ g_topology_lock();
+ gsp = gp->softc;
+ va_start(ap, fmt);
+ sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ sbuf_vprintf(sb, fmt, ap);
+ sbuf_finish(sb);
+ pp = g_new_providerf(gp, sbuf_data(sb));
+
+ pp->index = index;
+ gsp->slices[index].length = length;
+ gsp->slices[index].offset = offset;
+ gsp->slices[index].provider = pp;
+ sbuf_delete(sb);
+ g_topology_unlock();
+ return(pp);
+}
+
+struct g_geom *
+g_slice_new(struct g_method *mp, int slices, struct g_provider *pp, struct g_consumer **cpp, void *extrap, int extra, g_slice_start_t *start)
+{
+ struct g_geom *gp;
+ struct g_slicer *gsp;
+ struct g_consumer *cp;
+ void **vp;
+ int error;
+
+ g_topology_assert();
+ vp = (void **)extrap;
+ gp = g_new_geomf(mp, "%s", pp->name);
+ gsp = g_slice_init(slices, extra);
+ gsp->start = start;
+ gp->softc = gsp;
+ gp->start = g_slice_start;
+ gp->spoiled = g_std_spoiled;
+ gp->dumpconf = g_slice_dumpconf;
+ cp = g_new_consumer(gp);
+ g_attach(cp, pp);
+ error = g_access_rel(cp, 1, 0, 0);
+ if (error) {
+ g_dettach(cp);
+ g_destroy_consumer(cp);
+ g_free(gp->softc);
+ g_destroy_geom(gp);
+ return (NULL);
+ }
+ *vp = gsp->softc;
+ *cpp = cp;
+ return (gp);
+}
+
+void
+g_slice_orphan(struct g_consumer *cp, struct thread *tp __unused)
+{
+ struct g_geom *gp;
+ struct g_provider *pp;
+ int error;
+
+ g_trace(G_T_TOPOLOGY, "g_slice_orphan(%p/%s)", cp, cp->provider->name);
+ g_topology_assert();
+ KASSERT(cp->provider->error != 0,
+ ("g_slice_orphan with error == 0"));
+
+ gp = cp->geom;
+ gp->flags |= G_GEOM_WITHER;
+ /* First prevent any new requests */
+ error = cp->provider->error;
+ LIST_FOREACH(pp, &gp->provider, provider)
+ g_orphan_provider(pp, error);
+
+ return;
+ if (cp->biocount > 0)
+ return;
+
+ /* Then selfdestruct */
+ if (cp->acr != 0 || cp->acw != 0 || cp->ace != 0)
+ g_access_abs(cp, 0, 0, 0);
+ g_dettach(cp);
+ g_destroy_consumer(cp);
+ return;
+}
diff --git a/sys/geom/geom_slice.h b/sys/geom/geom_slice.h
new file mode 100644
index 0000000..4ef484e
--- /dev/null
+++ b/sys/geom/geom_slice.h
@@ -0,0 +1,60 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+struct g_slice {
+ off_t offset;
+ off_t length;
+ struct g_provider *provider;
+};
+
+typedef int g_slice_start_t (struct bio *bp);
+
+struct g_slicer {
+ int nslice;
+ struct g_slice *slices;
+ void *softc;
+ g_slice_start_t *start;
+};
+
+void g_slice_orphan(struct g_consumer *cp, struct thread *tp);
+struct g_slicer * g_slice_init(unsigned nslice, unsigned scsize);
+int g_slice_access(struct g_provider *pp, int dr, int dw, int de);
+void g_slice_start(struct bio *bp);
+void g_slice_dumpconf(struct sbuf *sb, char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp);
+struct g_provider * g_slice_addslice(struct g_geom *gp, int index, off_t offset, off_t length, char *fmt, ...);
+struct g_geom * g_slice_new(struct g_method *mp, int slices, struct g_provider *pp, struct g_consumer **cpp, void *extrap, int extra, g_slice_start_t *start);
+
diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c
new file mode 100644
index 0000000..a458550
--- /dev/null
+++ b/sys/geom/geom_subr.c
@@ -0,0 +1,639 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+
+#include <sys/param.h>
+#ifndef _KERNEL
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <err.h>
+#else
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bio.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#endif
+#include <sys/errno.h>
+#include <sys/sbuf.h>
+#include <geom/geom.h>
+#include <machine/stdarg.h>
+
+struct method_list_head g_methods = LIST_HEAD_INITIALIZER(g_methods);
+static struct g_tailq_head geoms = TAILQ_HEAD_INITIALIZER(geoms);
+static int g_nproviders;
+char *g_wait_event, *g_wait_up, *g_wait_down, *g_wait_sim;
+
+static int g_ignition;
+
+void
+g_add_method(struct g_method *mp)
+{
+
+ if (!g_ignition) {
+ g_ignition++;
+ g_init();
+ }
+ g_topology_lock();
+ g_trace(G_T_TOPOLOGY, "g_add_method(%s)", mp->name);
+ LIST_INIT(&mp->geom);
+ LIST_INSERT_HEAD(&g_methods, mp, method);
+ if (g_nproviders > 0)
+ g_post_event(EV_NEW_METHOD, mp, NULL, NULL, NULL);
+ g_topology_unlock();
+}
+
+struct g_geom *
+g_new_geomf(struct g_method *mp, char *fmt, ...)
+{
+ struct g_geom *gp;
+ va_list ap;
+ struct sbuf *sb;
+
+ g_topology_assert();
+ va_start(ap, fmt);
+ mtx_lock(&Giant);
+ sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ sbuf_vprintf(sb, fmt, ap);
+ sbuf_finish(sb);
+ mtx_unlock(&Giant);
+ gp = g_malloc(sizeof *gp + sbuf_len(sb) + 1, M_WAITOK | M_ZERO);
+ gp->name = (char *)(gp + 1);
+ gp->method = mp;
+ gp->rank = 1;
+ LIST_INIT(&gp->consumer);
+ LIST_INIT(&gp->provider);
+ LIST_INSERT_HEAD(&mp->geom, gp, geom);
+ TAILQ_INSERT_HEAD(&geoms, gp, geoms);
+ strcpy(gp->name, sbuf_data(sb));
+ sbuf_delete(sb);
+ return (gp);
+}
+
+void
+g_destroy_geom(struct g_geom *gp)
+{
+
+ g_trace(G_T_TOPOLOGY, "g_destroy_geom(%p(%s))", gp, gp->name);
+ g_topology_assert();
+ KASSERT(gp->event == NULL, ("g_destroy_geom() with event"));
+ KASSERT(LIST_EMPTY(&gp->consumer),
+ ("g_destroy_geom(%s) with consumer(s) [%p]",
+ gp->name, LIST_FIRST(&gp->consumer)));
+ KASSERT(LIST_EMPTY(&gp->provider),
+ ("g_destroy_geom(%s) with provider(s) [%p]",
+ gp->name, LIST_FIRST(&gp->consumer)));
+ LIST_REMOVE(gp, geom);
+ TAILQ_REMOVE(&geoms, gp, geoms);
+ g_free(gp);
+}
+
+struct g_consumer *
+g_new_consumer(struct g_geom *gp)
+{
+ struct g_consumer *cp;
+
+ g_topology_assert();
+ KASSERT(gp->method->orphan != NULL,
+ ("g_new_consumer on method(%s) without orphan", gp->method->name));
+
+ cp = g_malloc(sizeof *cp, M_WAITOK | M_ZERO);
+ cp->geom = gp;
+ LIST_INSERT_HEAD(&gp->consumer, cp, consumer);
+ return(cp);
+}
+
+void
+g_destroy_consumer(struct g_consumer *cp)
+{
+
+ g_trace(G_T_TOPOLOGY, "g_destroy_consumer(%p)", cp);
+ g_topology_assert();
+ KASSERT(cp->event == NULL, ("g_destroy_consumer() with event"));
+ KASSERT (cp->provider == NULL, ("g_destroy_consumer but attached"));
+ KASSERT (cp->acr == 0, ("g_destroy_consumer with acr"));
+ KASSERT (cp->acw == 0, ("g_destroy_consumer with acw"));
+ KASSERT (cp->ace == 0, ("g_destroy_consumer with ace"));
+ LIST_REMOVE(cp, consumer);
+ g_free(cp);
+}
+
+struct g_provider *
+g_new_providerf(struct g_geom *gp, char *fmt, ...)
+{
+ struct g_provider *pp;
+ struct sbuf *sb;
+ va_list ap;
+
+ g_topology_assert();
+ va_start(ap, fmt);
+ mtx_lock(&Giant);
+ sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ sbuf_vprintf(sb, fmt, ap);
+ sbuf_finish(sb);
+ mtx_unlock(&Giant);
+ pp = g_malloc(sizeof *pp + sbuf_len(sb) + 1, M_WAITOK | M_ZERO);
+ pp->name = (char *)(pp + 1);
+ strcpy(pp->name, sbuf_data(sb));
+ sbuf_delete(sb);
+ LIST_INIT(&pp->consumers);
+ pp->error = ENXIO;
+ pp->geom = gp;
+ LIST_INSERT_HEAD(&gp->provider, pp, provider);
+ g_nproviders++;
+ g_post_event(EV_NEW_PROVIDER, NULL, NULL, pp, NULL);
+ return (pp);
+}
+
+void
+g_error_provider(struct g_provider *pp, int error)
+{
+
+ pp->error = error;
+}
+
+
+void
+g_destroy_provider(struct g_provider *pp)
+{
+ struct g_geom *gp;
+ struct g_consumer *cp;
+
+ g_topology_assert();
+ KASSERT(pp->event == NULL, ("g_destroy_provider() with event"));
+ KASSERT(LIST_EMPTY(&pp->consumers),
+ ("g_destroy_provider but attached"));
+ KASSERT (pp->acr == 0, ("g_destroy_provider with acr"));
+ KASSERT (pp->acw == 0, ("g_destroy_provider with acw"));
+ KASSERT (pp->acw == 0, ("g_destroy_provider with ace"));
+ g_nproviders--;
+ LIST_REMOVE(pp, provider);
+ gp = pp->geom;
+ g_free(pp);
+ if (!(gp->flags & G_GEOM_WITHER))
+ return;
+ if (!LIST_EMPTY(&gp->provider))
+ return;
+ for (;;) {
+ cp = LIST_FIRST(&gp->consumer);
+ if (cp == NULL)
+ break;
+ g_dettach(cp);
+ g_destroy_consumer(cp);
+ }
+ g_destroy_geom(gp);
+}
+
+/*
+ * We keep the "geoms" list sorted by topological order (== increasing
+ * numerical rank) at all times.
+ * When an attach is done, the attaching geoms rank is invalidated
+ * and it is moved to the tail of the list.
+ * All geoms later in the sequence has their ranks reevaluated in
+ * sequence. If we cannot assign rank to a geom because it's
+ * prerequisites do not have rank, we move that element to the tail
+ * of the sequence with invalid rank as well.
+ * At some point we encounter our original geom and if we stil fail
+ * to assign it a rank, there must be a loop and we fail back to
+ * g_attach() which dettach again and calls redo_rank again
+ * to fix up the damage.
+ * It would be much simpler code wise to do it recursively, but we
+ * can't risk that on the kernel stack.
+ */
+
+static int
+redo_rank(struct g_geom *gp)
+{
+ struct g_consumer *cp;
+ struct g_geom *gp1, *gp2;
+ int n, m;
+
+ g_topology_assert();
+
+ /* Invalidate this geoms rank and move it to the tail */
+ gp1 = TAILQ_NEXT(gp, geoms);
+ if (gp1 != NULL) {
+ gp->rank = 0;
+ TAILQ_REMOVE(&geoms, gp, geoms);
+ TAILQ_INSERT_TAIL(&geoms, gp, geoms);
+ } else {
+ gp1 = gp;
+ }
+
+ /* re-rank the rest of the sequence */
+ for (; gp1 != NULL; gp1 = gp2) {
+ gp1->rank = 0;
+ m = 1;
+ LIST_FOREACH(cp, &gp1->consumer, consumer) {
+ if (cp->provider == NULL)
+ continue;
+ n = cp->provider->geom->rank;
+ if (n == 0) {
+ m = 0;
+ break;
+ } else if (n >= m)
+ m = n + 1;
+ }
+ gp1->rank = m;
+ gp2 = TAILQ_NEXT(gp1, geoms);
+
+ /* got a rank, moving on */
+ if (m != 0)
+ continue;
+
+ /* no rank to original geom means loop */
+ if (gp == gp1) {
+ return (ELOOP);
+
+ /* no rank, put it at the end move on */
+ TAILQ_REMOVE(&geoms, gp1, geoms);
+ TAILQ_INSERT_TAIL(&geoms, gp1, geoms);
+ }
+ }
+ return (0);
+}
+
+int
+g_attach(struct g_consumer *cp, struct g_provider *pp)
+{
+ int error;
+
+ g_topology_assert();
+ KASSERT(cp->provider == NULL, ("attach but attached"));
+ cp->provider = pp;
+ LIST_INSERT_HEAD(&pp->consumers, cp, consumers);
+ error = redo_rank(cp->geom);
+ if (error) {
+ LIST_REMOVE(cp, consumers);
+ cp->provider = NULL;
+ redo_rank(cp->geom);
+ }
+ return (error);
+}
+
+void
+g_dettach(struct g_consumer *cp)
+{
+ struct g_provider *pp;
+
+ g_trace(G_T_TOPOLOGY, "g_dettach(%p)", cp);
+ KASSERT(cp != (void*)0xd0d0d0d0, ("ARGH!"));
+ g_topology_assert();
+ KASSERT(cp->provider != NULL, ("dettach but not attached"));
+ KASSERT(cp->acr == 0, ("dettach but nonzero acr"));
+ KASSERT(cp->acw == 0, ("dettach but nonzero acw"));
+ KASSERT(cp->ace == 0, ("dettach but nonzero ace"));
+ KASSERT(cp->biocount == 0, ("dettach but nonzero biocount"));
+ pp = cp->provider;
+ LIST_REMOVE(cp, consumers);
+ cp->provider = NULL;
+ if (LIST_EMPTY(&pp->consumers)) {
+ if (pp->geom->flags & G_GEOM_WITHER)
+ g_destroy_provider(pp);
+ }
+ redo_rank(cp->geom);
+}
+
+
+/*
+ * g_access_abs()
+ *
+ * Access-check with absolute new values: Just fall through
+ * and use the relative version.
+ */
+int
+g_access_abs(struct g_consumer *cp, int acr, int acw, int ace)
+{
+
+ g_topology_assert();
+ return(g_access_rel(cp,
+ acr - cp->acr,
+ acw - cp->acw,
+ ace - cp->ace));
+}
+
+/*
+ * g_access_rel()
+ *
+ * Access-check with delta values. The question asked is "can provider
+ * "cp" change the access counters by the relative amounts dc[rwe] ?"
+ */
+
+int
+g_access_rel(struct g_consumer *cp, int dcr, int dcw, int dce)
+{
+ struct g_provider *pp;
+ int pr,pw,pe;
+ int error;
+
+ pp = cp->provider;
+
+ g_trace(G_T_ACCESS, "g_access_rel(%p(%s), %d, %d, %d)",
+ cp, pp->name, dcr, dcw, dce);
+
+ g_topology_assert();
+ KASSERT(cp->provider != NULL, ("access but not attached"));
+ KASSERT(cp->acr + dcr >= 0, ("access resulting in negative acr"));
+ KASSERT(cp->acw + dcw >= 0, ("access resulting in negative acw"));
+ KASSERT(cp->ace + dce >= 0, ("access resulting in negative ace"));
+ KASSERT(pp->geom->method->access != NULL, ("NULL method->access"));
+
+ /*
+ * If our method cares about being spoiled, and we have been, we
+ * are probably just ahead of the event telling us that. Fail
+ * now rather than having to unravel this later.
+ */
+ if (cp->geom->spoiled != NULL && cp->spoiled) {
+ KASSERT(dcr >= 0, ("spoiled but dcr = %d", dcr));
+ KASSERT(dcw >= 0, ("spoiled but dce = %d", dcw));
+ KASSERT(dce >= 0, ("spoiled but dcw = %d", dce));
+ KASSERT(cp->acr == 0, ("spoiled but cp->acr = %d", cp->acr));
+ KASSERT(cp->acw == 0, ("spoiled but cp->acw = %d", cp->acw));
+ KASSERT(cp->ace == 0, ("spoiled but cp->ace = %d", cp->ace));
+ return(ENXIO);
+ }
+
+ /*
+ * Figure out what counts the provider would have had, if this
+ * consumer had (r0w0e0) at this time.
+ */
+ pr = pp->acr - cp->acr;
+ pw = pp->acw - cp->acw;
+ pe = pp->ace - cp->ace;
+
+ g_trace(G_T_ACCESS,
+ "open delta:[r%dw%de%d] old:[r%dw%de%d] provider:[r%dw%de%d] %p(%s)",
+ dcr, dcw, dce,
+ cp->acr, cp->acw, cp->ace,
+ pp->acr, pp->acw, pp->ace,
+ pp, pp->name);
+
+ /* If we try exclusive but already write: fail */
+ if (dce > 0 && pw > 0)
+ return (EPERM);
+ /* If we try write but already exclusive: fail */
+ if (dcw > 0 && pe > 0)
+ return (EPERM);
+ /* If we try to open more but provider is error'ed: fail */
+ if ((dcr > 0 || dcw > 0 || dce > 0) && pp->error != 0)
+ return (pp->error);
+
+ /* Ok then... */
+
+ /*
+ * If we open first write, spoil any partner consumers.
+ * If we close last write, trigger re-taste.
+ */
+ if (pp->acw == 0 && dcw != 0)
+ g_spoil(pp, cp);
+ else if (pp->acw != 0 && pp->acw == -dcw && !(pp->geom->flags & G_GEOM_WITHER))
+ g_post_event(EV_NEW_PROVIDER, NULL, NULL, pp, NULL);
+
+ error = pp->geom->method->access(pp, dcr, dcw, dce);
+ if (!error) {
+ pp->acr += dcr;
+ pp->acw += dcw;
+ pp->ace += dce;
+ cp->acr += dcr;
+ cp->acw += dcw;
+ cp->ace += dce;
+ }
+ return (error);
+}
+
+int
+g_haveattr_int(struct bio *bp, char *attribute, int val)
+{
+
+ return (g_haveattr(bp, attribute, &val, sizeof val));
+}
+
+int
+g_haveattr_off_t(struct bio *bp, char *attribute, off_t val)
+{
+
+ return (g_haveattr(bp, attribute, &val, sizeof val));
+}
+
+
+int
+g_haveattr(struct bio *bp, char *attribute, void *val, int len)
+{
+ int error;
+
+ if (strcmp(bp->bio_attribute, attribute))
+ return (0);
+ if (bp->bio_length != len) {
+ printf("bio_length %lld len %d -> EFAULT\n", bp->bio_length, len);
+ error = EFAULT;
+ } else {
+ error = 0;
+ bcopy(val, bp->bio_data, len);
+ bp->bio_completed = len;
+ }
+ bp->bio_error = error;
+ g_io_deliver(bp);
+ return (1);
+}
+
+int
+g_std_access(struct g_provider *pp __unused,
+ int dr __unused, int dw __unused, int de __unused)
+{
+
+ return (0);
+}
+
+void
+g_std_done(struct bio *bp)
+{
+ struct bio *bp2;
+
+ bp2 = bp->bio_linkage;
+ bp2->bio_error = bp->bio_error;
+ bp2->bio_completed = bp->bio_completed;
+ g_destroy_bio(bp);
+ g_io_deliver(bp2);
+}
+
+/* XXX: maybe this is only g_slice_spoiled */
+
+void
+g_std_spoiled(struct g_consumer *cp)
+{
+ struct g_geom *gp;
+ struct g_provider *pp;
+
+ g_trace(G_T_TOPOLOGY, "g_std_spoiled(%p)", cp);
+ g_topology_assert();
+ g_dettach(cp);
+ gp = cp->geom;
+ LIST_FOREACH(pp, &gp->provider, provider)
+ g_orphan_provider(pp, ENXIO);
+ g_destroy_consumer(cp);
+ if (LIST_EMPTY(&gp->provider) && LIST_EMPTY(&gp->consumer))
+ g_destroy_geom(gp);
+ else
+ gp->flags |= G_GEOM_WITHER;
+}
+
+/*
+ * Spoiling happens when a provider is opened for writing, but consumers
+ * which are configured by in-band data are attached (slicers for instance).
+ * Since the write might potentially change the in-band data, such consumers
+ * need to re-evaluate their existence after the writing session closes.
+ * We do this by (offering to) tear them down when the open for write happens
+ * in return for a re-taste when it closes again.
+ * Together with the fact that such consumers grab an 'e' bit whenever they
+ * are open, regardless of mode, this ends up DTRT.
+ */
+
+void
+g_spoil(struct g_provider *pp, struct g_consumer *cp)
+{
+ struct g_consumer *cp2;
+
+ g_topology_assert();
+
+ LIST_FOREACH(cp2, &pp->consumers, consumers) {
+ if (cp2 == cp)
+ continue;
+/*
+ KASSERT(cp2->acr == 0, ("spoiling cp->acr = %d", cp2->acr));
+ KASSERT(cp2->acw == 0, ("spoiling cp->acw = %d", cp2->acw));
+*/
+ KASSERT(cp2->ace == 0, ("spoiling cp->ace = %d", cp2->ace));
+ cp2->spoiled++;
+ }
+ g_post_event(EV_SPOILED, NULL, NULL, pp, cp);
+}
+
+static struct g_method *
+g_method_by_name(char *name)
+{
+ struct g_method *mp;
+
+ g_trace(G_T_TOPOLOGY, "g_method_by_name(%s)", name);
+ g_topology_assert();
+ LIST_FOREACH(mp, &g_methods, method)
+ if (!strcmp(mp->name, name))
+ return (mp);
+ return (NULL);
+}
+
+struct g_geom *
+g_create_geomf(char *method, struct g_provider *pp, char *fmt, ...)
+{
+ va_list ap;
+ struct sbuf *sb;
+ char *s;
+ struct g_method *mp;
+ struct g_geom *gp;
+
+ g_trace(G_T_TOPOLOGY, "g_create_geom(%s, %p(%s))", method,
+ pp, pp == NULL ? "" : pp->name);
+ g_topology_assert();
+ gp = NULL;
+ mp = g_method_by_name(method);
+ if (mp == NULL)
+ return (NULL);
+ if (fmt != NULL) {
+ va_start(ap, fmt);
+ mtx_lock(&Giant);
+ sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ sbuf_vprintf(sb, fmt, ap);
+ sbuf_finish(sb);
+ mtx_unlock(&Giant);
+ s = sbuf_data(sb);
+ } else {
+ s = NULL;
+ }
+ if (pp != NULL)
+ gp = mp->taste(mp, pp, NULL, G_TF_INSIST);
+ if (gp == NULL && mp->create_geom == NULL)
+ return (NULL);
+ if (gp == NULL)
+ gp = mp->create_geom(mp, pp, s);
+ /* XXX: delete sbuf */
+ return (gp);
+}
+
+struct g_geom *
+g_insert_geom(char *method, struct g_consumer *cp)
+{
+ struct g_method *mp;
+ struct g_geom *gp;
+ struct g_provider *pp, *pp2;
+ struct g_consumer *cp2;
+ int error;
+
+ g_trace(G_T_TOPOLOGY, "g_insert_geomf(%s, %p)", method, cp);
+ g_topology_assert();
+ KASSERT(cp->provider != NULL, ("g_insert_geomf but not attached"));
+ /* XXX: check for events ?? */
+ mp = g_method_by_name(method);
+ if (mp == NULL)
+ return (NULL);
+ if (mp->create_geom == NULL)
+ return (NULL);
+ pp = cp->provider;
+ gp = mp->taste(mp, pp, NULL, G_TF_TRANSPARENT);
+ if (gp == NULL)
+ return (NULL);
+ pp2 = LIST_FIRST(&gp->provider);
+ cp2 = LIST_FIRST(&gp->consumer);
+ cp2->acr += pp->acr;
+ cp2->acw += pp->acw;
+ cp2->ace += pp->ace;
+ pp2->acr += pp->acr;
+ pp2->acw += pp->acw;
+ pp2->ace += pp->ace;
+ LIST_REMOVE(cp, consumers);
+ LIST_INSERT_HEAD(&pp2->consumers, cp, consumers);
+ cp->provider = pp2;
+ error = redo_rank(gp);
+ KASSERT(error == 0, ("redo_rank failed in g_insert_geom"));
+ return (gp);
+}
+
OpenPOWER on IntegriCloud