]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/geom/gate/g_gate.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / geom / gate / g_gate.c
1 /*-
2  * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bio.h>
33 #include <sys/conf.h>
34 #include <sys/kernel.h>
35 #include <sys/kthread.h>
36 #include <sys/fcntl.h>
37 #include <sys/linker.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/mutex.h>
41 #include <sys/proc.h>
42 #include <sys/limits.h>
43 #include <sys/queue.h>
44 #include <sys/sysctl.h>
45 #include <sys/signalvar.h>
46 #include <sys/time.h>
47 #include <machine/atomic.h>
48
49 #include <geom/geom.h>
50 #include <geom/gate/g_gate.h>
51
52 static MALLOC_DEFINE(M_GATE, "gg_data", "GEOM Gate Data");
53
54 SYSCTL_DECL(_kern_geom);
55 SYSCTL_NODE(_kern_geom, OID_AUTO, gate, CTLFLAG_RW, 0, "GEOM_GATE stuff");
56 static u_int g_gate_debug = 0;
57 SYSCTL_UINT(_kern_geom_gate, OID_AUTO, debug, CTLFLAG_RW, &g_gate_debug, 0,
58     "Debug level");
59
60 struct g_class g_gate_class = {
61         .name = G_GATE_CLASS_NAME,
62         .version = G_VERSION,
63 };
64
65 static struct cdev *status_dev;
66 static d_ioctl_t g_gate_ioctl;
67 static struct cdevsw g_gate_cdevsw = {
68         .d_version =    D_VERSION,
69         .d_ioctl =      g_gate_ioctl,
70         .d_name =       G_GATE_CTL_NAME
71 };
72
73
74 static LIST_HEAD(, g_gate_softc) g_gate_list =
75     LIST_HEAD_INITIALIZER(&g_gate_list);
76 static struct mtx g_gate_list_mtx;
77
78
79 static int
80 g_gate_destroy(struct g_gate_softc *sc, boolean_t force)
81 {
82         struct g_provider *pp;
83         struct g_geom *gp;
84         struct bio *bp;
85
86         g_topology_assert();
87         mtx_assert(&g_gate_list_mtx, MA_OWNED);
88         pp = sc->sc_provider;
89         if (!force && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
90                 mtx_unlock(&g_gate_list_mtx);
91                 return (EBUSY);
92         }
93         mtx_unlock(&g_gate_list_mtx);
94         mtx_lock(&sc->sc_queue_mtx);
95         if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0)
96                 sc->sc_flags |= G_GATE_FLAG_DESTROY;
97         wakeup(sc);
98         mtx_unlock(&sc->sc_queue_mtx);
99         gp = pp->geom;
100         pp->flags |= G_PF_WITHER;
101         g_orphan_provider(pp, ENXIO);
102         callout_drain(&sc->sc_callout);
103         mtx_lock(&sc->sc_queue_mtx);
104         for (;;) {
105                 bp = bioq_first(&sc->sc_inqueue);
106                 if (bp != NULL) {
107                         bioq_remove(&sc->sc_inqueue, bp);
108                         sc->sc_queue_count--;
109                         G_GATE_LOGREQ(1, bp, "Request canceled.");
110                         g_io_deliver(bp, ENXIO);
111                 } else {
112                         break;
113                 }
114         }
115         for (;;) {
116                 bp = bioq_first(&sc->sc_outqueue);
117                 if (bp != NULL) {
118                         bioq_remove(&sc->sc_outqueue, bp);
119                         sc->sc_queue_count--;
120                         G_GATE_LOGREQ(1, bp, "Request canceled.");
121                         g_io_deliver(bp, ENXIO);
122                 } else {
123                         break;
124                 }
125         }
126         mtx_unlock(&sc->sc_queue_mtx);
127         g_topology_unlock();
128         mtx_lock(&g_gate_list_mtx);
129         /* One reference is ours. */
130         sc->sc_ref--;
131         while (sc->sc_ref > 0) {
132                 msleep(&sc->sc_ref, &g_gate_list_mtx, 0, "gg:destroy", 0);
133         }
134         LIST_REMOVE(sc, sc_next);
135         mtx_unlock(&g_gate_list_mtx);
136         mtx_destroy(&sc->sc_queue_mtx);
137         g_topology_lock();
138         G_GATE_DEBUG(0, "Device %s destroyed.", gp->name);
139         gp->softc = NULL;
140         g_wither_geom(gp, ENXIO);
141         sc->sc_provider = NULL;
142         free(sc, M_GATE);
143         return (0);
144 }
145
146 static int
147 g_gate_access(struct g_provider *pp, int dr, int dw, int de)
148 {
149         struct g_gate_softc *sc;
150
151         if (dr <= 0 && dw <= 0 && de <= 0)
152                 return (0);
153         sc = pp->geom->softc;
154         if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0)
155                 return (ENXIO);
156         /* XXX: Hack to allow read-only mounts. */
157 #if 0
158         if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0 && dw > 0)
159                 return (EPERM);
160 #endif
161         if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0 && dr > 0)
162                 return (EPERM);
163         return (0);
164 }
165
166 static void
167 g_gate_start(struct bio *bp)
168 {
169         struct g_gate_softc *sc;
170
171         sc = bp->bio_to->geom->softc;
172         if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) {
173                 g_io_deliver(bp, ENXIO);
174                 return;
175         }
176         G_GATE_LOGREQ(2, bp, "Request received.");
177         switch (bp->bio_cmd) {
178         case BIO_READ:
179                 break;
180         case BIO_DELETE:
181         case BIO_WRITE:
182                 /* XXX: Hack to allow read-only mounts. */
183                 if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) {
184                         g_io_deliver(bp, EPERM);
185                         return;
186                 }
187                 break;
188         case BIO_GETATTR:
189         default:
190                 G_GATE_LOGREQ(2, bp, "Ignoring request.");
191                 g_io_deliver(bp, EOPNOTSUPP);
192                 return;
193         }
194
195         mtx_lock(&sc->sc_queue_mtx);
196         if (sc->sc_queue_count > sc->sc_queue_size) {
197                 mtx_unlock(&sc->sc_queue_mtx);
198                 G_GATE_LOGREQ(1, bp, "Queue full, request canceled.");
199                 g_io_deliver(bp, EIO);
200                 return;
201         }
202
203         bp->bio_driver1 = (void *)sc->sc_seq;
204         sc->sc_seq++;
205         sc->sc_queue_count++;
206
207         bioq_insert_tail(&sc->sc_inqueue, bp);
208         wakeup(sc);
209
210         mtx_unlock(&sc->sc_queue_mtx);
211 }
212
213 static struct g_gate_softc *
214 g_gate_hold(u_int unit)
215 {
216         struct g_gate_softc *sc;
217
218         mtx_lock(&g_gate_list_mtx);
219         LIST_FOREACH(sc, &g_gate_list, sc_next) {
220                 if (sc->sc_unit == unit)
221                         break;
222         }
223         if (sc != NULL)
224                 sc->sc_ref++;
225         mtx_unlock(&g_gate_list_mtx);
226         return (sc);
227 }
228
229 static void
230 g_gate_release(struct g_gate_softc *sc)
231 {
232
233         g_topology_assert_not();
234         mtx_lock(&g_gate_list_mtx);
235         sc->sc_ref--;
236         KASSERT(sc->sc_ref >= 0, ("Negative sc_ref for %s.", sc->sc_name));
237         if (sc->sc_ref == 0 && (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) {
238                 wakeup(&sc->sc_ref);
239                 mtx_unlock(&g_gate_list_mtx);
240         } else {
241                 mtx_unlock(&g_gate_list_mtx);
242         }
243 }
244
245 static int
246 g_gate_getunit(int unit)
247 {
248         struct g_gate_softc *sc;
249
250         mtx_assert(&g_gate_list_mtx, MA_OWNED);
251         if (unit >= 0) {
252                 LIST_FOREACH(sc, &g_gate_list, sc_next) {
253                         if (sc->sc_unit == unit)
254                                 return (-1);
255                 }
256         } else {
257                 unit = 0;
258 once_again:
259                 LIST_FOREACH(sc, &g_gate_list, sc_next) {
260                         if (sc->sc_unit == unit) {
261                                 if (++unit > 666)
262                                         return (-1);
263                                 goto once_again;
264                         }
265                 }
266         }
267         return (unit);
268 }
269
270 static void
271 g_gate_guard(void *arg)
272 {
273         struct g_gate_softc *sc;
274         struct bintime curtime;
275         struct bio *bp, *bp2;
276
277         sc = arg;
278         binuptime(&curtime);
279         g_gate_hold(sc->sc_unit);
280         mtx_lock(&sc->sc_queue_mtx);
281         TAILQ_FOREACH_SAFE(bp, &sc->sc_inqueue.queue, bio_queue, bp2) {
282                 if (curtime.sec - bp->bio_t0.sec < 5)
283                         continue;
284                 bioq_remove(&sc->sc_inqueue, bp);
285                 sc->sc_queue_count--;
286                 G_GATE_LOGREQ(1, bp, "Request timeout.");
287                 g_io_deliver(bp, EIO);
288         }
289         TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, bp2) {
290                 if (curtime.sec - bp->bio_t0.sec < 5)
291                         continue;
292                 bioq_remove(&sc->sc_outqueue, bp);
293                 sc->sc_queue_count--;
294                 G_GATE_LOGREQ(1, bp, "Request timeout.");
295                 g_io_deliver(bp, EIO);
296         }
297         mtx_unlock(&sc->sc_queue_mtx);
298         if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0) {
299                 callout_reset(&sc->sc_callout, sc->sc_timeout * hz,
300                     g_gate_guard, sc);
301         }
302         g_gate_release(sc);
303 }
304
305 static void
306 g_gate_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
307     struct g_consumer *cp, struct g_provider *pp)
308 {
309         struct g_gate_softc *sc;
310
311         sc = gp->softc;
312         if (sc == NULL || pp != NULL || cp != NULL)
313                 return;
314         g_gate_hold(sc->sc_unit);
315         if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) {
316                 sbuf_printf(sb, "%s<access>%s</access>\n", indent, "read-only");
317         } else if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0) {
318                 sbuf_printf(sb, "%s<access>%s</access>\n", indent,
319                     "write-only");
320         } else {
321                 sbuf_printf(sb, "%s<access>%s</access>\n", indent,
322                     "read-write");
323         }
324         sbuf_printf(sb, "%s<timeout>%u</timeout>\n", indent, sc->sc_timeout);
325         sbuf_printf(sb, "%s<info>%s</info>\n", indent, sc->sc_info);
326         sbuf_printf(sb, "%s<queue_count>%u</queue_count>\n", indent,
327             sc->sc_queue_count);
328         sbuf_printf(sb, "%s<queue_size>%u</queue_size>\n", indent,
329             sc->sc_queue_size);
330         sbuf_printf(sb, "%s<ref>%u</ref>\n", indent, sc->sc_ref);
331         g_topology_unlock();
332         g_gate_release(sc);
333         g_topology_lock();
334 }
335
336 static int
337 g_gate_create(struct g_gate_ctl_create *ggio)
338 {
339         struct g_gate_softc *sc;
340         struct g_geom *gp;
341         struct g_provider *pp;
342
343         if (ggio->gctl_mediasize == 0) {
344                 G_GATE_DEBUG(1, "Invalid media size.");
345                 return (EINVAL);
346         }
347         if (ggio->gctl_sectorsize > 0 && !powerof2(ggio->gctl_sectorsize)) {
348                 G_GATE_DEBUG(1, "Invalid sector size.");
349                 return (EINVAL);
350         }
351         if ((ggio->gctl_mediasize % ggio->gctl_sectorsize) != 0) {
352                 G_GATE_DEBUG(1, "Invalid media size.");
353                 return (EINVAL);
354         }
355         if ((ggio->gctl_flags & G_GATE_FLAG_READONLY) != 0 &&
356             (ggio->gctl_flags & G_GATE_FLAG_WRITEONLY) != 0) {
357                 G_GATE_DEBUG(1, "Invalid flags.");
358                 return (EINVAL);
359         }
360         if (ggio->gctl_unit < -1) {
361                 G_GATE_DEBUG(1, "Invalid unit number.");
362                 return (EINVAL);
363         }
364
365         sc = malloc(sizeof(*sc), M_GATE, M_WAITOK | M_ZERO);
366         sc->sc_flags = (ggio->gctl_flags & G_GATE_USERFLAGS);
367         strlcpy(sc->sc_info, ggio->gctl_info, sizeof(sc->sc_info));
368         sc->sc_seq = 0;
369         bioq_init(&sc->sc_inqueue);
370         bioq_init(&sc->sc_outqueue);
371         mtx_init(&sc->sc_queue_mtx, "gg:queue", NULL, MTX_DEF);
372         sc->sc_queue_count = 0;
373         sc->sc_queue_size = ggio->gctl_maxcount;
374         if (sc->sc_queue_size > G_GATE_MAX_QUEUE_SIZE)
375                 sc->sc_queue_size = G_GATE_MAX_QUEUE_SIZE;
376         sc->sc_timeout = ggio->gctl_timeout;
377         callout_init(&sc->sc_callout, CALLOUT_MPSAFE);
378         mtx_lock(&g_gate_list_mtx);
379         ggio->gctl_unit = g_gate_getunit(ggio->gctl_unit);
380         if (ggio->gctl_unit == -1) {
381                 mtx_unlock(&g_gate_list_mtx);
382                 mtx_destroy(&sc->sc_queue_mtx);
383                 free(sc, M_GATE);
384                 return (EBUSY);
385         }
386         sc->sc_unit = ggio->gctl_unit;
387         LIST_INSERT_HEAD(&g_gate_list, sc, sc_next);
388         mtx_unlock(&g_gate_list_mtx);
389
390         g_topology_lock();
391         gp = g_new_geomf(&g_gate_class, "%s%d", G_GATE_PROVIDER_NAME,
392             sc->sc_unit);
393         gp->start = g_gate_start;
394         gp->access = g_gate_access;
395         gp->dumpconf = g_gate_dumpconf;
396         gp->softc = sc;
397         pp = g_new_providerf(gp, "%s%d", G_GATE_PROVIDER_NAME, sc->sc_unit);
398         pp->mediasize = ggio->gctl_mediasize;
399         pp->sectorsize = ggio->gctl_sectorsize;
400         sc->sc_provider = pp;
401         g_error_provider(pp, 0);
402         g_topology_unlock();
403
404         if (sc->sc_timeout > 0) {
405                 callout_reset(&sc->sc_callout, sc->sc_timeout * hz,
406                     g_gate_guard, sc);
407         }
408         return (0);
409 }
410
411 #define G_GATE_CHECK_VERSION(ggio)      do {                            \
412         if ((ggio)->gctl_version != G_GATE_VERSION) {                   \
413                 printf("Version mismatch %d != %d.\n",                  \
414                     ggio->gctl_version, G_GATE_VERSION);                \
415                 return (EINVAL);                                        \
416         }                                                               \
417 } while (0)
418 static int
419 g_gate_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
420 {
421         struct g_gate_softc *sc;
422         struct bio *bp;
423         int error = 0;
424
425         G_GATE_DEBUG(4, "ioctl(%s, %lx, %p, %x, %p)", devtoname(dev), cmd, addr,
426             flags, td);
427
428         switch (cmd) {
429         case G_GATE_CMD_CREATE:
430             {
431                 struct g_gate_ctl_create *ggio = (void *)addr;
432
433                 G_GATE_CHECK_VERSION(ggio);
434                 error = g_gate_create(ggio);
435                 /*
436                  * Reset TDP_GEOM flag.
437                  * There are pending events for sure, because we just created
438                  * new provider and other classes want to taste it, but we
439                  * cannot answer on I/O requests until we're here.
440                  */
441                 td->td_pflags &= ~TDP_GEOM;
442                 return (error);
443             }
444         case G_GATE_CMD_DESTROY:
445             {
446                 struct g_gate_ctl_destroy *ggio = (void *)addr;
447
448                 G_GATE_CHECK_VERSION(ggio);
449                 sc = g_gate_hold(ggio->gctl_unit);
450                 if (sc == NULL)
451                         return (ENXIO);
452                 g_topology_lock();
453                 mtx_lock(&g_gate_list_mtx);
454                 error = g_gate_destroy(sc, ggio->gctl_force);
455                 g_topology_unlock();
456                 if (error != 0)
457                         g_gate_release(sc);
458                 return (error);
459             }
460         case G_GATE_CMD_CANCEL:
461             {
462                 struct g_gate_ctl_cancel *ggio = (void *)addr;
463                 struct bio *tbp, *lbp;
464
465                 G_GATE_CHECK_VERSION(ggio);
466                 sc = g_gate_hold(ggio->gctl_unit);
467                 if (sc == NULL)
468                         return (ENXIO);
469                 lbp = NULL;
470                 mtx_lock(&sc->sc_queue_mtx);
471                 TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, tbp) {
472                         if (ggio->gctl_seq == 0 ||
473                             ggio->gctl_seq == (uintptr_t)bp->bio_driver1) {
474                                 G_GATE_LOGREQ(1, bp, "Request canceled.");
475                                 bioq_remove(&sc->sc_outqueue, bp);
476                                 /*
477                                  * Be sure to put requests back onto incoming
478                                  * queue in the proper order.
479                                  */
480                                 if (lbp == NULL)
481                                         bioq_insert_head(&sc->sc_inqueue, bp);
482                                 else {
483                                         TAILQ_INSERT_AFTER(&sc->sc_inqueue.queue,
484                                             lbp, bp, bio_queue);
485                                 }
486                                 lbp = bp;
487                                 /*
488                                  * If only one request was canceled, leave now.
489                                  */
490                                 if (ggio->gctl_seq != 0)
491                                         break;
492                         }
493                 }
494                 mtx_unlock(&sc->sc_queue_mtx);
495                 g_gate_release(sc);
496                 return (error);
497             }
498         case G_GATE_CMD_START:
499             {
500                 struct g_gate_ctl_io *ggio = (void *)addr;
501
502                 G_GATE_CHECK_VERSION(ggio);
503                 sc = g_gate_hold(ggio->gctl_unit);
504                 if (sc == NULL)
505                         return (ENXIO);
506                 error = 0;
507                 for (;;) {
508                         mtx_lock(&sc->sc_queue_mtx);
509                         bp = bioq_first(&sc->sc_inqueue);
510                         if (bp != NULL)
511                                 break;
512                         if ((sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) {
513                                 ggio->gctl_error = ECANCELED;
514                                 mtx_unlock(&sc->sc_queue_mtx);
515                                 goto start_end;
516                         }
517                         if (msleep(sc, &sc->sc_queue_mtx,
518                             PPAUSE | PDROP | PCATCH, "ggwait", 0) != 0) {
519                                 ggio->gctl_error = ECANCELED;
520                                 goto start_end;
521                         }
522                 }
523                 ggio->gctl_cmd = bp->bio_cmd;
524                 if ((bp->bio_cmd == BIO_DELETE || bp->bio_cmd == BIO_WRITE) &&
525                     bp->bio_length > ggio->gctl_length) {
526                         mtx_unlock(&sc->sc_queue_mtx);
527                         ggio->gctl_length = bp->bio_length;
528                         ggio->gctl_error = ENOMEM;
529                         goto start_end;
530                 }
531                 bioq_remove(&sc->sc_inqueue, bp);
532                 bioq_insert_tail(&sc->sc_outqueue, bp);
533                 mtx_unlock(&sc->sc_queue_mtx);
534
535                 ggio->gctl_seq = (uintptr_t)bp->bio_driver1;
536                 ggio->gctl_offset = bp->bio_offset;
537                 ggio->gctl_length = bp->bio_length;
538
539                 switch (bp->bio_cmd) {
540                 case BIO_READ:
541                         break;
542                 case BIO_DELETE:
543                 case BIO_WRITE:
544                         error = copyout(bp->bio_data, ggio->gctl_data,
545                             bp->bio_length);
546                         if (error != 0) {
547                                 mtx_lock(&sc->sc_queue_mtx);
548                                 bioq_remove(&sc->sc_outqueue, bp);
549                                 bioq_insert_head(&sc->sc_inqueue, bp);
550                                 mtx_unlock(&sc->sc_queue_mtx);
551                                 goto start_end;
552                         }
553                         break;
554                 }
555 start_end:
556                 g_gate_release(sc);
557                 return (error);
558             }
559         case G_GATE_CMD_DONE:
560             {
561                 struct g_gate_ctl_io *ggio = (void *)addr;
562
563                 G_GATE_CHECK_VERSION(ggio);
564                 sc = g_gate_hold(ggio->gctl_unit);
565                 if (sc == NULL)
566                         return (ENOENT);
567                 error = 0;
568                 mtx_lock(&sc->sc_queue_mtx);
569                 TAILQ_FOREACH(bp, &sc->sc_outqueue.queue, bio_queue) {
570                         if (ggio->gctl_seq == (uintptr_t)bp->bio_driver1)
571                                 break;
572                 }
573                 if (bp != NULL) {
574                         bioq_remove(&sc->sc_outqueue, bp);
575                         sc->sc_queue_count--;
576                 }
577                 mtx_unlock(&sc->sc_queue_mtx);
578                 if (bp == NULL) {
579                         /*
580                          * Request was probably canceled.
581                          */
582                         goto done_end;
583                 }
584                 if (ggio->gctl_error == EAGAIN) {
585                         bp->bio_error = 0;
586                         G_GATE_LOGREQ(1, bp, "Request desisted.");
587                         mtx_lock(&sc->sc_queue_mtx);
588                         sc->sc_queue_count++;
589                         bioq_insert_head(&sc->sc_inqueue, bp);
590                         wakeup(sc);
591                         mtx_unlock(&sc->sc_queue_mtx);
592                 } else {
593                         bp->bio_error = ggio->gctl_error;
594                         if (bp->bio_error == 0) {
595                                 bp->bio_completed = bp->bio_length;
596                                 switch (bp->bio_cmd) {
597                                 case BIO_READ:
598                                         error = copyin(ggio->gctl_data,
599                                             bp->bio_data, bp->bio_length);
600                                         if (error != 0)
601                                                 bp->bio_error = error;
602                                         break;
603                                 case BIO_DELETE:
604                                 case BIO_WRITE:
605                                         break;
606                                 }
607                         }
608                         G_GATE_LOGREQ(2, bp, "Request done.");
609                         g_io_deliver(bp, bp->bio_error);
610                 }
611 done_end:
612                 g_gate_release(sc);
613                 return (error);
614             }
615         }
616         return (ENOIOCTL);
617 }
618
619 static void
620 g_gate_device(void)
621 {
622
623         status_dev = make_dev(&g_gate_cdevsw, 0x0, UID_ROOT, GID_WHEEL, 0600,
624             G_GATE_CTL_NAME);
625 }
626
627 static int
628 g_gate_modevent(module_t mod, int type, void *data)
629 {
630         int error = 0;
631
632         switch (type) {
633         case MOD_LOAD:
634                 mtx_init(&g_gate_list_mtx, "gg_list_lock", NULL, MTX_DEF);
635                 g_gate_device();
636                 break;
637         case MOD_UNLOAD:
638                 mtx_lock(&g_gate_list_mtx);
639                 if (!LIST_EMPTY(&g_gate_list)) {
640                         mtx_unlock(&g_gate_list_mtx);
641                         error = EBUSY;
642                         break;
643                 }
644                 mtx_unlock(&g_gate_list_mtx);
645                 mtx_destroy(&g_gate_list_mtx);
646                 if (status_dev != 0)
647                         destroy_dev(status_dev);
648                 break;
649         default:
650                 return (EOPNOTSUPP);
651                 break;
652         }
653
654         return (error);
655 }
656 static moduledata_t g_gate_module = {
657         G_GATE_MOD_NAME,
658         g_gate_modevent,
659         NULL
660 };
661 DECLARE_MODULE(geom_gate, g_gate_module, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
662 DECLARE_GEOM_CLASS(g_gate_class, g_gate);