1129471Spjd/*-
2162142Spjd * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3129471Spjd * All rights reserved.
4129471Spjd *
5129471Spjd * Redistribution and use in source and binary forms, with or without
6129471Spjd * modification, are permitted provided that the following conditions
7129471Spjd * are met:
8129471Spjd * 1. Redistributions of source code must retain the above copyright
9129471Spjd *    notice, this list of conditions and the following disclaimer.
10129471Spjd * 2. Redistributions in binary form must reproduce the above copyright
11129471Spjd *    notice, this list of conditions and the following disclaimer in the
12129471Spjd *    documentation and/or other materials provided with the distribution.
13155174Spjd *
14129471Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15129471Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16129471Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17129471Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18129471Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19129471Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20129471Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21129471Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22129471Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23129471Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24129471Spjd * SUCH DAMAGE.
25129471Spjd */
26129471Spjd
27129471Spjd#include <sys/cdefs.h>
28129471Spjd__FBSDID("$FreeBSD$");
29129471Spjd
30129471Spjd#include <sys/param.h>
31129471Spjd#include <sys/systm.h>
32129471Spjd#include <sys/kernel.h>
33129471Spjd#include <sys/module.h>
34129471Spjd#include <sys/lock.h>
35129471Spjd#include <sys/mutex.h>
36129471Spjd#include <sys/bio.h>
37223921Sae#include <sys/sbuf.h>
38129471Spjd#include <sys/sysctl.h>
39129471Spjd#include <sys/malloc.h>
40129471Spjd#include <geom/geom.h>
41129471Spjd#include <geom/nop/g_nop.h>
42129471Spjd
43129471Spjd
44129471SpjdSYSCTL_DECL(_kern_geom);
45227309Sedstatic SYSCTL_NODE(_kern_geom, OID_AUTO, nop, CTLFLAG_RW, 0, "GEOM_NOP stuff");
46129471Spjdstatic u_int g_nop_debug = 0;
47129471SpjdSYSCTL_UINT(_kern_geom_nop, OID_AUTO, debug, CTLFLAG_RW, &g_nop_debug, 0,
48129471Spjd    "Debug level");
49129471Spjd
50129471Spjdstatic int g_nop_destroy(struct g_geom *gp, boolean_t force);
51129471Spjdstatic int g_nop_destroy_geom(struct gctl_req *req, struct g_class *mp,
52129471Spjd    struct g_geom *gp);
53129471Spjdstatic void g_nop_config(struct gctl_req *req, struct g_class *mp,
54129471Spjd    const char *verb);
55129471Spjdstatic void g_nop_dumpconf(struct sbuf *sb, const char *indent,
56129471Spjd    struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp);
57129471Spjd
58129471Spjdstruct g_class g_nop_class = {
59129471Spjd	.name = G_NOP_CLASS_NAME,
60133318Sphk	.version = G_VERSION,
61129471Spjd	.ctlreq = g_nop_config,
62129471Spjd	.destroy_geom = g_nop_destroy_geom
63129471Spjd};
64129471Spjd
65129471Spjd
66129471Spjdstatic void
67129471Spjdg_nop_orphan(struct g_consumer *cp)
68129471Spjd{
69129471Spjd
70129471Spjd	g_topology_assert();
71129471Spjd	g_nop_destroy(cp->geom, 1);
72129471Spjd}
73129471Spjd
74129471Spjdstatic void
75238219Straszg_nop_resize(struct g_consumer *cp)
76238219Strasz{
77238219Strasz	struct g_nop_softc *sc;
78238219Strasz	struct g_geom *gp;
79238219Strasz	struct g_provider *pp;
80238219Strasz	off_t size;
81238219Strasz
82238219Strasz	g_topology_assert();
83238219Strasz
84238219Strasz	gp = cp->geom;
85238219Strasz	sc = gp->softc;
86238219Strasz
87238219Strasz	if (sc->sc_explicitsize != 0)
88238219Strasz		return;
89238219Strasz	if (cp->provider->mediasize < sc->sc_offset) {
90238219Strasz		g_nop_destroy(gp, 1);
91238219Strasz		return;
92238219Strasz	}
93238219Strasz	size = cp->provider->mediasize - sc->sc_offset;
94238219Strasz	LIST_FOREACH(pp, &gp->provider, provider)
95238219Strasz		g_resize_provider(pp, size);
96238219Strasz}
97238219Strasz
98238219Straszstatic void
99129471Spjdg_nop_start(struct bio *bp)
100129471Spjd{
101132381Spjd	struct g_nop_softc *sc;
102129471Spjd	struct g_geom *gp;
103129471Spjd	struct g_provider *pp;
104129471Spjd	struct bio *cbp;
105162142Spjd	u_int failprob = 0;
106129471Spjd
107129471Spjd	gp = bp->bio_to->geom;
108132381Spjd	sc = gp->softc;
109129471Spjd	G_NOP_LOGREQ(bp, "Request received.");
110153250Spjd	switch (bp->bio_cmd) {
111153250Spjd	case BIO_READ:
112153250Spjd		sc->sc_reads++;
113153250Spjd		sc->sc_readbytes += bp->bio_length;
114162142Spjd		failprob = sc->sc_rfailprob;
115153250Spjd		break;
116153250Spjd	case BIO_WRITE:
117153250Spjd		sc->sc_writes++;
118153250Spjd		sc->sc_wrotebytes += bp->bio_length;
119162142Spjd		failprob = sc->sc_wfailprob;
120153250Spjd		break;
121153250Spjd	}
122162142Spjd	if (failprob > 0) {
123129471Spjd		u_int rval;
124129471Spjd
125129471Spjd		rval = arc4random() % 100;
126162142Spjd		if (rval < failprob) {
127249440Sjmg			G_NOP_LOGREQLVL(1, bp, "Returning error=%d.", sc->sc_error);
128162142Spjd			g_io_deliver(bp, sc->sc_error);
129129471Spjd			return;
130129471Spjd		}
131129471Spjd	}
132154458Spjd	cbp = g_clone_bio(bp);
133154458Spjd	if (cbp == NULL) {
134154458Spjd		g_io_deliver(bp, ENOMEM);
135154458Spjd		return;
136154458Spjd	}
137129471Spjd	cbp->bio_done = g_std_done;
138132381Spjd	cbp->bio_offset = bp->bio_offset + sc->sc_offset;
139132988Spjd	pp = LIST_FIRST(&gp->provider);
140132988Spjd	KASSERT(pp != NULL, ("NULL pp"));
141132988Spjd	cbp->bio_to = pp;
142129471Spjd	G_NOP_LOGREQ(cbp, "Sending request.");
143129471Spjd	g_io_request(cbp, LIST_FIRST(&gp->consumer));
144129471Spjd}
145129471Spjd
146129471Spjdstatic int
147129471Spjdg_nop_access(struct g_provider *pp, int dr, int dw, int de)
148129471Spjd{
149129471Spjd	struct g_geom *gp;
150129471Spjd	struct g_consumer *cp;
151129471Spjd	int error;
152129471Spjd
153129471Spjd	gp = pp->geom;
154129471Spjd	cp = LIST_FIRST(&gp->consumer);
155129471Spjd	error = g_access(cp, dr, dw, de);
156129471Spjd
157129471Spjd	return (error);
158129471Spjd}
159129471Spjd
160129471Spjdstatic int
161129471Spjdg_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
162162142Spjd    int ioerror, u_int rfailprob, u_int wfailprob, off_t offset, off_t size,
163162142Spjd    u_int secsize)
164129471Spjd{
165132381Spjd	struct g_nop_softc *sc;
166129471Spjd	struct g_geom *gp;
167129471Spjd	struct g_provider *newpp;
168129471Spjd	struct g_consumer *cp;
169130191Spjd	char name[64];
170129471Spjd	int error;
171238219Strasz	off_t explicitsize;
172129471Spjd
173129471Spjd	g_topology_assert();
174129471Spjd
175129471Spjd	gp = NULL;
176129471Spjd	newpp = NULL;
177129471Spjd	cp = NULL;
178129471Spjd
179132381Spjd	if ((offset % pp->sectorsize) != 0) {
180132381Spjd		gctl_error(req, "Invalid offset for provider %s.", pp->name);
181132381Spjd		return (EINVAL);
182132381Spjd	}
183132381Spjd	if ((size % pp->sectorsize) != 0) {
184132381Spjd		gctl_error(req, "Invalid size for provider %s.", pp->name);
185132381Spjd		return (EINVAL);
186132381Spjd	}
187132381Spjd	if (offset >= pp->mediasize) {
188132381Spjd		gctl_error(req, "Invalid offset for provider %s.", pp->name);
189132381Spjd		return (EINVAL);
190132381Spjd	}
191238219Strasz	explicitsize = size;
192132381Spjd	if (size == 0)
193132381Spjd		size = pp->mediasize - offset;
194132381Spjd	if (offset + size > pp->mediasize) {
195132381Spjd		gctl_error(req, "Invalid size for provider %s.", pp->name);
196132381Spjd		return (EINVAL);
197132381Spjd	}
198132877Spjd	if (secsize == 0)
199132877Spjd		secsize = pp->sectorsize;
200132877Spjd	else if ((secsize % pp->sectorsize) != 0) {
201132877Spjd		gctl_error(req, "Invalid secsize for provider %s.", pp->name);
202132877Spjd		return (EINVAL);
203132877Spjd	}
204217303Sae	if (secsize > MAXPHYS) {
205217303Sae		gctl_error(req, "secsize is too big.");
206217303Sae		return (EINVAL);
207217303Sae	}
208217263Sae	size -= size % secsize;
209130191Spjd	snprintf(name, sizeof(name), "%s%s", pp->name, G_NOP_SUFFIX);
210130191Spjd	LIST_FOREACH(gp, &mp->geom, geom) {
211130191Spjd		if (strcmp(gp->name, name) == 0) {
212130191Spjd			gctl_error(req, "Provider %s already exists.", name);
213130191Spjd			return (EEXIST);
214130191Spjd		}
215130191Spjd	}
216243333Sjh	gp = g_new_geomf(mp, "%s", name);
217258505Smjg	sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
218132381Spjd	sc->sc_offset = offset;
219238219Strasz	sc->sc_explicitsize = explicitsize;
220162142Spjd	sc->sc_error = ioerror;
221162142Spjd	sc->sc_rfailprob = rfailprob;
222162142Spjd	sc->sc_wfailprob = wfailprob;
223153250Spjd	sc->sc_reads = 0;
224153250Spjd	sc->sc_writes = 0;
225153250Spjd	sc->sc_readbytes = 0;
226153250Spjd	sc->sc_wrotebytes = 0;
227132381Spjd	gp->softc = sc;
228129471Spjd	gp->start = g_nop_start;
229129471Spjd	gp->orphan = g_nop_orphan;
230238219Strasz	gp->resize = g_nop_resize;
231129471Spjd	gp->access = g_nop_access;
232129471Spjd	gp->dumpconf = g_nop_dumpconf;
233129471Spjd
234243333Sjh	newpp = g_new_providerf(gp, "%s", gp->name);
235132381Spjd	newpp->mediasize = size;
236132877Spjd	newpp->sectorsize = secsize;
237129471Spjd
238129471Spjd	cp = g_new_consumer(gp);
239129471Spjd	error = g_attach(cp, pp);
240129471Spjd	if (error != 0) {
241129471Spjd		gctl_error(req, "Cannot attach to provider %s.", pp->name);
242129471Spjd		goto fail;
243129471Spjd	}
244129471Spjd
245248721Smav	newpp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED;
246129471Spjd	g_error_provider(newpp, 0);
247129471Spjd	G_NOP_DEBUG(0, "Device %s created.", gp->name);
248129471Spjd	return (0);
249129471Spjdfail:
250220184Sae	if (cp->provider != NULL)
251220184Sae		g_detach(cp);
252220184Sae	g_destroy_consumer(cp);
253220184Sae	g_destroy_provider(newpp);
254220184Sae	g_free(gp->softc);
255220184Sae	g_destroy_geom(gp);
256129471Spjd	return (error);
257129471Spjd}
258129471Spjd
259129471Spjdstatic int
260129471Spjdg_nop_destroy(struct g_geom *gp, boolean_t force)
261129471Spjd{
262129471Spjd	struct g_provider *pp;
263129471Spjd
264129471Spjd	g_topology_assert();
265132988Spjd	if (gp->softc == NULL)
266132988Spjd		return (ENXIO);
267129471Spjd	pp = LIST_FIRST(&gp->provider);
268129471Spjd	if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
269129471Spjd		if (force) {
270129471Spjd			G_NOP_DEBUG(0, "Device %s is still open, so it "
271129471Spjd			    "can't be definitely removed.", pp->name);
272129471Spjd		} else {
273129471Spjd			G_NOP_DEBUG(1, "Device %s is still open (r%dw%de%d).",
274129471Spjd			    pp->name, pp->acr, pp->acw, pp->ace);
275129471Spjd			return (EBUSY);
276129471Spjd		}
277129471Spjd	} else {
278129471Spjd		G_NOP_DEBUG(0, "Device %s removed.", gp->name);
279129471Spjd	}
280132381Spjd	g_free(gp->softc);
281132381Spjd	gp->softc = NULL;
282129471Spjd	g_wither_geom(gp, ENXIO);
283129471Spjd
284129471Spjd	return (0);
285129471Spjd}
286129471Spjd
287129471Spjdstatic int
288129471Spjdg_nop_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
289129471Spjd{
290129471Spjd
291129471Spjd	return (g_nop_destroy(gp, 0));
292129471Spjd}
293129471Spjd
294129471Spjdstatic void
295129471Spjdg_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
296129471Spjd{
297129471Spjd	struct g_provider *pp;
298162142Spjd	intmax_t *error, *rfailprob, *wfailprob, *offset, *secsize, *size;
299129471Spjd	const char *name;
300129471Spjd	char param[16];
301129471Spjd	int i, *nargs;
302129471Spjd
303129471Spjd	g_topology_assert();
304129471Spjd
305129471Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
306129471Spjd	if (nargs == NULL) {
307129471Spjd		gctl_error(req, "No '%s' argument", "nargs");
308129471Spjd		return;
309129471Spjd	}
310129471Spjd	if (*nargs <= 0) {
311129471Spjd		gctl_error(req, "Missing device(s).");
312129471Spjd		return;
313129471Spjd	}
314162142Spjd	error = gctl_get_paraml(req, "error", sizeof(*error));
315162142Spjd	if (error == NULL) {
316162142Spjd		gctl_error(req, "No '%s' argument", "error");
317129471Spjd		return;
318129471Spjd	}
319162142Spjd	rfailprob = gctl_get_paraml(req, "rfailprob", sizeof(*rfailprob));
320162142Spjd	if (rfailprob == NULL) {
321162142Spjd		gctl_error(req, "No '%s' argument", "rfailprob");
322129471Spjd		return;
323129471Spjd	}
324162142Spjd	if (*rfailprob < -1 || *rfailprob > 100) {
325162142Spjd		gctl_error(req, "Invalid '%s' argument", "rfailprob");
326162142Spjd		return;
327162142Spjd	}
328162142Spjd	wfailprob = gctl_get_paraml(req, "wfailprob", sizeof(*wfailprob));
329162142Spjd	if (wfailprob == NULL) {
330162142Spjd		gctl_error(req, "No '%s' argument", "wfailprob");
331162142Spjd		return;
332162142Spjd	}
333162142Spjd	if (*wfailprob < -1 || *wfailprob > 100) {
334162142Spjd		gctl_error(req, "Invalid '%s' argument", "wfailprob");
335162142Spjd		return;
336162142Spjd	}
337132381Spjd	offset = gctl_get_paraml(req, "offset", sizeof(*offset));
338132381Spjd	if (offset == NULL) {
339132381Spjd		gctl_error(req, "No '%s' argument", "offset");
340132381Spjd		return;
341132381Spjd	}
342132381Spjd	if (*offset < 0) {
343132381Spjd		gctl_error(req, "Invalid '%s' argument", "offset");
344132381Spjd		return;
345132381Spjd	}
346132381Spjd	size = gctl_get_paraml(req, "size", sizeof(*size));
347132381Spjd	if (size == NULL) {
348132381Spjd		gctl_error(req, "No '%s' argument", "size");
349132381Spjd		return;
350132381Spjd	}
351132381Spjd	if (*size < 0) {
352132381Spjd		gctl_error(req, "Invalid '%s' argument", "size");
353132381Spjd		return;
354132381Spjd	}
355132877Spjd	secsize = gctl_get_paraml(req, "secsize", sizeof(*secsize));
356132877Spjd	if (secsize == NULL) {
357132877Spjd		gctl_error(req, "No '%s' argument", "secsize");
358132877Spjd		return;
359132877Spjd	}
360132877Spjd	if (*secsize < 0) {
361132877Spjd		gctl_error(req, "Invalid '%s' argument", "secsize");
362132877Spjd		return;
363132877Spjd	}
364129471Spjd
365129471Spjd	for (i = 0; i < *nargs; i++) {
366129471Spjd		snprintf(param, sizeof(param), "arg%d", i);
367155174Spjd		name = gctl_get_asciiparam(req, param);
368129471Spjd		if (name == NULL) {
369129471Spjd			gctl_error(req, "No 'arg%d' argument", i);
370129471Spjd			return;
371129471Spjd		}
372129471Spjd		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
373129471Spjd			name += strlen("/dev/");
374129471Spjd		pp = g_provider_by_name(name);
375129471Spjd		if (pp == NULL) {
376129471Spjd			G_NOP_DEBUG(1, "Provider %s is invalid.", name);
377129471Spjd			gctl_error(req, "Provider %s is invalid.", name);
378155174Spjd			return;
379129471Spjd		}
380162142Spjd		if (g_nop_create(req, mp, pp,
381162142Spjd		    *error == -1 ? EIO : (int)*error,
382162142Spjd		    *rfailprob == -1 ? 0 : (u_int)*rfailprob,
383162142Spjd		    *wfailprob == -1 ? 0 : (u_int)*wfailprob,
384162142Spjd		    (off_t)*offset, (off_t)*size, (u_int)*secsize) != 0) {
385129471Spjd			return;
386132381Spjd		}
387129471Spjd	}
388129471Spjd}
389129471Spjd
390129471Spjdstatic void
391129548Spjdg_nop_ctl_configure(struct gctl_req *req, struct g_class *mp)
392129471Spjd{
393132381Spjd	struct g_nop_softc *sc;
394129471Spjd	struct g_provider *pp;
395162142Spjd	intmax_t *error, *rfailprob, *wfailprob;
396129471Spjd	const char *name;
397129471Spjd	char param[16];
398129471Spjd	int i, *nargs;
399129471Spjd
400129471Spjd	g_topology_assert();
401129471Spjd
402129471Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
403129471Spjd	if (nargs == NULL) {
404129471Spjd		gctl_error(req, "No '%s' argument", "nargs");
405129471Spjd		return;
406129471Spjd	}
407129471Spjd	if (*nargs <= 0) {
408129471Spjd		gctl_error(req, "Missing device(s).");
409129471Spjd		return;
410129471Spjd	}
411162142Spjd	error = gctl_get_paraml(req, "error", sizeof(*error));
412162142Spjd	if (error == NULL) {
413162142Spjd		gctl_error(req, "No '%s' argument", "error");
414129471Spjd		return;
415129471Spjd	}
416162142Spjd	rfailprob = gctl_get_paraml(req, "rfailprob", sizeof(*rfailprob));
417162142Spjd	if (rfailprob == NULL) {
418162142Spjd		gctl_error(req, "No '%s' argument", "rfailprob");
419129471Spjd		return;
420129471Spjd	}
421162142Spjd	if (*rfailprob < -1 || *rfailprob > 100) {
422162142Spjd		gctl_error(req, "Invalid '%s' argument", "rfailprob");
423162142Spjd		return;
424162142Spjd	}
425162142Spjd	wfailprob = gctl_get_paraml(req, "wfailprob", sizeof(*wfailprob));
426162142Spjd	if (wfailprob == NULL) {
427162142Spjd		gctl_error(req, "No '%s' argument", "wfailprob");
428162142Spjd		return;
429162142Spjd	}
430162142Spjd	if (*wfailprob < -1 || *wfailprob > 100) {
431162142Spjd		gctl_error(req, "Invalid '%s' argument", "wfailprob");
432162142Spjd		return;
433162142Spjd	}
434129471Spjd
435129471Spjd	for (i = 0; i < *nargs; i++) {
436129471Spjd		snprintf(param, sizeof(param), "arg%d", i);
437155174Spjd		name = gctl_get_asciiparam(req, param);
438129471Spjd		if (name == NULL) {
439129471Spjd			gctl_error(req, "No 'arg%d' argument", i);
440129471Spjd			return;
441129471Spjd		}
442129471Spjd		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
443129471Spjd			name += strlen("/dev/");
444129471Spjd		pp = g_provider_by_name(name);
445129471Spjd		if (pp == NULL || pp->geom->class != mp) {
446129471Spjd			G_NOP_DEBUG(1, "Provider %s is invalid.", name);
447129471Spjd			gctl_error(req, "Provider %s is invalid.", name);
448155174Spjd			return;
449129471Spjd		}
450132381Spjd		sc = pp->geom->softc;
451162142Spjd		if (*error != -1)
452162142Spjd			sc->sc_error = (int)*error;
453162142Spjd		if (*rfailprob != -1)
454162142Spjd			sc->sc_rfailprob = (u_int)*rfailprob;
455162142Spjd		if (*wfailprob != -1)
456162142Spjd			sc->sc_wfailprob = (u_int)*wfailprob;
457129471Spjd	}
458129471Spjd}
459129471Spjd
460129471Spjdstatic struct g_geom *
461129471Spjdg_nop_find_geom(struct g_class *mp, const char *name)
462129471Spjd{
463129471Spjd	struct g_geom *gp;
464129471Spjd
465129471Spjd	LIST_FOREACH(gp, &mp->geom, geom) {
466129471Spjd		if (strcmp(gp->name, name) == 0)
467129471Spjd			return (gp);
468129471Spjd	}
469129471Spjd	return (NULL);
470129471Spjd}
471129471Spjd
472129471Spjdstatic void
473129471Spjdg_nop_ctl_destroy(struct gctl_req *req, struct g_class *mp)
474129471Spjd{
475129471Spjd	int *nargs, *force, error, i;
476129471Spjd	struct g_geom *gp;
477129471Spjd	const char *name;
478129471Spjd	char param[16];
479129471Spjd
480129471Spjd	g_topology_assert();
481129471Spjd
482129471Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
483129471Spjd	if (nargs == NULL) {
484129471Spjd		gctl_error(req, "No '%s' argument", "nargs");
485129471Spjd		return;
486129471Spjd	}
487129471Spjd	if (*nargs <= 0) {
488129471Spjd		gctl_error(req, "Missing device(s).");
489129471Spjd		return;
490129471Spjd	}
491129471Spjd	force = gctl_get_paraml(req, "force", sizeof(*force));
492129471Spjd	if (force == NULL) {
493129471Spjd		gctl_error(req, "No 'force' argument");
494129471Spjd		return;
495129471Spjd	}
496129471Spjd
497129471Spjd	for (i = 0; i < *nargs; i++) {
498129471Spjd		snprintf(param, sizeof(param), "arg%d", i);
499155174Spjd		name = gctl_get_asciiparam(req, param);
500129471Spjd		if (name == NULL) {
501129471Spjd			gctl_error(req, "No 'arg%d' argument", i);
502129471Spjd			return;
503129471Spjd		}
504129471Spjd		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
505129471Spjd			name += strlen("/dev/");
506129471Spjd		gp = g_nop_find_geom(mp, name);
507129471Spjd		if (gp == NULL) {
508129471Spjd			G_NOP_DEBUG(1, "Device %s is invalid.", name);
509129471Spjd			gctl_error(req, "Device %s is invalid.", name);
510155174Spjd			return;
511129471Spjd		}
512129471Spjd		error = g_nop_destroy(gp, *force);
513129471Spjd		if (error != 0) {
514129471Spjd			gctl_error(req, "Cannot destroy device %s (error=%d).",
515129471Spjd			    gp->name, error);
516129471Spjd			return;
517129471Spjd		}
518129471Spjd	}
519129471Spjd}
520129471Spjd
521129471Spjdstatic void
522153250Spjdg_nop_ctl_reset(struct gctl_req *req, struct g_class *mp)
523153250Spjd{
524153250Spjd	struct g_nop_softc *sc;
525153250Spjd	struct g_provider *pp;
526153250Spjd	const char *name;
527153250Spjd	char param[16];
528153250Spjd	int i, *nargs;
529153250Spjd
530153250Spjd	g_topology_assert();
531153250Spjd
532153250Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
533153250Spjd	if (nargs == NULL) {
534153250Spjd		gctl_error(req, "No '%s' argument", "nargs");
535153250Spjd		return;
536153250Spjd	}
537153250Spjd	if (*nargs <= 0) {
538153250Spjd		gctl_error(req, "Missing device(s).");
539153250Spjd		return;
540153250Spjd	}
541153250Spjd
542153250Spjd	for (i = 0; i < *nargs; i++) {
543153250Spjd		snprintf(param, sizeof(param), "arg%d", i);
544155174Spjd		name = gctl_get_asciiparam(req, param);
545153250Spjd		if (name == NULL) {
546153250Spjd			gctl_error(req, "No 'arg%d' argument", i);
547153250Spjd			return;
548153250Spjd		}
549153250Spjd		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
550153250Spjd			name += strlen("/dev/");
551153250Spjd		pp = g_provider_by_name(name);
552153250Spjd		if (pp == NULL || pp->geom->class != mp) {
553153250Spjd			G_NOP_DEBUG(1, "Provider %s is invalid.", name);
554153250Spjd			gctl_error(req, "Provider %s is invalid.", name);
555155174Spjd			return;
556153250Spjd		}
557153250Spjd		sc = pp->geom->softc;
558153250Spjd		sc->sc_reads = 0;
559153250Spjd		sc->sc_writes = 0;
560153250Spjd		sc->sc_readbytes = 0;
561153250Spjd		sc->sc_wrotebytes = 0;
562153250Spjd	}
563153250Spjd}
564153250Spjd
565153250Spjdstatic void
566129471Spjdg_nop_config(struct gctl_req *req, struct g_class *mp, const char *verb)
567129471Spjd{
568129471Spjd	uint32_t *version;
569129471Spjd
570129471Spjd	g_topology_assert();
571129471Spjd
572129471Spjd	version = gctl_get_paraml(req, "version", sizeof(*version));
573129471Spjd	if (version == NULL) {
574129471Spjd		gctl_error(req, "No '%s' argument.", "version");
575129471Spjd		return;
576129471Spjd	}
577129471Spjd	if (*version != G_NOP_VERSION) {
578129471Spjd		gctl_error(req, "Userland and kernel parts are out of sync.");
579129471Spjd		return;
580129471Spjd	}
581129471Spjd
582129471Spjd	if (strcmp(verb, "create") == 0) {
583129471Spjd		g_nop_ctl_create(req, mp);
584129471Spjd		return;
585129548Spjd	} else if (strcmp(verb, "configure") == 0) {
586129548Spjd		g_nop_ctl_configure(req, mp);
587129471Spjd		return;
588129471Spjd	} else if (strcmp(verb, "destroy") == 0) {
589129471Spjd		g_nop_ctl_destroy(req, mp);
590129471Spjd		return;
591153250Spjd	} else if (strcmp(verb, "reset") == 0) {
592153250Spjd		g_nop_ctl_reset(req, mp);
593153250Spjd		return;
594129471Spjd	}
595129471Spjd
596129471Spjd	gctl_error(req, "Unknown verb.");
597129471Spjd}
598129471Spjd
599129471Spjdstatic void
600129471Spjdg_nop_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
601129471Spjd    struct g_consumer *cp, struct g_provider *pp)
602129471Spjd{
603132381Spjd	struct g_nop_softc *sc;
604129471Spjd
605132665Spjd	if (pp != NULL || cp != NULL)
606132381Spjd		return;
607132381Spjd	sc = gp->softc;
608132665Spjd	sbuf_printf(sb, "%s<Offset>%jd</Offset>\n", indent,
609132381Spjd	    (intmax_t)sc->sc_offset);
610162142Spjd	sbuf_printf(sb, "%s<ReadFailProb>%u</ReadFailProb>\n", indent,
611162142Spjd	    sc->sc_rfailprob);
612162142Spjd	sbuf_printf(sb, "%s<WriteFailProb>%u</WriteFailProb>\n", indent,
613162142Spjd	    sc->sc_wfailprob);
614162153Spjd	sbuf_printf(sb, "%s<Error>%d</Error>\n", indent, sc->sc_error);
615153250Spjd	sbuf_printf(sb, "%s<Reads>%ju</Reads>\n", indent, sc->sc_reads);
616153250Spjd	sbuf_printf(sb, "%s<Writes>%ju</Writes>\n", indent, sc->sc_writes);
617153532Spjd	sbuf_printf(sb, "%s<ReadBytes>%ju</ReadBytes>\n", indent,
618153250Spjd	    sc->sc_readbytes);
619153250Spjd	sbuf_printf(sb, "%s<WroteBytes>%ju</WroteBytes>\n", indent,
620153265Spjd	    sc->sc_wrotebytes);
621129471Spjd}
622129471Spjd
623129471SpjdDECLARE_GEOM_CLASS(g_nop_class, g_nop);
624