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