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); 65*7029da5cSPawel 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 87fe27e772SPawel Jakub Dawidek 8832115b10SPawel Jakub Dawidek static struct g_gate_softc **g_gate_units; 8932115b10SPawel Jakub Dawidek static u_int g_gate_nunits; 9032115b10SPawel Jakub Dawidek static struct mtx g_gate_units_lock; 91fe27e772SPawel Jakub Dawidek 92351d0fa6SAlexander Motin static void 93351d0fa6SAlexander Motin g_gate_detach(void *arg, int flags __unused) 94351d0fa6SAlexander Motin { 95351d0fa6SAlexander Motin struct g_consumer *cp = arg; 96351d0fa6SAlexander Motin 97351d0fa6SAlexander Motin g_topology_assert(); 98351d0fa6SAlexander Motin G_GATE_DEBUG(1, "Destroying read consumer on provider %s orphan.", 99351d0fa6SAlexander Motin cp->provider->name); 100351d0fa6SAlexander Motin (void)g_access(cp, -1, 0, 0); 101351d0fa6SAlexander Motin g_detach(cp); 102351d0fa6SAlexander Motin g_destroy_consumer(cp); 103351d0fa6SAlexander Motin } 104351d0fa6SAlexander Motin 105fe27e772SPawel Jakub Dawidek static int 106fe27e772SPawel Jakub Dawidek g_gate_destroy(struct g_gate_softc *sc, boolean_t force) 107fe27e772SPawel Jakub Dawidek { 10840ea77a0SAlexander Motin struct bio_queue_head queue; 109fe27e772SPawel Jakub Dawidek struct g_provider *pp; 110e08ec037SPawel Jakub Dawidek struct g_consumer *cp; 1117ffb6e0fSPawel Jakub Dawidek struct g_geom *gp; 112fe27e772SPawel Jakub Dawidek struct bio *bp; 113fe27e772SPawel Jakub Dawidek 114fe27e772SPawel Jakub Dawidek g_topology_assert(); 11532115b10SPawel Jakub Dawidek mtx_assert(&g_gate_units_lock, MA_OWNED); 116fe27e772SPawel Jakub Dawidek pp = sc->sc_provider; 117fe27e772SPawel Jakub Dawidek if (!force && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 11832115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 119fe27e772SPawel Jakub Dawidek return (EBUSY); 120fe27e772SPawel Jakub Dawidek } 12132115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 122e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 1237ffb6e0fSPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0) 1247ffb6e0fSPawel Jakub Dawidek sc->sc_flags |= G_GATE_FLAG_DESTROY; 125fe27e772SPawel Jakub Dawidek wakeup(sc); 126e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 1277ffb6e0fSPawel Jakub Dawidek gp = pp->geom; 1288b64f3caSAlexander Motin g_wither_provider(pp, ENXIO); 129fe27e772SPawel Jakub Dawidek callout_drain(&sc->sc_callout); 13040ea77a0SAlexander Motin bioq_init(&queue); 131e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 13240ea77a0SAlexander Motin while ((bp = bioq_takefirst(&sc->sc_inqueue)) != NULL) { 133e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 13440ea77a0SAlexander Motin bioq_insert_tail(&queue, bp); 135fe27e772SPawel Jakub Dawidek } 13640ea77a0SAlexander Motin while ((bp = bioq_takefirst(&sc->sc_outqueue)) != NULL) { 137e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 13840ea77a0SAlexander Motin bioq_insert_tail(&queue, bp); 139fe27e772SPawel Jakub Dawidek } 1407ffb6e0fSPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 1417ffb6e0fSPawel Jakub Dawidek g_topology_unlock(); 14240ea77a0SAlexander Motin while ((bp = bioq_takefirst(&queue)) != NULL) { 14340ea77a0SAlexander Motin G_GATE_LOGREQ(1, bp, "Request canceled."); 14440ea77a0SAlexander Motin g_io_deliver(bp, ENXIO); 14540ea77a0SAlexander Motin } 14632115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 1477ffb6e0fSPawel Jakub Dawidek /* One reference is ours. */ 1487ffb6e0fSPawel Jakub Dawidek sc->sc_ref--; 14932115b10SPawel Jakub Dawidek while (sc->sc_ref > 0) 15032115b10SPawel Jakub Dawidek msleep(&sc->sc_ref, &g_gate_units_lock, 0, "gg:destroy", 0); 15132115b10SPawel Jakub Dawidek g_gate_units[sc->sc_unit] = NULL; 15232115b10SPawel Jakub Dawidek KASSERT(g_gate_nunits > 0, ("negative g_gate_nunits?")); 15332115b10SPawel Jakub Dawidek g_gate_nunits--; 15432115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 155e35d3a78SPawel Jakub Dawidek mtx_destroy(&sc->sc_queue_mtx); 156351d0fa6SAlexander Motin mtx_destroy(&sc->sc_read_mtx); 1577ffb6e0fSPawel Jakub Dawidek g_topology_lock(); 158e08ec037SPawel Jakub Dawidek if ((cp = sc->sc_readcons) != NULL) { 159e08ec037SPawel Jakub Dawidek sc->sc_readcons = NULL; 160e08ec037SPawel Jakub Dawidek (void)g_access(cp, -1, 0, 0); 161e08ec037SPawel Jakub Dawidek g_detach(cp); 162e08ec037SPawel Jakub Dawidek g_destroy_consumer(cp); 163e08ec037SPawel Jakub Dawidek } 164bd119384SMikolaj Golub G_GATE_DEBUG(1, "Device %s destroyed.", gp->name); 1657ffb6e0fSPawel Jakub Dawidek gp->softc = NULL; 1667ffb6e0fSPawel Jakub Dawidek g_wither_geom(gp, ENXIO); 167fe27e772SPawel Jakub Dawidek sc->sc_provider = NULL; 168fe27e772SPawel Jakub Dawidek free(sc, M_GATE); 169fe27e772SPawel Jakub Dawidek return (0); 170fe27e772SPawel Jakub Dawidek } 171fe27e772SPawel Jakub Dawidek 172fe27e772SPawel Jakub Dawidek static int 173fe27e772SPawel Jakub Dawidek g_gate_access(struct g_provider *pp, int dr, int dw, int de) 174fe27e772SPawel Jakub Dawidek { 175fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 176fe27e772SPawel Jakub Dawidek 177fe27e772SPawel Jakub Dawidek if (dr <= 0 && dw <= 0 && de <= 0) 178fe27e772SPawel Jakub Dawidek return (0); 179fe27e772SPawel Jakub Dawidek sc = pp->geom->softc; 180fe27e772SPawel Jakub Dawidek if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) 181fe27e772SPawel Jakub Dawidek return (ENXIO); 18255336b83SPawel Jakub Dawidek /* XXX: Hack to allow read-only mounts. */ 18355336b83SPawel Jakub Dawidek #if 0 184fe27e772SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0 && dw > 0) 185fe27e772SPawel Jakub Dawidek return (EPERM); 18655336b83SPawel Jakub Dawidek #endif 187fe27e772SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0 && dr > 0) 188fe27e772SPawel Jakub Dawidek return (EPERM); 189fe27e772SPawel Jakub Dawidek return (0); 190fe27e772SPawel Jakub Dawidek } 191fe27e772SPawel Jakub Dawidek 192fe27e772SPawel Jakub Dawidek static void 193e08ec037SPawel Jakub Dawidek g_gate_queue_io(struct bio *bp) 194fe27e772SPawel Jakub Dawidek { 195fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 196fe27e772SPawel Jakub Dawidek 197fe27e772SPawel Jakub Dawidek sc = bp->bio_to->geom->softc; 198fe27e772SPawel Jakub Dawidek if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) { 199fe27e772SPawel Jakub Dawidek g_io_deliver(bp, ENXIO); 200fe27e772SPawel Jakub Dawidek return; 201fe27e772SPawel Jakub Dawidek } 202fe27e772SPawel Jakub Dawidek 203e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 204e08ec037SPawel Jakub Dawidek 20563a6c5c1SPawel Jakub Dawidek if (sc->sc_queue_size > 0 && sc->sc_queue_count > sc->sc_queue_size) { 20635f855d9SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 207fe27e772SPawel Jakub Dawidek G_GATE_LOGREQ(1, bp, "Queue full, request canceled."); 20832115b10SPawel Jakub Dawidek g_io_deliver(bp, ENOMEM); 209fe27e772SPawel Jakub Dawidek return; 210fe27e772SPawel Jakub Dawidek } 211e35d3a78SPawel Jakub Dawidek 212fe27e772SPawel Jakub Dawidek bp->bio_driver1 = (void *)sc->sc_seq; 213fe27e772SPawel Jakub Dawidek sc->sc_seq++; 214e35d3a78SPawel Jakub Dawidek sc->sc_queue_count++; 215fe27e772SPawel Jakub Dawidek 216662a4e58SPawel Jakub Dawidek bioq_insert_tail(&sc->sc_inqueue, bp); 217fe27e772SPawel Jakub Dawidek wakeup(sc); 218e35d3a78SPawel Jakub Dawidek 219e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 220fe27e772SPawel Jakub Dawidek } 221fe27e772SPawel Jakub Dawidek 222e08ec037SPawel Jakub Dawidek static void 223e08ec037SPawel Jakub Dawidek g_gate_done(struct bio *cbp) 224e08ec037SPawel Jakub Dawidek { 225351d0fa6SAlexander Motin struct g_gate_softc *sc; 226e08ec037SPawel Jakub Dawidek struct bio *pbp; 227351d0fa6SAlexander Motin struct g_consumer *cp; 228e08ec037SPawel Jakub Dawidek 229351d0fa6SAlexander Motin cp = cbp->bio_from; 230e08ec037SPawel Jakub Dawidek pbp = cbp->bio_parent; 231e08ec037SPawel Jakub Dawidek if (cbp->bio_error == 0) { 232e08ec037SPawel Jakub Dawidek pbp->bio_completed = cbp->bio_completed; 233e08ec037SPawel Jakub Dawidek g_destroy_bio(cbp); 234e08ec037SPawel Jakub Dawidek pbp->bio_inbed++; 235e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, 0); 236e08ec037SPawel Jakub Dawidek } else { 237e08ec037SPawel Jakub Dawidek /* If direct read failed, pass it through userland daemon. */ 238e08ec037SPawel Jakub Dawidek g_destroy_bio(cbp); 239e08ec037SPawel Jakub Dawidek pbp->bio_children--; 240e08ec037SPawel Jakub Dawidek g_gate_queue_io(pbp); 241e08ec037SPawel Jakub Dawidek } 242351d0fa6SAlexander Motin 243351d0fa6SAlexander Motin sc = cp->geom->softc; 244351d0fa6SAlexander Motin mtx_lock(&sc->sc_read_mtx); 245351d0fa6SAlexander Motin if (--cp->index == 0 && sc->sc_readcons != cp) 246351d0fa6SAlexander Motin g_post_event(g_gate_detach, cp, M_NOWAIT, NULL); 247351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 248e08ec037SPawel Jakub Dawidek } 249e08ec037SPawel Jakub Dawidek 250e08ec037SPawel Jakub Dawidek static void 251e08ec037SPawel Jakub Dawidek g_gate_start(struct bio *pbp) 252e08ec037SPawel Jakub Dawidek { 253e08ec037SPawel Jakub Dawidek struct g_gate_softc *sc; 254351d0fa6SAlexander Motin struct g_consumer *cp; 255351d0fa6SAlexander Motin struct bio *cbp; 256e08ec037SPawel Jakub Dawidek 257e08ec037SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 258e08ec037SPawel Jakub Dawidek if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) { 259e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, ENXIO); 260e08ec037SPawel Jakub Dawidek return; 261e08ec037SPawel Jakub Dawidek } 262e08ec037SPawel Jakub Dawidek G_GATE_LOGREQ(2, pbp, "Request received."); 263e08ec037SPawel Jakub Dawidek switch (pbp->bio_cmd) { 264e08ec037SPawel Jakub Dawidek case BIO_READ: 265351d0fa6SAlexander Motin if (sc->sc_readcons == NULL) 266351d0fa6SAlexander Motin break; 267e08ec037SPawel Jakub Dawidek cbp = g_clone_bio(pbp); 268e08ec037SPawel Jakub Dawidek if (cbp == NULL) { 269e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, ENOMEM); 270e08ec037SPawel Jakub Dawidek return; 271e08ec037SPawel Jakub Dawidek } 272351d0fa6SAlexander Motin mtx_lock(&sc->sc_read_mtx); 273351d0fa6SAlexander Motin if ((cp = sc->sc_readcons) == NULL) { 274351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 275351d0fa6SAlexander Motin g_destroy_bio(cbp); 276351d0fa6SAlexander Motin pbp->bio_children--; 277e08ec037SPawel Jakub Dawidek break; 278351d0fa6SAlexander Motin } 279351d0fa6SAlexander Motin cp->index++; 280351d0fa6SAlexander Motin cbp->bio_offset = pbp->bio_offset + sc->sc_readoffset; 281351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 282351d0fa6SAlexander Motin cbp->bio_done = g_gate_done; 283351d0fa6SAlexander Motin g_io_request(cbp, cp); 284351d0fa6SAlexander Motin return; 285e08ec037SPawel Jakub Dawidek case BIO_DELETE: 286e08ec037SPawel Jakub Dawidek case BIO_WRITE: 287e08ec037SPawel Jakub Dawidek case BIO_FLUSH: 2888b522bdaSWarner Losh case BIO_SPEEDUP: 289e08ec037SPawel Jakub Dawidek /* XXX: Hack to allow read-only mounts. */ 290e08ec037SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) { 291e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, EPERM); 292e08ec037SPawel Jakub Dawidek return; 293e08ec037SPawel Jakub Dawidek } 294e08ec037SPawel Jakub Dawidek break; 295e08ec037SPawel Jakub Dawidek case BIO_GETATTR: 296e08ec037SPawel Jakub Dawidek default: 297e08ec037SPawel Jakub Dawidek G_GATE_LOGREQ(2, pbp, "Ignoring request."); 298e08ec037SPawel Jakub Dawidek g_io_deliver(pbp, EOPNOTSUPP); 299e08ec037SPawel Jakub Dawidek return; 300e08ec037SPawel Jakub Dawidek } 301e08ec037SPawel Jakub Dawidek 302e08ec037SPawel Jakub Dawidek g_gate_queue_io(pbp); 303e08ec037SPawel Jakub Dawidek } 304e08ec037SPawel Jakub Dawidek 305fe27e772SPawel Jakub Dawidek static struct g_gate_softc * 3062aa15ffdSPawel Jakub Dawidek g_gate_hold(int unit, const char *name) 307fe27e772SPawel Jakub Dawidek { 30832115b10SPawel Jakub Dawidek struct g_gate_softc *sc = NULL; 309fe27e772SPawel Jakub Dawidek 31032115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 31132115b10SPawel Jakub Dawidek if (unit >= 0 && unit < g_gate_maxunits) 31232115b10SPawel Jakub Dawidek sc = g_gate_units[unit]; 31332115b10SPawel Jakub Dawidek else if (unit == G_GATE_NAME_GIVEN) { 31432115b10SPawel Jakub Dawidek KASSERT(name != NULL, ("name is NULL")); 31532115b10SPawel Jakub Dawidek for (unit = 0; unit < g_gate_maxunits; unit++) { 31632115b10SPawel Jakub Dawidek if (g_gate_units[unit] == NULL) 31732115b10SPawel Jakub Dawidek continue; 31832115b10SPawel Jakub Dawidek if (strcmp(name, 31932115b10SPawel Jakub Dawidek g_gate_units[unit]->sc_provider->name) != 0) { 32032115b10SPawel Jakub Dawidek continue; 32132115b10SPawel Jakub Dawidek } 32232115b10SPawel Jakub Dawidek sc = g_gate_units[unit]; 3237ffb6e0fSPawel Jakub Dawidek break; 324fe27e772SPawel Jakub Dawidek } 32532115b10SPawel Jakub Dawidek } 3267ffb6e0fSPawel Jakub Dawidek if (sc != NULL) 3277ffb6e0fSPawel Jakub Dawidek sc->sc_ref++; 32832115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 329fe27e772SPawel Jakub Dawidek return (sc); 330fe27e772SPawel Jakub Dawidek } 331fe27e772SPawel Jakub Dawidek 332fe27e772SPawel Jakub Dawidek static void 333fe27e772SPawel Jakub Dawidek g_gate_release(struct g_gate_softc *sc) 334fe27e772SPawel Jakub Dawidek { 335fe27e772SPawel Jakub Dawidek 336fe27e772SPawel Jakub Dawidek g_topology_assert_not(); 33732115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 338fe27e772SPawel Jakub Dawidek sc->sc_ref--; 339fe27e772SPawel Jakub Dawidek KASSERT(sc->sc_ref >= 0, ("Negative sc_ref for %s.", sc->sc_name)); 34032115b10SPawel Jakub Dawidek if (sc->sc_ref == 0 && (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) 3417ffb6e0fSPawel Jakub Dawidek wakeup(&sc->sc_ref); 34232115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 343fe27e772SPawel Jakub Dawidek } 344fe27e772SPawel Jakub Dawidek 345fe27e772SPawel Jakub Dawidek static int 34632115b10SPawel Jakub Dawidek g_gate_getunit(int unit, int *errorp) 347fe27e772SPawel Jakub Dawidek { 348fe27e772SPawel Jakub Dawidek 34932115b10SPawel Jakub Dawidek mtx_assert(&g_gate_units_lock, MA_OWNED); 350fe27e772SPawel Jakub Dawidek if (unit >= 0) { 35132115b10SPawel Jakub Dawidek if (unit >= g_gate_maxunits) 35232115b10SPawel Jakub Dawidek *errorp = EINVAL; 35332115b10SPawel Jakub Dawidek else if (g_gate_units[unit] == NULL) 354fe27e772SPawel Jakub Dawidek return (unit); 35532115b10SPawel Jakub Dawidek else 35632115b10SPawel Jakub Dawidek *errorp = EEXIST; 35732115b10SPawel Jakub Dawidek } else { 35832115b10SPawel Jakub Dawidek for (unit = 0; unit < g_gate_maxunits; unit++) { 35932115b10SPawel Jakub Dawidek if (g_gate_units[unit] == NULL) 36032115b10SPawel Jakub Dawidek return (unit); 36132115b10SPawel Jakub Dawidek } 36232115b10SPawel Jakub Dawidek *errorp = ENFILE; 36332115b10SPawel Jakub Dawidek } 36432115b10SPawel Jakub Dawidek return (-1); 365fe27e772SPawel Jakub Dawidek } 366fe27e772SPawel Jakub Dawidek 367fe27e772SPawel Jakub Dawidek static void 368fe27e772SPawel Jakub Dawidek g_gate_guard(void *arg) 369fe27e772SPawel Jakub Dawidek { 37040ea77a0SAlexander Motin struct bio_queue_head queue; 371fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 372fe27e772SPawel Jakub Dawidek struct bintime curtime; 373fe27e772SPawel Jakub Dawidek struct bio *bp, *bp2; 374fe27e772SPawel Jakub Dawidek 375fe27e772SPawel Jakub Dawidek sc = arg; 376fe27e772SPawel Jakub Dawidek binuptime(&curtime); 37732115b10SPawel Jakub Dawidek g_gate_hold(sc->sc_unit, NULL); 37840ea77a0SAlexander Motin bioq_init(&queue); 379e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 380fe27e772SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(bp, &sc->sc_inqueue.queue, bio_queue, bp2) { 381fe27e772SPawel Jakub Dawidek if (curtime.sec - bp->bio_t0.sec < 5) 382fe27e772SPawel Jakub Dawidek continue; 383fe27e772SPawel Jakub Dawidek bioq_remove(&sc->sc_inqueue, bp); 384e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 38540ea77a0SAlexander Motin bioq_insert_tail(&queue, bp); 386fe27e772SPawel Jakub Dawidek } 387fe27e772SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, bp2) { 388fe27e772SPawel Jakub Dawidek if (curtime.sec - bp->bio_t0.sec < 5) 389fe27e772SPawel Jakub Dawidek continue; 390fe27e772SPawel Jakub Dawidek bioq_remove(&sc->sc_outqueue, bp); 391e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 39240ea77a0SAlexander Motin bioq_insert_tail(&queue, bp); 39340ea77a0SAlexander Motin } 39440ea77a0SAlexander Motin mtx_unlock(&sc->sc_queue_mtx); 39540ea77a0SAlexander Motin while ((bp = bioq_takefirst(&queue)) != NULL) { 396fe27e772SPawel Jakub Dawidek G_GATE_LOGREQ(1, bp, "Request timeout."); 397fe27e772SPawel Jakub Dawidek g_io_deliver(bp, EIO); 398fe27e772SPawel Jakub Dawidek } 399fe27e772SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0) { 400fe27e772SPawel Jakub Dawidek callout_reset(&sc->sc_callout, sc->sc_timeout * hz, 401fe27e772SPawel Jakub Dawidek g_gate_guard, sc); 402fe27e772SPawel Jakub Dawidek } 403fe27e772SPawel Jakub Dawidek g_gate_release(sc); 404fe27e772SPawel Jakub Dawidek } 405fe27e772SPawel Jakub Dawidek 406fe27e772SPawel Jakub Dawidek static void 407e08ec037SPawel Jakub Dawidek g_gate_orphan(struct g_consumer *cp) 408e08ec037SPawel Jakub Dawidek { 409e08ec037SPawel Jakub Dawidek struct g_gate_softc *sc; 410e08ec037SPawel Jakub Dawidek struct g_geom *gp; 411351d0fa6SAlexander Motin int done; 412e08ec037SPawel Jakub Dawidek 413e08ec037SPawel Jakub Dawidek g_topology_assert(); 414e08ec037SPawel Jakub Dawidek gp = cp->geom; 415e08ec037SPawel Jakub Dawidek sc = gp->softc; 416351d0fa6SAlexander Motin mtx_lock(&sc->sc_read_mtx); 417351d0fa6SAlexander Motin if (sc->sc_readcons == cp) 418e08ec037SPawel Jakub Dawidek sc->sc_readcons = NULL; 419351d0fa6SAlexander Motin done = (cp->index == 0); 420351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 421351d0fa6SAlexander Motin if (done) 422351d0fa6SAlexander Motin g_gate_detach(cp, 0); 423e08ec037SPawel Jakub Dawidek } 424e08ec037SPawel Jakub Dawidek 425e08ec037SPawel Jakub Dawidek static void 426fe27e772SPawel Jakub Dawidek g_gate_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 427fe27e772SPawel Jakub Dawidek struct g_consumer *cp, struct g_provider *pp) 428fe27e772SPawel Jakub Dawidek { 429fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 430fe27e772SPawel Jakub Dawidek 431fe27e772SPawel Jakub Dawidek sc = gp->softc; 432fe27e772SPawel Jakub Dawidek if (sc == NULL || pp != NULL || cp != NULL) 433fe27e772SPawel Jakub Dawidek return; 4341d9db37cSMikolaj Golub sc = g_gate_hold(sc->sc_unit, NULL); 4351d9db37cSMikolaj Golub if (sc == NULL) 4361d9db37cSMikolaj Golub return; 437fe27e772SPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) { 438fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<access>%s</access>\n", indent, "read-only"); 439fe27e772SPawel Jakub Dawidek } else if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0) { 440fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<access>%s</access>\n", indent, 441fe27e772SPawel Jakub Dawidek "write-only"); 442fe27e772SPawel Jakub Dawidek } else { 443fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<access>%s</access>\n", indent, 444fe27e772SPawel Jakub Dawidek "read-write"); 445fe27e772SPawel Jakub Dawidek } 446e08ec037SPawel Jakub Dawidek if (sc->sc_readcons != NULL) { 447e08ec037SPawel Jakub Dawidek sbuf_printf(sb, "%s<read_offset>%jd</read_offset>\n", 448e08ec037SPawel Jakub Dawidek indent, (intmax_t)sc->sc_readoffset); 449e08ec037SPawel Jakub Dawidek sbuf_printf(sb, "%s<read_provider>%s</read_provider>\n", 450e08ec037SPawel Jakub Dawidek indent, sc->sc_readcons->provider->name); 451e08ec037SPawel Jakub Dawidek } 452fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<timeout>%u</timeout>\n", indent, sc->sc_timeout); 453fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<info>%s</info>\n", indent, sc->sc_info); 454fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<queue_count>%u</queue_count>\n", indent, 455fe27e772SPawel Jakub Dawidek sc->sc_queue_count); 456fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<queue_size>%u</queue_size>\n", indent, 457fe27e772SPawel Jakub Dawidek sc->sc_queue_size); 458fe27e772SPawel Jakub Dawidek sbuf_printf(sb, "%s<ref>%u</ref>\n", indent, sc->sc_ref); 45932115b10SPawel Jakub Dawidek sbuf_printf(sb, "%s<unit>%d</unit>\n", indent, sc->sc_unit); 46047f44cb7SPawel Jakub Dawidek g_topology_unlock(); 461fe27e772SPawel Jakub Dawidek g_gate_release(sc); 46247f44cb7SPawel Jakub Dawidek g_topology_lock(); 463fe27e772SPawel Jakub Dawidek } 464fe27e772SPawel Jakub Dawidek 465fe27e772SPawel Jakub Dawidek static int 466fe27e772SPawel Jakub Dawidek g_gate_create(struct g_gate_ctl_create *ggio) 467fe27e772SPawel Jakub Dawidek { 468fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 469fe27e772SPawel Jakub Dawidek struct g_geom *gp; 470e08ec037SPawel Jakub Dawidek struct g_provider *pp, *ropp; 471e08ec037SPawel Jakub Dawidek struct g_consumer *cp; 47232115b10SPawel Jakub Dawidek char name[NAME_MAX]; 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); 510fe27e772SPawel Jakub Dawidek strlcpy(sc->sc_info, ggio->gctl_info, sizeof(sc->sc_info)); 51132115b10SPawel Jakub Dawidek sc->sc_seq = 1; 512fe27e772SPawel Jakub Dawidek bioq_init(&sc->sc_inqueue); 513fe27e772SPawel Jakub Dawidek bioq_init(&sc->sc_outqueue); 514e35d3a78SPawel Jakub Dawidek mtx_init(&sc->sc_queue_mtx, "gg:queue", NULL, MTX_DEF); 515351d0fa6SAlexander Motin mtx_init(&sc->sc_read_mtx, "gg:read", NULL, MTX_DEF); 516fe27e772SPawel Jakub Dawidek sc->sc_queue_count = 0; 517fe27e772SPawel Jakub Dawidek sc->sc_queue_size = ggio->gctl_maxcount; 518fe27e772SPawel Jakub Dawidek if (sc->sc_queue_size > G_GATE_MAX_QUEUE_SIZE) 519fe27e772SPawel Jakub Dawidek sc->sc_queue_size = G_GATE_MAX_QUEUE_SIZE; 520fe27e772SPawel Jakub Dawidek sc->sc_timeout = ggio->gctl_timeout; 521fd90e2edSJung-uk Kim callout_init(&sc->sc_callout, 1); 522e08ec037SPawel Jakub Dawidek 52332115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 52432115b10SPawel Jakub Dawidek sc->sc_unit = g_gate_getunit(ggio->gctl_unit, &error); 525a277f47bSMikolaj Golub if (sc->sc_unit < 0) 526a277f47bSMikolaj Golub goto fail1; 52732115b10SPawel Jakub Dawidek if (ggio->gctl_unit == G_GATE_NAME_GIVEN) 52832115b10SPawel Jakub Dawidek snprintf(name, sizeof(name), "%s", ggio->gctl_name); 52932115b10SPawel Jakub Dawidek else { 53032115b10SPawel Jakub Dawidek snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME, 53132115b10SPawel Jakub Dawidek sc->sc_unit); 53232115b10SPawel Jakub Dawidek } 53332115b10SPawel Jakub Dawidek /* Check for name collision. */ 53432115b10SPawel Jakub Dawidek for (unit = 0; unit < g_gate_maxunits; unit++) { 53532115b10SPawel Jakub Dawidek if (g_gate_units[unit] == NULL) 53632115b10SPawel Jakub Dawidek continue; 537baf63f65SMikolaj Golub if (strcmp(name, g_gate_units[unit]->sc_name) != 0) 53832115b10SPawel Jakub Dawidek continue; 539a277f47bSMikolaj Golub error = EEXIST; 540a277f47bSMikolaj Golub goto fail1; 54132115b10SPawel Jakub Dawidek } 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 { 552a277f47bSMikolaj Golub ropp = g_provider_by_name(ggio->gctl_readprov); 553a277f47bSMikolaj Golub if (ropp == NULL) { 554a277f47bSMikolaj Golub G_GATE_DEBUG(1, "Provider %s doesn't exist.", 555a277f47bSMikolaj Golub ggio->gctl_readprov); 556a277f47bSMikolaj Golub error = EINVAL; 557a277f47bSMikolaj Golub goto fail2; 558a277f47bSMikolaj Golub } 559a277f47bSMikolaj Golub if ((ggio->gctl_readoffset % ggio->gctl_sectorsize) != 0) { 560a277f47bSMikolaj Golub G_GATE_DEBUG(1, "Invalid read offset."); 561a277f47bSMikolaj Golub error = EINVAL; 562a277f47bSMikolaj Golub goto fail2; 563a277f47bSMikolaj Golub } 564a277f47bSMikolaj Golub if (ggio->gctl_mediasize + ggio->gctl_readoffset > 565a277f47bSMikolaj Golub ropp->mediasize) { 566a277f47bSMikolaj Golub G_GATE_DEBUG(1, "Invalid read offset or media size."); 567a277f47bSMikolaj Golub error = EINVAL; 568a277f47bSMikolaj Golub goto fail2; 569a277f47bSMikolaj Golub } 570a277f47bSMikolaj Golub } 571a277f47bSMikolaj Golub 572a277f47bSMikolaj Golub gp = g_new_geomf(&g_gate_class, "%s", name); 573a277f47bSMikolaj Golub gp->start = g_gate_start; 574a277f47bSMikolaj Golub gp->access = g_gate_access; 575a277f47bSMikolaj Golub gp->orphan = g_gate_orphan; 576a277f47bSMikolaj Golub gp->dumpconf = g_gate_dumpconf; 577a277f47bSMikolaj Golub gp->softc = sc; 578a277f47bSMikolaj Golub 579a277f47bSMikolaj Golub if (ropp != NULL) { 580a277f47bSMikolaj Golub cp = g_new_consumer(gp); 58140ea77a0SAlexander Motin cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 582a277f47bSMikolaj Golub error = g_attach(cp, ropp); 583a277f47bSMikolaj Golub if (error != 0) { 584a277f47bSMikolaj Golub G_GATE_DEBUG(1, "Unable to attach to %s.", ropp->name); 585a277f47bSMikolaj Golub goto fail3; 586a277f47bSMikolaj Golub } 587a277f47bSMikolaj Golub error = g_access(cp, 1, 0, 0); 588a277f47bSMikolaj Golub if (error != 0) { 589a277f47bSMikolaj Golub G_GATE_DEBUG(1, "Unable to access %s.", ropp->name); 590a277f47bSMikolaj Golub g_detach(cp); 591a277f47bSMikolaj Golub goto fail3; 592a277f47bSMikolaj Golub } 593a277f47bSMikolaj Golub sc->sc_readcons = cp; 594a277f47bSMikolaj Golub sc->sc_readoffset = ggio->gctl_readoffset; 595a277f47bSMikolaj Golub } 596a277f47bSMikolaj Golub 59732115b10SPawel Jakub Dawidek ggio->gctl_unit = sc->sc_unit; 598fe27e772SPawel Jakub Dawidek 59932115b10SPawel Jakub Dawidek pp = g_new_providerf(gp, "%s", name); 60040ea77a0SAlexander Motin pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; 601fe27e772SPawel Jakub Dawidek pp->mediasize = ggio->gctl_mediasize; 602fe27e772SPawel Jakub Dawidek pp->sectorsize = ggio->gctl_sectorsize; 603fe27e772SPawel Jakub Dawidek sc->sc_provider = pp; 604fe27e772SPawel Jakub Dawidek g_error_provider(pp, 0); 605e08ec037SPawel Jakub Dawidek 606fe27e772SPawel Jakub Dawidek g_topology_unlock(); 607baf63f65SMikolaj Golub mtx_lock(&g_gate_units_lock); 608baf63f65SMikolaj Golub sc->sc_name = sc->sc_provider->name; 609baf63f65SMikolaj Golub mtx_unlock(&g_gate_units_lock); 610bd119384SMikolaj Golub G_GATE_DEBUG(1, "Device %s created.", gp->name); 611fe27e772SPawel Jakub Dawidek 612fe27e772SPawel Jakub Dawidek if (sc->sc_timeout > 0) { 613fe27e772SPawel Jakub Dawidek callout_reset(&sc->sc_callout, sc->sc_timeout * hz, 614fe27e772SPawel Jakub Dawidek g_gate_guard, sc); 615fe27e772SPawel Jakub Dawidek } 616fe27e772SPawel Jakub Dawidek return (0); 617a277f47bSMikolaj Golub fail3: 618a277f47bSMikolaj Golub g_destroy_consumer(cp); 619a277f47bSMikolaj Golub g_destroy_geom(gp); 620a277f47bSMikolaj Golub fail2: 621a277f47bSMikolaj Golub g_topology_unlock(); 622a277f47bSMikolaj Golub mtx_lock(&g_gate_units_lock); 623a277f47bSMikolaj Golub g_gate_units[sc->sc_unit] = NULL; 624a277f47bSMikolaj Golub KASSERT(g_gate_nunits > 0, ("negative g_gate_nunits?")); 625a277f47bSMikolaj Golub g_gate_nunits--; 626a277f47bSMikolaj Golub fail1: 627a277f47bSMikolaj Golub mtx_unlock(&g_gate_units_lock); 628a277f47bSMikolaj Golub mtx_destroy(&sc->sc_queue_mtx); 629351d0fa6SAlexander Motin mtx_destroy(&sc->sc_read_mtx); 630a277f47bSMikolaj Golub free(sc, M_GATE); 631a277f47bSMikolaj Golub return (error); 632fe27e772SPawel Jakub Dawidek } 633fe27e772SPawel Jakub Dawidek 634e08ec037SPawel Jakub Dawidek static int 635e08ec037SPawel Jakub Dawidek g_gate_modify(struct g_gate_softc *sc, struct g_gate_ctl_modify *ggio) 636e08ec037SPawel Jakub Dawidek { 637e08ec037SPawel Jakub Dawidek struct g_provider *pp; 638e08ec037SPawel Jakub Dawidek struct g_consumer *cp; 639351d0fa6SAlexander Motin int done, error; 640e08ec037SPawel Jakub Dawidek 641e08ec037SPawel Jakub Dawidek if ((ggio->gctl_modify & GG_MODIFY_MEDIASIZE) != 0) { 642e08ec037SPawel Jakub Dawidek if (ggio->gctl_mediasize <= 0) { 643e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid media size."); 644e08ec037SPawel Jakub Dawidek return (EINVAL); 645e08ec037SPawel Jakub Dawidek } 646e08ec037SPawel Jakub Dawidek pp = sc->sc_provider; 647e08ec037SPawel Jakub Dawidek if ((ggio->gctl_mediasize % pp->sectorsize) != 0) { 648e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid media size."); 649e08ec037SPawel Jakub Dawidek return (EINVAL); 650e08ec037SPawel Jakub Dawidek } 651874774c5SMikolaj Golub g_resize_provider(pp, ggio->gctl_mediasize); 652874774c5SMikolaj Golub return (0); 653e08ec037SPawel Jakub Dawidek } 654e08ec037SPawel Jakub Dawidek 655e08ec037SPawel Jakub Dawidek if ((ggio->gctl_modify & GG_MODIFY_INFO) != 0) 656e08ec037SPawel Jakub Dawidek (void)strlcpy(sc->sc_info, ggio->gctl_info, sizeof(sc->sc_info)); 657e08ec037SPawel Jakub Dawidek 658e08ec037SPawel Jakub Dawidek cp = NULL; 659e08ec037SPawel Jakub Dawidek 660e08ec037SPawel Jakub Dawidek if ((ggio->gctl_modify & GG_MODIFY_READPROV) != 0) { 661e08ec037SPawel Jakub Dawidek g_topology_lock(); 662351d0fa6SAlexander Motin mtx_lock(&sc->sc_read_mtx); 663351d0fa6SAlexander Motin if ((cp = sc->sc_readcons) != NULL) { 664e08ec037SPawel Jakub Dawidek sc->sc_readcons = NULL; 665351d0fa6SAlexander Motin done = (cp->index == 0); 666351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 667351d0fa6SAlexander Motin if (done) 668351d0fa6SAlexander Motin g_gate_detach(cp, 0); 669351d0fa6SAlexander Motin } else 670351d0fa6SAlexander Motin mtx_unlock(&sc->sc_read_mtx); 671e08ec037SPawel Jakub Dawidek if (ggio->gctl_readprov[0] != '\0') { 672e08ec037SPawel Jakub Dawidek pp = g_provider_by_name(ggio->gctl_readprov); 673e08ec037SPawel Jakub Dawidek if (pp == NULL) { 674e08ec037SPawel Jakub Dawidek g_topology_unlock(); 675e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Provider %s doesn't exist.", 676e08ec037SPawel Jakub Dawidek ggio->gctl_readprov); 677e08ec037SPawel Jakub Dawidek return (EINVAL); 678e08ec037SPawel Jakub Dawidek } 679e08ec037SPawel Jakub Dawidek cp = g_new_consumer(sc->sc_provider->geom); 68040ea77a0SAlexander Motin cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 681e08ec037SPawel Jakub Dawidek error = g_attach(cp, pp); 682e08ec037SPawel Jakub Dawidek if (error != 0) { 683e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Unable to attach to %s.", 684e08ec037SPawel Jakub Dawidek pp->name); 685e08ec037SPawel Jakub Dawidek } else { 686e08ec037SPawel Jakub Dawidek error = g_access(cp, 1, 0, 0); 687e08ec037SPawel Jakub Dawidek if (error != 0) { 688e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Unable to access %s.", 689e08ec037SPawel Jakub Dawidek pp->name); 690e08ec037SPawel Jakub Dawidek g_detach(cp); 691e08ec037SPawel Jakub Dawidek } 692e08ec037SPawel Jakub Dawidek } 693e08ec037SPawel Jakub Dawidek if (error != 0) { 694e08ec037SPawel Jakub Dawidek g_destroy_consumer(cp); 695e08ec037SPawel Jakub Dawidek g_topology_unlock(); 696e08ec037SPawel Jakub Dawidek return (error); 697e08ec037SPawel Jakub Dawidek } 698e08ec037SPawel Jakub Dawidek } 699e08ec037SPawel Jakub Dawidek } else { 700e08ec037SPawel Jakub Dawidek cp = sc->sc_readcons; 701e08ec037SPawel Jakub Dawidek } 702e08ec037SPawel Jakub Dawidek 703e08ec037SPawel Jakub Dawidek if ((ggio->gctl_modify & GG_MODIFY_READOFFSET) != 0) { 704e08ec037SPawel Jakub Dawidek if (cp == NULL) { 705e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "No read provider."); 706e08ec037SPawel Jakub Dawidek return (EINVAL); 707e08ec037SPawel Jakub Dawidek } 708e08ec037SPawel Jakub Dawidek pp = sc->sc_provider; 709e08ec037SPawel Jakub Dawidek if ((ggio->gctl_readoffset % pp->sectorsize) != 0) { 710e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid read offset."); 711e08ec037SPawel Jakub Dawidek return (EINVAL); 712e08ec037SPawel Jakub Dawidek } 713e08ec037SPawel Jakub Dawidek if (pp->mediasize + ggio->gctl_readoffset > 714e08ec037SPawel Jakub Dawidek cp->provider->mediasize) { 715e08ec037SPawel Jakub Dawidek G_GATE_DEBUG(1, "Invalid read offset or media size."); 716e08ec037SPawel Jakub Dawidek return (EINVAL); 717e08ec037SPawel Jakub Dawidek } 718e08ec037SPawel Jakub Dawidek sc->sc_readoffset = ggio->gctl_readoffset; 719e08ec037SPawel Jakub Dawidek } 720e08ec037SPawel Jakub Dawidek 721e08ec037SPawel Jakub Dawidek if ((ggio->gctl_modify & GG_MODIFY_READPROV) != 0) { 722e08ec037SPawel Jakub Dawidek sc->sc_readcons = cp; 723e08ec037SPawel Jakub Dawidek g_topology_unlock(); 724e08ec037SPawel Jakub Dawidek } 725e08ec037SPawel Jakub Dawidek 726e08ec037SPawel Jakub Dawidek return (0); 727e08ec037SPawel Jakub Dawidek } 728e08ec037SPawel Jakub Dawidek 729fe27e772SPawel Jakub Dawidek #define G_GATE_CHECK_VERSION(ggio) do { \ 73084436f14SPawel Jakub Dawidek if ((ggio)->gctl_version != G_GATE_VERSION) { \ 73184436f14SPawel Jakub Dawidek printf("Version mismatch %d != %d.\n", \ 73284436f14SPawel Jakub Dawidek ggio->gctl_version, G_GATE_VERSION); \ 733fe27e772SPawel Jakub Dawidek return (EINVAL); \ 73484436f14SPawel Jakub Dawidek } \ 735fe27e772SPawel Jakub Dawidek } while (0) 736fe27e772SPawel Jakub Dawidek static int 73789c9c53dSPoul-Henning Kamp g_gate_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 738fe27e772SPawel Jakub Dawidek { 739fe27e772SPawel Jakub Dawidek struct g_gate_softc *sc; 740fe27e772SPawel Jakub Dawidek struct bio *bp; 741fe27e772SPawel Jakub Dawidek int error = 0; 742fe27e772SPawel Jakub Dawidek 743fe27e772SPawel Jakub Dawidek G_GATE_DEBUG(4, "ioctl(%s, %lx, %p, %x, %p)", devtoname(dev), cmd, addr, 744fe27e772SPawel Jakub Dawidek flags, td); 745fe27e772SPawel Jakub Dawidek 746fe27e772SPawel Jakub Dawidek switch (cmd) { 747fe27e772SPawel Jakub Dawidek case G_GATE_CMD_CREATE: 748fe27e772SPawel Jakub Dawidek { 749fe27e772SPawel Jakub Dawidek struct g_gate_ctl_create *ggio = (void *)addr; 750fe27e772SPawel Jakub Dawidek 751fe27e772SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 752a17dd95fSPawel Jakub Dawidek error = g_gate_create(ggio); 753f9065812SPawel Jakub Dawidek /* 754f9065812SPawel Jakub Dawidek * Reset TDP_GEOM flag. 755f9065812SPawel Jakub Dawidek * There are pending events for sure, because we just created 756f9065812SPawel Jakub Dawidek * new provider and other classes want to taste it, but we 757f9065812SPawel Jakub Dawidek * cannot answer on I/O requests until we're here. 758f9065812SPawel Jakub Dawidek */ 759f9065812SPawel Jakub Dawidek td->td_pflags &= ~TDP_GEOM; 760a17dd95fSPawel Jakub Dawidek return (error); 761fe27e772SPawel Jakub Dawidek } 762e08ec037SPawel Jakub Dawidek case G_GATE_CMD_MODIFY: 763e08ec037SPawel Jakub Dawidek { 764e08ec037SPawel Jakub Dawidek struct g_gate_ctl_modify *ggio = (void *)addr; 765e08ec037SPawel Jakub Dawidek 766e08ec037SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 767e08ec037SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, NULL); 768e08ec037SPawel Jakub Dawidek if (sc == NULL) 769e08ec037SPawel Jakub Dawidek return (ENXIO); 770e08ec037SPawel Jakub Dawidek error = g_gate_modify(sc, ggio); 771e08ec037SPawel Jakub Dawidek g_gate_release(sc); 772e08ec037SPawel Jakub Dawidek return (error); 773e08ec037SPawel Jakub Dawidek } 774fe27e772SPawel Jakub Dawidek case G_GATE_CMD_DESTROY: 775fe27e772SPawel Jakub Dawidek { 776fe27e772SPawel Jakub Dawidek struct g_gate_ctl_destroy *ggio = (void *)addr; 777fe27e772SPawel Jakub Dawidek 778fe27e772SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 77932115b10SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, ggio->gctl_name); 780fe27e772SPawel Jakub Dawidek if (sc == NULL) 781fe27e772SPawel Jakub Dawidek return (ENXIO); 782fe27e772SPawel Jakub Dawidek g_topology_lock(); 78332115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 784fe27e772SPawel Jakub Dawidek error = g_gate_destroy(sc, ggio->gctl_force); 785fe27e772SPawel Jakub Dawidek g_topology_unlock(); 7867ffb6e0fSPawel Jakub Dawidek if (error != 0) 787fe27e772SPawel Jakub Dawidek g_gate_release(sc); 788fe27e772SPawel Jakub Dawidek return (error); 789fe27e772SPawel Jakub Dawidek } 79084436f14SPawel Jakub Dawidek case G_GATE_CMD_CANCEL: 79184436f14SPawel Jakub Dawidek { 79284436f14SPawel Jakub Dawidek struct g_gate_ctl_cancel *ggio = (void *)addr; 79384436f14SPawel Jakub Dawidek struct bio *tbp, *lbp; 79484436f14SPawel Jakub Dawidek 79584436f14SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 79632115b10SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, ggio->gctl_name); 79784436f14SPawel Jakub Dawidek if (sc == NULL) 79884436f14SPawel Jakub Dawidek return (ENXIO); 79984436f14SPawel Jakub Dawidek lbp = NULL; 80084436f14SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 80184436f14SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, tbp) { 80284436f14SPawel Jakub Dawidek if (ggio->gctl_seq == 0 || 80384436f14SPawel Jakub Dawidek ggio->gctl_seq == (uintptr_t)bp->bio_driver1) { 80484436f14SPawel Jakub Dawidek G_GATE_LOGREQ(1, bp, "Request canceled."); 80584436f14SPawel Jakub Dawidek bioq_remove(&sc->sc_outqueue, bp); 80684436f14SPawel Jakub Dawidek /* 80784436f14SPawel Jakub Dawidek * Be sure to put requests back onto incoming 80884436f14SPawel Jakub Dawidek * queue in the proper order. 80984436f14SPawel Jakub Dawidek */ 81084436f14SPawel Jakub Dawidek if (lbp == NULL) 81184436f14SPawel Jakub Dawidek bioq_insert_head(&sc->sc_inqueue, bp); 81284436f14SPawel Jakub Dawidek else { 81384436f14SPawel Jakub Dawidek TAILQ_INSERT_AFTER(&sc->sc_inqueue.queue, 81484436f14SPawel Jakub Dawidek lbp, bp, bio_queue); 81584436f14SPawel Jakub Dawidek } 81684436f14SPawel Jakub Dawidek lbp = bp; 81784436f14SPawel Jakub Dawidek /* 81884436f14SPawel Jakub Dawidek * If only one request was canceled, leave now. 81984436f14SPawel Jakub Dawidek */ 82084436f14SPawel Jakub Dawidek if (ggio->gctl_seq != 0) 82184436f14SPawel Jakub Dawidek break; 82284436f14SPawel Jakub Dawidek } 82384436f14SPawel Jakub Dawidek } 82432115b10SPawel Jakub Dawidek if (ggio->gctl_unit == G_GATE_NAME_GIVEN) 82532115b10SPawel Jakub Dawidek ggio->gctl_unit = sc->sc_unit; 82684436f14SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 82784436f14SPawel Jakub Dawidek g_gate_release(sc); 82884436f14SPawel Jakub Dawidek return (error); 82984436f14SPawel Jakub Dawidek } 830fe27e772SPawel Jakub Dawidek case G_GATE_CMD_START: 831fe27e772SPawel Jakub Dawidek { 832fe27e772SPawel Jakub Dawidek struct g_gate_ctl_io *ggio = (void *)addr; 833fe27e772SPawel Jakub Dawidek 834fe27e772SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 83532115b10SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, NULL); 836fe27e772SPawel Jakub Dawidek if (sc == NULL) 837fe27e772SPawel Jakub Dawidek return (ENXIO); 8387ffb6e0fSPawel Jakub Dawidek error = 0; 839fe27e772SPawel Jakub Dawidek for (;;) { 840e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 841fe27e772SPawel Jakub Dawidek bp = bioq_first(&sc->sc_inqueue); 842fe27e772SPawel Jakub Dawidek if (bp != NULL) 843fe27e772SPawel Jakub Dawidek break; 8447ffb6e0fSPawel Jakub Dawidek if ((sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) { 8457ffb6e0fSPawel Jakub Dawidek ggio->gctl_error = ECANCELED; 8467ffb6e0fSPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 8477ffb6e0fSPawel Jakub Dawidek goto start_end; 8487ffb6e0fSPawel Jakub Dawidek } 849e35d3a78SPawel Jakub Dawidek if (msleep(sc, &sc->sc_queue_mtx, 850fe27e772SPawel Jakub Dawidek PPAUSE | PDROP | PCATCH, "ggwait", 0) != 0) { 851fe27e772SPawel Jakub Dawidek ggio->gctl_error = ECANCELED; 8527ffb6e0fSPawel Jakub Dawidek goto start_end; 853fe27e772SPawel Jakub Dawidek } 854fe27e772SPawel Jakub Dawidek } 8554d1e1bf3SPawel Jakub Dawidek ggio->gctl_cmd = bp->bio_cmd; 856c4d2d401SPawel Jakub Dawidek if (bp->bio_cmd == BIO_WRITE && 857fe27e772SPawel Jakub Dawidek bp->bio_length > ggio->gctl_length) { 858e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 859fe27e772SPawel Jakub Dawidek ggio->gctl_length = bp->bio_length; 860fe27e772SPawel Jakub Dawidek ggio->gctl_error = ENOMEM; 8617ffb6e0fSPawel Jakub Dawidek goto start_end; 862fe27e772SPawel Jakub Dawidek } 863fe27e772SPawel Jakub Dawidek bioq_remove(&sc->sc_inqueue, bp); 864e35d3a78SPawel Jakub Dawidek bioq_insert_tail(&sc->sc_outqueue, bp); 865e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 866e35d3a78SPawel Jakub Dawidek 8670d785336SPawel Jakub Dawidek ggio->gctl_seq = (uintptr_t)bp->bio_driver1; 868fe27e772SPawel Jakub Dawidek ggio->gctl_offset = bp->bio_offset; 869fe27e772SPawel Jakub Dawidek ggio->gctl_length = bp->bio_length; 87084436f14SPawel Jakub Dawidek 871fe27e772SPawel Jakub Dawidek switch (bp->bio_cmd) { 872fe27e772SPawel Jakub Dawidek case BIO_READ: 873fe27e772SPawel Jakub Dawidek case BIO_DELETE: 874204a4e19SPawel Jakub Dawidek case BIO_FLUSH: 8758b522bdaSWarner Losh case BIO_SPEEDUP: 87615725379SPawel Jakub Dawidek break; 877fe27e772SPawel Jakub Dawidek case BIO_WRITE: 878fe27e772SPawel Jakub Dawidek error = copyout(bp->bio_data, ggio->gctl_data, 879fe27e772SPawel Jakub Dawidek bp->bio_length); 880fe27e772SPawel Jakub Dawidek if (error != 0) { 881e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 882e35d3a78SPawel Jakub Dawidek bioq_remove(&sc->sc_outqueue, bp); 883662a4e58SPawel Jakub Dawidek bioq_insert_head(&sc->sc_inqueue, bp); 884e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 8857ffb6e0fSPawel Jakub Dawidek goto start_end; 886fe27e772SPawel Jakub Dawidek } 887fe27e772SPawel Jakub Dawidek break; 888fe27e772SPawel Jakub Dawidek } 8897ffb6e0fSPawel Jakub Dawidek start_end: 8907ffb6e0fSPawel Jakub Dawidek g_gate_release(sc); 8917ffb6e0fSPawel Jakub Dawidek return (error); 892fe27e772SPawel Jakub Dawidek } 893fe27e772SPawel Jakub Dawidek case G_GATE_CMD_DONE: 894fe27e772SPawel Jakub Dawidek { 895fe27e772SPawel Jakub Dawidek struct g_gate_ctl_io *ggio = (void *)addr; 896fe27e772SPawel Jakub Dawidek 897fe27e772SPawel Jakub Dawidek G_GATE_CHECK_VERSION(ggio); 89832115b10SPawel Jakub Dawidek sc = g_gate_hold(ggio->gctl_unit, NULL); 899fe27e772SPawel Jakub Dawidek if (sc == NULL) 900fe27e772SPawel Jakub Dawidek return (ENOENT); 9017ffb6e0fSPawel Jakub Dawidek error = 0; 902e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 903fe27e772SPawel Jakub Dawidek TAILQ_FOREACH(bp, &sc->sc_outqueue.queue, bio_queue) { 9040d785336SPawel Jakub Dawidek if (ggio->gctl_seq == (uintptr_t)bp->bio_driver1) 905fe27e772SPawel Jakub Dawidek break; 906fe27e772SPawel Jakub Dawidek } 907fe27e772SPawel Jakub Dawidek if (bp != NULL) { 908fe27e772SPawel Jakub Dawidek bioq_remove(&sc->sc_outqueue, bp); 909e35d3a78SPawel Jakub Dawidek sc->sc_queue_count--; 910fe27e772SPawel Jakub Dawidek } 911e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 912fe27e772SPawel Jakub Dawidek if (bp == NULL) { 913fe27e772SPawel Jakub Dawidek /* 914fe27e772SPawel Jakub Dawidek * Request was probably canceled. 915fe27e772SPawel Jakub Dawidek */ 9167ffb6e0fSPawel Jakub Dawidek goto done_end; 917fe27e772SPawel Jakub Dawidek } 918fe27e772SPawel Jakub Dawidek if (ggio->gctl_error == EAGAIN) { 919fe27e772SPawel Jakub Dawidek bp->bio_error = 0; 920fe27e772SPawel Jakub Dawidek G_GATE_LOGREQ(1, bp, "Request desisted."); 921e35d3a78SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 922e35d3a78SPawel Jakub Dawidek sc->sc_queue_count++; 923662a4e58SPawel Jakub Dawidek bioq_insert_head(&sc->sc_inqueue, bp); 924fe27e772SPawel Jakub Dawidek wakeup(sc); 925e35d3a78SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 926fe27e772SPawel Jakub Dawidek } else { 927fe27e772SPawel Jakub Dawidek bp->bio_error = ggio->gctl_error; 928fe27e772SPawel Jakub Dawidek if (bp->bio_error == 0) { 929fe27e772SPawel Jakub Dawidek bp->bio_completed = bp->bio_length; 930fe27e772SPawel Jakub Dawidek switch (bp->bio_cmd) { 931fe27e772SPawel Jakub Dawidek case BIO_READ: 932fe27e772SPawel Jakub Dawidek error = copyin(ggio->gctl_data, 933fe27e772SPawel Jakub Dawidek bp->bio_data, bp->bio_length); 934fe27e772SPawel Jakub Dawidek if (error != 0) 935fe27e772SPawel Jakub Dawidek bp->bio_error = error; 936fe27e772SPawel Jakub Dawidek break; 937fe27e772SPawel Jakub Dawidek case BIO_DELETE: 938fe27e772SPawel Jakub Dawidek case BIO_WRITE: 939204a4e19SPawel Jakub Dawidek case BIO_FLUSH: 9408b522bdaSWarner Losh case BIO_SPEEDUP: 941fe27e772SPawel Jakub Dawidek break; 942fe27e772SPawel Jakub Dawidek } 943fe27e772SPawel Jakub Dawidek } 944fe27e772SPawel Jakub Dawidek G_GATE_LOGREQ(2, bp, "Request done."); 945fe27e772SPawel Jakub Dawidek g_io_deliver(bp, bp->bio_error); 946fe27e772SPawel Jakub Dawidek } 9477ffb6e0fSPawel Jakub Dawidek done_end: 9487ffb6e0fSPawel Jakub Dawidek g_gate_release(sc); 949fe27e772SPawel Jakub Dawidek return (error); 950fe27e772SPawel Jakub Dawidek } 951fe27e772SPawel Jakub Dawidek } 952fe27e772SPawel Jakub Dawidek return (ENOIOCTL); 953fe27e772SPawel Jakub Dawidek } 954fe27e772SPawel Jakub Dawidek 955fe27e772SPawel Jakub Dawidek static void 9569ecdd506SPawel Jakub Dawidek g_gate_device(void) 957fe27e772SPawel Jakub Dawidek { 958fe27e772SPawel Jakub Dawidek 959fe27e772SPawel Jakub Dawidek status_dev = make_dev(&g_gate_cdevsw, 0x0, UID_ROOT, GID_WHEEL, 0600, 960fe27e772SPawel Jakub Dawidek G_GATE_CTL_NAME); 961fe27e772SPawel Jakub Dawidek } 962fe27e772SPawel Jakub Dawidek 963fe27e772SPawel Jakub Dawidek static int 964fe27e772SPawel Jakub Dawidek g_gate_modevent(module_t mod, int type, void *data) 965fe27e772SPawel Jakub Dawidek { 966fe27e772SPawel Jakub Dawidek int error = 0; 967fe27e772SPawel Jakub Dawidek 968fe27e772SPawel Jakub Dawidek switch (type) { 969fe27e772SPawel Jakub Dawidek case MOD_LOAD: 97032115b10SPawel Jakub Dawidek mtx_init(&g_gate_units_lock, "gg_units_lock", NULL, MTX_DEF); 97132115b10SPawel Jakub Dawidek g_gate_units = malloc(g_gate_maxunits * sizeof(g_gate_units[0]), 97232115b10SPawel Jakub Dawidek M_GATE, M_WAITOK | M_ZERO); 97332115b10SPawel Jakub Dawidek g_gate_nunits = 0; 9749ecdd506SPawel Jakub Dawidek g_gate_device(); 975fe27e772SPawel Jakub Dawidek break; 976fe27e772SPawel Jakub Dawidek case MOD_UNLOAD: 97732115b10SPawel Jakub Dawidek mtx_lock(&g_gate_units_lock); 97832115b10SPawel Jakub Dawidek if (g_gate_nunits > 0) { 97932115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 980fe27e772SPawel Jakub Dawidek error = EBUSY; 981fe27e772SPawel Jakub Dawidek break; 982fe27e772SPawel Jakub Dawidek } 98332115b10SPawel Jakub Dawidek mtx_unlock(&g_gate_units_lock); 98432115b10SPawel Jakub Dawidek mtx_destroy(&g_gate_units_lock); 98501b5c6f7SPedro F. Giffuni if (status_dev != NULL) 986fe27e772SPawel Jakub Dawidek destroy_dev(status_dev); 98732115b10SPawel Jakub Dawidek free(g_gate_units, M_GATE); 988fe27e772SPawel Jakub Dawidek break; 989fe27e772SPawel Jakub Dawidek default: 9903e019deaSPoul-Henning Kamp return (EOPNOTSUPP); 991fe27e772SPawel Jakub Dawidek break; 992fe27e772SPawel Jakub Dawidek } 993fe27e772SPawel Jakub Dawidek 994fe27e772SPawel Jakub Dawidek return (error); 995fe27e772SPawel Jakub Dawidek } 996fe27e772SPawel Jakub Dawidek static moduledata_t g_gate_module = { 997fe27e772SPawel Jakub Dawidek G_GATE_MOD_NAME, 998fe27e772SPawel Jakub Dawidek g_gate_modevent, 999fe27e772SPawel Jakub Dawidek NULL 1000fe27e772SPawel Jakub Dawidek }; 1001fe27e772SPawel Jakub Dawidek DECLARE_MODULE(geom_gate, g_gate_module, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 1002fe27e772SPawel Jakub Dawidek DECLARE_GEOM_CLASS(g_gate_class, g_gate); 100374d6c131SKyle Evans MODULE_VERSION(geom_gate, 0); 1004