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