1fe27e772SPawel Jakub Dawidek /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 33728855aSPedro F. Giffuni * 4fc024f7aSPawel Jakub Dawidek * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> 532115b10SPawel Jakub Dawidek * Copyright (c) 2009-2010 The FreeBSD Foundation 6fe27e772SPawel Jakub Dawidek * All rights reserved. 7fe27e772SPawel Jakub Dawidek * 832115b10SPawel Jakub Dawidek * Portions of this software were developed by Pawel Jakub Dawidek 932115b10SPawel Jakub Dawidek * under sponsorship from the FreeBSD Foundation. 1032115b10SPawel Jakub Dawidek * 11fe27e772SPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 12fe27e772SPawel Jakub Dawidek * modification, are permitted provided that the following conditions 13fe27e772SPawel Jakub Dawidek * are met: 14fe27e772SPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 15fe27e772SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 16fe27e772SPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 17fe27e772SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 18fe27e772SPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 19fe27e772SPawel Jakub Dawidek * 20fe27e772SPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 21fe27e772SPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22fe27e772SPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23fe27e772SPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 24fe27e772SPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25fe27e772SPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26fe27e772SPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27fe27e772SPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28fe27e772SPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29fe27e772SPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30fe27e772SPawel Jakub Dawidek * SUCH DAMAGE. 31fe27e772SPawel Jakub Dawidek */ 32fe27e772SPawel Jakub Dawidek 33fe27e772SPawel Jakub Dawidek #include <sys/param.h> 34fe27e772SPawel Jakub Dawidek #include <sys/systm.h> 35fe27e772SPawel Jakub Dawidek #include <sys/bio.h> 36fe27e772SPawel Jakub Dawidek #include <sys/conf.h> 37fe27e772SPawel Jakub Dawidek #include <sys/kernel.h> 38fe27e772SPawel Jakub Dawidek #include <sys/kthread.h> 39fe27e772SPawel Jakub Dawidek #include <sys/fcntl.h> 40fe27e772SPawel Jakub Dawidek #include <sys/linker.h> 41fe27e772SPawel Jakub Dawidek #include <sys/lock.h> 42fe27e772SPawel Jakub Dawidek #include <sys/malloc.h> 43fe27e772SPawel Jakub Dawidek #include <sys/mutex.h> 44fe27e772SPawel Jakub Dawidek #include <sys/proc.h> 45fe27e772SPawel Jakub Dawidek #include <sys/limits.h> 46fe27e772SPawel Jakub Dawidek #include <sys/queue.h> 475d807a0eSAndrey V. Elsukov #include <sys/sbuf.h> 48fe27e772SPawel Jakub Dawidek #include <sys/sysctl.h> 49fe27e772SPawel Jakub Dawidek #include <sys/signalvar.h> 50fe27e772SPawel Jakub Dawidek #include <sys/time.h> 51fe27e772SPawel Jakub Dawidek #include <machine/atomic.h> 52fe27e772SPawel Jakub Dawidek 53fe27e772SPawel Jakub Dawidek #include <geom/geom.h> 54ac03832eSConrad Meyer #include <geom/geom_dbg.h> 55fe27e772SPawel Jakub Dawidek #include <geom/gate/g_gate.h> 56fe27e772SPawel Jakub Dawidek 57cb08c2ccSAlexander Leidinger FEATURE(geom_gate, "GEOM Gate module"); 58cb08c2ccSAlexander Leidinger 595bb84bc8SRobert Watson static MALLOC_DEFINE(M_GATE, "gg_data", "GEOM Gate Data"); 60fe27e772SPawel Jakub Dawidek 61fe27e772SPawel Jakub Dawidek SYSCTL_DECL(_kern_geom); 627029da5cSPawel Biernacki static SYSCTL_NODE(_kern_geom, OID_AUTO, gate, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 63e08ec037SPawel Jakub Dawidek "GEOM_GATE configuration"); 6432115b10SPawel Jakub Dawidek static int g_gate_debug = 0; 65af3b2549SHans Petter Selasky SYSCTL_INT(_kern_geom_gate, OID_AUTO, debug, CTLFLAG_RWTUN, &g_gate_debug, 0, 66fe27e772SPawel Jakub Dawidek "Debug level"); 6732115b10SPawel Jakub Dawidek static u_int g_gate_maxunits = 256; 6832115b10SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_gate, OID_AUTO, maxunits, CTLFLAG_RDTUN, 6932115b10SPawel Jakub Dawidek &g_gate_maxunits, 0, "Maximum number of ggate devices"); 70fe27e772SPawel Jakub Dawidek 71fe27e772SPawel Jakub Dawidek struct g_class g_gate_class = { 72fe27e772SPawel Jakub Dawidek .name = G_GATE_CLASS_NAME, 735721c9c7SPoul-Henning Kamp .version = G_VERSION, 74fe27e772SPawel Jakub Dawidek }; 75fe27e772SPawel Jakub Dawidek 7689c9c53dSPoul-Henning Kamp static struct cdev *status_dev; 77fe27e772SPawel Jakub Dawidek static d_ioctl_t g_gate_ioctl; 78fe27e772SPawel Jakub Dawidek static struct cdevsw g_gate_cdevsw = { 79fe27e772SPawel Jakub Dawidek .d_version = D_VERSION, 80fe27e772SPawel Jakub Dawidek .d_ioctl = g_gate_ioctl, 81fe27e772SPawel Jakub Dawidek .d_name = G_GATE_CTL_NAME 82fe27e772SPawel Jakub Dawidek }; 83fe27e772SPawel Jakub Dawidek 8432115b10SPawel Jakub Dawidek static struct g_gate_softc **g_gate_units; 8532115b10SPawel Jakub Dawidek static u_int g_gate_nunits; 8632115b10SPawel Jakub Dawidek static struct mtx g_gate_units_lock; 87fe27e772SPawel Jakub Dawidek 88351d0fa6SAlexander Motin static void 89351d0fa6SAlexander Motin g_gate_detach(void *arg, int flags __unused) 90351d0fa6SAlexander Motin { 91351d0fa6SAlexander Motin struct g_consumer *cp = arg; 92351d0fa6SAlexander Motin 93351d0fa6SAlexander Motin g_topology_assert(); 94351d0fa6SAlexander Motin G_GATE_DEBUG(1, "Destroying read consumer on provider %s orphan.", 95351d0fa6SAlexander Motin cp->provider->name); 96351d0fa6SAlexander Motin (void)g_access(cp, -1, 0, 0); 97351d0fa6SAlexander Motin g_detach(cp); 98351d0fa6SAlexander Motin g_destroy_consumer(cp); 99351d0fa6SAlexander Motin } 100351d0fa6SAlexander Motin 101fe27e772SPawel Jakub Dawidek static int 102fe27e772SPawel Jakub Dawidek g_gate_destroy(struct g_gate_softc *sc, boolean_t force) 103fe27e772SPawel Jakub Dawidek { 10440ea77a0SAlexander Motin struct bio_queue_head queue; 105fe27e772SPawel Jakub Dawidek struct g_provider *pp; 106e08ec037SPawel Jakub Dawidek struct g_consumer *cp; 1077ffb6e0fSPawel Jakub Dawidek struct g_geom *gp; 108fe27e772SPawel Jakub Dawidek struct bio *bp; 109fe27e772SPawel Jakub Dawidek 110fe27e772SPawel Jakub Dawidek g_topology_assert(); 11132115b10SPawel Jakub Dawidek mtx_assert(&g_gate_units_lock, MA_OWNED); 112fe27e772SPawel Jakub Dawidek pp = sc->sc_provider; 113fe27e772SPawel Jakub Dawidek if (!force && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 11432115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 115fe27e772SPawel Jakub Dawidek return (EBUSY); 116fe27e772SPawel Jakub Dawidek } 11732115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 118e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 1197ffb6e0fSPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0) 1207ffb6e0fSPawel Jakub Dawidek sc->sc_flags |= G_GATE_FLAG_DESTROY; 121fe27e772SPawel Jakub Dawidek wakeup(sc); 122e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 1237ffb6e0fSPawel Jakub Dawidek gp = pp->geom; 1248b64f3caSAlexander Motin g_wither_provider(pp, ENXIO); 125fe27e772SPawel Jakub Dawidek callout_drain(&sc->sc_callout); 12640ea77a0SAlexander Motin bioq_init(&queue); 127e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 12840ea77a0SAlexander Motin while ((bp = bioq_takefirst(&sc->sc_inqueue)) != NULL) { 129e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 13040ea77a0SAlexander Motin bioq_insert_tail(&queue, bp); 131fe27e772SPawel Jakub Dawidek } 13240ea77a0SAlexander Motin while ((bp = bioq_takefirst(&sc->sc_outqueue)) != NULL) { 133e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 13440ea77a0SAlexander Motin bioq_insert_tail(&queue, bp); 135fe27e772SPawel Jakub Dawidek } 1367ffb6e0fSPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 1377ffb6e0fSPawel Jakub Dawidek g_topology_unlock(); 13840ea77a0SAlexander Motin while ((bp = bioq_takefirst(&queue)) != NULL) { 13940ea77a0SAlexander Motin G_GATE_LOGREQ(1, bp, "Request canceled."); 14040ea77a0SAlexander Motin g_io_deliver(bp, ENXIO); 14140ea77a0SAlexander Motin } 14232115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 1437ffb6e0fSPawel Jakub Dawidek /* One reference is ours. */ 1447ffb6e0fSPawel Jakub Dawidek sc->sc_ref--; 14532115b10SPawel Jakub Dawidek while (sc->sc_ref > 0) 14632115b10SPawel Jakub Dawidek msleep(&sc->sc_ref, &g_gate_units_lock, 0, "gg:destroy", 0); 14732115b10SPawel Jakub Dawidek g_gate_units[sc->sc_unit] = NULL; 14832115b10SPawel Jakub Dawidek KASSERT(g_gate_nunits > 0, ("negative g_gate_nunits?")); 14932115b10SPawel Jakub Dawidek g_gate_nunits--; 15032115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 151e35d3a78SPawel Jakub Dawidek mtx_destroy(&sc->sc_queue_mtx); 152351d0fa6SAlexander Motin mtx_destroy(&sc->sc_read_mtx); 1537ffb6e0fSPawel Jakub Dawidek g_topology_lock(); 154e08ec037SPawel Jakub Dawidek if ((cp = sc->sc_readcons) != NULL) { 155e08ec037SPawel Jakub Dawidek sc->sc_readcons = NULL; 156e08ec037SPawel Jakub Dawidek (void)g_access(cp, -1, 0, 0); 157e08ec037SPawel Jakub Dawidek g_detach(cp); 158e08ec037SPawel Jakub Dawidek g_destroy_consumer(cp); 159e08ec037SPawel Jakub Dawidek } 160bd119384SMikolaj Golub G_GATE_DEBUG(1, "Device %s destroyed.", gp->name); 1617ffb6e0fSPawel Jakub Dawidek gp->softc = NULL; 1627ffb6e0fSPawel Jakub Dawidek g_wither_geom(gp, ENXIO); 163fe27e772SPawel Jakub Dawidek sc->sc_provider = NULL; 164fe27e772SPawel Jakub Dawidek free(sc, M_GATE); 165fe27e772SPawel Jakub Dawidek return (0); 166fe27e772SPawel Jakub Dawidek } 167fe27e772SPawel Jakub Dawidek 168fe27e772SPawel Jakub Dawidek static int 169fe27e772SPawel Jakub Dawidek g_gate_access(struct g_provider *pp, int dr, int dw, int de) 170fe27e772SPawel Jakub Dawidek { 171fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 172fe27e772SPawel Jakub Dawidek 173fe27e772SPawel Jakub Dawidek if (dr <= 0 && dw <= 0 && de <= 0) 174fe27e772SPawel Jakub Dawidek return (0); 175fe27e772SPawel Jakub Dawidek sc = pp->geom->softc; 176fe27e772SPawel Jakub Dawidek if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) 177fe27e772SPawel Jakub Dawidek return (ENXIO); 17855336b83SPawel Jakub Dawidek /* XXX: Hack to allow read-only mounts. */ 17955336b83SPawel Jakub Dawidek #if 0 180fe27e772SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0 && dw > 0) 181fe27e772SPawel Jakub Dawidek return (EPERM); 18255336b83SPawel Jakub Dawidek #endif 183fe27e772SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0 && dr > 0) 184fe27e772SPawel Jakub Dawidek return (EPERM); 185fe27e772SPawel Jakub Dawidek return (0); 186fe27e772SPawel Jakub Dawidek } 187fe27e772SPawel Jakub Dawidek 188fe27e772SPawel Jakub Dawidek static void 189e08ec037SPawel Jakub Dawidek g_gate_queue_io(struct bio *bp) 190fe27e772SPawel Jakub Dawidek { 191fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 192fe27e772SPawel Jakub Dawidek 193fe27e772SPawel Jakub Dawidek sc = bp->bio_to->geom->softc; 194fe27e772SPawel Jakub Dawidek if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) { 195fe27e772SPawel Jakub Dawidek g_io_deliver(bp, ENXIO); 196fe27e772SPawel Jakub Dawidek return; 197fe27e772SPawel Jakub Dawidek } 198fe27e772SPawel Jakub Dawidek 199e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 200e08ec037SPawel Jakub Dawidek 20163a6c5c1SPawel Jakub Dawidek if (sc->sc_queue_size > 0 && sc->sc_queue_count > sc->sc_queue_size) { 20235f855d9SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 203fe27e772SPawel Jakub Dawidek G_GATE_LOGREQ(1, bp, "Queue full, request canceled."); 20432115b10SPawel Jakub Dawidek g_io_deliver(bp, ENOMEM); 205fe27e772SPawel Jakub Dawidek return; 206fe27e772SPawel Jakub Dawidek } 207e35d3a78SPawel Jakub Dawidek 208fe27e772SPawel Jakub Dawidek bp->bio_driver1 = (void *)sc->sc_seq; 209fe27e772SPawel Jakub Dawidek sc->sc_seq++; 210e35d3a78SPawel Jakub Dawidek sc->sc_queue_count++; 211fe27e772SPawel Jakub Dawidek 212662a4e58SPawel Jakub Dawidek bioq_insert_tail(&sc->sc_inqueue, bp); 213fe27e772SPawel Jakub Dawidek wakeup(sc); 214e35d3a78SPawel Jakub Dawidek 215e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 216fe27e772SPawel Jakub Dawidek } 217fe27e772SPawel Jakub Dawidek 218e08ec037SPawel Jakub Dawidek static void 219e08ec037SPawel Jakub Dawidek g_gate_done(struct bio *cbp) 220e08ec037SPawel Jakub Dawidek { 221351d0fa6SAlexander Motin struct g_gate_softc *sc; 222e08ec037SPawel Jakub Dawidek struct bio *pbp; 223351d0fa6SAlexander Motin struct g_consumer *cp; 224e08ec037SPawel Jakub Dawidek 225351d0fa6SAlexander Motin cp = cbp->bio_from; 226e08ec037SPawel Jakub Dawidek pbp = cbp->bio_parent; 227e08ec037SPawel Jakub Dawidek if (cbp->bio_error == 0) { 228e08ec037SPawel Jakub Dawidek pbp->bio_completed = cbp->bio_completed; 229e08ec037SPawel Jakub Dawidek g_destroy_bio(cbp); 230e08ec037SPawel Jakub Dawidek pbp->bio_inbed++; 231e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, 0); 232e08ec037SPawel Jakub Dawidek } else { 233e08ec037SPawel Jakub Dawidek /* If direct read failed, pass it through userland daemon. */ 234e08ec037SPawel Jakub Dawidek g_destroy_bio(cbp); 235e08ec037SPawel Jakub Dawidek pbp->bio_children--; 236e08ec037SPawel Jakub Dawidek g_gate_queue_io(pbp); 237e08ec037SPawel Jakub Dawidek } 238351d0fa6SAlexander Motin 239351d0fa6SAlexander Motin sc = cp->geom->softc; 240351d0fa6SAlexander Motin mtx_lock(&sc->sc_read_mtx); 241351d0fa6SAlexander Motin if (--cp->index == 0 && sc->sc_readcons != cp) 242351d0fa6SAlexander Motin g_post_event(g_gate_detach, cp, M_NOWAIT, NULL); 243351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 244e08ec037SPawel Jakub Dawidek } 245e08ec037SPawel Jakub Dawidek 246e08ec037SPawel Jakub Dawidek static void 247e08ec037SPawel Jakub Dawidek g_gate_start(struct bio *pbp) 248e08ec037SPawel Jakub Dawidek { 249e08ec037SPawel Jakub Dawidek struct g_gate_softc *sc; 250351d0fa6SAlexander Motin struct g_consumer *cp; 251351d0fa6SAlexander Motin struct bio *cbp; 252e08ec037SPawel Jakub Dawidek 253e08ec037SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 254e08ec037SPawel Jakub Dawidek if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) { 255e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, ENXIO); 256e08ec037SPawel Jakub Dawidek return; 257e08ec037SPawel Jakub Dawidek } 258e08ec037SPawel Jakub Dawidek G_GATE_LOGREQ(2, pbp, "Request received."); 259e08ec037SPawel Jakub Dawidek switch (pbp->bio_cmd) { 260e08ec037SPawel Jakub Dawidek case BIO_READ: 261351d0fa6SAlexander Motin if (sc->sc_readcons == NULL) 262351d0fa6SAlexander Motin break; 263e08ec037SPawel Jakub Dawidek cbp = g_clone_bio(pbp); 264e08ec037SPawel Jakub Dawidek if (cbp == NULL) { 265e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, ENOMEM); 266e08ec037SPawel Jakub Dawidek return; 267e08ec037SPawel Jakub Dawidek } 268351d0fa6SAlexander Motin mtx_lock(&sc->sc_read_mtx); 269351d0fa6SAlexander Motin if ((cp = sc->sc_readcons) == NULL) { 270351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 271351d0fa6SAlexander Motin g_destroy_bio(cbp); 272351d0fa6SAlexander Motin pbp->bio_children--; 273e08ec037SPawel Jakub Dawidek break; 274351d0fa6SAlexander Motin } 275351d0fa6SAlexander Motin cp->index++; 276351d0fa6SAlexander Motin cbp->bio_offset = pbp->bio_offset + sc->sc_readoffset; 277351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 278351d0fa6SAlexander Motin cbp->bio_done = g_gate_done; 279351d0fa6SAlexander Motin g_io_request(cbp, cp); 280351d0fa6SAlexander Motin return; 281e08ec037SPawel Jakub Dawidek case BIO_DELETE: 282e08ec037SPawel Jakub Dawidek case BIO_WRITE: 283e08ec037SPawel Jakub Dawidek case BIO_FLUSH: 2848b522bdaSWarner Losh case BIO_SPEEDUP: 285e08ec037SPawel Jakub Dawidek /* XXX: Hack to allow read-only mounts. */ 286e08ec037SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) { 287e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, EPERM); 288e08ec037SPawel Jakub Dawidek return; 289e08ec037SPawel Jakub Dawidek } 290e08ec037SPawel Jakub Dawidek break; 291e08ec037SPawel Jakub Dawidek case BIO_GETATTR: 292e08ec037SPawel Jakub Dawidek default: 293e08ec037SPawel Jakub Dawidek G_GATE_LOGREQ(2, pbp, "Ignoring request."); 294e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, EOPNOTSUPP); 295e08ec037SPawel Jakub Dawidek return; 296e08ec037SPawel Jakub Dawidek } 297e08ec037SPawel Jakub Dawidek 298e08ec037SPawel Jakub Dawidek g_gate_queue_io(pbp); 299e08ec037SPawel Jakub Dawidek } 300e08ec037SPawel Jakub Dawidek 301fe27e772SPawel Jakub Dawidek static struct g_gate_softc * 3022aa15ffdSPawel Jakub Dawidek g_gate_hold(int unit, const char *name) 303fe27e772SPawel Jakub Dawidek { 30432115b10SPawel Jakub Dawidek struct g_gate_softc *sc = NULL; 305fe27e772SPawel Jakub Dawidek 30632115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 30732115b10SPawel Jakub Dawidek if (unit >= 0 && unit < g_gate_maxunits) 30832115b10SPawel Jakub Dawidek sc = g_gate_units[unit]; 30932115b10SPawel Jakub Dawidek else if (unit == G_GATE_NAME_GIVEN) { 31032115b10SPawel Jakub Dawidek KASSERT(name != NULL, ("name is NULL")); 31132115b10SPawel Jakub Dawidek for (unit = 0; unit < g_gate_maxunits; unit++) { 31232115b10SPawel Jakub Dawidek if (g_gate_units[unit] == NULL) 31332115b10SPawel Jakub Dawidek continue; 31432115b10SPawel Jakub Dawidek if (strcmp(name, 31532115b10SPawel Jakub Dawidek g_gate_units[unit]->sc_provider->name) != 0) { 31632115b10SPawel Jakub Dawidek continue; 31732115b10SPawel Jakub Dawidek } 31832115b10SPawel Jakub Dawidek sc = g_gate_units[unit]; 3197ffb6e0fSPawel Jakub Dawidek break; 320fe27e772SPawel Jakub Dawidek } 32132115b10SPawel Jakub Dawidek } 3227ffb6e0fSPawel Jakub Dawidek if (sc != NULL) 3237ffb6e0fSPawel Jakub Dawidek sc->sc_ref++; 32432115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 325fe27e772SPawel Jakub Dawidek return (sc); 326fe27e772SPawel Jakub Dawidek } 327fe27e772SPawel Jakub Dawidek 328fe27e772SPawel Jakub Dawidek static void 329fe27e772SPawel Jakub Dawidek g_gate_release(struct g_gate_softc *sc) 330fe27e772SPawel Jakub Dawidek { 331fe27e772SPawel Jakub Dawidek 33232115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 333fe27e772SPawel Jakub Dawidek sc->sc_ref--; 334fe27e772SPawel Jakub Dawidek KASSERT(sc->sc_ref >= 0, ("Negative sc_ref for %s.", sc->sc_name)); 33532115b10SPawel Jakub Dawidek if (sc->sc_ref == 0 && (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) 3367ffb6e0fSPawel Jakub Dawidek wakeup(&sc->sc_ref); 33732115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 338fe27e772SPawel Jakub Dawidek } 339fe27e772SPawel Jakub Dawidek 340fe27e772SPawel Jakub Dawidek static int 34132115b10SPawel Jakub Dawidek g_gate_getunit(int unit, int *errorp) 342fe27e772SPawel Jakub Dawidek { 343fe27e772SPawel Jakub Dawidek 34432115b10SPawel Jakub Dawidek mtx_assert(&g_gate_units_lock, MA_OWNED); 345fe27e772SPawel Jakub Dawidek if (unit >= 0) { 34632115b10SPawel Jakub Dawidek if (unit >= g_gate_maxunits) 34732115b10SPawel Jakub Dawidek *errorp = EINVAL; 34832115b10SPawel Jakub Dawidek else if (g_gate_units[unit] == NULL) 349fe27e772SPawel Jakub Dawidek return (unit); 35032115b10SPawel Jakub Dawidek else 35132115b10SPawel Jakub Dawidek *errorp = EEXIST; 35232115b10SPawel Jakub Dawidek } else { 35332115b10SPawel Jakub Dawidek for (unit = 0; unit < g_gate_maxunits; unit++) { 35432115b10SPawel Jakub Dawidek if (g_gate_units[unit] == NULL) 35532115b10SPawel Jakub Dawidek return (unit); 35632115b10SPawel Jakub Dawidek } 35732115b10SPawel Jakub Dawidek *errorp = ENFILE; 35832115b10SPawel Jakub Dawidek } 35932115b10SPawel Jakub Dawidek return (-1); 360fe27e772SPawel Jakub Dawidek } 361fe27e772SPawel Jakub Dawidek 362fe27e772SPawel Jakub Dawidek static void 363fe27e772SPawel Jakub Dawidek g_gate_guard(void *arg) 364fe27e772SPawel Jakub Dawidek { 36540ea77a0SAlexander Motin struct bio_queue_head queue; 366fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 367fe27e772SPawel Jakub Dawidek struct bintime curtime; 368fe27e772SPawel Jakub Dawidek struct bio *bp, *bp2; 369fe27e772SPawel Jakub Dawidek 370fe27e772SPawel Jakub Dawidek sc = arg; 371fe27e772SPawel Jakub Dawidek binuptime(&curtime); 37232115b10SPawel Jakub Dawidek g_gate_hold(sc->sc_unit, NULL); 37340ea77a0SAlexander Motin bioq_init(&queue); 374e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 375fe27e772SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(bp, &sc->sc_inqueue.queue, bio_queue, bp2) { 376fe27e772SPawel Jakub Dawidek if (curtime.sec - bp->bio_t0.sec < 5) 377fe27e772SPawel Jakub Dawidek continue; 378fe27e772SPawel Jakub Dawidek bioq_remove(&sc->sc_inqueue, bp); 379e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 38040ea77a0SAlexander Motin bioq_insert_tail(&queue, bp); 381fe27e772SPawel Jakub Dawidek } 382fe27e772SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, bp2) { 383fe27e772SPawel Jakub Dawidek if (curtime.sec - bp->bio_t0.sec < 5) 384fe27e772SPawel Jakub Dawidek continue; 385fe27e772SPawel Jakub Dawidek bioq_remove(&sc->sc_outqueue, bp); 386e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 38740ea77a0SAlexander Motin bioq_insert_tail(&queue, bp); 38840ea77a0SAlexander Motin } 38940ea77a0SAlexander Motin mtx_unlock(&sc->sc_queue_mtx); 39040ea77a0SAlexander Motin while ((bp = bioq_takefirst(&queue)) != NULL) { 391fe27e772SPawel Jakub Dawidek G_GATE_LOGREQ(1, bp, "Request timeout."); 392fe27e772SPawel Jakub Dawidek g_io_deliver(bp, EIO); 393fe27e772SPawel Jakub Dawidek } 394fe27e772SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0) { 395fe27e772SPawel Jakub Dawidek callout_reset(&sc->sc_callout, sc->sc_timeout * hz, 396fe27e772SPawel Jakub Dawidek g_gate_guard, sc); 397fe27e772SPawel Jakub Dawidek } 398fe27e772SPawel Jakub Dawidek g_gate_release(sc); 399fe27e772SPawel Jakub Dawidek } 400fe27e772SPawel Jakub Dawidek 401fe27e772SPawel Jakub Dawidek static void 402e08ec037SPawel Jakub Dawidek g_gate_orphan(struct g_consumer *cp) 403e08ec037SPawel Jakub Dawidek { 404e08ec037SPawel Jakub Dawidek struct g_gate_softc *sc; 405e08ec037SPawel Jakub Dawidek struct g_geom *gp; 406351d0fa6SAlexander Motin int done; 407e08ec037SPawel Jakub Dawidek 408e08ec037SPawel Jakub Dawidek g_topology_assert(); 409e08ec037SPawel Jakub Dawidek gp = cp->geom; 410e08ec037SPawel Jakub Dawidek sc = gp->softc; 411351d0fa6SAlexander Motin mtx_lock(&sc->sc_read_mtx); 412351d0fa6SAlexander Motin if (sc->sc_readcons == cp) 413e08ec037SPawel Jakub Dawidek sc->sc_readcons = NULL; 414351d0fa6SAlexander Motin done = (cp->index == 0); 415351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 416351d0fa6SAlexander Motin if (done) 417351d0fa6SAlexander Motin g_gate_detach(cp, 0); 418e08ec037SPawel Jakub Dawidek } 419e08ec037SPawel Jakub Dawidek 420e08ec037SPawel Jakub Dawidek static void 421fe27e772SPawel Jakub Dawidek g_gate_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 422fe27e772SPawel Jakub Dawidek struct g_consumer *cp, struct g_provider *pp) 423fe27e772SPawel Jakub Dawidek { 424fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 425fe27e772SPawel Jakub Dawidek 426fe27e772SPawel Jakub Dawidek sc = gp->softc; 427fe27e772SPawel Jakub Dawidek if (sc == NULL || pp != NULL || cp != NULL) 428fe27e772SPawel Jakub Dawidek return; 4291d9db37cSMikolaj Golub sc = g_gate_hold(sc->sc_unit, NULL); 4301d9db37cSMikolaj Golub if (sc == NULL) 4311d9db37cSMikolaj Golub return; 432fe27e772SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) { 433fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<access>%s</access>\n", indent, "read-only"); 434fe27e772SPawel Jakub Dawidek } else if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0) { 435fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<access>%s</access>\n", indent, 436fe27e772SPawel Jakub Dawidek "write-only"); 437fe27e772SPawel Jakub Dawidek } else { 438fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<access>%s</access>\n", indent, 439fe27e772SPawel Jakub Dawidek "read-write"); 440fe27e772SPawel Jakub Dawidek } 441e08ec037SPawel Jakub Dawidek if (sc->sc_readcons != NULL) { 442e08ec037SPawel Jakub Dawidek sbuf_printf(sb, "%s<read_offset>%jd</read_offset>\n", 443e08ec037SPawel Jakub Dawidek indent, (intmax_t)sc->sc_readoffset); 444e08ec037SPawel Jakub Dawidek sbuf_printf(sb, "%s<read_provider>%s</read_provider>\n", 445e08ec037SPawel Jakub Dawidek indent, sc->sc_readcons->provider->name); 446e08ec037SPawel Jakub Dawidek } 447fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<timeout>%u</timeout>\n", indent, sc->sc_timeout); 448fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<info>%s</info>\n", indent, sc->sc_info); 449fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<queue_count>%u</queue_count>\n", indent, 450fe27e772SPawel Jakub Dawidek sc->sc_queue_count); 451fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<queue_size>%u</queue_size>\n", indent, 452fe27e772SPawel Jakub Dawidek sc->sc_queue_size); 453fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<ref>%u</ref>\n", indent, sc->sc_ref); 45432115b10SPawel Jakub Dawidek sbuf_printf(sb, "%s<unit>%d</unit>\n", indent, sc->sc_unit); 455fe27e772SPawel Jakub Dawidek g_gate_release(sc); 456fe27e772SPawel Jakub Dawidek } 457fe27e772SPawel Jakub Dawidek 458fe27e772SPawel Jakub Dawidek static int 459fe27e772SPawel Jakub Dawidek g_gate_create(struct g_gate_ctl_create *ggio) 460fe27e772SPawel Jakub Dawidek { 461fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 462fe27e772SPawel Jakub Dawidek struct g_geom *gp; 463e08ec037SPawel Jakub Dawidek struct g_provider *pp, *ropp; 464e08ec037SPawel Jakub Dawidek struct g_consumer *cp; 465f284bed2SAlan Somers char name[NAME_MAX + 1]; 466f284bed2SAlan Somers char readprov[NAME_MAX + 1]; 46732115b10SPawel Jakub Dawidek int error = 0, unit; 468fe27e772SPawel Jakub Dawidek 469e08ec037SPawel Jakub Dawidek if (ggio->gctl_mediasize <= 0) { 470fe27e772SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid media size."); 471fe27e772SPawel Jakub Dawidek return (EINVAL); 472fe27e772SPawel Jakub Dawidek } 473e08ec037SPawel Jakub Dawidek if (ggio->gctl_sectorsize <= 0) { 474e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid sector size."); 475e08ec037SPawel Jakub Dawidek return (EINVAL); 476e08ec037SPawel Jakub Dawidek } 477e08ec037SPawel Jakub Dawidek if (!powerof2(ggio->gctl_sectorsize)) { 478fe27e772SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid sector size."); 479fe27e772SPawel Jakub Dawidek return (EINVAL); 480fe27e772SPawel Jakub Dawidek } 481662a4e58SPawel Jakub Dawidek if ((ggio->gctl_mediasize % ggio->gctl_sectorsize) != 0) { 482662a4e58SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid media size."); 483662a4e58SPawel Jakub Dawidek return (EINVAL); 484662a4e58SPawel Jakub Dawidek } 485fe27e772SPawel Jakub Dawidek if ((ggio->gctl_flags & G_GATE_FLAG_READONLY) != 0 && 486fe27e772SPawel Jakub Dawidek (ggio->gctl_flags & G_GATE_FLAG_WRITEONLY) != 0) { 487fe27e772SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid flags."); 488fe27e772SPawel Jakub Dawidek return (EINVAL); 489fe27e772SPawel Jakub Dawidek } 49032115b10SPawel Jakub Dawidek if (ggio->gctl_unit != G_GATE_UNIT_AUTO && 49132115b10SPawel Jakub Dawidek ggio->gctl_unit != G_GATE_NAME_GIVEN && 49232115b10SPawel Jakub Dawidek ggio->gctl_unit < 0) { 493fe27e772SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid unit number."); 494fe27e772SPawel Jakub Dawidek return (EINVAL); 495fe27e772SPawel Jakub Dawidek } 49632115b10SPawel Jakub Dawidek if (ggio->gctl_unit == G_GATE_NAME_GIVEN && 49732115b10SPawel Jakub Dawidek ggio->gctl_name[0] == '\0') { 49832115b10SPawel Jakub Dawidek G_GATE_DEBUG(1, "No device name."); 49932115b10SPawel Jakub Dawidek return (EINVAL); 50032115b10SPawel Jakub Dawidek } 501fe27e772SPawel Jakub Dawidek 502fe27e772SPawel Jakub Dawidek sc = malloc(sizeof(*sc), M_GATE, M_WAITOK | M_ZERO); 503fe27e772SPawel Jakub Dawidek sc->sc_flags = (ggio->gctl_flags & G_GATE_USERFLAGS); 504f284bed2SAlan Somers memset(sc->sc_info, 0, sizeof(sc->sc_info)); 505f284bed2SAlan Somers strncpy(sc->sc_info, ggio->gctl_info, 506f284bed2SAlan Somers MIN(sizeof(sc->sc_info) - 1, sizeof(ggio->gctl_info))); 50732115b10SPawel Jakub Dawidek sc->sc_seq = 1; 508fe27e772SPawel Jakub Dawidek bioq_init(&sc->sc_inqueue); 509fe27e772SPawel Jakub Dawidek bioq_init(&sc->sc_outqueue); 510e35d3a78SPawel Jakub Dawidek mtx_init(&sc->sc_queue_mtx, "gg:queue", NULL, MTX_DEF); 511351d0fa6SAlexander Motin mtx_init(&sc->sc_read_mtx, "gg:read", NULL, MTX_DEF); 512fe27e772SPawel Jakub Dawidek sc->sc_queue_count = 0; 513fe27e772SPawel Jakub Dawidek sc->sc_queue_size = ggio->gctl_maxcount; 514fe27e772SPawel Jakub Dawidek if (sc->sc_queue_size > G_GATE_MAX_QUEUE_SIZE) 515fe27e772SPawel Jakub Dawidek sc->sc_queue_size = G_GATE_MAX_QUEUE_SIZE; 516fe27e772SPawel Jakub Dawidek sc->sc_timeout = ggio->gctl_timeout; 517fd90e2edSJung-uk Kim callout_init(&sc->sc_callout, 1); 518e08ec037SPawel Jakub Dawidek 51932115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 52032115b10SPawel Jakub Dawidek sc->sc_unit = g_gate_getunit(ggio->gctl_unit, &error); 521a277f47bSMikolaj Golub if (sc->sc_unit < 0) 522a277f47bSMikolaj Golub goto fail1; 523f284bed2SAlan Somers if (ggio->gctl_unit == G_GATE_NAME_GIVEN) { 524f284bed2SAlan Somers memset(name, 0, sizeof(name)); 525f284bed2SAlan Somers strncpy(name, ggio->gctl_name, 526f284bed2SAlan Somers MIN(sizeof(name) - 1, sizeof(ggio->gctl_name))); 527f284bed2SAlan Somers } else { 52832115b10SPawel Jakub Dawidek snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME, 52932115b10SPawel Jakub Dawidek sc->sc_unit); 53032115b10SPawel Jakub Dawidek } 53132115b10SPawel Jakub Dawidek /* Check for name collision. */ 53232115b10SPawel Jakub Dawidek for (unit = 0; unit < g_gate_maxunits; unit++) { 53332115b10SPawel Jakub Dawidek if (g_gate_units[unit] == NULL) 53432115b10SPawel Jakub Dawidek continue; 535baf63f65SMikolaj Golub if (strcmp(name, g_gate_units[unit]->sc_name) != 0) 53632115b10SPawel Jakub Dawidek continue; 537a277f47bSMikolaj Golub error = EEXIST; 538a277f47bSMikolaj Golub goto fail1; 53932115b10SPawel Jakub Dawidek } 540f284bed2SAlan Somers // local stack buffer 'name' assigned here temporarily only. 541f284bed2SAlan Somers // the real provider name is assigned below. 542baf63f65SMikolaj Golub sc->sc_name = name; 54332115b10SPawel Jakub Dawidek g_gate_units[sc->sc_unit] = sc; 54432115b10SPawel Jakub Dawidek g_gate_nunits++; 54532115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 54632115b10SPawel Jakub Dawidek 547a277f47bSMikolaj Golub g_topology_lock(); 548a277f47bSMikolaj Golub 549a277f47bSMikolaj Golub if (ggio->gctl_readprov[0] == '\0') { 550a277f47bSMikolaj Golub ropp = NULL; 551a277f47bSMikolaj Golub } else { 552f284bed2SAlan Somers memset(readprov, 0, sizeof(readprov)); 553f284bed2SAlan Somers strncpy(readprov, ggio->gctl_readprov, 554f284bed2SAlan Somers MIN(sizeof(readprov) - 1, sizeof(ggio->gctl_readprov))); 555f284bed2SAlan Somers ropp = g_provider_by_name(readprov); 556a277f47bSMikolaj Golub if (ropp == NULL) { 557f284bed2SAlan Somers G_GATE_DEBUG(1, "Provider %s doesn't exist.", readprov); 558a277f47bSMikolaj Golub error = EINVAL; 559a277f47bSMikolaj Golub goto fail2; 560a277f47bSMikolaj Golub } 561a277f47bSMikolaj Golub if ((ggio->gctl_readoffset % ggio->gctl_sectorsize) != 0) { 562a277f47bSMikolaj Golub G_GATE_DEBUG(1, "Invalid read offset."); 563a277f47bSMikolaj Golub error = EINVAL; 564a277f47bSMikolaj Golub goto fail2; 565a277f47bSMikolaj Golub } 566a277f47bSMikolaj Golub if (ggio->gctl_mediasize + ggio->gctl_readoffset > 567a277f47bSMikolaj Golub ropp->mediasize) { 568a277f47bSMikolaj Golub G_GATE_DEBUG(1, "Invalid read offset or media size."); 569a277f47bSMikolaj Golub error = EINVAL; 570a277f47bSMikolaj Golub goto fail2; 571a277f47bSMikolaj Golub } 572a277f47bSMikolaj Golub } 573a277f47bSMikolaj Golub 574a277f47bSMikolaj Golub gp = g_new_geomf(&g_gate_class, "%s", name); 575a277f47bSMikolaj Golub gp->start = g_gate_start; 576a277f47bSMikolaj Golub gp->access = g_gate_access; 577a277f47bSMikolaj Golub gp->orphan = g_gate_orphan; 578a277f47bSMikolaj Golub gp->dumpconf = g_gate_dumpconf; 579a277f47bSMikolaj Golub gp->softc = sc; 580a277f47bSMikolaj Golub 581a277f47bSMikolaj Golub if (ropp != NULL) { 582a277f47bSMikolaj Golub cp = g_new_consumer(gp); 58340ea77a0SAlexander Motin cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 584a277f47bSMikolaj Golub error = g_attach(cp, ropp); 585a277f47bSMikolaj Golub if (error != 0) { 586a277f47bSMikolaj Golub G_GATE_DEBUG(1, "Unable to attach to %s.", ropp->name); 587a277f47bSMikolaj Golub goto fail3; 588a277f47bSMikolaj Golub } 589a277f47bSMikolaj Golub error = g_access(cp, 1, 0, 0); 590a277f47bSMikolaj Golub if (error != 0) { 591a277f47bSMikolaj Golub G_GATE_DEBUG(1, "Unable to access %s.", ropp->name); 592a277f47bSMikolaj Golub g_detach(cp); 593a277f47bSMikolaj Golub goto fail3; 594a277f47bSMikolaj Golub } 595a277f47bSMikolaj Golub sc->sc_readcons = cp; 596a277f47bSMikolaj Golub sc->sc_readoffset = ggio->gctl_readoffset; 597a277f47bSMikolaj Golub } 598a277f47bSMikolaj Golub 59932115b10SPawel Jakub Dawidek ggio->gctl_unit = sc->sc_unit; 600fe27e772SPawel Jakub Dawidek 60132115b10SPawel Jakub Dawidek pp = g_new_providerf(gp, "%s", name); 60240ea77a0SAlexander Motin pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; 603fe27e772SPawel Jakub Dawidek pp->mediasize = ggio->gctl_mediasize; 604fe27e772SPawel Jakub Dawidek pp->sectorsize = ggio->gctl_sectorsize; 605fe27e772SPawel Jakub Dawidek sc->sc_provider = pp; 606fe27e772SPawel Jakub Dawidek g_error_provider(pp, 0); 607e08ec037SPawel Jakub Dawidek 608fe27e772SPawel Jakub Dawidek g_topology_unlock(); 609baf63f65SMikolaj Golub mtx_lock(&g_gate_units_lock); 610baf63f65SMikolaj Golub sc->sc_name = sc->sc_provider->name; 611baf63f65SMikolaj Golub mtx_unlock(&g_gate_units_lock); 612bd119384SMikolaj Golub G_GATE_DEBUG(1, "Device %s created.", gp->name); 613fe27e772SPawel Jakub Dawidek 614fe27e772SPawel Jakub Dawidek if (sc->sc_timeout > 0) { 615fe27e772SPawel Jakub Dawidek callout_reset(&sc->sc_callout, sc->sc_timeout * hz, 616fe27e772SPawel Jakub Dawidek g_gate_guard, sc); 617fe27e772SPawel Jakub Dawidek } 618fe27e772SPawel Jakub Dawidek return (0); 619a277f47bSMikolaj Golub fail3: 620a277f47bSMikolaj Golub g_destroy_consumer(cp); 621a277f47bSMikolaj Golub g_destroy_geom(gp); 622a277f47bSMikolaj Golub fail2: 623a277f47bSMikolaj Golub g_topology_unlock(); 624a277f47bSMikolaj Golub mtx_lock(&g_gate_units_lock); 625a277f47bSMikolaj Golub g_gate_units[sc->sc_unit] = NULL; 626a277f47bSMikolaj Golub KASSERT(g_gate_nunits > 0, ("negative g_gate_nunits?")); 627a277f47bSMikolaj Golub g_gate_nunits--; 628a277f47bSMikolaj Golub fail1: 629a277f47bSMikolaj Golub mtx_unlock(&g_gate_units_lock); 630a277f47bSMikolaj Golub mtx_destroy(&sc->sc_queue_mtx); 631351d0fa6SAlexander Motin mtx_destroy(&sc->sc_read_mtx); 632a277f47bSMikolaj Golub free(sc, M_GATE); 633a277f47bSMikolaj Golub return (error); 634fe27e772SPawel Jakub Dawidek } 635fe27e772SPawel Jakub Dawidek 636e08ec037SPawel Jakub Dawidek static int 637e08ec037SPawel Jakub Dawidek g_gate_modify(struct g_gate_softc *sc, struct g_gate_ctl_modify *ggio) 638e08ec037SPawel Jakub Dawidek { 639f284bed2SAlan Somers char readprov[NAME_MAX + 1]; 640e08ec037SPawel Jakub Dawidek struct g_provider *pp; 641e08ec037SPawel Jakub Dawidek struct g_consumer *cp; 642351d0fa6SAlexander Motin int done, error; 643e08ec037SPawel Jakub Dawidek 644e08ec037SPawel Jakub Dawidek if ((ggio->gctl_modify & GG_MODIFY_MEDIASIZE) != 0) { 645e08ec037SPawel Jakub Dawidek if (ggio->gctl_mediasize <= 0) { 646e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid media size."); 647e08ec037SPawel Jakub Dawidek return (EINVAL); 648e08ec037SPawel Jakub Dawidek } 649e08ec037SPawel Jakub Dawidek pp = sc->sc_provider; 650e08ec037SPawel Jakub Dawidek if ((ggio->gctl_mediasize % pp->sectorsize) != 0) { 651e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid media size."); 652e08ec037SPawel Jakub Dawidek return (EINVAL); 653e08ec037SPawel Jakub Dawidek } 654874774c5SMikolaj Golub g_resize_provider(pp, ggio->gctl_mediasize); 655874774c5SMikolaj Golub return (0); 656e08ec037SPawel Jakub Dawidek } 657e08ec037SPawel Jakub Dawidek 658f284bed2SAlan Somers if ((ggio->gctl_modify & GG_MODIFY_INFO) != 0) { 659f284bed2SAlan Somers memset(sc->sc_info, 0, sizeof(sc->sc_info)); 660f284bed2SAlan Somers strncpy(sc->sc_info, ggio->gctl_info, 661f284bed2SAlan Somers MIN(sizeof(sc->sc_info) - 1, sizeof(ggio->gctl_info))); 662f284bed2SAlan Somers } 663e08ec037SPawel Jakub Dawidek cp = NULL; 664e08ec037SPawel Jakub Dawidek 665e08ec037SPawel Jakub Dawidek if ((ggio->gctl_modify & GG_MODIFY_READPROV) != 0) { 666e08ec037SPawel Jakub Dawidek g_topology_lock(); 667351d0fa6SAlexander Motin mtx_lock(&sc->sc_read_mtx); 668351d0fa6SAlexander Motin if ((cp = sc->sc_readcons) != NULL) { 669e08ec037SPawel Jakub Dawidek sc->sc_readcons = NULL; 670351d0fa6SAlexander Motin done = (cp->index == 0); 671351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 672351d0fa6SAlexander Motin if (done) 673351d0fa6SAlexander Motin g_gate_detach(cp, 0); 674351d0fa6SAlexander Motin } else 675351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 676e08ec037SPawel Jakub Dawidek if (ggio->gctl_readprov[0] != '\0') { 677f284bed2SAlan Somers memset(readprov, 0, sizeof(readprov)); 678f284bed2SAlan Somers strncpy(readprov, ggio->gctl_readprov, 679f284bed2SAlan Somers MIN(sizeof(readprov) - 1, 680f284bed2SAlan Somers sizeof(ggio->gctl_readprov))); 681f284bed2SAlan Somers pp = g_provider_by_name(readprov); 682e08ec037SPawel Jakub Dawidek if (pp == NULL) { 683e08ec037SPawel Jakub Dawidek g_topology_unlock(); 684e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Provider %s doesn't exist.", 685f284bed2SAlan Somers readprov); 686e08ec037SPawel Jakub Dawidek return (EINVAL); 687e08ec037SPawel Jakub Dawidek } 688e08ec037SPawel Jakub Dawidek cp = g_new_consumer(sc->sc_provider->geom); 68940ea77a0SAlexander Motin cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 690e08ec037SPawel Jakub Dawidek error = g_attach(cp, pp); 691e08ec037SPawel Jakub Dawidek if (error != 0) { 692e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Unable to attach to %s.", 693e08ec037SPawel Jakub Dawidek pp->name); 694e08ec037SPawel Jakub Dawidek } else { 695e08ec037SPawel Jakub Dawidek error = g_access(cp, 1, 0, 0); 696e08ec037SPawel Jakub Dawidek if (error != 0) { 697e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Unable to access %s.", 698e08ec037SPawel Jakub Dawidek pp->name); 699e08ec037SPawel Jakub Dawidek g_detach(cp); 700e08ec037SPawel Jakub Dawidek } 701e08ec037SPawel Jakub Dawidek } 702e08ec037SPawel Jakub Dawidek if (error != 0) { 703e08ec037SPawel Jakub Dawidek g_destroy_consumer(cp); 704e08ec037SPawel Jakub Dawidek g_topology_unlock(); 705e08ec037SPawel Jakub Dawidek return (error); 706e08ec037SPawel Jakub Dawidek } 707e08ec037SPawel Jakub Dawidek } 708e08ec037SPawel Jakub Dawidek } else { 709e08ec037SPawel Jakub Dawidek cp = sc->sc_readcons; 710e08ec037SPawel Jakub Dawidek } 711e08ec037SPawel Jakub Dawidek 712e08ec037SPawel Jakub Dawidek if ((ggio->gctl_modify & GG_MODIFY_READOFFSET) != 0) { 713e08ec037SPawel Jakub Dawidek if (cp == NULL) { 714e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "No read provider."); 715e08ec037SPawel Jakub Dawidek return (EINVAL); 716e08ec037SPawel Jakub Dawidek } 717e08ec037SPawel Jakub Dawidek pp = sc->sc_provider; 718e08ec037SPawel Jakub Dawidek if ((ggio->gctl_readoffset % pp->sectorsize) != 0) { 719e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid read offset."); 720e08ec037SPawel Jakub Dawidek return (EINVAL); 721e08ec037SPawel Jakub Dawidek } 722e08ec037SPawel Jakub Dawidek if (pp->mediasize + ggio->gctl_readoffset > 723e08ec037SPawel Jakub Dawidek cp->provider->mediasize) { 724e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid read offset or media size."); 725e08ec037SPawel Jakub Dawidek return (EINVAL); 726e08ec037SPawel Jakub Dawidek } 727e08ec037SPawel Jakub Dawidek sc->sc_readoffset = ggio->gctl_readoffset; 728e08ec037SPawel Jakub Dawidek } 729e08ec037SPawel Jakub Dawidek 730e08ec037SPawel Jakub Dawidek if ((ggio->gctl_modify & GG_MODIFY_READPROV) != 0) { 731e08ec037SPawel Jakub Dawidek sc->sc_readcons = cp; 732e08ec037SPawel Jakub Dawidek g_topology_unlock(); 733e08ec037SPawel Jakub Dawidek } 734e08ec037SPawel Jakub Dawidek 735e08ec037SPawel Jakub Dawidek return (0); 736e08ec037SPawel Jakub Dawidek } 737e08ec037SPawel Jakub Dawidek 738fe27e772SPawel Jakub Dawidek #define G_GATE_CHECK_VERSION(ggio) do { \ 73984436f14SPawel Jakub Dawidek if ((ggio)->gctl_version != G_GATE_VERSION) { \ 74084436f14SPawel Jakub Dawidek printf("Version mismatch %d != %d.\n", \ 74184436f14SPawel Jakub Dawidek ggio->gctl_version, G_GATE_VERSION); \ 742fe27e772SPawel Jakub Dawidek return (EINVAL); \ 74384436f14SPawel Jakub Dawidek } \ 744fe27e772SPawel Jakub Dawidek } while (0) 745fe27e772SPawel Jakub Dawidek static int 74689c9c53dSPoul-Henning Kamp g_gate_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 747fe27e772SPawel Jakub Dawidek { 748fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 749fe27e772SPawel Jakub Dawidek struct bio *bp; 750fe27e772SPawel Jakub Dawidek int error = 0; 751fe27e772SPawel Jakub Dawidek 752fe27e772SPawel Jakub Dawidek G_GATE_DEBUG(4, "ioctl(%s, %lx, %p, %x, %p)", devtoname(dev), cmd, addr, 753fe27e772SPawel Jakub Dawidek flags, td); 754fe27e772SPawel Jakub Dawidek 755fe27e772SPawel Jakub Dawidek switch (cmd) { 756fe27e772SPawel Jakub Dawidek case G_GATE_CMD_CREATE: 757fe27e772SPawel Jakub Dawidek { 758fe27e772SPawel Jakub Dawidek struct g_gate_ctl_create *ggio = (void *)addr; 759fe27e772SPawel Jakub Dawidek 760fe27e772SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 761a17dd95fSPawel Jakub Dawidek error = g_gate_create(ggio); 762f9065812SPawel Jakub Dawidek /* 763f9065812SPawel Jakub Dawidek * Reset TDP_GEOM flag. 764f9065812SPawel Jakub Dawidek * There are pending events for sure, because we just created 765f9065812SPawel Jakub Dawidek * new provider and other classes want to taste it, but we 766f9065812SPawel Jakub Dawidek * cannot answer on I/O requests until we're here. 767f9065812SPawel Jakub Dawidek */ 768f9065812SPawel Jakub Dawidek td->td_pflags &= ~TDP_GEOM; 769a17dd95fSPawel Jakub Dawidek return (error); 770fe27e772SPawel Jakub Dawidek } 771e08ec037SPawel Jakub Dawidek case G_GATE_CMD_MODIFY: 772e08ec037SPawel Jakub Dawidek { 773e08ec037SPawel Jakub Dawidek struct g_gate_ctl_modify *ggio = (void *)addr; 774e08ec037SPawel Jakub Dawidek 775e08ec037SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 776e08ec037SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, NULL); 777e08ec037SPawel Jakub Dawidek if (sc == NULL) 778e08ec037SPawel Jakub Dawidek return (ENXIO); 779e08ec037SPawel Jakub Dawidek error = g_gate_modify(sc, ggio); 780e08ec037SPawel Jakub Dawidek g_gate_release(sc); 781e08ec037SPawel Jakub Dawidek return (error); 782e08ec037SPawel Jakub Dawidek } 783fe27e772SPawel Jakub Dawidek case G_GATE_CMD_DESTROY: 784fe27e772SPawel Jakub Dawidek { 785fe27e772SPawel Jakub Dawidek struct g_gate_ctl_destroy *ggio = (void *)addr; 786fe27e772SPawel Jakub Dawidek 787fe27e772SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 78832115b10SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, ggio->gctl_name); 789fe27e772SPawel Jakub Dawidek if (sc == NULL) 790fe27e772SPawel Jakub Dawidek return (ENXIO); 791fe27e772SPawel Jakub Dawidek g_topology_lock(); 79232115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 793fe27e772SPawel Jakub Dawidek error = g_gate_destroy(sc, ggio->gctl_force); 794fe27e772SPawel Jakub Dawidek g_topology_unlock(); 7957ffb6e0fSPawel Jakub Dawidek if (error != 0) 796fe27e772SPawel Jakub Dawidek g_gate_release(sc); 797fe27e772SPawel Jakub Dawidek return (error); 798fe27e772SPawel Jakub Dawidek } 79984436f14SPawel Jakub Dawidek case G_GATE_CMD_CANCEL: 80084436f14SPawel Jakub Dawidek { 80184436f14SPawel Jakub Dawidek struct g_gate_ctl_cancel *ggio = (void *)addr; 80284436f14SPawel Jakub Dawidek struct bio *tbp, *lbp; 80384436f14SPawel Jakub Dawidek 80484436f14SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 80532115b10SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, ggio->gctl_name); 80684436f14SPawel Jakub Dawidek if (sc == NULL) 80784436f14SPawel Jakub Dawidek return (ENXIO); 80884436f14SPawel Jakub Dawidek lbp = NULL; 80984436f14SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 81084436f14SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, tbp) { 81184436f14SPawel Jakub Dawidek if (ggio->gctl_seq == 0 || 81284436f14SPawel Jakub Dawidek ggio->gctl_seq == (uintptr_t)bp->bio_driver1) { 81384436f14SPawel Jakub Dawidek G_GATE_LOGREQ(1, bp, "Request canceled."); 81484436f14SPawel Jakub Dawidek bioq_remove(&sc->sc_outqueue, bp); 81584436f14SPawel Jakub Dawidek /* 81684436f14SPawel Jakub Dawidek * Be sure to put requests back onto incoming 81784436f14SPawel Jakub Dawidek * queue in the proper order. 81884436f14SPawel Jakub Dawidek */ 81984436f14SPawel Jakub Dawidek if (lbp == NULL) 82084436f14SPawel Jakub Dawidek bioq_insert_head(&sc->sc_inqueue, bp); 82184436f14SPawel Jakub Dawidek else { 82284436f14SPawel Jakub Dawidek TAILQ_INSERT_AFTER(&sc->sc_inqueue.queue, 82384436f14SPawel Jakub Dawidek lbp, bp, bio_queue); 82484436f14SPawel Jakub Dawidek } 82584436f14SPawel Jakub Dawidek lbp = bp; 82684436f14SPawel Jakub Dawidek /* 82784436f14SPawel Jakub Dawidek * If only one request was canceled, leave now. 82884436f14SPawel Jakub Dawidek */ 82984436f14SPawel Jakub Dawidek if (ggio->gctl_seq != 0) 83084436f14SPawel Jakub Dawidek break; 83184436f14SPawel Jakub Dawidek } 83284436f14SPawel Jakub Dawidek } 83332115b10SPawel Jakub Dawidek if (ggio->gctl_unit == G_GATE_NAME_GIVEN) 83432115b10SPawel Jakub Dawidek ggio->gctl_unit = sc->sc_unit; 83584436f14SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 83684436f14SPawel Jakub Dawidek g_gate_release(sc); 83784436f14SPawel Jakub Dawidek return (error); 83884436f14SPawel Jakub Dawidek } 839fe27e772SPawel Jakub Dawidek case G_GATE_CMD_START: 840fe27e772SPawel Jakub Dawidek { 841fe27e772SPawel Jakub Dawidek struct g_gate_ctl_io *ggio = (void *)addr; 842fe27e772SPawel Jakub Dawidek 843fe27e772SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 84432115b10SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, NULL); 845fe27e772SPawel Jakub Dawidek if (sc == NULL) 846fe27e772SPawel Jakub Dawidek return (ENXIO); 8477ffb6e0fSPawel Jakub Dawidek error = 0; 848fe27e772SPawel Jakub Dawidek for (;;) { 849e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 850fe27e772SPawel Jakub Dawidek bp = bioq_first(&sc->sc_inqueue); 851fe27e772SPawel Jakub Dawidek if (bp != NULL) 852fe27e772SPawel Jakub Dawidek break; 8537ffb6e0fSPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) { 8547ffb6e0fSPawel Jakub Dawidek ggio->gctl_error = ECANCELED; 8557ffb6e0fSPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 8567ffb6e0fSPawel Jakub Dawidek goto start_end; 8577ffb6e0fSPawel Jakub Dawidek } 858afcd1210SPeter Jeremy error = msleep(sc, &sc->sc_queue_mtx, 859afcd1210SPeter Jeremy PPAUSE | PDROP | PCATCH, "ggwait", 0); 860afcd1210SPeter Jeremy if (error != 0) 8617ffb6e0fSPawel Jakub Dawidek goto start_end; 862fe27e772SPawel Jakub Dawidek } 8634d1e1bf3SPawel Jakub Dawidek ggio->gctl_cmd = bp->bio_cmd; 864c4d2d401SPawel Jakub Dawidek if (bp->bio_cmd == BIO_WRITE && 865fe27e772SPawel Jakub Dawidek bp->bio_length > ggio->gctl_length) { 866e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 867fe27e772SPawel Jakub Dawidek ggio->gctl_length = bp->bio_length; 868fe27e772SPawel Jakub Dawidek ggio->gctl_error = ENOMEM; 8697ffb6e0fSPawel Jakub Dawidek goto start_end; 870fe27e772SPawel Jakub Dawidek } 871fe27e772SPawel Jakub Dawidek bioq_remove(&sc->sc_inqueue, bp); 872e35d3a78SPawel Jakub Dawidek bioq_insert_tail(&sc->sc_outqueue, bp); 873e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 874e35d3a78SPawel Jakub Dawidek 8750d785336SPawel Jakub Dawidek ggio->gctl_seq = (uintptr_t)bp->bio_driver1; 876fe27e772SPawel Jakub Dawidek ggio->gctl_offset = bp->bio_offset; 877fe27e772SPawel Jakub Dawidek ggio->gctl_length = bp->bio_length; 87884436f14SPawel Jakub Dawidek 879fe27e772SPawel Jakub Dawidek switch (bp->bio_cmd) { 880fe27e772SPawel Jakub Dawidek case BIO_READ: 881fe27e772SPawel Jakub Dawidek case BIO_DELETE: 882204a4e19SPawel Jakub Dawidek case BIO_FLUSH: 8838b522bdaSWarner Losh case BIO_SPEEDUP: 88415725379SPawel Jakub Dawidek break; 885fe27e772SPawel Jakub Dawidek case BIO_WRITE: 886fe27e772SPawel Jakub Dawidek error = copyout(bp->bio_data, ggio->gctl_data, 887fe27e772SPawel Jakub Dawidek bp->bio_length); 888fe27e772SPawel Jakub Dawidek if (error != 0) { 889e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 890e35d3a78SPawel Jakub Dawidek bioq_remove(&sc->sc_outqueue, bp); 891662a4e58SPawel Jakub Dawidek bioq_insert_head(&sc->sc_inqueue, bp); 892e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 8937ffb6e0fSPawel Jakub Dawidek goto start_end; 894fe27e772SPawel Jakub Dawidek } 895fe27e772SPawel Jakub Dawidek break; 896fe27e772SPawel Jakub Dawidek } 8977ffb6e0fSPawel Jakub Dawidek start_end: 8987ffb6e0fSPawel Jakub Dawidek g_gate_release(sc); 8997ffb6e0fSPawel Jakub Dawidek return (error); 900fe27e772SPawel Jakub Dawidek } 901fe27e772SPawel Jakub Dawidek case G_GATE_CMD_DONE: 902fe27e772SPawel Jakub Dawidek { 903fe27e772SPawel Jakub Dawidek struct g_gate_ctl_io *ggio = (void *)addr; 904fe27e772SPawel Jakub Dawidek 905fe27e772SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 90632115b10SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, NULL); 907fe27e772SPawel Jakub Dawidek if (sc == NULL) 908fe27e772SPawel Jakub Dawidek return (ENOENT); 9097ffb6e0fSPawel Jakub Dawidek error = 0; 910e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 911fe27e772SPawel Jakub Dawidek TAILQ_FOREACH(bp, &sc->sc_outqueue.queue, bio_queue) { 9120d785336SPawel Jakub Dawidek if (ggio->gctl_seq == (uintptr_t)bp->bio_driver1) 913fe27e772SPawel Jakub Dawidek break; 914fe27e772SPawel Jakub Dawidek } 915fe27e772SPawel Jakub Dawidek if (bp != NULL) { 916fe27e772SPawel Jakub Dawidek bioq_remove(&sc->sc_outqueue, bp); 917e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 918fe27e772SPawel Jakub Dawidek } 919e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 920fe27e772SPawel Jakub Dawidek if (bp == NULL) { 921fe27e772SPawel Jakub Dawidek /* 922fe27e772SPawel Jakub Dawidek * Request was probably canceled. 923fe27e772SPawel Jakub Dawidek */ 9247ffb6e0fSPawel Jakub Dawidek goto done_end; 925fe27e772SPawel Jakub Dawidek } 926fe27e772SPawel Jakub Dawidek if (ggio->gctl_error == EAGAIN) { 927fe27e772SPawel Jakub Dawidek bp->bio_error = 0; 928fe27e772SPawel Jakub Dawidek G_GATE_LOGREQ(1, bp, "Request desisted."); 929e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 930e35d3a78SPawel Jakub Dawidek sc->sc_queue_count++; 931662a4e58SPawel Jakub Dawidek bioq_insert_head(&sc->sc_inqueue, bp); 932fe27e772SPawel Jakub Dawidek wakeup(sc); 933e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 934fe27e772SPawel Jakub Dawidek } else { 935fe27e772SPawel Jakub Dawidek bp->bio_error = ggio->gctl_error; 936fe27e772SPawel Jakub Dawidek if (bp->bio_error == 0) { 937fe27e772SPawel Jakub Dawidek bp->bio_completed = bp->bio_length; 938fe27e772SPawel Jakub Dawidek switch (bp->bio_cmd) { 939fe27e772SPawel Jakub Dawidek case BIO_READ: 940fe27e772SPawel Jakub Dawidek error = copyin(ggio->gctl_data, 941fe27e772SPawel Jakub Dawidek bp->bio_data, bp->bio_length); 942fe27e772SPawel Jakub Dawidek if (error != 0) 943fe27e772SPawel Jakub Dawidek bp->bio_error = error; 944fe27e772SPawel Jakub Dawidek break; 945fe27e772SPawel Jakub Dawidek case BIO_DELETE: 946fe27e772SPawel Jakub Dawidek case BIO_WRITE: 947204a4e19SPawel Jakub Dawidek case BIO_FLUSH: 9488b522bdaSWarner Losh case BIO_SPEEDUP: 949fe27e772SPawel Jakub Dawidek break; 950fe27e772SPawel Jakub Dawidek } 951fe27e772SPawel Jakub Dawidek } 952fe27e772SPawel Jakub Dawidek G_GATE_LOGREQ(2, bp, "Request done."); 953fe27e772SPawel Jakub Dawidek g_io_deliver(bp, bp->bio_error); 954fe27e772SPawel Jakub Dawidek } 9557ffb6e0fSPawel Jakub Dawidek done_end: 9567ffb6e0fSPawel Jakub Dawidek g_gate_release(sc); 957fe27e772SPawel Jakub Dawidek return (error); 958fe27e772SPawel Jakub Dawidek } 959fe27e772SPawel Jakub Dawidek } 960fe27e772SPawel Jakub Dawidek return (ENOIOCTL); 961fe27e772SPawel Jakub Dawidek } 962fe27e772SPawel Jakub Dawidek 963fe27e772SPawel Jakub Dawidek static void 9649ecdd506SPawel Jakub Dawidek g_gate_device(void) 965fe27e772SPawel Jakub Dawidek { 966fe27e772SPawel Jakub Dawidek 967fe27e772SPawel Jakub Dawidek status_dev = make_dev(&g_gate_cdevsw, 0x0, UID_ROOT, GID_WHEEL, 0600, 968fe27e772SPawel Jakub Dawidek G_GATE_CTL_NAME); 969fe27e772SPawel Jakub Dawidek } 970fe27e772SPawel Jakub Dawidek 971fe27e772SPawel Jakub Dawidek static int 972fe27e772SPawel Jakub Dawidek g_gate_modevent(module_t mod, int type, void *data) 973fe27e772SPawel Jakub Dawidek { 974fe27e772SPawel Jakub Dawidek int error = 0; 975fe27e772SPawel Jakub Dawidek 976fe27e772SPawel Jakub Dawidek switch (type) { 977fe27e772SPawel Jakub Dawidek case MOD_LOAD: 97832115b10SPawel Jakub Dawidek mtx_init(&g_gate_units_lock, "gg_units_lock", NULL, MTX_DEF); 97932115b10SPawel Jakub Dawidek g_gate_units = malloc(g_gate_maxunits * sizeof(g_gate_units[0]), 98032115b10SPawel Jakub Dawidek M_GATE, M_WAITOK | M_ZERO); 98132115b10SPawel Jakub Dawidek g_gate_nunits = 0; 9829ecdd506SPawel Jakub Dawidek g_gate_device(); 983fe27e772SPawel Jakub Dawidek break; 984fe27e772SPawel Jakub Dawidek case MOD_UNLOAD: 98532115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 98632115b10SPawel Jakub Dawidek if (g_gate_nunits > 0) { 98732115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 988fe27e772SPawel Jakub Dawidek error = EBUSY; 989fe27e772SPawel Jakub Dawidek break; 990fe27e772SPawel Jakub Dawidek } 99132115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 99232115b10SPawel Jakub Dawidek mtx_destroy(&g_gate_units_lock); 99301b5c6f7SPedro F. Giffuni if (status_dev != NULL) 994fe27e772SPawel Jakub Dawidek destroy_dev(status_dev); 99532115b10SPawel Jakub Dawidek free(g_gate_units, M_GATE); 996fe27e772SPawel Jakub Dawidek break; 997fe27e772SPawel Jakub Dawidek default: 9983e019deaSPoul-Henning Kamp return (EOPNOTSUPP); 999fe27e772SPawel Jakub Dawidek break; 1000fe27e772SPawel Jakub Dawidek } 1001fe27e772SPawel Jakub Dawidek 1002fe27e772SPawel Jakub Dawidek return (error); 1003fe27e772SPawel Jakub Dawidek } 1004fe27e772SPawel Jakub Dawidek static moduledata_t g_gate_module = { 1005fe27e772SPawel Jakub Dawidek G_GATE_MOD_NAME, 1006fe27e772SPawel Jakub Dawidek g_gate_modevent, 1007fe27e772SPawel Jakub Dawidek NULL 1008fe27e772SPawel Jakub Dawidek }; 1009fe27e772SPawel Jakub Dawidek DECLARE_MODULE(geom_gate, g_gate_module, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 1010fe27e772SPawel Jakub Dawidek DECLARE_GEOM_CLASS(g_gate_class, g_gate); 101174d6c131SKyle Evans MODULE_VERSION(geom_gate, 0); 1012