diff -uNr /usr/src/sys/geom/log/g_log.c geom/log/g_log.c --- /usr/src/sys/geom/log/g_log.c 1970-01-01 00:00:00.000000000 +0000 +++ geom/log/g_log.c 2009-07-09 05:57:48.000000000 +0000 @@ -0,0 +1,556 @@ +/*- + * Copyright (c) 2004-2006 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: src/sys/geom/log/g_log.c,v 1.19 2006/09/08 13:46:18 pjd Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +SYSCTL_DECL(_kern_geom); +SYSCTL_NODE(_kern_geom, OID_AUTO, log, CTLFLAG_RW, 0, "GEOM_LOG stuff"); +static u_int g_log_debug = 0; +SYSCTL_UINT(_kern_geom_log, OID_AUTO, debug, CTLFLAG_RW, &g_log_debug, 0, + "Debug level"); + +static int g_log_destroy(struct g_geom *gp, boolean_t force); +static int g_log_destroy_geom(struct gctl_req *req, struct g_class *mp, + struct g_geom *gp); +static void g_log_config(struct gctl_req *req, struct g_class *mp, + const char *verb); +static void g_log_dumpconf(struct sbuf *sb, const char *indent, + struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp); + +struct g_class g_log_class = { + .name = G_LOG_CLASS_NAME, + .version = G_VERSION, + .ctlreq = g_log_config, + .destroy_geom = g_log_destroy_geom +}; + + +static void +g_log_orphan(struct g_consumer *cp) +{ + + g_topology_assert(); + g_log_destroy(cp->geom, 1); +} + +static void +g_log_done(struct bio *bp) +{ + G_LOG_LOGREQ(bp, "Request completed."); + g_std_done(bp); +} + +static void +g_log_start(struct bio *bp) +{ + struct g_log_softc *sc; + struct g_geom *gp; + struct g_provider *pp; + struct bio *cbp; + + gp = bp->bio_to->geom; + sc = gp->softc; + G_LOG_LOGREQ(bp, "Request received."); + switch (bp->bio_cmd) { + case BIO_READ: + sc->sc_reads++; + sc->sc_readbytes += bp->bio_length; + break; + case BIO_WRITE: + sc->sc_writes++; + sc->sc_wrotebytes += bp->bio_length; + break; + } + cbp = g_clone_bio(bp); + if (cbp == NULL) { + g_io_deliver(bp, ENOMEM); + return; + } + cbp->bio_done = g_log_done; + cbp->bio_offset = bp->bio_offset + sc->sc_offset; + cbp->bio_data = bp->bio_data; + cbp->bio_length = bp->bio_length; + pp = LIST_FIRST(&gp->provider); + KASSERT(pp != NULL, ("NULL pp")); + cbp->bio_to = pp; + G_LOG_LOGREQ(cbp, "Sending request."); + g_io_request(cbp, LIST_FIRST(&gp->consumer)); +} + +static int +g_log_access(struct g_provider *pp, int dr, int dw, int de) +{ + struct g_geom *gp; + struct g_consumer *cp; + int error; + + gp = pp->geom; + cp = LIST_FIRST(&gp->consumer); + error = g_access(cp, dr, dw, de); + + return (error); +} + +static int +g_log_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp, + int ioerror, off_t offset, off_t size, + u_int secsize) +{ + struct g_log_softc *sc; + struct g_geom *gp; + struct g_provider *newpp; + struct g_consumer *cp; + char name[64]; + int error; + + g_topology_assert(); + + gp = NULL; + newpp = NULL; + cp = NULL; + + if ((offset % pp->sectorsize) != 0) { + gctl_error(req, "Invalid offset for provider %s.", pp->name); + return (EINVAL); + } + if ((size % pp->sectorsize) != 0) { + gctl_error(req, "Invalid size for provider %s.", pp->name); + return (EINVAL); + } + if (offset >= pp->mediasize) { + gctl_error(req, "Invalid offset for provider %s.", pp->name); + return (EINVAL); + } + if (size == 0) + size = pp->mediasize - offset; + if (offset + size > pp->mediasize) { + gctl_error(req, "Invalid size for provider %s.", pp->name); + return (EINVAL); + } + if (secsize == 0) + secsize = pp->sectorsize; + else if ((secsize % pp->sectorsize) != 0) { + gctl_error(req, "Invalid secsize for provider %s.", pp->name); + return (EINVAL); + } + snprintf(name, sizeof(name), "%s%s", pp->name, G_LOG_SUFFIX); + LIST_FOREACH(gp, &mp->geom, geom) { + if (strcmp(gp->name, name) == 0) { + gctl_error(req, "Provider %s already exists.", name); + return (EEXIST); + } + } + gp = g_new_geomf(mp, name); + if (gp == NULL) { + gctl_error(req, "Cannot create geom %s.", name); + return (ENOMEM); + } + sc = g_malloc(sizeof(*sc), M_WAITOK); + sc->sc_offset = offset; + sc->sc_error = ioerror; + sc->sc_reads = 0; + sc->sc_writes = 0; + sc->sc_readbytes = 0; + sc->sc_wrotebytes = 0; + gp->softc = sc; + gp->start = g_log_start; + gp->orphan = g_log_orphan; + gp->access = g_log_access; + gp->dumpconf = g_log_dumpconf; + + newpp = g_new_providerf(gp, gp->name); + if (newpp == NULL) { + gctl_error(req, "Cannot create provider %s.", name); + error = ENOMEM; + goto fail; + } + newpp->mediasize = size; + newpp->sectorsize = secsize; + + cp = g_new_consumer(gp); + if (cp == NULL) { + gctl_error(req, "Cannot create consumer for %s.", gp->name); + error = ENOMEM; + goto fail; + } + error = g_attach(cp, pp); + if (error != 0) { + gctl_error(req, "Cannot attach to provider %s.", pp->name); + goto fail; + } + + g_error_provider(newpp, 0); + G_LOG_DEBUG(0, "Device %s created.", gp->name); + return (0); +fail: + if (cp != NULL) { + if (cp->provider != NULL) + g_detach(cp); + g_destroy_consumer(cp); + } + if (newpp != NULL) + g_destroy_provider(newpp); + if (gp != NULL) { + if (gp->softc != NULL) + g_free(gp->softc); + g_destroy_geom(gp); + } + return (error); +} + +static int +g_log_destroy(struct g_geom *gp, boolean_t force) +{ + struct g_provider *pp; + + g_topology_assert(); + if (gp->softc == NULL) + return (ENXIO); + pp = LIST_FIRST(&gp->provider); + if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { + if (force) { + G_LOG_DEBUG(0, "Device %s is still open, so it " + "can't be definitely removed.", pp->name); + } else { + G_LOG_DEBUG(1, "Device %s is still open (r%dw%de%d).", + pp->name, pp->acr, pp->acw, pp->ace); + return (EBUSY); + } + } else { + G_LOG_DEBUG(0, "Device %s removed.", gp->name); + } + g_free(gp->softc); + gp->softc = NULL; + g_wither_geom(gp, ENXIO); + + return (0); +} + +static int +g_log_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) +{ + + return (g_log_destroy(gp, 0)); +} + +static void +g_log_ctl_create(struct gctl_req *req, struct g_class *mp) +{ + struct g_provider *pp; + intmax_t *error, *offset, *secsize, *size; + const char *name; + char param[16]; + int i, *nargs; + + g_topology_assert(); + + nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); + if (nargs == NULL) { + gctl_error(req, "No '%s' argument", "nargs"); + return; + } + if (*nargs <= 0) { + gctl_error(req, "Missing device(s)."); + return; + } + error = gctl_get_paraml(req, "error", sizeof(*error)); + if (error == NULL) { + gctl_error(req, "No '%s' argument", "error"); + return; + } + offset = gctl_get_paraml(req, "offset", sizeof(*offset)); + if (offset == NULL) { + gctl_error(req, "No '%s' argument", "offset"); + return; + } + if (*offset < 0) { + gctl_error(req, "Invalid '%s' argument", "offset"); + return; + } + size = gctl_get_paraml(req, "size", sizeof(*size)); + if (size == NULL) { + gctl_error(req, "No '%s' argument", "size"); + return; + } + if (*size < 0) { + gctl_error(req, "Invalid '%s' argument", "size"); + return; + } + secsize = gctl_get_paraml(req, "secsize", sizeof(*secsize)); + if (secsize == NULL) { + gctl_error(req, "No '%s' argument", "secsize"); + return; + } + if (*secsize < 0) { + gctl_error(req, "Invalid '%s' argument", "secsize"); + return; + } + + for (i = 0; i < *nargs; i++) { + snprintf(param, sizeof(param), "arg%d", i); + name = gctl_get_asciiparam(req, param); + if (name == NULL) { + gctl_error(req, "No 'arg%d' argument", i); + return; + } + if (strncmp(name, "/dev/", strlen("/dev/")) == 0) + name += strlen("/dev/"); + pp = g_provider_by_name(name); + if (pp == NULL) { + G_LOG_DEBUG(1, "Provider %s is invalid.", name); + gctl_error(req, "Provider %s is invalid.", name); + return; + } + if (g_log_create(req, mp, pp, + *error == -1 ? EIO : (int)*error, + (off_t)*offset, (off_t)*size, (u_int)*secsize) != 0) { + return; + } + } +} + +static void +g_log_ctl_configure(struct gctl_req *req, struct g_class *mp) +{ + struct g_log_softc *sc; + struct g_provider *pp; + intmax_t *error; + const char *name; + char param[16]; + int i, *nargs; + + g_topology_assert(); + + nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); + if (nargs == NULL) { + gctl_error(req, "No '%s' argument", "nargs"); + return; + } + if (*nargs <= 0) { + gctl_error(req, "Missing device(s)."); + return; + } + error = gctl_get_paraml(req, "error", sizeof(*error)); + if (error == NULL) { + gctl_error(req, "No '%s' argument", "error"); + return; + } + + for (i = 0; i < *nargs; i++) { + snprintf(param, sizeof(param), "arg%d", i); + name = gctl_get_asciiparam(req, param); + if (name == NULL) { + gctl_error(req, "No 'arg%d' argument", i); + return; + } + if (strncmp(name, "/dev/", strlen("/dev/")) == 0) + name += strlen("/dev/"); + pp = g_provider_by_name(name); + if (pp == NULL || pp->geom->class != mp) { + G_LOG_DEBUG(1, "Provider %s is invalid.", name); + gctl_error(req, "Provider %s is invalid.", name); + return; + } + sc = pp->geom->softc; + if (*error != -1) + sc->sc_error = (int)*error; + } +} + +static struct g_geom * +g_log_find_geom(struct g_class *mp, const char *name) +{ + struct g_geom *gp; + + LIST_FOREACH(gp, &mp->geom, geom) { + if (strcmp(gp->name, name) == 0) + return (gp); + } + return (NULL); +} + +static void +g_log_ctl_destroy(struct gctl_req *req, struct g_class *mp) +{ + int *nargs, *force, error, i; + struct g_geom *gp; + const char *name; + char param[16]; + + g_topology_assert(); + + nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); + if (nargs == NULL) { + gctl_error(req, "No '%s' argument", "nargs"); + return; + } + if (*nargs <= 0) { + gctl_error(req, "Missing device(s)."); + return; + } + force = gctl_get_paraml(req, "force", sizeof(*force)); + if (force == NULL) { + gctl_error(req, "No 'force' argument"); + return; + } + + for (i = 0; i < *nargs; i++) { + snprintf(param, sizeof(param), "arg%d", i); + name = gctl_get_asciiparam(req, param); + if (name == NULL) { + gctl_error(req, "No 'arg%d' argument", i); + return; + } + if (strncmp(name, "/dev/", strlen("/dev/")) == 0) + name += strlen("/dev/"); + gp = g_log_find_geom(mp, name); + if (gp == NULL) { + G_LOG_DEBUG(1, "Device %s is invalid.", name); + gctl_error(req, "Device %s is invalid.", name); + return; + } + error = g_log_destroy(gp, *force); + if (error != 0) { + gctl_error(req, "Cannot destroy device %s (error=%d).", + gp->name, error); + return; + } + } +} + +static void +g_log_ctl_reset(struct gctl_req *req, struct g_class *mp) +{ + struct g_log_softc *sc; + struct g_provider *pp; + const char *name; + char param[16]; + int i, *nargs; + + g_topology_assert(); + + nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); + if (nargs == NULL) { + gctl_error(req, "No '%s' argument", "nargs"); + return; + } + if (*nargs <= 0) { + gctl_error(req, "Missing device(s)."); + return; + } + + for (i = 0; i < *nargs; i++) { + snprintf(param, sizeof(param), "arg%d", i); + name = gctl_get_asciiparam(req, param); + if (name == NULL) { + gctl_error(req, "No 'arg%d' argument", i); + return; + } + if (strncmp(name, "/dev/", strlen("/dev/")) == 0) + name += strlen("/dev/"); + pp = g_provider_by_name(name); + if (pp == NULL || pp->geom->class != mp) { + G_LOG_DEBUG(1, "Provider %s is invalid.", name); + gctl_error(req, "Provider %s is invalid.", name); + return; + } + sc = pp->geom->softc; + sc->sc_reads = 0; + sc->sc_writes = 0; + sc->sc_readbytes = 0; + sc->sc_wrotebytes = 0; + } +} + +static void +g_log_config(struct gctl_req *req, struct g_class *mp, const char *verb) +{ + uint32_t *version; + + g_topology_assert(); + + version = gctl_get_paraml(req, "version", sizeof(*version)); + if (version == NULL) { + gctl_error(req, "No '%s' argument.", "version"); + return; + } + if (*version != G_LOG_VERSION) { + gctl_error(req, "Userland and kernel parts are out of sync."); + return; + } + + if (strcmp(verb, "create") == 0) { + g_log_ctl_create(req, mp); + return; + } else if (strcmp(verb, "configure") == 0) { + g_log_ctl_configure(req, mp); + return; + } else if (strcmp(verb, "destroy") == 0) { + g_log_ctl_destroy(req, mp); + return; + } else if (strcmp(verb, "reset") == 0) { + g_log_ctl_reset(req, mp); + return; + } + + gctl_error(req, "Unknown verb."); +} + +static void +g_log_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, + struct g_consumer *cp, struct g_provider *pp) +{ + struct g_log_softc *sc; + + if (pp != NULL || cp != NULL) + return; + sc = gp->softc; + sbuf_printf(sb, "%s%jd\n", indent, + (intmax_t)sc->sc_offset); + sbuf_printf(sb, "%s%d\n", indent, sc->sc_error); + sbuf_printf(sb, "%s%ju\n", indent, sc->sc_reads); + sbuf_printf(sb, "%s%ju\n", indent, sc->sc_writes); + sbuf_printf(sb, "%s%ju\n", indent, + sc->sc_readbytes); + sbuf_printf(sb, "%s%ju\n", indent, + sc->sc_wrotebytes); +} + +DECLARE_GEOM_CLASS(g_log_class, g_log); diff -uNr /usr/src/sys/geom/log/g_log.h geom/log/g_log.h --- /usr/src/sys/geom/log/g_log.h 1970-01-01 00:00:00.000000000 +0000 +++ geom/log/g_log.h 2009-07-09 06:00:22.000000000 +0000 @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2004-2006 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/geom/log/g_log.h,v 1.7 2006/09/30 08:16:49 pjd Exp $ + */ + +#ifndef _G_LOG_H_ +#define _G_LOG_H_ + +#define G_LOG_CLASS_NAME "LOG" +#define G_LOG_VERSION 4 +#define G_LOG_SUFFIX ".log" + +#ifdef _KERNEL +#define G_LOG_DEBUG(lvl, ...) do { \ + if (g_log_debug >= (lvl)) { \ + printf("GEOM_LOG"); \ + if (g_log_debug > 0) \ + printf("[%u]", lvl); \ + printf(": "); \ + printf(__VA_ARGS__); \ + printf("\n"); \ + } \ +} while (0) +#define G_LOG_LOGREQ(bp, ...) do { \ + if (g_log_debug >= 2) { \ + printf("GEOM_LOG[2]: %p: ", bp); \ + printf(__VA_ARGS__); \ + printf(" "); \ + g_print_bio(bp); \ + printf("\n"); \ + } \ +} while (0) + +struct g_log_softc { + int sc_error; + off_t sc_offset; + uintmax_t sc_reads; + uintmax_t sc_writes; + uintmax_t sc_readbytes; + uintmax_t sc_wrotebytes; +}; +#endif /* _KERNEL */ + +#endif /* _G_LOG_H_ */