1fe27e772SPawel Jakub Dawidek /*- 23728855aSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 33c0767902SPawel Jakub Dawidek #include <sys/cdefs.h> 34c0767902SPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 35c0767902SPawel Jakub Dawidek 36fe27e772SPawel Jakub Dawidek #include <sys/param.h> 37fe27e772SPawel Jakub Dawidek #include <sys/systm.h> 38fe27e772SPawel Jakub Dawidek #include <sys/bio.h> 39fe27e772SPawel Jakub Dawidek #include <sys/conf.h> 40fe27e772SPawel Jakub Dawidek #include <sys/kernel.h> 41fe27e772SPawel Jakub Dawidek #include <sys/kthread.h> 42fe27e772SPawel Jakub Dawidek #include <sys/fcntl.h> 43fe27e772SPawel Jakub Dawidek #include <sys/linker.h> 44fe27e772SPawel Jakub Dawidek #include <sys/lock.h> 45fe27e772SPawel Jakub Dawidek #include <sys/malloc.h> 46fe27e772SPawel Jakub Dawidek #include <sys/mutex.h> 47fe27e772SPawel Jakub Dawidek #include <sys/proc.h> 48fe27e772SPawel Jakub Dawidek #include <sys/limits.h> 49fe27e772SPawel Jakub Dawidek #include <sys/queue.h> 505d807a0eSAndrey V. Elsukov #include <sys/sbuf.h> 51fe27e772SPawel Jakub Dawidek #include <sys/sysctl.h> 52fe27e772SPawel Jakub Dawidek #include <sys/signalvar.h> 53fe27e772SPawel Jakub Dawidek #include <sys/time.h> 54fe27e772SPawel Jakub Dawidek #include <machine/atomic.h> 55fe27e772SPawel Jakub Dawidek 56fe27e772SPawel Jakub Dawidek #include <geom/geom.h> 57ac03832eSConrad Meyer #include <geom/geom_dbg.h> 58fe27e772SPawel Jakub Dawidek #include <geom/gate/g_gate.h> 59fe27e772SPawel Jakub Dawidek 60cb08c2ccSAlexander Leidinger FEATURE(geom_gate, "GEOM Gate module"); 61cb08c2ccSAlexander Leidinger 625bb84bc8SRobert Watson static MALLOC_DEFINE(M_GATE, "gg_data", "GEOM Gate Data"); 63fe27e772SPawel Jakub Dawidek 64fe27e772SPawel Jakub Dawidek SYSCTL_DECL(_kern_geom); 657029da5cSPawel Biernacki static SYSCTL_NODE(_kern_geom, OID_AUTO, gate, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 66e08ec037SPawel Jakub Dawidek "GEOM_GATE configuration"); 6732115b10SPawel Jakub Dawidek static int g_gate_debug = 0; 68af3b2549SHans Petter Selasky SYSCTL_INT(_kern_geom_gate, OID_AUTO, debug, CTLFLAG_RWTUN, &g_gate_debug, 0, 69fe27e772SPawel Jakub Dawidek "Debug level"); 7032115b10SPawel Jakub Dawidek static u_int g_gate_maxunits = 256; 7132115b10SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_gate, OID_AUTO, maxunits, CTLFLAG_RDTUN, 7232115b10SPawel Jakub Dawidek &g_gate_maxunits, 0, "Maximum number of ggate devices"); 73fe27e772SPawel Jakub Dawidek 74fe27e772SPawel Jakub Dawidek struct g_class g_gate_class = { 75fe27e772SPawel Jakub Dawidek .name = G_GATE_CLASS_NAME, 765721c9c7SPoul-Henning Kamp .version = G_VERSION, 77fe27e772SPawel Jakub Dawidek }; 78fe27e772SPawel Jakub Dawidek 7989c9c53dSPoul-Henning Kamp static struct cdev *status_dev; 80fe27e772SPawel Jakub Dawidek static d_ioctl_t g_gate_ioctl; 81fe27e772SPawel Jakub Dawidek static struct cdevsw g_gate_cdevsw = { 82fe27e772SPawel Jakub Dawidek .d_version = D_VERSION, 83fe27e772SPawel Jakub Dawidek .d_ioctl = g_gate_ioctl, 84fe27e772SPawel Jakub Dawidek .d_name = G_GATE_CTL_NAME 85fe27e772SPawel Jakub Dawidek }; 86fe27e772SPawel Jakub Dawidek 8732115b10SPawel Jakub Dawidek static struct g_gate_softc **g_gate_units; 8832115b10SPawel Jakub Dawidek static u_int g_gate_nunits; 8932115b10SPawel Jakub Dawidek static struct mtx g_gate_units_lock; 90fe27e772SPawel Jakub Dawidek 91351d0fa6SAlexander Motin static void 92351d0fa6SAlexander Motin g_gate_detach(void *arg, int flags __unused) 93351d0fa6SAlexander Motin { 94351d0fa6SAlexander Motin struct g_consumer *cp = arg; 95351d0fa6SAlexander Motin 96351d0fa6SAlexander Motin g_topology_assert(); 97351d0fa6SAlexander Motin G_GATE_DEBUG(1, "Destroying read consumer on provider %s orphan.", 98351d0fa6SAlexander Motin cp->provider->name); 99351d0fa6SAlexander Motin (void)g_access(cp, -1, 0, 0); 100351d0fa6SAlexander Motin g_detach(cp); 101351d0fa6SAlexander Motin g_destroy_consumer(cp); 102351d0fa6SAlexander Motin } 103351d0fa6SAlexander Motin 104fe27e772SPawel Jakub Dawidek static int 105fe27e772SPawel Jakub Dawidek g_gate_destroy(struct g_gate_softc *sc, boolean_t force) 106fe27e772SPawel Jakub Dawidek { 10740ea77a0SAlexander Motin struct bio_queue_head queue; 108fe27e772SPawel Jakub Dawidek struct g_provider *pp; 109e08ec037SPawel Jakub Dawidek struct g_consumer *cp; 1107ffb6e0fSPawel Jakub Dawidek struct g_geom *gp; 111fe27e772SPawel Jakub Dawidek struct bio *bp; 112fe27e772SPawel Jakub Dawidek 113fe27e772SPawel Jakub Dawidek g_topology_assert(); 11432115b10SPawel Jakub Dawidek mtx_assert(&g_gate_units_lock, MA_OWNED); 115fe27e772SPawel Jakub Dawidek pp = sc->sc_provider; 116fe27e772SPawel Jakub Dawidek if (!force && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 11732115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 118fe27e772SPawel Jakub Dawidek return (EBUSY); 119fe27e772SPawel Jakub Dawidek } 12032115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 121e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 1227ffb6e0fSPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0) 1237ffb6e0fSPawel Jakub Dawidek sc->sc_flags |= G_GATE_FLAG_DESTROY; 124fe27e772SPawel Jakub Dawidek wakeup(sc); 125e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 1267ffb6e0fSPawel Jakub Dawidek gp = pp->geom; 1278b64f3caSAlexander Motin g_wither_provider(pp, ENXIO); 128fe27e772SPawel Jakub Dawidek callout_drain(&sc->sc_callout); 12940ea77a0SAlexander Motin bioq_init(&queue); 130e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 13140ea77a0SAlexander Motin while ((bp = bioq_takefirst(&sc->sc_inqueue)) != NULL) { 132e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 13340ea77a0SAlexander Motin bioq_insert_tail(&queue, bp); 134fe27e772SPawel Jakub Dawidek } 13540ea77a0SAlexander Motin while ((bp = bioq_takefirst(&sc->sc_outqueue)) != NULL) { 136e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 13740ea77a0SAlexander Motin bioq_insert_tail(&queue, bp); 138fe27e772SPawel Jakub Dawidek } 1397ffb6e0fSPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 1407ffb6e0fSPawel Jakub Dawidek g_topology_unlock(); 14140ea77a0SAlexander Motin while ((bp = bioq_takefirst(&queue)) != NULL) { 14240ea77a0SAlexander Motin G_GATE_LOGREQ(1, bp, "Request canceled."); 14340ea77a0SAlexander Motin g_io_deliver(bp, ENXIO); 14440ea77a0SAlexander Motin } 14532115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 1467ffb6e0fSPawel Jakub Dawidek /* One reference is ours. */ 1477ffb6e0fSPawel Jakub Dawidek sc->sc_ref--; 14832115b10SPawel Jakub Dawidek while (sc->sc_ref > 0) 14932115b10SPawel Jakub Dawidek msleep(&sc->sc_ref, &g_gate_units_lock, 0, "gg:destroy", 0); 15032115b10SPawel Jakub Dawidek g_gate_units[sc->sc_unit] = NULL; 15132115b10SPawel Jakub Dawidek KASSERT(g_gate_nunits > 0, ("negative g_gate_nunits?")); 15232115b10SPawel Jakub Dawidek g_gate_nunits--; 15332115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 154e35d3a78SPawel Jakub Dawidek mtx_destroy(&sc->sc_queue_mtx); 155351d0fa6SAlexander Motin mtx_destroy(&sc->sc_read_mtx); 1567ffb6e0fSPawel Jakub Dawidek g_topology_lock(); 157e08ec037SPawel Jakub Dawidek if ((cp = sc->sc_readcons) != NULL) { 158e08ec037SPawel Jakub Dawidek sc->sc_readcons = NULL; 159e08ec037SPawel Jakub Dawidek (void)g_access(cp, -1, 0, 0); 160e08ec037SPawel Jakub Dawidek g_detach(cp); 161e08ec037SPawel Jakub Dawidek g_destroy_consumer(cp); 162e08ec037SPawel Jakub Dawidek } 163bd119384SMikolaj Golub G_GATE_DEBUG(1, "Device %s destroyed.", gp->name); 1647ffb6e0fSPawel Jakub Dawidek gp->softc = NULL; 1657ffb6e0fSPawel Jakub Dawidek g_wither_geom(gp, ENXIO); 166fe27e772SPawel Jakub Dawidek sc->sc_provider = NULL; 167fe27e772SPawel Jakub Dawidek free(sc, M_GATE); 168fe27e772SPawel Jakub Dawidek return (0); 169fe27e772SPawel Jakub Dawidek } 170fe27e772SPawel Jakub Dawidek 171fe27e772SPawel Jakub Dawidek static int 172fe27e772SPawel Jakub Dawidek g_gate_access(struct g_provider *pp, int dr, int dw, int de) 173fe27e772SPawel Jakub Dawidek { 174fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 175fe27e772SPawel Jakub Dawidek 176fe27e772SPawel Jakub Dawidek if (dr <= 0 && dw <= 0 && de <= 0) 177fe27e772SPawel Jakub Dawidek return (0); 178fe27e772SPawel Jakub Dawidek sc = pp->geom->softc; 179fe27e772SPawel Jakub Dawidek if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) 180fe27e772SPawel Jakub Dawidek return (ENXIO); 18155336b83SPawel Jakub Dawidek /* XXX: Hack to allow read-only mounts. */ 18255336b83SPawel Jakub Dawidek #if 0 183fe27e772SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0 && dw > 0) 184fe27e772SPawel Jakub Dawidek return (EPERM); 18555336b83SPawel Jakub Dawidek #endif 186fe27e772SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0 && dr > 0) 187fe27e772SPawel Jakub Dawidek return (EPERM); 188fe27e772SPawel Jakub Dawidek return (0); 189fe27e772SPawel Jakub Dawidek } 190fe27e772SPawel Jakub Dawidek 191fe27e772SPawel Jakub Dawidek static void 192e08ec037SPawel Jakub Dawidek g_gate_queue_io(struct bio *bp) 193fe27e772SPawel Jakub Dawidek { 194fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 195fe27e772SPawel Jakub Dawidek 196fe27e772SPawel Jakub Dawidek sc = bp->bio_to->geom->softc; 197fe27e772SPawel Jakub Dawidek if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) { 198fe27e772SPawel Jakub Dawidek g_io_deliver(bp, ENXIO); 199fe27e772SPawel Jakub Dawidek return; 200fe27e772SPawel Jakub Dawidek } 201fe27e772SPawel Jakub Dawidek 202e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 203e08ec037SPawel Jakub Dawidek 20463a6c5c1SPawel Jakub Dawidek if (sc->sc_queue_size > 0 && sc->sc_queue_count > sc->sc_queue_size) { 20535f855d9SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 206fe27e772SPawel Jakub Dawidek G_GATE_LOGREQ(1, bp, "Queue full, request canceled."); 20732115b10SPawel Jakub Dawidek g_io_deliver(bp, ENOMEM); 208fe27e772SPawel Jakub Dawidek return; 209fe27e772SPawel Jakub Dawidek } 210e35d3a78SPawel Jakub Dawidek 211fe27e772SPawel Jakub Dawidek bp->bio_driver1 = (void *)sc->sc_seq; 212fe27e772SPawel Jakub Dawidek sc->sc_seq++; 213e35d3a78SPawel Jakub Dawidek sc->sc_queue_count++; 214fe27e772SPawel Jakub Dawidek 215662a4e58SPawel Jakub Dawidek bioq_insert_tail(&sc->sc_inqueue, bp); 216fe27e772SPawel Jakub Dawidek wakeup(sc); 217e35d3a78SPawel Jakub Dawidek 218e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 219fe27e772SPawel Jakub Dawidek } 220fe27e772SPawel Jakub Dawidek 221e08ec037SPawel Jakub Dawidek static void 222e08ec037SPawel Jakub Dawidek g_gate_done(struct bio *cbp) 223e08ec037SPawel Jakub Dawidek { 224351d0fa6SAlexander Motin struct g_gate_softc *sc; 225e08ec037SPawel Jakub Dawidek struct bio *pbp; 226351d0fa6SAlexander Motin struct g_consumer *cp; 227e08ec037SPawel Jakub Dawidek 228351d0fa6SAlexander Motin cp = cbp->bio_from; 229e08ec037SPawel Jakub Dawidek pbp = cbp->bio_parent; 230e08ec037SPawel Jakub Dawidek if (cbp->bio_error == 0) { 231e08ec037SPawel Jakub Dawidek pbp->bio_completed = cbp->bio_completed; 232e08ec037SPawel Jakub Dawidek g_destroy_bio(cbp); 233e08ec037SPawel Jakub Dawidek pbp->bio_inbed++; 234e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, 0); 235e08ec037SPawel Jakub Dawidek } else { 236e08ec037SPawel Jakub Dawidek /* If direct read failed, pass it through userland daemon. */ 237e08ec037SPawel Jakub Dawidek g_destroy_bio(cbp); 238e08ec037SPawel Jakub Dawidek pbp->bio_children--; 239e08ec037SPawel Jakub Dawidek g_gate_queue_io(pbp); 240e08ec037SPawel Jakub Dawidek } 241351d0fa6SAlexander Motin 242351d0fa6SAlexander Motin sc = cp->geom->softc; 243351d0fa6SAlexander Motin mtx_lock(&sc->sc_read_mtx); 244351d0fa6SAlexander Motin if (--cp->index == 0 && sc->sc_readcons != cp) 245351d0fa6SAlexander Motin g_post_event(g_gate_detach, cp, M_NOWAIT, NULL); 246351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 247e08ec037SPawel Jakub Dawidek } 248e08ec037SPawel Jakub Dawidek 249e08ec037SPawel Jakub Dawidek static void 250e08ec037SPawel Jakub Dawidek g_gate_start(struct bio *pbp) 251e08ec037SPawel Jakub Dawidek { 252e08ec037SPawel Jakub Dawidek struct g_gate_softc *sc; 253351d0fa6SAlexander Motin struct g_consumer *cp; 254351d0fa6SAlexander Motin struct bio *cbp; 255e08ec037SPawel Jakub Dawidek 256e08ec037SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 257e08ec037SPawel Jakub Dawidek if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) { 258e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, ENXIO); 259e08ec037SPawel Jakub Dawidek return; 260e08ec037SPawel Jakub Dawidek } 261e08ec037SPawel Jakub Dawidek G_GATE_LOGREQ(2, pbp, "Request received."); 262e08ec037SPawel Jakub Dawidek switch (pbp->bio_cmd) { 263e08ec037SPawel Jakub Dawidek case BIO_READ: 264351d0fa6SAlexander Motin if (sc->sc_readcons == NULL) 265351d0fa6SAlexander Motin break; 266e08ec037SPawel Jakub Dawidek cbp = g_clone_bio(pbp); 267e08ec037SPawel Jakub Dawidek if (cbp == NULL) { 268e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, ENOMEM); 269e08ec037SPawel Jakub Dawidek return; 270e08ec037SPawel Jakub Dawidek } 271351d0fa6SAlexander Motin mtx_lock(&sc->sc_read_mtx); 272351d0fa6SAlexander Motin if ((cp = sc->sc_readcons) == NULL) { 273351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 274351d0fa6SAlexander Motin g_destroy_bio(cbp); 275351d0fa6SAlexander Motin pbp->bio_children--; 276e08ec037SPawel Jakub Dawidek break; 277351d0fa6SAlexander Motin } 278351d0fa6SAlexander Motin cp->index++; 279351d0fa6SAlexander Motin cbp->bio_offset = pbp->bio_offset + sc->sc_readoffset; 280351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 281351d0fa6SAlexander Motin cbp->bio_done = g_gate_done; 282351d0fa6SAlexander Motin g_io_request(cbp, cp); 283351d0fa6SAlexander Motin return; 284e08ec037SPawel Jakub Dawidek case BIO_DELETE: 285e08ec037SPawel Jakub Dawidek case BIO_WRITE: 286e08ec037SPawel Jakub Dawidek case BIO_FLUSH: 2878b522bdaSWarner Losh case BIO_SPEEDUP: 288e08ec037SPawel Jakub Dawidek /* XXX: Hack to allow read-only mounts. */ 289e08ec037SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) { 290e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, EPERM); 291e08ec037SPawel Jakub Dawidek return; 292e08ec037SPawel Jakub Dawidek } 293e08ec037SPawel Jakub Dawidek break; 294e08ec037SPawel Jakub Dawidek case BIO_GETATTR: 295e08ec037SPawel Jakub Dawidek default: 296e08ec037SPawel Jakub Dawidek G_GATE_LOGREQ(2, pbp, "Ignoring request."); 297e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, EOPNOTSUPP); 298e08ec037SPawel Jakub Dawidek return; 299e08ec037SPawel Jakub Dawidek } 300e08ec037SPawel Jakub Dawidek 301e08ec037SPawel Jakub Dawidek g_gate_queue_io(pbp); 302e08ec037SPawel Jakub Dawidek } 303e08ec037SPawel Jakub Dawidek 304fe27e772SPawel Jakub Dawidek static struct g_gate_softc * 3052aa15ffdSPawel Jakub Dawidek g_gate_hold(int unit, const char *name) 306fe27e772SPawel Jakub Dawidek { 30732115b10SPawel Jakub Dawidek struct g_gate_softc *sc = NULL; 308fe27e772SPawel Jakub Dawidek 30932115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 31032115b10SPawel Jakub Dawidek if (unit >= 0 && unit < g_gate_maxunits) 31132115b10SPawel Jakub Dawidek sc = g_gate_units[unit]; 31232115b10SPawel Jakub Dawidek else if (unit == G_GATE_NAME_GIVEN) { 31332115b10SPawel Jakub Dawidek KASSERT(name != NULL, ("name is NULL")); 31432115b10SPawel Jakub Dawidek for (unit = 0; unit < g_gate_maxunits; unit++) { 31532115b10SPawel Jakub Dawidek if (g_gate_units[unit] == NULL) 31632115b10SPawel Jakub Dawidek continue; 31732115b10SPawel Jakub Dawidek if (strcmp(name, 31832115b10SPawel Jakub Dawidek g_gate_units[unit]->sc_provider->name) != 0) { 31932115b10SPawel Jakub Dawidek continue; 32032115b10SPawel Jakub Dawidek } 32132115b10SPawel Jakub Dawidek sc = g_gate_units[unit]; 3227ffb6e0fSPawel Jakub Dawidek break; 323fe27e772SPawel Jakub Dawidek } 32432115b10SPawel Jakub Dawidek } 3257ffb6e0fSPawel Jakub Dawidek if (sc != NULL) 3267ffb6e0fSPawel Jakub Dawidek sc->sc_ref++; 32732115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 328fe27e772SPawel Jakub Dawidek return (sc); 329fe27e772SPawel Jakub Dawidek } 330fe27e772SPawel Jakub Dawidek 331fe27e772SPawel Jakub Dawidek static void 332fe27e772SPawel Jakub Dawidek g_gate_release(struct g_gate_softc *sc) 333fe27e772SPawel Jakub Dawidek { 334fe27e772SPawel Jakub Dawidek 335fe27e772SPawel Jakub Dawidek g_topology_assert_not(); 33632115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 337fe27e772SPawel Jakub Dawidek sc->sc_ref--; 338fe27e772SPawel Jakub Dawidek KASSERT(sc->sc_ref >= 0, ("Negative sc_ref for %s.", sc->sc_name)); 33932115b10SPawel Jakub Dawidek if (sc->sc_ref == 0 && (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) 3407ffb6e0fSPawel Jakub Dawidek wakeup(&sc->sc_ref); 34132115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 342fe27e772SPawel Jakub Dawidek } 343fe27e772SPawel Jakub Dawidek 344fe27e772SPawel Jakub Dawidek static int 34532115b10SPawel Jakub Dawidek g_gate_getunit(int unit, int *errorp) 346fe27e772SPawel Jakub Dawidek { 347fe27e772SPawel Jakub Dawidek 34832115b10SPawel Jakub Dawidek mtx_assert(&g_gate_units_lock, MA_OWNED); 349fe27e772SPawel Jakub Dawidek if (unit >= 0) { 35032115b10SPawel Jakub Dawidek if (unit >= g_gate_maxunits) 35132115b10SPawel Jakub Dawidek *errorp = EINVAL; 35232115b10SPawel Jakub Dawidek else if (g_gate_units[unit] == NULL) 353fe27e772SPawel Jakub Dawidek return (unit); 35432115b10SPawel Jakub Dawidek else 35532115b10SPawel Jakub Dawidek *errorp = EEXIST; 35632115b10SPawel Jakub Dawidek } else { 35732115b10SPawel Jakub Dawidek for (unit = 0; unit < g_gate_maxunits; unit++) { 35832115b10SPawel Jakub Dawidek if (g_gate_units[unit] == NULL) 35932115b10SPawel Jakub Dawidek return (unit); 36032115b10SPawel Jakub Dawidek } 36132115b10SPawel Jakub Dawidek *errorp = ENFILE; 36232115b10SPawel Jakub Dawidek } 36332115b10SPawel Jakub Dawidek return (-1); 364fe27e772SPawel Jakub Dawidek } 365fe27e772SPawel Jakub Dawidek 366fe27e772SPawel Jakub Dawidek static void 367fe27e772SPawel Jakub Dawidek g_gate_guard(void *arg) 368fe27e772SPawel Jakub Dawidek { 36940ea77a0SAlexander Motin struct bio_queue_head queue; 370fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 371fe27e772SPawel Jakub Dawidek struct bintime curtime; 372fe27e772SPawel Jakub Dawidek struct bio *bp, *bp2; 373fe27e772SPawel Jakub Dawidek 374fe27e772SPawel Jakub Dawidek sc = arg; 375fe27e772SPawel Jakub Dawidek binuptime(&curtime); 37632115b10SPawel Jakub Dawidek g_gate_hold(sc->sc_unit, NULL); 37740ea77a0SAlexander Motin bioq_init(&queue); 378e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 379fe27e772SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(bp, &sc->sc_inqueue.queue, bio_queue, bp2) { 380fe27e772SPawel Jakub Dawidek if (curtime.sec - bp->bio_t0.sec < 5) 381fe27e772SPawel Jakub Dawidek continue; 382fe27e772SPawel Jakub Dawidek bioq_remove(&sc->sc_inqueue, bp); 383e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 38440ea77a0SAlexander Motin bioq_insert_tail(&queue, bp); 385fe27e772SPawel Jakub Dawidek } 386fe27e772SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, bp2) { 387fe27e772SPawel Jakub Dawidek if (curtime.sec - bp->bio_t0.sec < 5) 388fe27e772SPawel Jakub Dawidek continue; 389fe27e772SPawel Jakub Dawidek bioq_remove(&sc->sc_outqueue, bp); 390e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 39140ea77a0SAlexander Motin bioq_insert_tail(&queue, bp); 39240ea77a0SAlexander Motin } 39340ea77a0SAlexander Motin mtx_unlock(&sc->sc_queue_mtx); 39440ea77a0SAlexander Motin while ((bp = bioq_takefirst(&queue)) != NULL) { 395fe27e772SPawel Jakub Dawidek G_GATE_LOGREQ(1, bp, "Request timeout."); 396fe27e772SPawel Jakub Dawidek g_io_deliver(bp, EIO); 397fe27e772SPawel Jakub Dawidek } 398fe27e772SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0) { 399fe27e772SPawel Jakub Dawidek callout_reset(&sc->sc_callout, sc->sc_timeout * hz, 400fe27e772SPawel Jakub Dawidek g_gate_guard, sc); 401fe27e772SPawel Jakub Dawidek } 402fe27e772SPawel Jakub Dawidek g_gate_release(sc); 403fe27e772SPawel Jakub Dawidek } 404fe27e772SPawel Jakub Dawidek 405fe27e772SPawel Jakub Dawidek static void 406e08ec037SPawel Jakub Dawidek g_gate_orphan(struct g_consumer *cp) 407e08ec037SPawel Jakub Dawidek { 408e08ec037SPawel Jakub Dawidek struct g_gate_softc *sc; 409e08ec037SPawel Jakub Dawidek struct g_geom *gp; 410351d0fa6SAlexander Motin int done; 411e08ec037SPawel Jakub Dawidek 412e08ec037SPawel Jakub Dawidek g_topology_assert(); 413e08ec037SPawel Jakub Dawidek gp = cp->geom; 414e08ec037SPawel Jakub Dawidek sc = gp->softc; 415351d0fa6SAlexander Motin mtx_lock(&sc->sc_read_mtx); 416351d0fa6SAlexander Motin if (sc->sc_readcons == cp) 417e08ec037SPawel Jakub Dawidek sc->sc_readcons = NULL; 418351d0fa6SAlexander Motin done = (cp->index == 0); 419351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 420351d0fa6SAlexander Motin if (done) 421351d0fa6SAlexander Motin g_gate_detach(cp, 0); 422e08ec037SPawel Jakub Dawidek } 423e08ec037SPawel Jakub Dawidek 424e08ec037SPawel Jakub Dawidek static void 425fe27e772SPawel Jakub Dawidek g_gate_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 426fe27e772SPawel Jakub Dawidek struct g_consumer *cp, struct g_provider *pp) 427fe27e772SPawel Jakub Dawidek { 428fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 429fe27e772SPawel Jakub Dawidek 430fe27e772SPawel Jakub Dawidek sc = gp->softc; 431fe27e772SPawel Jakub Dawidek if (sc == NULL || pp != NULL || cp != NULL) 432fe27e772SPawel Jakub Dawidek return; 4331d9db37cSMikolaj Golub sc = g_gate_hold(sc->sc_unit, NULL); 4341d9db37cSMikolaj Golub if (sc == NULL) 4351d9db37cSMikolaj Golub return; 436fe27e772SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) { 437fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<access>%s</access>\n", indent, "read-only"); 438fe27e772SPawel Jakub Dawidek } else if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0) { 439fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<access>%s</access>\n", indent, 440fe27e772SPawel Jakub Dawidek "write-only"); 441fe27e772SPawel Jakub Dawidek } else { 442fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<access>%s</access>\n", indent, 443fe27e772SPawel Jakub Dawidek "read-write"); 444fe27e772SPawel Jakub Dawidek } 445e08ec037SPawel Jakub Dawidek if (sc->sc_readcons != NULL) { 446e08ec037SPawel Jakub Dawidek sbuf_printf(sb, "%s<read_offset>%jd</read_offset>\n", 447e08ec037SPawel Jakub Dawidek indent, (intmax_t)sc->sc_readoffset); 448e08ec037SPawel Jakub Dawidek sbuf_printf(sb, "%s<read_provider>%s</read_provider>\n", 449e08ec037SPawel Jakub Dawidek indent, sc->sc_readcons->provider->name); 450e08ec037SPawel Jakub Dawidek } 451fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<timeout>%u</timeout>\n", indent, sc->sc_timeout); 452fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<info>%s</info>\n", indent, sc->sc_info); 453fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<queue_count>%u</queue_count>\n", indent, 454fe27e772SPawel Jakub Dawidek sc->sc_queue_count); 455fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<queue_size>%u</queue_size>\n", indent, 456fe27e772SPawel Jakub Dawidek sc->sc_queue_size); 457fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<ref>%u</ref>\n", indent, sc->sc_ref); 45832115b10SPawel Jakub Dawidek sbuf_printf(sb, "%s<unit>%d</unit>\n", indent, sc->sc_unit); 45947f44cb7SPawel Jakub Dawidek g_topology_unlock(); 460fe27e772SPawel Jakub Dawidek g_gate_release(sc); 46147f44cb7SPawel Jakub Dawidek g_topology_lock(); 462fe27e772SPawel Jakub Dawidek } 463fe27e772SPawel Jakub Dawidek 464fe27e772SPawel Jakub Dawidek static int 465fe27e772SPawel Jakub Dawidek g_gate_create(struct g_gate_ctl_create *ggio) 466fe27e772SPawel Jakub Dawidek { 467fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 468fe27e772SPawel Jakub Dawidek struct g_geom *gp; 469e08ec037SPawel Jakub Dawidek struct g_provider *pp, *ropp; 470e08ec037SPawel Jakub Dawidek struct g_consumer *cp; 471*f284bed2SAlan Somers char name[NAME_MAX + 1]; 472*f284bed2SAlan Somers char readprov[NAME_MAX + 1]; 47332115b10SPawel Jakub Dawidek int error = 0, unit; 474fe27e772SPawel Jakub Dawidek 475e08ec037SPawel Jakub Dawidek if (ggio->gctl_mediasize <= 0) { 476fe27e772SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid media size."); 477fe27e772SPawel Jakub Dawidek return (EINVAL); 478fe27e772SPawel Jakub Dawidek } 479e08ec037SPawel Jakub Dawidek if (ggio->gctl_sectorsize <= 0) { 480e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid sector size."); 481e08ec037SPawel Jakub Dawidek return (EINVAL); 482e08ec037SPawel Jakub Dawidek } 483e08ec037SPawel Jakub Dawidek if (!powerof2(ggio->gctl_sectorsize)) { 484fe27e772SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid sector size."); 485fe27e772SPawel Jakub Dawidek return (EINVAL); 486fe27e772SPawel Jakub Dawidek } 487662a4e58SPawel Jakub Dawidek if ((ggio->gctl_mediasize % ggio->gctl_sectorsize) != 0) { 488662a4e58SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid media size."); 489662a4e58SPawel Jakub Dawidek return (EINVAL); 490662a4e58SPawel Jakub Dawidek } 491fe27e772SPawel Jakub Dawidek if ((ggio->gctl_flags & G_GATE_FLAG_READONLY) != 0 && 492fe27e772SPawel Jakub Dawidek (ggio->gctl_flags & G_GATE_FLAG_WRITEONLY) != 0) { 493fe27e772SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid flags."); 494fe27e772SPawel Jakub Dawidek return (EINVAL); 495fe27e772SPawel Jakub Dawidek } 49632115b10SPawel Jakub Dawidek if (ggio->gctl_unit != G_GATE_UNIT_AUTO && 49732115b10SPawel Jakub Dawidek ggio->gctl_unit != G_GATE_NAME_GIVEN && 49832115b10SPawel Jakub Dawidek ggio->gctl_unit < 0) { 499fe27e772SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid unit number."); 500fe27e772SPawel Jakub Dawidek return (EINVAL); 501fe27e772SPawel Jakub Dawidek } 50232115b10SPawel Jakub Dawidek if (ggio->gctl_unit == G_GATE_NAME_GIVEN && 50332115b10SPawel Jakub Dawidek ggio->gctl_name[0] == '\0') { 50432115b10SPawel Jakub Dawidek G_GATE_DEBUG(1, "No device name."); 50532115b10SPawel Jakub Dawidek return (EINVAL); 50632115b10SPawel Jakub Dawidek } 507fe27e772SPawel Jakub Dawidek 508fe27e772SPawel Jakub Dawidek sc = malloc(sizeof(*sc), M_GATE, M_WAITOK | M_ZERO); 509fe27e772SPawel Jakub Dawidek sc->sc_flags = (ggio->gctl_flags & G_GATE_USERFLAGS); 510*f284bed2SAlan Somers memset(sc->sc_info, 0, sizeof(sc->sc_info)); 511*f284bed2SAlan Somers strncpy(sc->sc_info, ggio->gctl_info, 512*f284bed2SAlan Somers MIN(sizeof(sc->sc_info) - 1, sizeof(ggio->gctl_info))); 51332115b10SPawel Jakub Dawidek sc->sc_seq = 1; 514fe27e772SPawel Jakub Dawidek bioq_init(&sc->sc_inqueue); 515fe27e772SPawel Jakub Dawidek bioq_init(&sc->sc_outqueue); 516e35d3a78SPawel Jakub Dawidek mtx_init(&sc->sc_queue_mtx, "gg:queue", NULL, MTX_DEF); 517351d0fa6SAlexander Motin mtx_init(&sc->sc_read_mtx, "gg:read", NULL, MTX_DEF); 518fe27e772SPawel Jakub Dawidek sc->sc_queue_count = 0; 519fe27e772SPawel Jakub Dawidek sc->sc_queue_size = ggio->gctl_maxcount; 520fe27e772SPawel Jakub Dawidek if (sc->sc_queue_size > G_GATE_MAX_QUEUE_SIZE) 521fe27e772SPawel Jakub Dawidek sc->sc_queue_size = G_GATE_MAX_QUEUE_SIZE; 522fe27e772SPawel Jakub Dawidek sc->sc_timeout = ggio->gctl_timeout; 523fd90e2edSJung-uk Kim callout_init(&sc->sc_callout, 1); 524e08ec037SPawel Jakub Dawidek 52532115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 52632115b10SPawel Jakub Dawidek sc->sc_unit = g_gate_getunit(ggio->gctl_unit, &error); 527a277f47bSMikolaj Golub if (sc->sc_unit < 0) 528a277f47bSMikolaj Golub goto fail1; 529*f284bed2SAlan Somers if (ggio->gctl_unit == G_GATE_NAME_GIVEN) { 530*f284bed2SAlan Somers memset(name, 0, sizeof(name)); 531*f284bed2SAlan Somers strncpy(name, ggio->gctl_name, 532*f284bed2SAlan Somers MIN(sizeof(name) - 1, sizeof(ggio->gctl_name))); 533*f284bed2SAlan Somers } else { 53432115b10SPawel Jakub Dawidek snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME, 53532115b10SPawel Jakub Dawidek sc->sc_unit); 53632115b10SPawel Jakub Dawidek } 53732115b10SPawel Jakub Dawidek /* Check for name collision. */ 53832115b10SPawel Jakub Dawidek for (unit = 0; unit < g_gate_maxunits; unit++) { 53932115b10SPawel Jakub Dawidek if (g_gate_units[unit] == NULL) 54032115b10SPawel Jakub Dawidek continue; 541baf63f65SMikolaj Golub if (strcmp(name, g_gate_units[unit]->sc_name) != 0) 54232115b10SPawel Jakub Dawidek continue; 543a277f47bSMikolaj Golub error = EEXIST; 544a277f47bSMikolaj Golub goto fail1; 54532115b10SPawel Jakub Dawidek } 546*f284bed2SAlan Somers // local stack buffer 'name' assigned here temporarily only. 547*f284bed2SAlan Somers // the real provider name is assigned below. 548baf63f65SMikolaj Golub sc->sc_name = name; 54932115b10SPawel Jakub Dawidek g_gate_units[sc->sc_unit] = sc; 55032115b10SPawel Jakub Dawidek g_gate_nunits++; 55132115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 55232115b10SPawel Jakub Dawidek 553a277f47bSMikolaj Golub g_topology_lock(); 554a277f47bSMikolaj Golub 555a277f47bSMikolaj Golub if (ggio->gctl_readprov[0] == '\0') { 556a277f47bSMikolaj Golub ropp = NULL; 557a277f47bSMikolaj Golub } else { 558*f284bed2SAlan Somers memset(readprov, 0, sizeof(readprov)); 559*f284bed2SAlan Somers strncpy(readprov, ggio->gctl_readprov, 560*f284bed2SAlan Somers MIN(sizeof(readprov) - 1, sizeof(ggio->gctl_readprov))); 561*f284bed2SAlan Somers ropp = g_provider_by_name(readprov); 562a277f47bSMikolaj Golub if (ropp == NULL) { 563*f284bed2SAlan Somers G_GATE_DEBUG(1, "Provider %s doesn't exist.", readprov); 564a277f47bSMikolaj Golub error = EINVAL; 565a277f47bSMikolaj Golub goto fail2; 566a277f47bSMikolaj Golub } 567a277f47bSMikolaj Golub if ((ggio->gctl_readoffset % ggio->gctl_sectorsize) != 0) { 568a277f47bSMikolaj Golub G_GATE_DEBUG(1, "Invalid read offset."); 569a277f47bSMikolaj Golub error = EINVAL; 570a277f47bSMikolaj Golub goto fail2; 571a277f47bSMikolaj Golub } 572a277f47bSMikolaj Golub if (ggio->gctl_mediasize + ggio->gctl_readoffset > 573a277f47bSMikolaj Golub ropp->mediasize) { 574a277f47bSMikolaj Golub G_GATE_DEBUG(1, "Invalid read offset or media size."); 575a277f47bSMikolaj Golub error = EINVAL; 576a277f47bSMikolaj Golub goto fail2; 577a277f47bSMikolaj Golub } 578a277f47bSMikolaj Golub } 579a277f47bSMikolaj Golub 580a277f47bSMikolaj Golub gp = g_new_geomf(&g_gate_class, "%s", name); 581a277f47bSMikolaj Golub gp->start = g_gate_start; 582a277f47bSMikolaj Golub gp->access = g_gate_access; 583a277f47bSMikolaj Golub gp->orphan = g_gate_orphan; 584a277f47bSMikolaj Golub gp->dumpconf = g_gate_dumpconf; 585a277f47bSMikolaj Golub gp->softc = sc; 586a277f47bSMikolaj Golub 587a277f47bSMikolaj Golub if (ropp != NULL) { 588a277f47bSMikolaj Golub cp = g_new_consumer(gp); 58940ea77a0SAlexander Motin cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 590a277f47bSMikolaj Golub error = g_attach(cp, ropp); 591a277f47bSMikolaj Golub if (error != 0) { 592a277f47bSMikolaj Golub G_GATE_DEBUG(1, "Unable to attach to %s.", ropp->name); 593a277f47bSMikolaj Golub goto fail3; 594a277f47bSMikolaj Golub } 595a277f47bSMikolaj Golub error = g_access(cp, 1, 0, 0); 596a277f47bSMikolaj Golub if (error != 0) { 597a277f47bSMikolaj Golub G_GATE_DEBUG(1, "Unable to access %s.", ropp->name); 598a277f47bSMikolaj Golub g_detach(cp); 599a277f47bSMikolaj Golub goto fail3; 600a277f47bSMikolaj Golub } 601a277f47bSMikolaj Golub sc->sc_readcons = cp; 602a277f47bSMikolaj Golub sc->sc_readoffset = ggio->gctl_readoffset; 603a277f47bSMikolaj Golub } 604a277f47bSMikolaj Golub 60532115b10SPawel Jakub Dawidek ggio->gctl_unit = sc->sc_unit; 606fe27e772SPawel Jakub Dawidek 60732115b10SPawel Jakub Dawidek pp = g_new_providerf(gp, "%s", name); 60840ea77a0SAlexander Motin pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; 609fe27e772SPawel Jakub Dawidek pp->mediasize = ggio->gctl_mediasize; 610fe27e772SPawel Jakub Dawidek pp->sectorsize = ggio->gctl_sectorsize; 611fe27e772SPawel Jakub Dawidek sc->sc_provider = pp; 612fe27e772SPawel Jakub Dawidek g_error_provider(pp, 0); 613e08ec037SPawel Jakub Dawidek 614fe27e772SPawel Jakub Dawidek g_topology_unlock(); 615baf63f65SMikolaj Golub mtx_lock(&g_gate_units_lock); 616baf63f65SMikolaj Golub sc->sc_name = sc->sc_provider->name; 617baf63f65SMikolaj Golub mtx_unlock(&g_gate_units_lock); 618bd119384SMikolaj Golub G_GATE_DEBUG(1, "Device %s created.", gp->name); 619fe27e772SPawel Jakub Dawidek 620fe27e772SPawel Jakub Dawidek if (sc->sc_timeout > 0) { 621fe27e772SPawel Jakub Dawidek callout_reset(&sc->sc_callout, sc->sc_timeout * hz, 622fe27e772SPawel Jakub Dawidek g_gate_guard, sc); 623fe27e772SPawel Jakub Dawidek } 624fe27e772SPawel Jakub Dawidek return (0); 625a277f47bSMikolaj Golub fail3: 626a277f47bSMikolaj Golub g_destroy_consumer(cp); 627a277f47bSMikolaj Golub g_destroy_geom(gp); 628a277f47bSMikolaj Golub fail2: 629a277f47bSMikolaj Golub g_topology_unlock(); 630a277f47bSMikolaj Golub mtx_lock(&g_gate_units_lock); 631a277f47bSMikolaj Golub g_gate_units[sc->sc_unit] = NULL; 632a277f47bSMikolaj Golub KASSERT(g_gate_nunits > 0, ("negative g_gate_nunits?")); 633a277f47bSMikolaj Golub g_gate_nunits--; 634a277f47bSMikolaj Golub fail1: 635a277f47bSMikolaj Golub mtx_unlock(&g_gate_units_lock); 636a277f47bSMikolaj Golub mtx_destroy(&sc->sc_queue_mtx); 637351d0fa6SAlexander Motin mtx_destroy(&sc->sc_read_mtx); 638a277f47bSMikolaj Golub free(sc, M_GATE); 639a277f47bSMikolaj Golub return (error); 640fe27e772SPawel Jakub Dawidek } 641fe27e772SPawel Jakub Dawidek 642e08ec037SPawel Jakub Dawidek static int 643e08ec037SPawel Jakub Dawidek g_gate_modify(struct g_gate_softc *sc, struct g_gate_ctl_modify *ggio) 644e08ec037SPawel Jakub Dawidek { 645*f284bed2SAlan Somers char readprov[NAME_MAX + 1]; 646e08ec037SPawel Jakub Dawidek struct g_provider *pp; 647e08ec037SPawel Jakub Dawidek struct g_consumer *cp; 648351d0fa6SAlexander Motin int done, error; 649e08ec037SPawel Jakub Dawidek 650e08ec037SPawel Jakub Dawidek if ((ggio->gctl_modify & GG_MODIFY_MEDIASIZE) != 0) { 651e08ec037SPawel Jakub Dawidek if (ggio->gctl_mediasize <= 0) { 652e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid media size."); 653e08ec037SPawel Jakub Dawidek return (EINVAL); 654e08ec037SPawel Jakub Dawidek } 655e08ec037SPawel Jakub Dawidek pp = sc->sc_provider; 656e08ec037SPawel Jakub Dawidek if ((ggio->gctl_mediasize % pp->sectorsize) != 0) { 657e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid media size."); 658e08ec037SPawel Jakub Dawidek return (EINVAL); 659e08ec037SPawel Jakub Dawidek } 660874774c5SMikolaj Golub g_resize_provider(pp, ggio->gctl_mediasize); 661874774c5SMikolaj Golub return (0); 662e08ec037SPawel Jakub Dawidek } 663e08ec037SPawel Jakub Dawidek 664*f284bed2SAlan Somers if ((ggio->gctl_modify & GG_MODIFY_INFO) != 0) { 665*f284bed2SAlan Somers memset(sc->sc_info, 0, sizeof(sc->sc_info)); 666*f284bed2SAlan Somers strncpy(sc->sc_info, ggio->gctl_info, 667*f284bed2SAlan Somers MIN(sizeof(sc->sc_info) - 1, sizeof(ggio->gctl_info))); 668*f284bed2SAlan Somers } 669e08ec037SPawel Jakub Dawidek cp = NULL; 670e08ec037SPawel Jakub Dawidek 671e08ec037SPawel Jakub Dawidek if ((ggio->gctl_modify & GG_MODIFY_READPROV) != 0) { 672e08ec037SPawel Jakub Dawidek g_topology_lock(); 673351d0fa6SAlexander Motin mtx_lock(&sc->sc_read_mtx); 674351d0fa6SAlexander Motin if ((cp = sc->sc_readcons) != NULL) { 675e08ec037SPawel Jakub Dawidek sc->sc_readcons = NULL; 676351d0fa6SAlexander Motin done = (cp->index == 0); 677351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 678351d0fa6SAlexander Motin if (done) 679351d0fa6SAlexander Motin g_gate_detach(cp, 0); 680351d0fa6SAlexander Motin } else 681351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 682e08ec037SPawel Jakub Dawidek if (ggio->gctl_readprov[0] != '\0') { 683*f284bed2SAlan Somers memset(readprov, 0, sizeof(readprov)); 684*f284bed2SAlan Somers strncpy(readprov, ggio->gctl_readprov, 685*f284bed2SAlan Somers MIN(sizeof(readprov) - 1, 686*f284bed2SAlan Somers sizeof(ggio->gctl_readprov))); 687*f284bed2SAlan Somers pp = g_provider_by_name(readprov); 688e08ec037SPawel Jakub Dawidek if (pp == NULL) { 689e08ec037SPawel Jakub Dawidek g_topology_unlock(); 690e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Provider %s doesn't exist.", 691*f284bed2SAlan Somers readprov); 692e08ec037SPawel Jakub Dawidek return (EINVAL); 693e08ec037SPawel Jakub Dawidek } 694e08ec037SPawel Jakub Dawidek cp = g_new_consumer(sc->sc_provider->geom); 69540ea77a0SAlexander Motin cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 696e08ec037SPawel Jakub Dawidek error = g_attach(cp, pp); 697e08ec037SPawel Jakub Dawidek if (error != 0) { 698e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Unable to attach to %s.", 699e08ec037SPawel Jakub Dawidek pp->name); 700e08ec037SPawel Jakub Dawidek } else { 701e08ec037SPawel Jakub Dawidek error = g_access(cp, 1, 0, 0); 702e08ec037SPawel Jakub Dawidek if (error != 0) { 703e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Unable to access %s.", 704e08ec037SPawel Jakub Dawidek pp->name); 705e08ec037SPawel Jakub Dawidek g_detach(cp); 706e08ec037SPawel Jakub Dawidek } 707e08ec037SPawel Jakub Dawidek } 708e08ec037SPawel Jakub Dawidek if (error != 0) { 709e08ec037SPawel Jakub Dawidek g_destroy_consumer(cp); 710e08ec037SPawel Jakub Dawidek g_topology_unlock(); 711e08ec037SPawel Jakub Dawidek return (error); 712e08ec037SPawel Jakub Dawidek } 713e08ec037SPawel Jakub Dawidek } 714e08ec037SPawel Jakub Dawidek } else { 715e08ec037SPawel Jakub Dawidek cp = sc->sc_readcons; 716e08ec037SPawel Jakub Dawidek } 717e08ec037SPawel Jakub Dawidek 718e08ec037SPawel Jakub Dawidek if ((ggio->gctl_modify & GG_MODIFY_READOFFSET) != 0) { 719e08ec037SPawel Jakub Dawidek if (cp == NULL) { 720e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "No read provider."); 721e08ec037SPawel Jakub Dawidek return (EINVAL); 722e08ec037SPawel Jakub Dawidek } 723e08ec037SPawel Jakub Dawidek pp = sc->sc_provider; 724e08ec037SPawel Jakub Dawidek if ((ggio->gctl_readoffset % pp->sectorsize) != 0) { 725e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid read offset."); 726e08ec037SPawel Jakub Dawidek return (EINVAL); 727e08ec037SPawel Jakub Dawidek } 728e08ec037SPawel Jakub Dawidek if (pp->mediasize + ggio->gctl_readoffset > 729e08ec037SPawel Jakub Dawidek cp->provider->mediasize) { 730e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid read offset or media size."); 731e08ec037SPawel Jakub Dawidek return (EINVAL); 732e08ec037SPawel Jakub Dawidek } 733e08ec037SPawel Jakub Dawidek sc->sc_readoffset = ggio->gctl_readoffset; 734e08ec037SPawel Jakub Dawidek } 735e08ec037SPawel Jakub Dawidek 736e08ec037SPawel Jakub Dawidek if ((ggio->gctl_modify & GG_MODIFY_READPROV) != 0) { 737e08ec037SPawel Jakub Dawidek sc->sc_readcons = cp; 738e08ec037SPawel Jakub Dawidek g_topology_unlock(); 739e08ec037SPawel Jakub Dawidek } 740e08ec037SPawel Jakub Dawidek 741e08ec037SPawel Jakub Dawidek return (0); 742e08ec037SPawel Jakub Dawidek } 743e08ec037SPawel Jakub Dawidek 744fe27e772SPawel Jakub Dawidek #define G_GATE_CHECK_VERSION(ggio) do { \ 74584436f14SPawel Jakub Dawidek if ((ggio)->gctl_version != G_GATE_VERSION) { \ 74684436f14SPawel Jakub Dawidek printf("Version mismatch %d != %d.\n", \ 74784436f14SPawel Jakub Dawidek ggio->gctl_version, G_GATE_VERSION); \ 748fe27e772SPawel Jakub Dawidek return (EINVAL); \ 74984436f14SPawel Jakub Dawidek } \ 750fe27e772SPawel Jakub Dawidek } while (0) 751fe27e772SPawel Jakub Dawidek static int 75289c9c53dSPoul-Henning Kamp g_gate_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 753fe27e772SPawel Jakub Dawidek { 754fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 755fe27e772SPawel Jakub Dawidek struct bio *bp; 756fe27e772SPawel Jakub Dawidek int error = 0; 757fe27e772SPawel Jakub Dawidek 758fe27e772SPawel Jakub Dawidek G_GATE_DEBUG(4, "ioctl(%s, %lx, %p, %x, %p)", devtoname(dev), cmd, addr, 759fe27e772SPawel Jakub Dawidek flags, td); 760fe27e772SPawel Jakub Dawidek 761fe27e772SPawel Jakub Dawidek switch (cmd) { 762fe27e772SPawel Jakub Dawidek case G_GATE_CMD_CREATE: 763fe27e772SPawel Jakub Dawidek { 764fe27e772SPawel Jakub Dawidek struct g_gate_ctl_create *ggio = (void *)addr; 765fe27e772SPawel Jakub Dawidek 766fe27e772SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 767a17dd95fSPawel Jakub Dawidek error = g_gate_create(ggio); 768f9065812SPawel Jakub Dawidek /* 769f9065812SPawel Jakub Dawidek * Reset TDP_GEOM flag. 770f9065812SPawel Jakub Dawidek * There are pending events for sure, because we just created 771f9065812SPawel Jakub Dawidek * new provider and other classes want to taste it, but we 772f9065812SPawel Jakub Dawidek * cannot answer on I/O requests until we're here. 773f9065812SPawel Jakub Dawidek */ 774f9065812SPawel Jakub Dawidek td->td_pflags &= ~TDP_GEOM; 775a17dd95fSPawel Jakub Dawidek return (error); 776fe27e772SPawel Jakub Dawidek } 777e08ec037SPawel Jakub Dawidek case G_GATE_CMD_MODIFY: 778e08ec037SPawel Jakub Dawidek { 779e08ec037SPawel Jakub Dawidek struct g_gate_ctl_modify *ggio = (void *)addr; 780e08ec037SPawel Jakub Dawidek 781e08ec037SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 782e08ec037SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, NULL); 783e08ec037SPawel Jakub Dawidek if (sc == NULL) 784e08ec037SPawel Jakub Dawidek return (ENXIO); 785e08ec037SPawel Jakub Dawidek error = g_gate_modify(sc, ggio); 786e08ec037SPawel Jakub Dawidek g_gate_release(sc); 787e08ec037SPawel Jakub Dawidek return (error); 788e08ec037SPawel Jakub Dawidek } 789fe27e772SPawel Jakub Dawidek case G_GATE_CMD_DESTROY: 790fe27e772SPawel Jakub Dawidek { 791fe27e772SPawel Jakub Dawidek struct g_gate_ctl_destroy *ggio = (void *)addr; 792fe27e772SPawel Jakub Dawidek 793fe27e772SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 79432115b10SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, ggio->gctl_name); 795fe27e772SPawel Jakub Dawidek if (sc == NULL) 796fe27e772SPawel Jakub Dawidek return (ENXIO); 797fe27e772SPawel Jakub Dawidek g_topology_lock(); 79832115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 799fe27e772SPawel Jakub Dawidek error = g_gate_destroy(sc, ggio->gctl_force); 800fe27e772SPawel Jakub Dawidek g_topology_unlock(); 8017ffb6e0fSPawel Jakub Dawidek if (error != 0) 802fe27e772SPawel Jakub Dawidek g_gate_release(sc); 803fe27e772SPawel Jakub Dawidek return (error); 804fe27e772SPawel Jakub Dawidek } 80584436f14SPawel Jakub Dawidek case G_GATE_CMD_CANCEL: 80684436f14SPawel Jakub Dawidek { 80784436f14SPawel Jakub Dawidek struct g_gate_ctl_cancel *ggio = (void *)addr; 80884436f14SPawel Jakub Dawidek struct bio *tbp, *lbp; 80984436f14SPawel Jakub Dawidek 81084436f14SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 81132115b10SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, ggio->gctl_name); 81284436f14SPawel Jakub Dawidek if (sc == NULL) 81384436f14SPawel Jakub Dawidek return (ENXIO); 81484436f14SPawel Jakub Dawidek lbp = NULL; 81584436f14SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 81684436f14SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, tbp) { 81784436f14SPawel Jakub Dawidek if (ggio->gctl_seq == 0 || 81884436f14SPawel Jakub Dawidek ggio->gctl_seq == (uintptr_t)bp->bio_driver1) { 81984436f14SPawel Jakub Dawidek G_GATE_LOGREQ(1, bp, "Request canceled."); 82084436f14SPawel Jakub Dawidek bioq_remove(&sc->sc_outqueue, bp); 82184436f14SPawel Jakub Dawidek /* 82284436f14SPawel Jakub Dawidek * Be sure to put requests back onto incoming 82384436f14SPawel Jakub Dawidek * queue in the proper order. 82484436f14SPawel Jakub Dawidek */ 82584436f14SPawel Jakub Dawidek if (lbp == NULL) 82684436f14SPawel Jakub Dawidek bioq_insert_head(&sc->sc_inqueue, bp); 82784436f14SPawel Jakub Dawidek else { 82884436f14SPawel Jakub Dawidek TAILQ_INSERT_AFTER(&sc->sc_inqueue.queue, 82984436f14SPawel Jakub Dawidek lbp, bp, bio_queue); 83084436f14SPawel Jakub Dawidek } 83184436f14SPawel Jakub Dawidek lbp = bp; 83284436f14SPawel Jakub Dawidek /* 83384436f14SPawel Jakub Dawidek * If only one request was canceled, leave now. 83484436f14SPawel Jakub Dawidek */ 83584436f14SPawel Jakub Dawidek if (ggio->gctl_seq != 0) 83684436f14SPawel Jakub Dawidek break; 83784436f14SPawel Jakub Dawidek } 83884436f14SPawel Jakub Dawidek } 83932115b10SPawel Jakub Dawidek if (ggio->gctl_unit == G_GATE_NAME_GIVEN) 84032115b10SPawel Jakub Dawidek ggio->gctl_unit = sc->sc_unit; 84184436f14SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 84284436f14SPawel Jakub Dawidek g_gate_release(sc); 84384436f14SPawel Jakub Dawidek return (error); 84484436f14SPawel Jakub Dawidek } 845fe27e772SPawel Jakub Dawidek case G_GATE_CMD_START: 846fe27e772SPawel Jakub Dawidek { 847fe27e772SPawel Jakub Dawidek struct g_gate_ctl_io *ggio = (void *)addr; 848fe27e772SPawel Jakub Dawidek 849fe27e772SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 85032115b10SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, NULL); 851fe27e772SPawel Jakub Dawidek if (sc == NULL) 852fe27e772SPawel Jakub Dawidek return (ENXIO); 8537ffb6e0fSPawel Jakub Dawidek error = 0; 854fe27e772SPawel Jakub Dawidek for (;;) { 855e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 856fe27e772SPawel Jakub Dawidek bp = bioq_first(&sc->sc_inqueue); 857fe27e772SPawel Jakub Dawidek if (bp != NULL) 858fe27e772SPawel Jakub Dawidek break; 8597ffb6e0fSPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) { 8607ffb6e0fSPawel Jakub Dawidek ggio->gctl_error = ECANCELED; 8617ffb6e0fSPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 8627ffb6e0fSPawel Jakub Dawidek goto start_end; 8637ffb6e0fSPawel Jakub Dawidek } 864e35d3a78SPawel Jakub Dawidek if (msleep(sc, &sc->sc_queue_mtx, 865fe27e772SPawel Jakub Dawidek PPAUSE | PDROP | PCATCH, "ggwait", 0) != 0) { 866fe27e772SPawel Jakub Dawidek ggio->gctl_error = ECANCELED; 8677ffb6e0fSPawel Jakub Dawidek goto start_end; 868fe27e772SPawel Jakub Dawidek } 869fe27e772SPawel Jakub Dawidek } 8704d1e1bf3SPawel Jakub Dawidek ggio->gctl_cmd = bp->bio_cmd; 871c4d2d401SPawel Jakub Dawidek if (bp->bio_cmd == BIO_WRITE && 872fe27e772SPawel Jakub Dawidek bp->bio_length > ggio->gctl_length) { 873e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 874fe27e772SPawel Jakub Dawidek ggio->gctl_length = bp->bio_length; 875fe27e772SPawel Jakub Dawidek ggio->gctl_error = ENOMEM; 8767ffb6e0fSPawel Jakub Dawidek goto start_end; 877fe27e772SPawel Jakub Dawidek } 878fe27e772SPawel Jakub Dawidek bioq_remove(&sc->sc_inqueue, bp); 879e35d3a78SPawel Jakub Dawidek bioq_insert_tail(&sc->sc_outqueue, bp); 880e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 881e35d3a78SPawel Jakub Dawidek 8820d785336SPawel Jakub Dawidek ggio->gctl_seq = (uintptr_t)bp->bio_driver1; 883fe27e772SPawel Jakub Dawidek ggio->gctl_offset = bp->bio_offset; 884fe27e772SPawel Jakub Dawidek ggio->gctl_length = bp->bio_length; 88584436f14SPawel Jakub Dawidek 886fe27e772SPawel Jakub Dawidek switch (bp->bio_cmd) { 887fe27e772SPawel Jakub Dawidek case BIO_READ: 888fe27e772SPawel Jakub Dawidek case BIO_DELETE: 889204a4e19SPawel Jakub Dawidek case BIO_FLUSH: 8908b522bdaSWarner Losh case BIO_SPEEDUP: 89115725379SPawel Jakub Dawidek break; 892fe27e772SPawel Jakub Dawidek case BIO_WRITE: 893fe27e772SPawel Jakub Dawidek error = copyout(bp->bio_data, ggio->gctl_data, 894fe27e772SPawel Jakub Dawidek bp->bio_length); 895fe27e772SPawel Jakub Dawidek if (error != 0) { 896e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 897e35d3a78SPawel Jakub Dawidek bioq_remove(&sc->sc_outqueue, bp); 898662a4e58SPawel Jakub Dawidek bioq_insert_head(&sc->sc_inqueue, bp); 899e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 9007ffb6e0fSPawel Jakub Dawidek goto start_end; 901fe27e772SPawel Jakub Dawidek } 902fe27e772SPawel Jakub Dawidek break; 903fe27e772SPawel Jakub Dawidek } 9047ffb6e0fSPawel Jakub Dawidek start_end: 9057ffb6e0fSPawel Jakub Dawidek g_gate_release(sc); 9067ffb6e0fSPawel Jakub Dawidek return (error); 907fe27e772SPawel Jakub Dawidek } 908fe27e772SPawel Jakub Dawidek case G_GATE_CMD_DONE: 909fe27e772SPawel Jakub Dawidek { 910fe27e772SPawel Jakub Dawidek struct g_gate_ctl_io *ggio = (void *)addr; 911fe27e772SPawel Jakub Dawidek 912fe27e772SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 91332115b10SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, NULL); 914fe27e772SPawel Jakub Dawidek if (sc == NULL) 915fe27e772SPawel Jakub Dawidek return (ENOENT); 9167ffb6e0fSPawel Jakub Dawidek error = 0; 917e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 918fe27e772SPawel Jakub Dawidek TAILQ_FOREACH(bp, &sc->sc_outqueue.queue, bio_queue) { 9190d785336SPawel Jakub Dawidek if (ggio->gctl_seq == (uintptr_t)bp->bio_driver1) 920fe27e772SPawel Jakub Dawidek break; 921fe27e772SPawel Jakub Dawidek } 922fe27e772SPawel Jakub Dawidek if (bp != NULL) { 923fe27e772SPawel Jakub Dawidek bioq_remove(&sc->sc_outqueue, bp); 924e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 925fe27e772SPawel Jakub Dawidek } 926e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 927fe27e772SPawel Jakub Dawidek if (bp == NULL) { 928fe27e772SPawel Jakub Dawidek /* 929fe27e772SPawel Jakub Dawidek * Request was probably canceled. 930fe27e772SPawel Jakub Dawidek */ 9317ffb6e0fSPawel Jakub Dawidek goto done_end; 932fe27e772SPawel Jakub Dawidek } 933fe27e772SPawel Jakub Dawidek if (ggio->gctl_error == EAGAIN) { 934fe27e772SPawel Jakub Dawidek bp->bio_error = 0; 935fe27e772SPawel Jakub Dawidek G_GATE_LOGREQ(1, bp, "Request desisted."); 936e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 937e35d3a78SPawel Jakub Dawidek sc->sc_queue_count++; 938662a4e58SPawel Jakub Dawidek bioq_insert_head(&sc->sc_inqueue, bp); 939fe27e772SPawel Jakub Dawidek wakeup(sc); 940e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 941fe27e772SPawel Jakub Dawidek } else { 942fe27e772SPawel Jakub Dawidek bp->bio_error = ggio->gctl_error; 943fe27e772SPawel Jakub Dawidek if (bp->bio_error == 0) { 944fe27e772SPawel Jakub Dawidek bp->bio_completed = bp->bio_length; 945fe27e772SPawel Jakub Dawidek switch (bp->bio_cmd) { 946fe27e772SPawel Jakub Dawidek case BIO_READ: 947fe27e772SPawel Jakub Dawidek error = copyin(ggio->gctl_data, 948fe27e772SPawel Jakub Dawidek bp->bio_data, bp->bio_length); 949fe27e772SPawel Jakub Dawidek if (error != 0) 950fe27e772SPawel Jakub Dawidek bp->bio_error = error; 951fe27e772SPawel Jakub Dawidek break; 952fe27e772SPawel Jakub Dawidek case BIO_DELETE: 953fe27e772SPawel Jakub Dawidek case BIO_WRITE: 954204a4e19SPawel Jakub Dawidek case BIO_FLUSH: 9558b522bdaSWarner Losh case BIO_SPEEDUP: 956fe27e772SPawel Jakub Dawidek break; 957fe27e772SPawel Jakub Dawidek } 958fe27e772SPawel Jakub Dawidek } 959fe27e772SPawel Jakub Dawidek G_GATE_LOGREQ(2, bp, "Request done."); 960fe27e772SPawel Jakub Dawidek g_io_deliver(bp, bp->bio_error); 961fe27e772SPawel Jakub Dawidek } 9627ffb6e0fSPawel Jakub Dawidek done_end: 9637ffb6e0fSPawel Jakub Dawidek g_gate_release(sc); 964fe27e772SPawel Jakub Dawidek return (error); 965fe27e772SPawel Jakub Dawidek } 966fe27e772SPawel Jakub Dawidek } 967fe27e772SPawel Jakub Dawidek return (ENOIOCTL); 968fe27e772SPawel Jakub Dawidek } 969fe27e772SPawel Jakub Dawidek 970fe27e772SPawel Jakub Dawidek static void 9719ecdd506SPawel Jakub Dawidek g_gate_device(void) 972fe27e772SPawel Jakub Dawidek { 973fe27e772SPawel Jakub Dawidek 974fe27e772SPawel Jakub Dawidek status_dev = make_dev(&g_gate_cdevsw, 0x0, UID_ROOT, GID_WHEEL, 0600, 975fe27e772SPawel Jakub Dawidek G_GATE_CTL_NAME); 976fe27e772SPawel Jakub Dawidek } 977fe27e772SPawel Jakub Dawidek 978fe27e772SPawel Jakub Dawidek static int 979fe27e772SPawel Jakub Dawidek g_gate_modevent(module_t mod, int type, void *data) 980fe27e772SPawel Jakub Dawidek { 981fe27e772SPawel Jakub Dawidek int error = 0; 982fe27e772SPawel Jakub Dawidek 983fe27e772SPawel Jakub Dawidek switch (type) { 984fe27e772SPawel Jakub Dawidek case MOD_LOAD: 98532115b10SPawel Jakub Dawidek mtx_init(&g_gate_units_lock, "gg_units_lock", NULL, MTX_DEF); 98632115b10SPawel Jakub Dawidek g_gate_units = malloc(g_gate_maxunits * sizeof(g_gate_units[0]), 98732115b10SPawel Jakub Dawidek M_GATE, M_WAITOK | M_ZERO); 98832115b10SPawel Jakub Dawidek g_gate_nunits = 0; 9899ecdd506SPawel Jakub Dawidek g_gate_device(); 990fe27e772SPawel Jakub Dawidek break; 991fe27e772SPawel Jakub Dawidek case MOD_UNLOAD: 99232115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 99332115b10SPawel Jakub Dawidek if (g_gate_nunits > 0) { 99432115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 995fe27e772SPawel Jakub Dawidek error = EBUSY; 996fe27e772SPawel Jakub Dawidek break; 997fe27e772SPawel Jakub Dawidek } 99832115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 99932115b10SPawel Jakub Dawidek mtx_destroy(&g_gate_units_lock); 100001b5c6f7SPedro F. Giffuni if (status_dev != NULL) 1001fe27e772SPawel Jakub Dawidek destroy_dev(status_dev); 100232115b10SPawel Jakub Dawidek free(g_gate_units, M_GATE); 1003fe27e772SPawel Jakub Dawidek break; 1004fe27e772SPawel Jakub Dawidek default: 10053e019deaSPoul-Henning Kamp return (EOPNOTSUPP); 1006fe27e772SPawel Jakub Dawidek break; 1007fe27e772SPawel Jakub Dawidek } 1008fe27e772SPawel Jakub Dawidek 1009fe27e772SPawel Jakub Dawidek return (error); 1010fe27e772SPawel Jakub Dawidek } 1011fe27e772SPawel Jakub Dawidek static moduledata_t g_gate_module = { 1012fe27e772SPawel Jakub Dawidek G_GATE_MOD_NAME, 1013fe27e772SPawel Jakub Dawidek g_gate_modevent, 1014fe27e772SPawel Jakub Dawidek NULL 1015fe27e772SPawel Jakub Dawidek }; 1016fe27e772SPawel Jakub Dawidek DECLARE_MODULE(geom_gate, g_gate_module, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 1017fe27e772SPawel Jakub Dawidek DECLARE_GEOM_CLASS(g_gate_class, g_gate); 101874d6c131SKyle Evans MODULE_VERSION(geom_gate, 0); 1019