g_gate.c revision 162148
1128760Spjd/*- 2141994Spjd * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3128760Spjd * All rights reserved. 4128760Spjd * 5128760Spjd * Redistribution and use in source and binary forms, with or without 6128760Spjd * modification, are permitted provided that the following conditions 7128760Spjd * are met: 8128760Spjd * 1. Redistributions of source code must retain the above copyright 9128760Spjd * notice, this list of conditions and the following disclaimer. 10128760Spjd * 2. Redistributions in binary form must reproduce the above copyright 11128760Spjd * notice, this list of conditions and the following disclaimer in the 12128760Spjd * documentation and/or other materials provided with the distribution. 13155174Spjd * 14128760Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15128760Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16128760Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17128760Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18128760Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19128760Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20128760Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21128760Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22128760Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23128760Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24128760Spjd * SUCH DAMAGE. 25128760Spjd */ 26128760Spjd 27162148Spjd#include <sys/cdefs.h> 28162148Spjd__FBSDID("$FreeBSD: head/sys/geom/gate/g_gate.c 162148 2006-09-08 10:19:24Z pjd $"); 29162148Spjd 30128760Spjd#include <sys/param.h> 31128760Spjd#include <sys/systm.h> 32128760Spjd#include <sys/bio.h> 33128760Spjd#include <sys/conf.h> 34128760Spjd#include <sys/kernel.h> 35128760Spjd#include <sys/kthread.h> 36128760Spjd#include <sys/fcntl.h> 37128760Spjd#include <sys/linker.h> 38128760Spjd#include <sys/lock.h> 39128760Spjd#include <sys/malloc.h> 40128760Spjd#include <sys/mutex.h> 41128760Spjd#include <sys/proc.h> 42128760Spjd#include <sys/limits.h> 43128760Spjd#include <sys/queue.h> 44128760Spjd#include <sys/sysctl.h> 45128760Spjd#include <sys/signalvar.h> 46128760Spjd#include <sys/time.h> 47128760Spjd#include <machine/atomic.h> 48128760Spjd 49128760Spjd#include <geom/geom.h> 50128760Spjd#include <geom/gate/g_gate.h> 51128760Spjd 52151897Srwatsonstatic MALLOC_DEFINE(M_GATE, "gg_data", "GEOM Gate Data"); 53128760Spjd 54128760SpjdSYSCTL_DECL(_kern_geom); 55128760SpjdSYSCTL_NODE(_kern_geom, OID_AUTO, gate, CTLFLAG_RW, 0, "GEOM_GATE stuff"); 56128889Spjdstatic u_int g_gate_debug = 0; 57128760SpjdSYSCTL_UINT(_kern_geom_gate, OID_AUTO, debug, CTLFLAG_RW, &g_gate_debug, 0, 58128760Spjd "Debug level"); 59128760Spjd 60128760Spjdstruct g_class g_gate_class = { 61128760Spjd .name = G_GATE_CLASS_NAME, 62133318Sphk .version = G_VERSION, 63128760Spjd}; 64128760Spjd 65130585Sphkstatic struct cdev *status_dev; 66128760Spjdstatic d_ioctl_t g_gate_ioctl; 67128760Spjdstatic struct cdevsw g_gate_cdevsw = { 68128760Spjd .d_version = D_VERSION, 69128760Spjd .d_ioctl = g_gate_ioctl, 70128760Spjd .d_name = G_GATE_CTL_NAME 71128760Spjd}; 72128760Spjd 73128760Spjd 74128760Spjdstatic LIST_HEAD(, g_gate_softc) g_gate_list = 75128760Spjd LIST_HEAD_INITIALIZER(&g_gate_list); 76128760Spjdstatic struct mtx g_gate_list_mtx; 77128760Spjd 78128760Spjd 79128760Spjdstatic int 80128760Spjdg_gate_destroy(struct g_gate_softc *sc, boolean_t force) 81128760Spjd{ 82128760Spjd struct g_provider *pp; 83162056Spjd struct g_geom *gp; 84128760Spjd struct bio *bp; 85128760Spjd 86128760Spjd g_topology_assert(); 87128760Spjd mtx_assert(&g_gate_list_mtx, MA_OWNED); 88128760Spjd pp = sc->sc_provider; 89128760Spjd if (!force && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 90128760Spjd mtx_unlock(&g_gate_list_mtx); 91128760Spjd return (EBUSY); 92128760Spjd } 93128760Spjd mtx_unlock(&g_gate_list_mtx); 94141561Spjd mtx_lock(&sc->sc_queue_mtx); 95162056Spjd if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0) 96162056Spjd sc->sc_flags |= G_GATE_FLAG_DESTROY; 97128760Spjd wakeup(sc); 98141561Spjd mtx_unlock(&sc->sc_queue_mtx); 99162056Spjd gp = pp->geom; 100162056Spjd pp->flags |= G_PF_WITHER; 101162056Spjd g_orphan_provider(pp, ENXIO); 102128760Spjd callout_drain(&sc->sc_callout); 103141561Spjd mtx_lock(&sc->sc_queue_mtx); 104128760Spjd for (;;) { 105128760Spjd bp = bioq_first(&sc->sc_inqueue); 106128760Spjd if (bp != NULL) { 107128760Spjd bioq_remove(&sc->sc_inqueue, bp); 108141561Spjd sc->sc_queue_count--; 109128760Spjd G_GATE_LOGREQ(1, bp, "Request canceled."); 110128760Spjd g_io_deliver(bp, ENXIO); 111128760Spjd } else { 112128760Spjd break; 113128760Spjd } 114128760Spjd } 115128760Spjd for (;;) { 116128760Spjd bp = bioq_first(&sc->sc_outqueue); 117128760Spjd if (bp != NULL) { 118128760Spjd bioq_remove(&sc->sc_outqueue, bp); 119141561Spjd sc->sc_queue_count--; 120128760Spjd G_GATE_LOGREQ(1, bp, "Request canceled."); 121128760Spjd g_io_deliver(bp, ENXIO); 122128760Spjd } else { 123128760Spjd break; 124128760Spjd } 125128760Spjd } 126162056Spjd mtx_unlock(&sc->sc_queue_mtx); 127162056Spjd g_topology_unlock(); 128162056Spjd mtx_lock(&g_gate_list_mtx); 129162056Spjd /* One reference is ours. */ 130162056Spjd sc->sc_ref--; 131162056Spjd while (sc->sc_ref > 0) { 132162056Spjd msleep(&sc->sc_ref, &g_gate_list_mtx, 0, "gg:destroy", 0); 133162056Spjd } 134162056Spjd LIST_REMOVE(sc, sc_next); 135162056Spjd mtx_unlock(&g_gate_list_mtx); 136141561Spjd mtx_destroy(&sc->sc_queue_mtx); 137162056Spjd g_topology_lock(); 138162056Spjd G_GATE_DEBUG(0, "Device %s destroyed.", gp->name); 139162056Spjd gp->softc = NULL; 140162056Spjd g_wither_geom(gp, ENXIO); 141128760Spjd sc->sc_provider = NULL; 142128760Spjd free(sc, M_GATE); 143128760Spjd return (0); 144128760Spjd} 145128760Spjd 146128760Spjdstatic int 147128760Spjdg_gate_access(struct g_provider *pp, int dr, int dw, int de) 148128760Spjd{ 149128760Spjd struct g_gate_softc *sc; 150128760Spjd 151128760Spjd if (dr <= 0 && dw <= 0 && de <= 0) 152128760Spjd return (0); 153128760Spjd sc = pp->geom->softc; 154128760Spjd if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) 155128760Spjd return (ENXIO); 156131188Spjd /* XXX: Hack to allow read-only mounts. */ 157131188Spjd#if 0 158128760Spjd if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0 && dw > 0) 159128760Spjd return (EPERM); 160131188Spjd#endif 161128760Spjd if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0 && dr > 0) 162128760Spjd return (EPERM); 163128760Spjd return (0); 164128760Spjd} 165128760Spjd 166128760Spjdstatic void 167128760Spjdg_gate_start(struct bio *bp) 168128760Spjd{ 169128760Spjd struct g_gate_softc *sc; 170128760Spjd 171128760Spjd sc = bp->bio_to->geom->softc; 172128760Spjd if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) { 173128760Spjd g_io_deliver(bp, ENXIO); 174128760Spjd return; 175128760Spjd } 176128760Spjd G_GATE_LOGREQ(2, bp, "Request received."); 177128760Spjd switch (bp->bio_cmd) { 178128760Spjd case BIO_READ: 179131188Spjd break; 180128760Spjd case BIO_DELETE: 181128760Spjd case BIO_WRITE: 182131188Spjd /* XXX: Hack to allow read-only mounts. */ 183131188Spjd if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) { 184131188Spjd g_io_deliver(bp, EPERM); 185131188Spjd return; 186131188Spjd } 187128760Spjd break; 188128760Spjd case BIO_GETATTR: 189128760Spjd default: 190128760Spjd G_GATE_LOGREQ(2, bp, "Ignoring request."); 191128760Spjd g_io_deliver(bp, EOPNOTSUPP); 192128760Spjd return; 193128760Spjd } 194128760Spjd 195141561Spjd mtx_lock(&sc->sc_queue_mtx); 196141561Spjd if (sc->sc_queue_count > sc->sc_queue_size) { 197141742Spjd mtx_unlock(&sc->sc_queue_mtx); 198128760Spjd G_GATE_LOGREQ(1, bp, "Queue full, request canceled."); 199128760Spjd g_io_deliver(bp, EIO); 200128760Spjd return; 201128760Spjd } 202141561Spjd 203128760Spjd bp->bio_driver1 = (void *)sc->sc_seq; 204128760Spjd sc->sc_seq++; 205141561Spjd sc->sc_queue_count++; 206128760Spjd 207141312Spjd bioq_insert_tail(&sc->sc_inqueue, bp); 208128957Spjd wakeup(sc); 209141561Spjd 210141561Spjd mtx_unlock(&sc->sc_queue_mtx); 211128760Spjd} 212128760Spjd 213128760Spjdstatic struct g_gate_softc * 214162056Spjdg_gate_hold(u_int unit) 215128760Spjd{ 216128760Spjd struct g_gate_softc *sc; 217128760Spjd 218162056Spjd mtx_lock(&g_gate_list_mtx); 219128760Spjd LIST_FOREACH(sc, &g_gate_list, sc_next) { 220128760Spjd if (sc->sc_unit == unit) 221128760Spjd break; 222128760Spjd } 223162056Spjd if (sc != NULL) 224162056Spjd sc->sc_ref++; 225128760Spjd mtx_unlock(&g_gate_list_mtx); 226128760Spjd return (sc); 227128760Spjd} 228128760Spjd 229128760Spjdstatic void 230128760Spjdg_gate_release(struct g_gate_softc *sc) 231128760Spjd{ 232128760Spjd 233128760Spjd g_topology_assert_not(); 234128760Spjd mtx_lock(&g_gate_list_mtx); 235128760Spjd sc->sc_ref--; 236128760Spjd KASSERT(sc->sc_ref >= 0, ("Negative sc_ref for %s.", sc->sc_name)); 237128760Spjd if (sc->sc_ref == 0 && (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) { 238162056Spjd wakeup(&sc->sc_ref); 239128760Spjd mtx_unlock(&g_gate_list_mtx); 240128760Spjd } else { 241128760Spjd mtx_unlock(&g_gate_list_mtx); 242128760Spjd } 243128760Spjd} 244128760Spjd 245128760Spjdstatic int 246128760Spjdg_gate_getunit(int unit) 247128760Spjd{ 248128760Spjd struct g_gate_softc *sc; 249128760Spjd 250128760Spjd mtx_assert(&g_gate_list_mtx, MA_OWNED); 251128760Spjd if (unit >= 0) { 252128760Spjd LIST_FOREACH(sc, &g_gate_list, sc_next) { 253128760Spjd if (sc->sc_unit == unit) 254128760Spjd return (-1); 255128760Spjd } 256128760Spjd } else { 257128760Spjd unit = 0; 258128760Spjdonce_again: 259128760Spjd LIST_FOREACH(sc, &g_gate_list, sc_next) { 260128760Spjd if (sc->sc_unit == unit) { 261128760Spjd if (++unit > 666) 262128760Spjd return (-1); 263128760Spjd goto once_again; 264128760Spjd } 265128760Spjd } 266128760Spjd } 267128760Spjd return (unit); 268128760Spjd} 269128760Spjd 270128760Spjdstatic void 271128760Spjdg_gate_guard(void *arg) 272128760Spjd{ 273128760Spjd struct g_gate_softc *sc; 274128760Spjd struct bintime curtime; 275128760Spjd struct bio *bp, *bp2; 276128760Spjd 277128760Spjd sc = arg; 278128760Spjd binuptime(&curtime); 279128760Spjd g_gate_hold(sc->sc_unit); 280141561Spjd mtx_lock(&sc->sc_queue_mtx); 281128760Spjd TAILQ_FOREACH_SAFE(bp, &sc->sc_inqueue.queue, bio_queue, bp2) { 282128760Spjd if (curtime.sec - bp->bio_t0.sec < 5) 283128760Spjd continue; 284128760Spjd bioq_remove(&sc->sc_inqueue, bp); 285141561Spjd sc->sc_queue_count--; 286128760Spjd G_GATE_LOGREQ(1, bp, "Request timeout."); 287128760Spjd g_io_deliver(bp, EIO); 288128760Spjd } 289128760Spjd TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, bp2) { 290128760Spjd if (curtime.sec - bp->bio_t0.sec < 5) 291128760Spjd continue; 292128760Spjd bioq_remove(&sc->sc_outqueue, bp); 293141561Spjd sc->sc_queue_count--; 294128760Spjd G_GATE_LOGREQ(1, bp, "Request timeout."); 295128760Spjd g_io_deliver(bp, EIO); 296128760Spjd } 297141561Spjd mtx_unlock(&sc->sc_queue_mtx); 298128760Spjd if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0) { 299128760Spjd callout_reset(&sc->sc_callout, sc->sc_timeout * hz, 300128760Spjd g_gate_guard, sc); 301128760Spjd } 302128760Spjd g_gate_release(sc); 303128760Spjd} 304128760Spjd 305128760Spjdstatic void 306128760Spjdg_gate_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 307128760Spjd struct g_consumer *cp, struct g_provider *pp) 308128760Spjd{ 309128760Spjd struct g_gate_softc *sc; 310128760Spjd 311128760Spjd sc = gp->softc; 312128760Spjd if (sc == NULL || pp != NULL || cp != NULL) 313128760Spjd return; 314128760Spjd g_gate_hold(sc->sc_unit); 315128760Spjd if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) { 316128760Spjd sbuf_printf(sb, "%s<access>%s</access>\n", indent, "read-only"); 317128760Spjd } else if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0) { 318128760Spjd sbuf_printf(sb, "%s<access>%s</access>\n", indent, 319128760Spjd "write-only"); 320128760Spjd } else { 321128760Spjd sbuf_printf(sb, "%s<access>%s</access>\n", indent, 322128760Spjd "read-write"); 323128760Spjd } 324128760Spjd sbuf_printf(sb, "%s<timeout>%u</timeout>\n", indent, sc->sc_timeout); 325128760Spjd sbuf_printf(sb, "%s<info>%s</info>\n", indent, sc->sc_info); 326128760Spjd sbuf_printf(sb, "%s<queue_count>%u</queue_count>\n", indent, 327128760Spjd sc->sc_queue_count); 328128760Spjd sbuf_printf(sb, "%s<queue_size>%u</queue_size>\n", indent, 329128760Spjd sc->sc_queue_size); 330128760Spjd sbuf_printf(sb, "%s<ref>%u</ref>\n", indent, sc->sc_ref); 331130836Spjd g_topology_unlock(); 332128760Spjd g_gate_release(sc); 333130836Spjd g_topology_lock(); 334128760Spjd} 335128760Spjd 336128760Spjdstatic int 337128760Spjdg_gate_create(struct g_gate_ctl_create *ggio) 338128760Spjd{ 339128760Spjd struct g_gate_softc *sc; 340128760Spjd struct g_geom *gp; 341128760Spjd struct g_provider *pp; 342128760Spjd 343128760Spjd if (ggio->gctl_mediasize == 0) { 344128760Spjd G_GATE_DEBUG(1, "Invalid media size."); 345128760Spjd return (EINVAL); 346128760Spjd } 347128760Spjd if (ggio->gctl_sectorsize > 0 && !powerof2(ggio->gctl_sectorsize)) { 348128760Spjd G_GATE_DEBUG(1, "Invalid sector size."); 349128760Spjd return (EINVAL); 350128760Spjd } 351141312Spjd if ((ggio->gctl_mediasize % ggio->gctl_sectorsize) != 0) { 352141312Spjd G_GATE_DEBUG(1, "Invalid media size."); 353141312Spjd return (EINVAL); 354141312Spjd } 355128760Spjd if ((ggio->gctl_flags & G_GATE_FLAG_READONLY) != 0 && 356128760Spjd (ggio->gctl_flags & G_GATE_FLAG_WRITEONLY) != 0) { 357128760Spjd G_GATE_DEBUG(1, "Invalid flags."); 358128760Spjd return (EINVAL); 359128760Spjd } 360128760Spjd if (ggio->gctl_unit < -1) { 361128760Spjd G_GATE_DEBUG(1, "Invalid unit number."); 362128760Spjd return (EINVAL); 363128760Spjd } 364128760Spjd 365128760Spjd sc = malloc(sizeof(*sc), M_GATE, M_WAITOK | M_ZERO); 366128760Spjd sc->sc_flags = (ggio->gctl_flags & G_GATE_USERFLAGS); 367128760Spjd strlcpy(sc->sc_info, ggio->gctl_info, sizeof(sc->sc_info)); 368128760Spjd sc->sc_seq = 0; 369128760Spjd bioq_init(&sc->sc_inqueue); 370128760Spjd bioq_init(&sc->sc_outqueue); 371141561Spjd mtx_init(&sc->sc_queue_mtx, "gg:queue", NULL, MTX_DEF); 372128760Spjd sc->sc_queue_count = 0; 373128760Spjd sc->sc_queue_size = ggio->gctl_maxcount; 374128760Spjd if (sc->sc_queue_size > G_GATE_MAX_QUEUE_SIZE) 375128760Spjd sc->sc_queue_size = G_GATE_MAX_QUEUE_SIZE; 376128760Spjd sc->sc_timeout = ggio->gctl_timeout; 377128881Spjd callout_init(&sc->sc_callout, CALLOUT_MPSAFE); 378128760Spjd mtx_lock(&g_gate_list_mtx); 379128881Spjd ggio->gctl_unit = g_gate_getunit(ggio->gctl_unit); 380128881Spjd if (ggio->gctl_unit == -1) { 381136056Spjd mtx_unlock(&g_gate_list_mtx); 382141561Spjd mtx_destroy(&sc->sc_queue_mtx); 383128881Spjd free(sc, M_GATE); 384128881Spjd return (EBUSY); 385128881Spjd } 386128760Spjd sc->sc_unit = ggio->gctl_unit; 387128760Spjd LIST_INSERT_HEAD(&g_gate_list, sc, sc_next); 388128760Spjd mtx_unlock(&g_gate_list_mtx); 389128760Spjd 390128760Spjd g_topology_lock(); 391128760Spjd gp = g_new_geomf(&g_gate_class, "%s%d", G_GATE_PROVIDER_NAME, 392128760Spjd sc->sc_unit); 393128760Spjd gp->start = g_gate_start; 394128760Spjd gp->access = g_gate_access; 395128760Spjd gp->dumpconf = g_gate_dumpconf; 396128760Spjd gp->softc = sc; 397128760Spjd pp = g_new_providerf(gp, "%s%d", G_GATE_PROVIDER_NAME, sc->sc_unit); 398128760Spjd pp->mediasize = ggio->gctl_mediasize; 399128760Spjd pp->sectorsize = ggio->gctl_sectorsize; 400128760Spjd sc->sc_provider = pp; 401128760Spjd g_error_provider(pp, 0); 402128760Spjd g_topology_unlock(); 403128760Spjd 404128760Spjd if (sc->sc_timeout > 0) { 405128760Spjd callout_reset(&sc->sc_callout, sc->sc_timeout * hz, 406128760Spjd g_gate_guard, sc); 407128760Spjd } 408128760Spjd return (0); 409128760Spjd} 410128760Spjd 411128760Spjd#define G_GATE_CHECK_VERSION(ggio) do { \ 412147843Spjd if ((ggio)->gctl_version != G_GATE_VERSION) { \ 413147843Spjd printf("Version mismatch %d != %d.\n", \ 414147843Spjd ggio->gctl_version, G_GATE_VERSION); \ 415128760Spjd return (EINVAL); \ 416147843Spjd } \ 417128760Spjd} while (0) 418128760Spjdstatic int 419130585Sphkg_gate_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 420128760Spjd{ 421128760Spjd struct g_gate_softc *sc; 422128760Spjd struct bio *bp; 423128760Spjd int error = 0; 424128760Spjd 425128760Spjd G_GATE_DEBUG(4, "ioctl(%s, %lx, %p, %x, %p)", devtoname(dev), cmd, addr, 426128760Spjd flags, td); 427128760Spjd 428128760Spjd switch (cmd) { 429128760Spjd case G_GATE_CMD_CREATE: 430128760Spjd { 431128760Spjd struct g_gate_ctl_create *ggio = (void *)addr; 432128760Spjd 433128760Spjd G_GATE_CHECK_VERSION(ggio); 434138014Spjd error = g_gate_create(ggio); 435141972Spjd /* 436141972Spjd * Reset TDP_GEOM flag. 437141972Spjd * There are pending events for sure, because we just created 438141972Spjd * new provider and other classes want to taste it, but we 439141972Spjd * cannot answer on I/O requests until we're here. 440141972Spjd */ 441141972Spjd td->td_pflags &= ~TDP_GEOM; 442138014Spjd return (error); 443128760Spjd } 444128760Spjd case G_GATE_CMD_DESTROY: 445128760Spjd { 446128760Spjd struct g_gate_ctl_destroy *ggio = (void *)addr; 447128760Spjd 448128760Spjd G_GATE_CHECK_VERSION(ggio); 449128760Spjd sc = g_gate_hold(ggio->gctl_unit); 450128760Spjd if (sc == NULL) 451128760Spjd return (ENXIO); 452128760Spjd g_topology_lock(); 453128760Spjd mtx_lock(&g_gate_list_mtx); 454128760Spjd error = g_gate_destroy(sc, ggio->gctl_force); 455128760Spjd g_topology_unlock(); 456162056Spjd if (error != 0) 457162056Spjd g_gate_release(sc); 458128760Spjd return (error); 459128760Spjd } 460147843Spjd case G_GATE_CMD_CANCEL: 461147843Spjd { 462147843Spjd struct g_gate_ctl_cancel *ggio = (void *)addr; 463147843Spjd struct bio *tbp, *lbp; 464147843Spjd 465147843Spjd G_GATE_CHECK_VERSION(ggio); 466147843Spjd sc = g_gate_hold(ggio->gctl_unit); 467147843Spjd if (sc == NULL) 468147843Spjd return (ENXIO); 469147843Spjd lbp = NULL; 470147843Spjd mtx_lock(&sc->sc_queue_mtx); 471147843Spjd TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, tbp) { 472147843Spjd if (ggio->gctl_seq == 0 || 473147843Spjd ggio->gctl_seq == (uintptr_t)bp->bio_driver1) { 474147843Spjd G_GATE_LOGREQ(1, bp, "Request canceled."); 475147843Spjd bioq_remove(&sc->sc_outqueue, bp); 476147843Spjd /* 477147843Spjd * Be sure to put requests back onto incoming 478147843Spjd * queue in the proper order. 479147843Spjd */ 480147843Spjd if (lbp == NULL) 481147843Spjd bioq_insert_head(&sc->sc_inqueue, bp); 482147843Spjd else { 483147843Spjd TAILQ_INSERT_AFTER(&sc->sc_inqueue.queue, 484147843Spjd lbp, bp, bio_queue); 485147843Spjd } 486147843Spjd lbp = bp; 487147843Spjd /* 488147843Spjd * If only one request was canceled, leave now. 489147843Spjd */ 490147843Spjd if (ggio->gctl_seq != 0) 491147843Spjd break; 492147843Spjd } 493147843Spjd } 494147843Spjd mtx_unlock(&sc->sc_queue_mtx); 495147843Spjd g_gate_release(sc); 496147843Spjd return (error); 497147843Spjd } 498128760Spjd case G_GATE_CMD_START: 499128760Spjd { 500128760Spjd struct g_gate_ctl_io *ggio = (void *)addr; 501128760Spjd 502128760Spjd G_GATE_CHECK_VERSION(ggio); 503162056Spjd sc = g_gate_hold(ggio->gctl_unit); 504128760Spjd if (sc == NULL) 505128760Spjd return (ENXIO); 506162056Spjd error = 0; 507128760Spjd for (;;) { 508141561Spjd mtx_lock(&sc->sc_queue_mtx); 509128760Spjd bp = bioq_first(&sc->sc_inqueue); 510128760Spjd if (bp != NULL) 511128760Spjd break; 512162056Spjd if ((sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) { 513162056Spjd ggio->gctl_error = ECANCELED; 514162056Spjd mtx_unlock(&sc->sc_queue_mtx); 515162056Spjd goto start_end; 516162056Spjd } 517141561Spjd if (msleep(sc, &sc->sc_queue_mtx, 518128760Spjd PPAUSE | PDROP | PCATCH, "ggwait", 0) != 0) { 519128760Spjd ggio->gctl_error = ECANCELED; 520162056Spjd goto start_end; 521128760Spjd } 522128760Spjd } 523128881Spjd ggio->gctl_cmd = bp->bio_cmd; 524128760Spjd if ((bp->bio_cmd == BIO_DELETE || bp->bio_cmd == BIO_WRITE) && 525128760Spjd bp->bio_length > ggio->gctl_length) { 526141561Spjd mtx_unlock(&sc->sc_queue_mtx); 527128760Spjd ggio->gctl_length = bp->bio_length; 528128760Spjd ggio->gctl_error = ENOMEM; 529162056Spjd goto start_end; 530128760Spjd } 531128760Spjd bioq_remove(&sc->sc_inqueue, bp); 532141561Spjd bioq_insert_tail(&sc->sc_outqueue, bp); 533141561Spjd mtx_unlock(&sc->sc_queue_mtx); 534141561Spjd 535128835Spjd ggio->gctl_seq = (uintptr_t)bp->bio_driver1; 536128760Spjd ggio->gctl_offset = bp->bio_offset; 537128760Spjd ggio->gctl_length = bp->bio_length; 538147843Spjd 539128760Spjd switch (bp->bio_cmd) { 540128760Spjd case BIO_READ: 541128760Spjd break; 542128760Spjd case BIO_DELETE: 543128760Spjd case BIO_WRITE: 544128760Spjd error = copyout(bp->bio_data, ggio->gctl_data, 545128760Spjd bp->bio_length); 546128760Spjd if (error != 0) { 547141561Spjd mtx_lock(&sc->sc_queue_mtx); 548141561Spjd bioq_remove(&sc->sc_outqueue, bp); 549141312Spjd bioq_insert_head(&sc->sc_inqueue, bp); 550141561Spjd mtx_unlock(&sc->sc_queue_mtx); 551162056Spjd goto start_end; 552128760Spjd } 553128760Spjd break; 554128760Spjd } 555162056Spjdstart_end: 556162056Spjd g_gate_release(sc); 557162056Spjd return (error); 558128760Spjd } 559128760Spjd case G_GATE_CMD_DONE: 560128760Spjd { 561128760Spjd struct g_gate_ctl_io *ggio = (void *)addr; 562128760Spjd 563128760Spjd G_GATE_CHECK_VERSION(ggio); 564162056Spjd sc = g_gate_hold(ggio->gctl_unit); 565128760Spjd if (sc == NULL) 566128760Spjd return (ENOENT); 567162056Spjd error = 0; 568141561Spjd mtx_lock(&sc->sc_queue_mtx); 569128760Spjd TAILQ_FOREACH(bp, &sc->sc_outqueue.queue, bio_queue) { 570128835Spjd if (ggio->gctl_seq == (uintptr_t)bp->bio_driver1) 571128760Spjd break; 572128760Spjd } 573128760Spjd if (bp != NULL) { 574128760Spjd bioq_remove(&sc->sc_outqueue, bp); 575141561Spjd sc->sc_queue_count--; 576128760Spjd } 577141561Spjd mtx_unlock(&sc->sc_queue_mtx); 578128760Spjd if (bp == NULL) { 579128760Spjd /* 580128760Spjd * Request was probably canceled. 581128760Spjd */ 582162056Spjd goto done_end; 583128760Spjd } 584128760Spjd if (ggio->gctl_error == EAGAIN) { 585128760Spjd bp->bio_error = 0; 586128760Spjd G_GATE_LOGREQ(1, bp, "Request desisted."); 587141561Spjd mtx_lock(&sc->sc_queue_mtx); 588141561Spjd sc->sc_queue_count++; 589141312Spjd bioq_insert_head(&sc->sc_inqueue, bp); 590128957Spjd wakeup(sc); 591141561Spjd mtx_unlock(&sc->sc_queue_mtx); 592128760Spjd } else { 593128760Spjd bp->bio_error = ggio->gctl_error; 594128760Spjd if (bp->bio_error == 0) { 595128760Spjd bp->bio_completed = bp->bio_length; 596128760Spjd switch (bp->bio_cmd) { 597128760Spjd case BIO_READ: 598128760Spjd error = copyin(ggio->gctl_data, 599128760Spjd bp->bio_data, bp->bio_length); 600128760Spjd if (error != 0) 601128760Spjd bp->bio_error = error; 602128760Spjd break; 603128760Spjd case BIO_DELETE: 604128760Spjd case BIO_WRITE: 605128760Spjd break; 606128760Spjd } 607128760Spjd } 608128760Spjd G_GATE_LOGREQ(2, bp, "Request done."); 609128760Spjd g_io_deliver(bp, bp->bio_error); 610128760Spjd } 611162056Spjddone_end: 612162056Spjd g_gate_release(sc); 613128760Spjd return (error); 614128760Spjd } 615128760Spjd } 616128760Spjd return (ENOIOCTL); 617128760Spjd} 618128760Spjd 619128760Spjdstatic void 620131411Spjdg_gate_device(void) 621128760Spjd{ 622128760Spjd 623128760Spjd status_dev = make_dev(&g_gate_cdevsw, 0x0, UID_ROOT, GID_WHEEL, 0600, 624128760Spjd G_GATE_CTL_NAME); 625128760Spjd} 626128760Spjd 627128760Spjdstatic int 628128760Spjdg_gate_modevent(module_t mod, int type, void *data) 629128760Spjd{ 630128760Spjd int error = 0; 631128760Spjd 632128760Spjd switch (type) { 633128760Spjd case MOD_LOAD: 634128760Spjd mtx_init(&g_gate_list_mtx, "gg_list_lock", NULL, MTX_DEF); 635131411Spjd g_gate_device(); 636128760Spjd break; 637128760Spjd case MOD_UNLOAD: 638128760Spjd mtx_lock(&g_gate_list_mtx); 639128760Spjd if (!LIST_EMPTY(&g_gate_list)) { 640128760Spjd mtx_unlock(&g_gate_list_mtx); 641128760Spjd error = EBUSY; 642128760Spjd break; 643128760Spjd } 644128760Spjd mtx_unlock(&g_gate_list_mtx); 645128760Spjd mtx_destroy(&g_gate_list_mtx); 646128760Spjd if (status_dev != 0) 647128760Spjd destroy_dev(status_dev); 648128760Spjd break; 649128760Spjd default: 650132199Sphk return (EOPNOTSUPP); 651128760Spjd break; 652128760Spjd } 653128760Spjd 654128760Spjd return (error); 655128760Spjd} 656128760Spjdstatic moduledata_t g_gate_module = { 657128760Spjd G_GATE_MOD_NAME, 658128760Spjd g_gate_modevent, 659128760Spjd NULL 660128760Spjd}; 661128760SpjdDECLARE_MODULE(geom_gate, g_gate_module, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 662128760SpjdDECLARE_GEOM_CLASS(g_gate_class, g_gate); 663