g_gate.c revision 306765
1/*-
2 * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3 * Copyright (c) 2009-2010 The FreeBSD Foundation
4 * All rights reserved.
5 *
6 * Portions of this software were developed by Pawel Jakub Dawidek
7 * under sponsorship from the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: stable/10/sys/geom/gate/g_gate.c 306765 2016-10-06 15:36:13Z mav $");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/bio.h>
37#include <sys/conf.h>
38#include <sys/kernel.h>
39#include <sys/kthread.h>
40#include <sys/fcntl.h>
41#include <sys/linker.h>
42#include <sys/lock.h>
43#include <sys/malloc.h>
44#include <sys/mutex.h>
45#include <sys/proc.h>
46#include <sys/limits.h>
47#include <sys/queue.h>
48#include <sys/sbuf.h>
49#include <sys/sysctl.h>
50#include <sys/signalvar.h>
51#include <sys/time.h>
52#include <machine/atomic.h>
53
54#include <geom/geom.h>
55#include <geom/gate/g_gate.h>
56
57FEATURE(geom_gate, "GEOM Gate module");
58
59static MALLOC_DEFINE(M_GATE, "gg_data", "GEOM Gate Data");
60
61SYSCTL_DECL(_kern_geom);
62static SYSCTL_NODE(_kern_geom, OID_AUTO, gate, CTLFLAG_RW, 0,
63    "GEOM_GATE configuration");
64static int g_gate_debug = 0;
65TUNABLE_INT("kern.geom.gate.debug", &g_gate_debug);
66SYSCTL_INT(_kern_geom_gate, OID_AUTO, debug, CTLFLAG_RW, &g_gate_debug, 0,
67    "Debug level");
68static u_int g_gate_maxunits = 256;
69TUNABLE_INT("kern.geom.gate.maxunits", &g_gate_maxunits);
70SYSCTL_UINT(_kern_geom_gate, OID_AUTO, maxunits, CTLFLAG_RDTUN,
71    &g_gate_maxunits, 0, "Maximum number of ggate devices");
72
73struct g_class g_gate_class = {
74	.name = G_GATE_CLASS_NAME,
75	.version = G_VERSION,
76};
77
78static struct cdev *status_dev;
79static d_ioctl_t g_gate_ioctl;
80static struct cdevsw g_gate_cdevsw = {
81	.d_version =	D_VERSION,
82	.d_ioctl =	g_gate_ioctl,
83	.d_name =	G_GATE_CTL_NAME
84};
85
86
87static struct g_gate_softc **g_gate_units;
88static u_int g_gate_nunits;
89static struct mtx g_gate_units_lock;
90
91static int
92g_gate_destroy(struct g_gate_softc *sc, boolean_t force)
93{
94	struct bio_queue_head queue;
95	struct g_provider *pp;
96	struct g_consumer *cp;
97	struct g_geom *gp;
98	struct bio *bp;
99
100	g_topology_assert();
101	mtx_assert(&g_gate_units_lock, MA_OWNED);
102	pp = sc->sc_provider;
103	if (!force && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
104		mtx_unlock(&g_gate_units_lock);
105		return (EBUSY);
106	}
107	mtx_unlock(&g_gate_units_lock);
108	mtx_lock(&sc->sc_queue_mtx);
109	if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0)
110		sc->sc_flags |= G_GATE_FLAG_DESTROY;
111	wakeup(sc);
112	mtx_unlock(&sc->sc_queue_mtx);
113	gp = pp->geom;
114	g_wither_provider(pp, ENXIO);
115	callout_drain(&sc->sc_callout);
116	bioq_init(&queue);
117	mtx_lock(&sc->sc_queue_mtx);
118	while ((bp = bioq_takefirst(&sc->sc_inqueue)) != NULL) {
119		sc->sc_queue_count--;
120		bioq_insert_tail(&queue, bp);
121	}
122	while ((bp = bioq_takefirst(&sc->sc_outqueue)) != NULL) {
123		sc->sc_queue_count--;
124		bioq_insert_tail(&queue, bp);
125	}
126	mtx_unlock(&sc->sc_queue_mtx);
127	g_topology_unlock();
128	while ((bp = bioq_takefirst(&queue)) != NULL) {
129		G_GATE_LOGREQ(1, bp, "Request canceled.");
130		g_io_deliver(bp, ENXIO);
131	}
132	mtx_lock(&g_gate_units_lock);
133	/* One reference is ours. */
134	sc->sc_ref--;
135	while (sc->sc_ref > 0)
136		msleep(&sc->sc_ref, &g_gate_units_lock, 0, "gg:destroy", 0);
137	g_gate_units[sc->sc_unit] = NULL;
138	KASSERT(g_gate_nunits > 0, ("negative g_gate_nunits?"));
139	g_gate_nunits--;
140	mtx_unlock(&g_gate_units_lock);
141	mtx_destroy(&sc->sc_queue_mtx);
142	g_topology_lock();
143	if ((cp = sc->sc_readcons) != NULL) {
144		sc->sc_readcons = NULL;
145		(void)g_access(cp, -1, 0, 0);
146		g_detach(cp);
147		g_destroy_consumer(cp);
148	}
149	G_GATE_DEBUG(1, "Device %s destroyed.", gp->name);
150	gp->softc = NULL;
151	g_wither_geom(gp, ENXIO);
152	sc->sc_provider = NULL;
153	free(sc, M_GATE);
154	return (0);
155}
156
157static int
158g_gate_access(struct g_provider *pp, int dr, int dw, int de)
159{
160	struct g_gate_softc *sc;
161
162	if (dr <= 0 && dw <= 0 && de <= 0)
163		return (0);
164	sc = pp->geom->softc;
165	if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0)
166		return (ENXIO);
167	/* XXX: Hack to allow read-only mounts. */
168#if 0
169	if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0 && dw > 0)
170		return (EPERM);
171#endif
172	if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0 && dr > 0)
173		return (EPERM);
174	return (0);
175}
176
177static void
178g_gate_queue_io(struct bio *bp)
179{
180	struct g_gate_softc *sc;
181
182	sc = bp->bio_to->geom->softc;
183	if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) {
184		g_io_deliver(bp, ENXIO);
185		return;
186	}
187
188	mtx_lock(&sc->sc_queue_mtx);
189
190	if (sc->sc_queue_size > 0 && sc->sc_queue_count > sc->sc_queue_size) {
191		mtx_unlock(&sc->sc_queue_mtx);
192		G_GATE_LOGREQ(1, bp, "Queue full, request canceled.");
193		g_io_deliver(bp, ENOMEM);
194		return;
195	}
196
197	bp->bio_driver1 = (void *)sc->sc_seq;
198	sc->sc_seq++;
199	sc->sc_queue_count++;
200
201	bioq_insert_tail(&sc->sc_inqueue, bp);
202	wakeup(sc);
203
204	mtx_unlock(&sc->sc_queue_mtx);
205}
206
207static void
208g_gate_done(struct bio *cbp)
209{
210	struct bio *pbp;
211
212	pbp = cbp->bio_parent;
213	if (cbp->bio_error == 0) {
214		pbp->bio_completed = cbp->bio_completed;
215		g_destroy_bio(cbp);
216		pbp->bio_inbed++;
217		g_io_deliver(pbp, 0);
218	} else {
219		/* If direct read failed, pass it through userland daemon. */
220		g_destroy_bio(cbp);
221		pbp->bio_children--;
222		g_gate_queue_io(pbp);
223	}
224}
225
226static void
227g_gate_start(struct bio *pbp)
228{
229	struct g_gate_softc *sc;
230
231	sc = pbp->bio_to->geom->softc;
232	if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) {
233		g_io_deliver(pbp, ENXIO);
234		return;
235	}
236	G_GATE_LOGREQ(2, pbp, "Request received.");
237	switch (pbp->bio_cmd) {
238	case BIO_READ:
239		if (sc->sc_readcons != NULL) {
240			struct bio *cbp;
241
242			cbp = g_clone_bio(pbp);
243			if (cbp == NULL) {
244				g_io_deliver(pbp, ENOMEM);
245				return;
246			}
247			cbp->bio_done = g_gate_done;
248			cbp->bio_offset = pbp->bio_offset + sc->sc_readoffset;
249			cbp->bio_to = sc->sc_readcons->provider;
250			g_io_request(cbp, sc->sc_readcons);
251			return;
252		}
253		break;
254	case BIO_DELETE:
255	case BIO_WRITE:
256	case BIO_FLUSH:
257		/* XXX: Hack to allow read-only mounts. */
258		if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) {
259			g_io_deliver(pbp, EPERM);
260			return;
261		}
262		break;
263	case BIO_GETATTR:
264	default:
265		G_GATE_LOGREQ(2, pbp, "Ignoring request.");
266		g_io_deliver(pbp, EOPNOTSUPP);
267		return;
268	}
269
270	g_gate_queue_io(pbp);
271}
272
273static struct g_gate_softc *
274g_gate_hold(int unit, const char *name)
275{
276	struct g_gate_softc *sc = NULL;
277
278	mtx_lock(&g_gate_units_lock);
279	if (unit >= 0 && unit < g_gate_maxunits)
280		sc = g_gate_units[unit];
281	else if (unit == G_GATE_NAME_GIVEN) {
282		KASSERT(name != NULL, ("name is NULL"));
283		for (unit = 0; unit < g_gate_maxunits; unit++) {
284			if (g_gate_units[unit] == NULL)
285				continue;
286			if (strcmp(name,
287			    g_gate_units[unit]->sc_provider->name) != 0) {
288				continue;
289			}
290			sc = g_gate_units[unit];
291			break;
292		}
293	}
294	if (sc != NULL)
295		sc->sc_ref++;
296	mtx_unlock(&g_gate_units_lock);
297	return (sc);
298}
299
300static void
301g_gate_release(struct g_gate_softc *sc)
302{
303
304	g_topology_assert_not();
305	mtx_lock(&g_gate_units_lock);
306	sc->sc_ref--;
307	KASSERT(sc->sc_ref >= 0, ("Negative sc_ref for %s.", sc->sc_name));
308	if (sc->sc_ref == 0 && (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0)
309		wakeup(&sc->sc_ref);
310	mtx_unlock(&g_gate_units_lock);
311}
312
313static int
314g_gate_getunit(int unit, int *errorp)
315{
316
317	mtx_assert(&g_gate_units_lock, MA_OWNED);
318	if (unit >= 0) {
319		if (unit >= g_gate_maxunits)
320			*errorp = EINVAL;
321		else if (g_gate_units[unit] == NULL)
322			return (unit);
323		else
324			*errorp = EEXIST;
325	} else {
326		for (unit = 0; unit < g_gate_maxunits; unit++) {
327			if (g_gate_units[unit] == NULL)
328				return (unit);
329		}
330		*errorp = ENFILE;
331	}
332	return (-1);
333}
334
335static void
336g_gate_guard(void *arg)
337{
338	struct bio_queue_head queue;
339	struct g_gate_softc *sc;
340	struct bintime curtime;
341	struct bio *bp, *bp2;
342
343	sc = arg;
344	binuptime(&curtime);
345	g_gate_hold(sc->sc_unit, NULL);
346	bioq_init(&queue);
347	mtx_lock(&sc->sc_queue_mtx);
348	TAILQ_FOREACH_SAFE(bp, &sc->sc_inqueue.queue, bio_queue, bp2) {
349		if (curtime.sec - bp->bio_t0.sec < 5)
350			continue;
351		bioq_remove(&sc->sc_inqueue, bp);
352		sc->sc_queue_count--;
353		bioq_insert_tail(&queue, bp);
354	}
355	TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, bp2) {
356		if (curtime.sec - bp->bio_t0.sec < 5)
357			continue;
358		bioq_remove(&sc->sc_outqueue, bp);
359		sc->sc_queue_count--;
360		bioq_insert_tail(&queue, bp);
361	}
362	mtx_unlock(&sc->sc_queue_mtx);
363	while ((bp = bioq_takefirst(&queue)) != NULL) {
364		G_GATE_LOGREQ(1, bp, "Request timeout.");
365		g_io_deliver(bp, EIO);
366	}
367	if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0) {
368		callout_reset(&sc->sc_callout, sc->sc_timeout * hz,
369		    g_gate_guard, sc);
370	}
371	g_gate_release(sc);
372}
373
374static void
375g_gate_orphan(struct g_consumer *cp)
376{
377	struct g_gate_softc *sc;
378	struct g_geom *gp;
379
380	g_topology_assert();
381	gp = cp->geom;
382	sc = gp->softc;
383	if (sc == NULL)
384		return;
385	KASSERT(cp == sc->sc_readcons, ("cp=%p sc_readcons=%p", cp,
386	    sc->sc_readcons));
387	sc->sc_readcons = NULL;
388	G_GATE_DEBUG(1, "Destroying read consumer on provider %s orphan.",
389	    cp->provider->name);
390	(void)g_access(cp, -1, 0, 0);
391	g_detach(cp);
392	g_destroy_consumer(cp);
393}
394
395static void
396g_gate_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
397    struct g_consumer *cp, struct g_provider *pp)
398{
399	struct g_gate_softc *sc;
400
401	sc = gp->softc;
402	if (sc == NULL || pp != NULL || cp != NULL)
403		return;
404	sc = g_gate_hold(sc->sc_unit, NULL);
405	if (sc == NULL)
406		return;
407	if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) {
408		sbuf_printf(sb, "%s<access>%s</access>\n", indent, "read-only");
409	} else if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0) {
410		sbuf_printf(sb, "%s<access>%s</access>\n", indent,
411		    "write-only");
412	} else {
413		sbuf_printf(sb, "%s<access>%s</access>\n", indent,
414		    "read-write");
415	}
416	if (sc->sc_readcons != NULL) {
417		sbuf_printf(sb, "%s<read_offset>%jd</read_offset>\n",
418		    indent, (intmax_t)sc->sc_readoffset);
419		sbuf_printf(sb, "%s<read_provider>%s</read_provider>\n",
420		    indent, sc->sc_readcons->provider->name);
421	}
422	sbuf_printf(sb, "%s<timeout>%u</timeout>\n", indent, sc->sc_timeout);
423	sbuf_printf(sb, "%s<info>%s</info>\n", indent, sc->sc_info);
424	sbuf_printf(sb, "%s<queue_count>%u</queue_count>\n", indent,
425	    sc->sc_queue_count);
426	sbuf_printf(sb, "%s<queue_size>%u</queue_size>\n", indent,
427	    sc->sc_queue_size);
428	sbuf_printf(sb, "%s<ref>%u</ref>\n", indent, sc->sc_ref);
429	sbuf_printf(sb, "%s<unit>%d</unit>\n", indent, sc->sc_unit);
430	g_topology_unlock();
431	g_gate_release(sc);
432	g_topology_lock();
433}
434
435static int
436g_gate_create(struct g_gate_ctl_create *ggio)
437{
438	struct g_gate_softc *sc;
439	struct g_geom *gp;
440	struct g_provider *pp, *ropp;
441	struct g_consumer *cp;
442	char name[NAME_MAX];
443	int error = 0, unit;
444
445	if (ggio->gctl_mediasize <= 0) {
446		G_GATE_DEBUG(1, "Invalid media size.");
447		return (EINVAL);
448	}
449	if (ggio->gctl_sectorsize <= 0) {
450		G_GATE_DEBUG(1, "Invalid sector size.");
451		return (EINVAL);
452	}
453	if (!powerof2(ggio->gctl_sectorsize)) {
454		G_GATE_DEBUG(1, "Invalid sector size.");
455		return (EINVAL);
456	}
457	if ((ggio->gctl_mediasize % ggio->gctl_sectorsize) != 0) {
458		G_GATE_DEBUG(1, "Invalid media size.");
459		return (EINVAL);
460	}
461	if ((ggio->gctl_flags & G_GATE_FLAG_READONLY) != 0 &&
462	    (ggio->gctl_flags & G_GATE_FLAG_WRITEONLY) != 0) {
463		G_GATE_DEBUG(1, "Invalid flags.");
464		return (EINVAL);
465	}
466	if (ggio->gctl_unit != G_GATE_UNIT_AUTO &&
467	    ggio->gctl_unit != G_GATE_NAME_GIVEN &&
468	    ggio->gctl_unit < 0) {
469		G_GATE_DEBUG(1, "Invalid unit number.");
470		return (EINVAL);
471	}
472	if (ggio->gctl_unit == G_GATE_NAME_GIVEN &&
473	    ggio->gctl_name[0] == '\0') {
474		G_GATE_DEBUG(1, "No device name.");
475		return (EINVAL);
476	}
477
478	sc = malloc(sizeof(*sc), M_GATE, M_WAITOK | M_ZERO);
479	sc->sc_flags = (ggio->gctl_flags & G_GATE_USERFLAGS);
480	strlcpy(sc->sc_info, ggio->gctl_info, sizeof(sc->sc_info));
481	sc->sc_seq = 1;
482	bioq_init(&sc->sc_inqueue);
483	bioq_init(&sc->sc_outqueue);
484	mtx_init(&sc->sc_queue_mtx, "gg:queue", NULL, MTX_DEF);
485	sc->sc_queue_count = 0;
486	sc->sc_queue_size = ggio->gctl_maxcount;
487	if (sc->sc_queue_size > G_GATE_MAX_QUEUE_SIZE)
488		sc->sc_queue_size = G_GATE_MAX_QUEUE_SIZE;
489	sc->sc_timeout = ggio->gctl_timeout;
490	callout_init(&sc->sc_callout, CALLOUT_MPSAFE);
491
492	mtx_lock(&g_gate_units_lock);
493	sc->sc_unit = g_gate_getunit(ggio->gctl_unit, &error);
494	if (sc->sc_unit < 0)
495		goto fail1;
496	if (ggio->gctl_unit == G_GATE_NAME_GIVEN)
497		snprintf(name, sizeof(name), "%s", ggio->gctl_name);
498	else {
499		snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME,
500		    sc->sc_unit);
501	}
502	/* Check for name collision. */
503	for (unit = 0; unit < g_gate_maxunits; unit++) {
504		if (g_gate_units[unit] == NULL)
505			continue;
506		if (strcmp(name, g_gate_units[unit]->sc_name) != 0)
507			continue;
508		error = EEXIST;
509		goto fail1;
510	}
511	sc->sc_name = name;
512	g_gate_units[sc->sc_unit] = sc;
513	g_gate_nunits++;
514	mtx_unlock(&g_gate_units_lock);
515
516	g_topology_lock();
517
518	if (ggio->gctl_readprov[0] == '\0') {
519		ropp = NULL;
520	} else {
521		ropp = g_provider_by_name(ggio->gctl_readprov);
522		if (ropp == NULL) {
523			G_GATE_DEBUG(1, "Provider %s doesn't exist.",
524			    ggio->gctl_readprov);
525			error = EINVAL;
526			goto fail2;
527		}
528		if ((ggio->gctl_readoffset % ggio->gctl_sectorsize) != 0) {
529			G_GATE_DEBUG(1, "Invalid read offset.");
530			error = EINVAL;
531			goto fail2;
532		}
533		if (ggio->gctl_mediasize + ggio->gctl_readoffset >
534		    ropp->mediasize) {
535			G_GATE_DEBUG(1, "Invalid read offset or media size.");
536			error = EINVAL;
537			goto fail2;
538		}
539	}
540
541	gp = g_new_geomf(&g_gate_class, "%s", name);
542	gp->start = g_gate_start;
543	gp->access = g_gate_access;
544	gp->orphan = g_gate_orphan;
545	gp->dumpconf = g_gate_dumpconf;
546	gp->softc = sc;
547
548	if (ropp != NULL) {
549		cp = g_new_consumer(gp);
550		cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
551		error = g_attach(cp, ropp);
552		if (error != 0) {
553			G_GATE_DEBUG(1, "Unable to attach to %s.", ropp->name);
554			goto fail3;
555		}
556		error = g_access(cp, 1, 0, 0);
557		if (error != 0) {
558			G_GATE_DEBUG(1, "Unable to access %s.", ropp->name);
559			g_detach(cp);
560			goto fail3;
561		}
562		sc->sc_readcons = cp;
563		sc->sc_readoffset = ggio->gctl_readoffset;
564	}
565
566	ggio->gctl_unit = sc->sc_unit;
567
568	pp = g_new_providerf(gp, "%s", name);
569	pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
570	pp->mediasize = ggio->gctl_mediasize;
571	pp->sectorsize = ggio->gctl_sectorsize;
572	sc->sc_provider = pp;
573	g_error_provider(pp, 0);
574
575	g_topology_unlock();
576	mtx_lock(&g_gate_units_lock);
577	sc->sc_name = sc->sc_provider->name;
578	mtx_unlock(&g_gate_units_lock);
579	G_GATE_DEBUG(1, "Device %s created.", gp->name);
580
581	if (sc->sc_timeout > 0) {
582		callout_reset(&sc->sc_callout, sc->sc_timeout * hz,
583		    g_gate_guard, sc);
584	}
585	return (0);
586fail3:
587	g_destroy_consumer(cp);
588	g_destroy_geom(gp);
589fail2:
590	g_topology_unlock();
591	mtx_lock(&g_gate_units_lock);
592	g_gate_units[sc->sc_unit] = NULL;
593	KASSERT(g_gate_nunits > 0, ("negative g_gate_nunits?"));
594	g_gate_nunits--;
595fail1:
596	mtx_unlock(&g_gate_units_lock);
597	mtx_destroy(&sc->sc_queue_mtx);
598	free(sc, M_GATE);
599	return (error);
600}
601
602static int
603g_gate_modify(struct g_gate_softc *sc, struct g_gate_ctl_modify *ggio)
604{
605	struct g_provider *pp;
606	struct g_consumer *cp;
607	int error;
608
609	if ((ggio->gctl_modify & GG_MODIFY_MEDIASIZE) != 0) {
610		if (ggio->gctl_mediasize <= 0) {
611			G_GATE_DEBUG(1, "Invalid media size.");
612			return (EINVAL);
613		}
614		pp = sc->sc_provider;
615		if ((ggio->gctl_mediasize % pp->sectorsize) != 0) {
616			G_GATE_DEBUG(1, "Invalid media size.");
617			return (EINVAL);
618		}
619		/* TODO */
620		return (EOPNOTSUPP);
621	}
622
623	if ((ggio->gctl_modify & GG_MODIFY_INFO) != 0)
624		(void)strlcpy(sc->sc_info, ggio->gctl_info, sizeof(sc->sc_info));
625
626	cp = NULL;
627
628	if ((ggio->gctl_modify & GG_MODIFY_READPROV) != 0) {
629		g_topology_lock();
630		if (sc->sc_readcons != NULL) {
631			cp = sc->sc_readcons;
632			sc->sc_readcons = NULL;
633			(void)g_access(cp, -1, 0, 0);
634			g_detach(cp);
635			g_destroy_consumer(cp);
636		}
637		if (ggio->gctl_readprov[0] != '\0') {
638			pp = g_provider_by_name(ggio->gctl_readprov);
639			if (pp == NULL) {
640				g_topology_unlock();
641				G_GATE_DEBUG(1, "Provider %s doesn't exist.",
642				    ggio->gctl_readprov);
643				return (EINVAL);
644			}
645			cp = g_new_consumer(sc->sc_provider->geom);
646			cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
647			error = g_attach(cp, pp);
648			if (error != 0) {
649				G_GATE_DEBUG(1, "Unable to attach to %s.",
650				    pp->name);
651			} else {
652				error = g_access(cp, 1, 0, 0);
653				if (error != 0) {
654					G_GATE_DEBUG(1, "Unable to access %s.",
655					    pp->name);
656					g_detach(cp);
657				}
658			}
659			if (error != 0) {
660				g_destroy_consumer(cp);
661				g_topology_unlock();
662				return (error);
663			}
664		}
665	} else {
666		cp = sc->sc_readcons;
667	}
668
669	if ((ggio->gctl_modify & GG_MODIFY_READOFFSET) != 0) {
670		if (cp == NULL) {
671			G_GATE_DEBUG(1, "No read provider.");
672			return (EINVAL);
673		}
674		pp = sc->sc_provider;
675		if ((ggio->gctl_readoffset % pp->sectorsize) != 0) {
676			G_GATE_DEBUG(1, "Invalid read offset.");
677			return (EINVAL);
678		}
679		if (pp->mediasize + ggio->gctl_readoffset >
680		    cp->provider->mediasize) {
681			G_GATE_DEBUG(1, "Invalid read offset or media size.");
682			return (EINVAL);
683		}
684		sc->sc_readoffset = ggio->gctl_readoffset;
685	}
686
687	if ((ggio->gctl_modify & GG_MODIFY_READPROV) != 0) {
688		sc->sc_readcons = cp;
689		g_topology_unlock();
690	}
691
692	return (0);
693}
694
695#define	G_GATE_CHECK_VERSION(ggio)	do {				\
696	if ((ggio)->gctl_version != G_GATE_VERSION) {			\
697		printf("Version mismatch %d != %d.\n",			\
698		    ggio->gctl_version, G_GATE_VERSION);		\
699		return (EINVAL);					\
700	}								\
701} while (0)
702static int
703g_gate_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
704{
705	struct g_gate_softc *sc;
706	struct bio *bp;
707	int error = 0;
708
709	G_GATE_DEBUG(4, "ioctl(%s, %lx, %p, %x, %p)", devtoname(dev), cmd, addr,
710	    flags, td);
711
712	switch (cmd) {
713	case G_GATE_CMD_CREATE:
714	    {
715		struct g_gate_ctl_create *ggio = (void *)addr;
716
717		G_GATE_CHECK_VERSION(ggio);
718		error = g_gate_create(ggio);
719		/*
720		 * Reset TDP_GEOM flag.
721		 * There are pending events for sure, because we just created
722		 * new provider and other classes want to taste it, but we
723		 * cannot answer on I/O requests until we're here.
724		 */
725		td->td_pflags &= ~TDP_GEOM;
726		return (error);
727	    }
728	case G_GATE_CMD_MODIFY:
729	    {
730		struct g_gate_ctl_modify *ggio = (void *)addr;
731
732		G_GATE_CHECK_VERSION(ggio);
733		sc = g_gate_hold(ggio->gctl_unit, NULL);
734		if (sc == NULL)
735			return (ENXIO);
736		error = g_gate_modify(sc, ggio);
737		g_gate_release(sc);
738		return (error);
739	    }
740	case G_GATE_CMD_DESTROY:
741	    {
742		struct g_gate_ctl_destroy *ggio = (void *)addr;
743
744		G_GATE_CHECK_VERSION(ggio);
745		sc = g_gate_hold(ggio->gctl_unit, ggio->gctl_name);
746		if (sc == NULL)
747			return (ENXIO);
748		g_topology_lock();
749		mtx_lock(&g_gate_units_lock);
750		error = g_gate_destroy(sc, ggio->gctl_force);
751		g_topology_unlock();
752		if (error != 0)
753			g_gate_release(sc);
754		return (error);
755	    }
756	case G_GATE_CMD_CANCEL:
757	    {
758		struct g_gate_ctl_cancel *ggio = (void *)addr;
759		struct bio *tbp, *lbp;
760
761		G_GATE_CHECK_VERSION(ggio);
762		sc = g_gate_hold(ggio->gctl_unit, ggio->gctl_name);
763		if (sc == NULL)
764			return (ENXIO);
765		lbp = NULL;
766		mtx_lock(&sc->sc_queue_mtx);
767		TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, tbp) {
768			if (ggio->gctl_seq == 0 ||
769			    ggio->gctl_seq == (uintptr_t)bp->bio_driver1) {
770				G_GATE_LOGREQ(1, bp, "Request canceled.");
771				bioq_remove(&sc->sc_outqueue, bp);
772				/*
773				 * Be sure to put requests back onto incoming
774				 * queue in the proper order.
775				 */
776				if (lbp == NULL)
777					bioq_insert_head(&sc->sc_inqueue, bp);
778				else {
779					TAILQ_INSERT_AFTER(&sc->sc_inqueue.queue,
780					    lbp, bp, bio_queue);
781				}
782				lbp = bp;
783				/*
784				 * If only one request was canceled, leave now.
785				 */
786				if (ggio->gctl_seq != 0)
787					break;
788			}
789		}
790		if (ggio->gctl_unit == G_GATE_NAME_GIVEN)
791			ggio->gctl_unit = sc->sc_unit;
792		mtx_unlock(&sc->sc_queue_mtx);
793		g_gate_release(sc);
794		return (error);
795	    }
796	case G_GATE_CMD_START:
797	    {
798		struct g_gate_ctl_io *ggio = (void *)addr;
799
800		G_GATE_CHECK_VERSION(ggio);
801		sc = g_gate_hold(ggio->gctl_unit, NULL);
802		if (sc == NULL)
803			return (ENXIO);
804		error = 0;
805		for (;;) {
806			mtx_lock(&sc->sc_queue_mtx);
807			bp = bioq_first(&sc->sc_inqueue);
808			if (bp != NULL)
809				break;
810			if ((sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) {
811				ggio->gctl_error = ECANCELED;
812				mtx_unlock(&sc->sc_queue_mtx);
813				goto start_end;
814			}
815			if (msleep(sc, &sc->sc_queue_mtx,
816			    PPAUSE | PDROP | PCATCH, "ggwait", 0) != 0) {
817				ggio->gctl_error = ECANCELED;
818				goto start_end;
819			}
820		}
821		ggio->gctl_cmd = bp->bio_cmd;
822		if (bp->bio_cmd == BIO_WRITE &&
823		    bp->bio_length > ggio->gctl_length) {
824			mtx_unlock(&sc->sc_queue_mtx);
825			ggio->gctl_length = bp->bio_length;
826			ggio->gctl_error = ENOMEM;
827			goto start_end;
828		}
829		bioq_remove(&sc->sc_inqueue, bp);
830		bioq_insert_tail(&sc->sc_outqueue, bp);
831		mtx_unlock(&sc->sc_queue_mtx);
832
833		ggio->gctl_seq = (uintptr_t)bp->bio_driver1;
834		ggio->gctl_offset = bp->bio_offset;
835		ggio->gctl_length = bp->bio_length;
836
837		switch (bp->bio_cmd) {
838		case BIO_READ:
839		case BIO_DELETE:
840		case BIO_FLUSH:
841			break;
842		case BIO_WRITE:
843			error = copyout(bp->bio_data, ggio->gctl_data,
844			    bp->bio_length);
845			if (error != 0) {
846				mtx_lock(&sc->sc_queue_mtx);
847				bioq_remove(&sc->sc_outqueue, bp);
848				bioq_insert_head(&sc->sc_inqueue, bp);
849				mtx_unlock(&sc->sc_queue_mtx);
850				goto start_end;
851			}
852			break;
853		}
854start_end:
855		g_gate_release(sc);
856		return (error);
857	    }
858	case G_GATE_CMD_DONE:
859	    {
860		struct g_gate_ctl_io *ggio = (void *)addr;
861
862		G_GATE_CHECK_VERSION(ggio);
863		sc = g_gate_hold(ggio->gctl_unit, NULL);
864		if (sc == NULL)
865			return (ENOENT);
866		error = 0;
867		mtx_lock(&sc->sc_queue_mtx);
868		TAILQ_FOREACH(bp, &sc->sc_outqueue.queue, bio_queue) {
869			if (ggio->gctl_seq == (uintptr_t)bp->bio_driver1)
870				break;
871		}
872		if (bp != NULL) {
873			bioq_remove(&sc->sc_outqueue, bp);
874			sc->sc_queue_count--;
875		}
876		mtx_unlock(&sc->sc_queue_mtx);
877		if (bp == NULL) {
878			/*
879			 * Request was probably canceled.
880			 */
881			goto done_end;
882		}
883		if (ggio->gctl_error == EAGAIN) {
884			bp->bio_error = 0;
885			G_GATE_LOGREQ(1, bp, "Request desisted.");
886			mtx_lock(&sc->sc_queue_mtx);
887			sc->sc_queue_count++;
888			bioq_insert_head(&sc->sc_inqueue, bp);
889			wakeup(sc);
890			mtx_unlock(&sc->sc_queue_mtx);
891		} else {
892			bp->bio_error = ggio->gctl_error;
893			if (bp->bio_error == 0) {
894				bp->bio_completed = bp->bio_length;
895				switch (bp->bio_cmd) {
896				case BIO_READ:
897					error = copyin(ggio->gctl_data,
898					    bp->bio_data, bp->bio_length);
899					if (error != 0)
900						bp->bio_error = error;
901					break;
902				case BIO_DELETE:
903				case BIO_WRITE:
904				case BIO_FLUSH:
905					break;
906				}
907			}
908			G_GATE_LOGREQ(2, bp, "Request done.");
909			g_io_deliver(bp, bp->bio_error);
910		}
911done_end:
912		g_gate_release(sc);
913		return (error);
914	    }
915	}
916	return (ENOIOCTL);
917}
918
919static void
920g_gate_device(void)
921{
922
923	status_dev = make_dev(&g_gate_cdevsw, 0x0, UID_ROOT, GID_WHEEL, 0600,
924	    G_GATE_CTL_NAME);
925}
926
927static int
928g_gate_modevent(module_t mod, int type, void *data)
929{
930	int error = 0;
931
932	switch (type) {
933	case MOD_LOAD:
934		mtx_init(&g_gate_units_lock, "gg_units_lock", NULL, MTX_DEF);
935		g_gate_units = malloc(g_gate_maxunits * sizeof(g_gate_units[0]),
936		    M_GATE, M_WAITOK | M_ZERO);
937		g_gate_nunits = 0;
938		g_gate_device();
939		break;
940	case MOD_UNLOAD:
941		mtx_lock(&g_gate_units_lock);
942		if (g_gate_nunits > 0) {
943			mtx_unlock(&g_gate_units_lock);
944			error = EBUSY;
945			break;
946		}
947		mtx_unlock(&g_gate_units_lock);
948		mtx_destroy(&g_gate_units_lock);
949		if (status_dev != 0)
950			destroy_dev(status_dev);
951		free(g_gate_units, M_GATE);
952		break;
953	default:
954		return (EOPNOTSUPP);
955		break;
956	}
957
958	return (error);
959}
960static moduledata_t g_gate_module = {
961	G_GATE_MOD_NAME,
962	g_gate_modevent,
963	NULL
964};
965DECLARE_MODULE(geom_gate, g_gate_module, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
966DECLARE_GEOM_CLASS(g_gate_class, g_gate);
967