]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/geom/nop/g_nop.c
Merge openmp release_80 branch r356034 (effectively, 8.0.0 rc5).
[FreeBSD/FreeBSD.git] / sys / geom / nop / g_nop.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36 #include <sys/lock.h>
37 #include <sys/mutex.h>
38 #include <sys/bio.h>
39 #include <sys/sbuf.h>
40 #include <sys/sysctl.h>
41 #include <sys/malloc.h>
42 #include <geom/geom.h>
43 #include <geom/nop/g_nop.h>
44
45
46 SYSCTL_DECL(_kern_geom);
47 static SYSCTL_NODE(_kern_geom, OID_AUTO, nop, CTLFLAG_RW, 0, "GEOM_NOP stuff");
48 static u_int g_nop_debug = 0;
49 SYSCTL_UINT(_kern_geom_nop, OID_AUTO, debug, CTLFLAG_RW, &g_nop_debug, 0,
50     "Debug level");
51
52 static int g_nop_destroy(struct g_geom *gp, boolean_t force);
53 static int g_nop_destroy_geom(struct gctl_req *req, struct g_class *mp,
54     struct g_geom *gp);
55 static void g_nop_config(struct gctl_req *req, struct g_class *mp,
56     const char *verb);
57 static void g_nop_dumpconf(struct sbuf *sb, const char *indent,
58     struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp);
59
60 struct g_class g_nop_class = {
61         .name = G_NOP_CLASS_NAME,
62         .version = G_VERSION,
63         .ctlreq = g_nop_config,
64         .destroy_geom = g_nop_destroy_geom
65 };
66
67
68 static void
69 g_nop_orphan(struct g_consumer *cp)
70 {
71
72         g_topology_assert();
73         g_nop_destroy(cp->geom, 1);
74 }
75
76 static void
77 g_nop_resize(struct g_consumer *cp)
78 {
79         struct g_nop_softc *sc;
80         struct g_geom *gp;
81         struct g_provider *pp;
82         off_t size;
83
84         g_topology_assert();
85
86         gp = cp->geom;
87         sc = gp->softc;
88
89         if (sc->sc_explicitsize != 0)
90                 return;
91         if (cp->provider->mediasize < sc->sc_offset) {
92                 g_nop_destroy(gp, 1);
93                 return;
94         }
95         size = cp->provider->mediasize - sc->sc_offset;
96         LIST_FOREACH(pp, &gp->provider, provider)
97                 g_resize_provider(pp, size);
98 }
99
100 static void
101 g_nop_start(struct bio *bp)
102 {
103         struct g_nop_softc *sc;
104         struct g_geom *gp;
105         struct g_provider *pp;
106         struct bio *cbp;
107         u_int failprob = 0;
108
109         gp = bp->bio_to->geom;
110         sc = gp->softc;
111         G_NOP_LOGREQ(bp, "Request received.");
112         mtx_lock(&sc->sc_lock);
113         switch (bp->bio_cmd) {
114         case BIO_READ:
115                 sc->sc_reads++;
116                 sc->sc_readbytes += bp->bio_length;
117                 failprob = sc->sc_rfailprob;
118                 break;
119         case BIO_WRITE:
120                 sc->sc_writes++;
121                 sc->sc_wrotebytes += bp->bio_length;
122                 failprob = sc->sc_wfailprob;
123                 break;
124         case BIO_DELETE:
125                 sc->sc_deletes++;
126                 break;
127         case BIO_GETATTR:
128                 sc->sc_getattrs++;
129                 if (sc->sc_physpath && 
130                     g_handleattr_str(bp, "GEOM::physpath", sc->sc_physpath)) {
131                         mtx_unlock(&sc->sc_lock);
132                         return;
133                 }
134                 break;
135         case BIO_FLUSH:
136                 sc->sc_flushes++;
137                 break;
138         case BIO_CMD0:
139                 sc->sc_cmd0s++;
140                 break;
141         case BIO_CMD1:
142                 sc->sc_cmd1s++;
143                 break;
144         case BIO_CMD2:
145                 sc->sc_cmd2s++;
146                 break;
147         }
148         mtx_unlock(&sc->sc_lock);
149         if (failprob > 0) {
150                 u_int rval;
151
152                 rval = arc4random() % 100;
153                 if (rval < failprob) {
154                         G_NOP_LOGREQLVL(1, bp, "Returning error=%d.", sc->sc_error);
155                         g_io_deliver(bp, sc->sc_error);
156                         return;
157                 }
158         }
159         cbp = g_clone_bio(bp);
160         if (cbp == NULL) {
161                 g_io_deliver(bp, ENOMEM);
162                 return;
163         }
164         cbp->bio_done = g_std_done;
165         cbp->bio_offset = bp->bio_offset + sc->sc_offset;
166         pp = LIST_FIRST(&gp->provider);
167         KASSERT(pp != NULL, ("NULL pp"));
168         cbp->bio_to = pp;
169         G_NOP_LOGREQ(cbp, "Sending request.");
170         g_io_request(cbp, LIST_FIRST(&gp->consumer));
171 }
172
173 static int
174 g_nop_access(struct g_provider *pp, int dr, int dw, int de)
175 {
176         struct g_geom *gp;
177         struct g_consumer *cp;
178         int error;
179
180         gp = pp->geom;
181         cp = LIST_FIRST(&gp->consumer);
182         error = g_access(cp, dr, dw, de);
183
184         return (error);
185 }
186
187 static int
188 g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
189     int ioerror, u_int rfailprob, u_int wfailprob, off_t offset, off_t size,
190     u_int secsize, off_t stripesize, off_t stripeoffset, const char *physpath)
191 {
192         struct g_nop_softc *sc;
193         struct g_geom *gp;
194         struct g_provider *newpp;
195         struct g_consumer *cp;
196         char name[64];
197         int error;
198         off_t explicitsize;
199
200         g_topology_assert();
201
202         gp = NULL;
203         newpp = NULL;
204         cp = NULL;
205
206         if ((offset % pp->sectorsize) != 0) {
207                 gctl_error(req, "Invalid offset for provider %s.", pp->name);
208                 return (EINVAL);
209         }
210         if ((size % pp->sectorsize) != 0) {
211                 gctl_error(req, "Invalid size for provider %s.", pp->name);
212                 return (EINVAL);
213         }
214         if (offset >= pp->mediasize) {
215                 gctl_error(req, "Invalid offset for provider %s.", pp->name);
216                 return (EINVAL);
217         }
218         explicitsize = size;
219         if (size == 0)
220                 size = pp->mediasize - offset;
221         if (offset + size > pp->mediasize) {
222                 gctl_error(req, "Invalid size for provider %s.", pp->name);
223                 return (EINVAL);
224         }
225         if (secsize == 0)
226                 secsize = pp->sectorsize;
227         else if ((secsize % pp->sectorsize) != 0) {
228                 gctl_error(req, "Invalid secsize for provider %s.", pp->name);
229                 return (EINVAL);
230         }
231         if (secsize > MAXPHYS) {
232                 gctl_error(req, "secsize is too big.");
233                 return (EINVAL);
234         }
235         size -= size % secsize;
236         if ((stripesize % pp->sectorsize) != 0) {
237                 gctl_error(req, "Invalid stripesize for provider %s.", pp->name);
238                 return (EINVAL);
239         }
240         if ((stripeoffset % pp->sectorsize) != 0) {
241                 gctl_error(req, "Invalid stripeoffset for provider %s.", pp->name);
242                 return (EINVAL);
243         }
244         if (stripesize != 0 && stripeoffset >= stripesize) {
245                 gctl_error(req, "stripeoffset is too big.");
246                 return (EINVAL);
247         }
248         snprintf(name, sizeof(name), "%s%s", pp->name, G_NOP_SUFFIX);
249         LIST_FOREACH(gp, &mp->geom, geom) {
250                 if (strcmp(gp->name, name) == 0) {
251                         gctl_error(req, "Provider %s already exists.", name);
252                         return (EEXIST);
253                 }
254         }
255         gp = g_new_geomf(mp, "%s", name);
256         sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
257         sc->sc_offset = offset;
258         sc->sc_explicitsize = explicitsize;
259         sc->sc_stripesize = stripesize;
260         sc->sc_stripeoffset = stripeoffset;
261         if (physpath && strcmp(physpath, G_NOP_PHYSPATH_PASSTHROUGH)) {
262                 sc->sc_physpath = strndup(physpath, MAXPATHLEN, M_GEOM);
263         } else
264                 sc->sc_physpath = NULL;
265         sc->sc_error = ioerror;
266         sc->sc_rfailprob = rfailprob;
267         sc->sc_wfailprob = wfailprob;
268         sc->sc_reads = 0;
269         sc->sc_writes = 0;
270         sc->sc_deletes = 0;
271         sc->sc_getattrs = 0;
272         sc->sc_flushes = 0;
273         sc->sc_cmd0s = 0;
274         sc->sc_cmd1s = 0;
275         sc->sc_cmd2s = 0;
276         sc->sc_readbytes = 0;
277         sc->sc_wrotebytes = 0;
278         mtx_init(&sc->sc_lock, "gnop lock", NULL, MTX_DEF);
279         gp->softc = sc;
280         gp->start = g_nop_start;
281         gp->orphan = g_nop_orphan;
282         gp->resize = g_nop_resize;
283         gp->access = g_nop_access;
284         gp->dumpconf = g_nop_dumpconf;
285
286         newpp = g_new_providerf(gp, "%s", gp->name);
287         newpp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
288         newpp->mediasize = size;
289         newpp->sectorsize = secsize;
290         newpp->stripesize = stripesize;
291         newpp->stripeoffset = stripeoffset;
292
293         cp = g_new_consumer(gp);
294         cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
295         error = g_attach(cp, pp);
296         if (error != 0) {
297                 gctl_error(req, "Cannot attach to provider %s.", pp->name);
298                 goto fail;
299         }
300
301         newpp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED;
302         g_error_provider(newpp, 0);
303         G_NOP_DEBUG(0, "Device %s created.", gp->name);
304         return (0);
305 fail:
306         if (cp->provider != NULL)
307                 g_detach(cp);
308         g_destroy_consumer(cp);
309         g_destroy_provider(newpp);
310         mtx_destroy(&sc->sc_lock);
311         free(sc->sc_physpath, M_GEOM);
312         g_free(gp->softc);
313         g_destroy_geom(gp);
314         return (error);
315 }
316
317 static int
318 g_nop_destroy(struct g_geom *gp, boolean_t force)
319 {
320         struct g_nop_softc *sc;
321         struct g_provider *pp;
322
323         g_topology_assert();
324         sc = gp->softc;
325         if (sc == NULL)
326                 return (ENXIO);
327         free(sc->sc_physpath, M_GEOM);
328         pp = LIST_FIRST(&gp->provider);
329         if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
330                 if (force) {
331                         G_NOP_DEBUG(0, "Device %s is still open, so it "
332                             "can't be definitely removed.", pp->name);
333                 } else {
334                         G_NOP_DEBUG(1, "Device %s is still open (r%dw%de%d).",
335                             pp->name, pp->acr, pp->acw, pp->ace);
336                         return (EBUSY);
337                 }
338         } else {
339                 G_NOP_DEBUG(0, "Device %s removed.", gp->name);
340         }
341         gp->softc = NULL;
342         mtx_destroy(&sc->sc_lock);
343         g_free(sc);
344         g_wither_geom(gp, ENXIO);
345
346         return (0);
347 }
348
349 static int
350 g_nop_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
351 {
352
353         return (g_nop_destroy(gp, 0));
354 }
355
356 static void
357 g_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
358 {
359         struct g_provider *pp;
360         intmax_t *error, *rfailprob, *wfailprob, *offset, *secsize, *size,
361             *stripesize, *stripeoffset;
362         const char *name, *physpath;
363         char param[16];
364         int i, *nargs;
365
366         g_topology_assert();
367
368         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
369         if (nargs == NULL) {
370                 gctl_error(req, "No '%s' argument", "nargs");
371                 return;
372         }
373         if (*nargs <= 0) {
374                 gctl_error(req, "Missing device(s).");
375                 return;
376         }
377         error = gctl_get_paraml(req, "error", sizeof(*error));
378         if (error == NULL) {
379                 gctl_error(req, "No '%s' argument", "error");
380                 return;
381         }
382         rfailprob = gctl_get_paraml(req, "rfailprob", sizeof(*rfailprob));
383         if (rfailprob == NULL) {
384                 gctl_error(req, "No '%s' argument", "rfailprob");
385                 return;
386         }
387         if (*rfailprob < -1 || *rfailprob > 100) {
388                 gctl_error(req, "Invalid '%s' argument", "rfailprob");
389                 return;
390         }
391         wfailprob = gctl_get_paraml(req, "wfailprob", sizeof(*wfailprob));
392         if (wfailprob == NULL) {
393                 gctl_error(req, "No '%s' argument", "wfailprob");
394                 return;
395         }
396         if (*wfailprob < -1 || *wfailprob > 100) {
397                 gctl_error(req, "Invalid '%s' argument", "wfailprob");
398                 return;
399         }
400         offset = gctl_get_paraml(req, "offset", sizeof(*offset));
401         if (offset == NULL) {
402                 gctl_error(req, "No '%s' argument", "offset");
403                 return;
404         }
405         if (*offset < 0) {
406                 gctl_error(req, "Invalid '%s' argument", "offset");
407                 return;
408         }
409         size = gctl_get_paraml(req, "size", sizeof(*size));
410         if (size == NULL) {
411                 gctl_error(req, "No '%s' argument", "size");
412                 return;
413         }
414         if (*size < 0) {
415                 gctl_error(req, "Invalid '%s' argument", "size");
416                 return;
417         }
418         secsize = gctl_get_paraml(req, "secsize", sizeof(*secsize));
419         if (secsize == NULL) {
420                 gctl_error(req, "No '%s' argument", "secsize");
421                 return;
422         }
423         if (*secsize < 0) {
424                 gctl_error(req, "Invalid '%s' argument", "secsize");
425                 return;
426         }
427         stripesize = gctl_get_paraml(req, "stripesize", sizeof(*stripesize));
428         if (stripesize == NULL) {
429                 gctl_error(req, "No '%s' argument", "stripesize");
430                 return;
431         }
432         if (*stripesize < 0) {
433                 gctl_error(req, "Invalid '%s' argument", "stripesize");
434                 return;
435         }
436         stripeoffset = gctl_get_paraml(req, "stripeoffset", sizeof(*stripeoffset));
437         if (stripeoffset == NULL) {
438                 gctl_error(req, "No '%s' argument", "stripeoffset");
439                 return;
440         }
441         if (*stripeoffset < 0) {
442                 gctl_error(req, "Invalid '%s' argument", "stripeoffset");
443                 return;
444         }
445         physpath = gctl_get_asciiparam(req, "physpath");
446
447         for (i = 0; i < *nargs; i++) {
448                 snprintf(param, sizeof(param), "arg%d", i);
449                 name = gctl_get_asciiparam(req, param);
450                 if (name == NULL) {
451                         gctl_error(req, "No 'arg%d' argument", i);
452                         return;
453                 }
454                 if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
455                         name += strlen("/dev/");
456                 pp = g_provider_by_name(name);
457                 if (pp == NULL) {
458                         G_NOP_DEBUG(1, "Provider %s is invalid.", name);
459                         gctl_error(req, "Provider %s is invalid.", name);
460                         return;
461                 }
462                 if (g_nop_create(req, mp, pp,
463                     *error == -1 ? EIO : (int)*error,
464                     *rfailprob == -1 ? 0 : (u_int)*rfailprob,
465                     *wfailprob == -1 ? 0 : (u_int)*wfailprob,
466                     (off_t)*offset, (off_t)*size, (u_int)*secsize,
467                     (off_t)*stripesize, (off_t)*stripeoffset,
468                     physpath) != 0) {
469                         return;
470                 }
471         }
472 }
473
474 static void
475 g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp)
476 {
477         struct g_nop_softc *sc;
478         struct g_provider *pp;
479         intmax_t *error, *rfailprob, *wfailprob;
480         const char *name;
481         char param[16];
482         int i, *nargs;
483
484         g_topology_assert();
485
486         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
487         if (nargs == NULL) {
488                 gctl_error(req, "No '%s' argument", "nargs");
489                 return;
490         }
491         if (*nargs <= 0) {
492                 gctl_error(req, "Missing device(s).");
493                 return;
494         }
495         error = gctl_get_paraml(req, "error", sizeof(*error));
496         if (error == NULL) {
497                 gctl_error(req, "No '%s' argument", "error");
498                 return;
499         }
500         rfailprob = gctl_get_paraml(req, "rfailprob", sizeof(*rfailprob));
501         if (rfailprob == NULL) {
502                 gctl_error(req, "No '%s' argument", "rfailprob");
503                 return;
504         }
505         if (*rfailprob < -1 || *rfailprob > 100) {
506                 gctl_error(req, "Invalid '%s' argument", "rfailprob");
507                 return;
508         }
509         wfailprob = gctl_get_paraml(req, "wfailprob", sizeof(*wfailprob));
510         if (wfailprob == NULL) {
511                 gctl_error(req, "No '%s' argument", "wfailprob");
512                 return;
513         }
514         if (*wfailprob < -1 || *wfailprob > 100) {
515                 gctl_error(req, "Invalid '%s' argument", "wfailprob");
516                 return;
517         }
518
519         for (i = 0; i < *nargs; i++) {
520                 snprintf(param, sizeof(param), "arg%d", i);
521                 name = gctl_get_asciiparam(req, param);
522                 if (name == NULL) {
523                         gctl_error(req, "No 'arg%d' argument", i);
524                         return;
525                 }
526                 if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
527                         name += strlen("/dev/");
528                 pp = g_provider_by_name(name);
529                 if (pp == NULL || pp->geom->class != mp) {
530                         G_NOP_DEBUG(1, "Provider %s is invalid.", name);
531                         gctl_error(req, "Provider %s is invalid.", name);
532                         return;
533                 }
534                 sc = pp->geom->softc;
535                 if (*error != -1)
536                         sc->sc_error = (int)*error;
537                 if (*rfailprob != -1)
538                         sc->sc_rfailprob = (u_int)*rfailprob;
539                 if (*wfailprob != -1)
540                         sc->sc_wfailprob = (u_int)*wfailprob;
541         }
542 }
543
544 static struct g_geom *
545 g_nop_find_geom(struct g_class *mp, const char *name)
546 {
547         struct g_geom *gp;
548
549         LIST_FOREACH(gp, &mp->geom, geom) {
550                 if (strcmp(gp->name, name) == 0)
551                         return (gp);
552         }
553         return (NULL);
554 }
555
556 static void
557 g_nop_ctl_destroy(struct gctl_req *req, struct g_class *mp)
558 {
559         int *nargs, *force, error, i;
560         struct g_geom *gp;
561         const char *name;
562         char param[16];
563
564         g_topology_assert();
565
566         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
567         if (nargs == NULL) {
568                 gctl_error(req, "No '%s' argument", "nargs");
569                 return;
570         }
571         if (*nargs <= 0) {
572                 gctl_error(req, "Missing device(s).");
573                 return;
574         }
575         force = gctl_get_paraml(req, "force", sizeof(*force));
576         if (force == NULL) {
577                 gctl_error(req, "No 'force' argument");
578                 return;
579         }
580
581         for (i = 0; i < *nargs; i++) {
582                 snprintf(param, sizeof(param), "arg%d", i);
583                 name = gctl_get_asciiparam(req, param);
584                 if (name == NULL) {
585                         gctl_error(req, "No 'arg%d' argument", i);
586                         return;
587                 }
588                 if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
589                         name += strlen("/dev/");
590                 gp = g_nop_find_geom(mp, name);
591                 if (gp == NULL) {
592                         G_NOP_DEBUG(1, "Device %s is invalid.", name);
593                         gctl_error(req, "Device %s is invalid.", name);
594                         return;
595                 }
596                 error = g_nop_destroy(gp, *force);
597                 if (error != 0) {
598                         gctl_error(req, "Cannot destroy device %s (error=%d).",
599                             gp->name, error);
600                         return;
601                 }
602         }
603 }
604
605 static void
606 g_nop_ctl_reset(struct gctl_req *req, struct g_class *mp)
607 {
608         struct g_nop_softc *sc;
609         struct g_provider *pp;
610         const char *name;
611         char param[16];
612         int i, *nargs;
613
614         g_topology_assert();
615
616         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
617         if (nargs == NULL) {
618                 gctl_error(req, "No '%s' argument", "nargs");
619                 return;
620         }
621         if (*nargs <= 0) {
622                 gctl_error(req, "Missing device(s).");
623                 return;
624         }
625
626         for (i = 0; i < *nargs; i++) {
627                 snprintf(param, sizeof(param), "arg%d", i);
628                 name = gctl_get_asciiparam(req, param);
629                 if (name == NULL) {
630                         gctl_error(req, "No 'arg%d' argument", i);
631                         return;
632                 }
633                 if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
634                         name += strlen("/dev/");
635                 pp = g_provider_by_name(name);
636                 if (pp == NULL || pp->geom->class != mp) {
637                         G_NOP_DEBUG(1, "Provider %s is invalid.", name);
638                         gctl_error(req, "Provider %s is invalid.", name);
639                         return;
640                 }
641                 sc = pp->geom->softc;
642                 sc->sc_reads = 0;
643                 sc->sc_writes = 0;
644                 sc->sc_deletes = 0;
645                 sc->sc_getattrs = 0;
646                 sc->sc_flushes = 0;
647                 sc->sc_cmd0s = 0;
648                 sc->sc_cmd1s = 0;
649                 sc->sc_cmd2s = 0;
650                 sc->sc_readbytes = 0;
651                 sc->sc_wrotebytes = 0;
652         }
653 }
654
655 static void
656 g_nop_config(struct gctl_req *req, struct g_class *mp, const char *verb)
657 {
658         uint32_t *version;
659
660         g_topology_assert();
661
662         version = gctl_get_paraml(req, "version", sizeof(*version));
663         if (version == NULL) {
664                 gctl_error(req, "No '%s' argument.", "version");
665                 return;
666         }
667         if (*version != G_NOP_VERSION) {
668                 gctl_error(req, "Userland and kernel parts are out of sync.");
669                 return;
670         }
671
672         if (strcmp(verb, "create") == 0) {
673                 g_nop_ctl_create(req, mp);
674                 return;
675         } else if (strcmp(verb, "configure") == 0) {
676                 g_nop_ctl_configure(req, mp);
677                 return;
678         } else if (strcmp(verb, "destroy") == 0) {
679                 g_nop_ctl_destroy(req, mp);
680                 return;
681         } else if (strcmp(verb, "reset") == 0) {
682                 g_nop_ctl_reset(req, mp);
683                 return;
684         }
685
686         gctl_error(req, "Unknown verb.");
687 }
688
689 static void
690 g_nop_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
691     struct g_consumer *cp, struct g_provider *pp)
692 {
693         struct g_nop_softc *sc;
694
695         if (pp != NULL || cp != NULL)
696                 return;
697         sc = gp->softc;
698         sbuf_printf(sb, "%s<Offset>%jd</Offset>\n", indent,
699             (intmax_t)sc->sc_offset);
700         sbuf_printf(sb, "%s<ReadFailProb>%u</ReadFailProb>\n", indent,
701             sc->sc_rfailprob);
702         sbuf_printf(sb, "%s<WriteFailProb>%u</WriteFailProb>\n", indent,
703             sc->sc_wfailprob);
704         sbuf_printf(sb, "%s<Error>%d</Error>\n", indent, sc->sc_error);
705         sbuf_printf(sb, "%s<Reads>%ju</Reads>\n", indent, sc->sc_reads);
706         sbuf_printf(sb, "%s<Writes>%ju</Writes>\n", indent, sc->sc_writes);
707         sbuf_printf(sb, "%s<Deletes>%ju</Deletes>\n", indent, sc->sc_deletes);
708         sbuf_printf(sb, "%s<Getattrs>%ju</Getattrs>\n", indent, sc->sc_getattrs);
709         sbuf_printf(sb, "%s<Flushes>%ju</Flushes>\n", indent, sc->sc_flushes);
710         sbuf_printf(sb, "%s<Cmd0s>%ju</Cmd0s>\n", indent, sc->sc_cmd0s);
711         sbuf_printf(sb, "%s<Cmd1s>%ju</Cmd1s>\n", indent, sc->sc_cmd1s);
712         sbuf_printf(sb, "%s<Cmd2s>%ju</Cmd2s>\n", indent, sc->sc_cmd2s);
713         sbuf_printf(sb, "%s<ReadBytes>%ju</ReadBytes>\n", indent,
714             sc->sc_readbytes);
715         sbuf_printf(sb, "%s<WroteBytes>%ju</WroteBytes>\n", indent,
716             sc->sc_wrotebytes);
717 }
718
719 DECLARE_GEOM_CLASS(g_nop_class, g_nop);
720 MODULE_VERSION(geom_nop, 0);