diff options
-rw-r--r-- | sys/geom/geom.h | 290 | ||||
-rw-r--r-- | sys/geom/geom_bsd.c | 257 | ||||
-rw-r--r-- | sys/geom/geom_dev.c | 382 | ||||
-rw-r--r-- | sys/geom/geom_disk.c | 232 | ||||
-rw-r--r-- | sys/geom/geom_dump.c | 275 | ||||
-rw-r--r-- | sys/geom/geom_event.c | 299 | ||||
-rw-r--r-- | sys/geom/geom_io.c | 375 | ||||
-rw-r--r-- | sys/geom/geom_kern.c | 192 | ||||
-rw-r--r-- | sys/geom/geom_mbr.c | 211 | ||||
-rw-r--r-- | sys/geom/geom_mbrext.c | 200 | ||||
-rw-r--r-- | sys/geom/geom_slice.c | 278 | ||||
-rw-r--r-- | sys/geom/geom_slice.h | 60 | ||||
-rw-r--r-- | sys/geom/geom_subr.c | 639 |
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); +} + |