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: releng/10.3/sys/geom/nop/g_nop.c 293738 2016-01-12 09:27:01Z trasz $");
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.");
110260385Sscottl	mtx_lock(&sc->sc_lock);
111153250Spjd	switch (bp->bio_cmd) {
112153250Spjd	case BIO_READ:
113153250Spjd		sc->sc_reads++;
114153250Spjd		sc->sc_readbytes += bp->bio_length;
115162142Spjd		failprob = sc->sc_rfailprob;
116153250Spjd		break;
117153250Spjd	case BIO_WRITE:
118153250Spjd		sc->sc_writes++;
119153250Spjd		sc->sc_wrotebytes += bp->bio_length;
120162142Spjd		failprob = sc->sc_wfailprob;
121153250Spjd		break;
122293738Strasz	case BIO_DELETE:
123293738Strasz		sc->sc_deletes++;
124293738Strasz		break;
125293738Strasz	case BIO_GETATTR:
126293738Strasz		sc->sc_getattrs++;
127293738Strasz		break;
128293738Strasz	case BIO_FLUSH:
129293738Strasz		sc->sc_flushes++;
130293738Strasz		break;
131293738Strasz	case BIO_CMD0:
132293738Strasz		sc->sc_cmd0s++;
133293738Strasz		break;
134293738Strasz	case BIO_CMD1:
135293738Strasz		sc->sc_cmd1s++;
136293738Strasz		break;
137293738Strasz	case BIO_CMD2:
138293738Strasz		sc->sc_cmd2s++;
139293738Strasz		break;
140153250Spjd	}
141260385Sscottl	mtx_unlock(&sc->sc_lock);
142162142Spjd	if (failprob > 0) {
143129471Spjd		u_int rval;
144129471Spjd
145129471Spjd		rval = arc4random() % 100;
146162142Spjd		if (rval < failprob) {
147249440Sjmg			G_NOP_LOGREQLVL(1, bp, "Returning error=%d.", sc->sc_error);
148162142Spjd			g_io_deliver(bp, sc->sc_error);
149129471Spjd			return;
150129471Spjd		}
151129471Spjd	}
152154458Spjd	cbp = g_clone_bio(bp);
153154458Spjd	if (cbp == NULL) {
154154458Spjd		g_io_deliver(bp, ENOMEM);
155154458Spjd		return;
156154458Spjd	}
157129471Spjd	cbp->bio_done = g_std_done;
158132381Spjd	cbp->bio_offset = bp->bio_offset + sc->sc_offset;
159132988Spjd	pp = LIST_FIRST(&gp->provider);
160132988Spjd	KASSERT(pp != NULL, ("NULL pp"));
161132988Spjd	cbp->bio_to = pp;
162129471Spjd	G_NOP_LOGREQ(cbp, "Sending request.");
163129471Spjd	g_io_request(cbp, LIST_FIRST(&gp->consumer));
164129471Spjd}
165129471Spjd
166129471Spjdstatic int
167129471Spjdg_nop_access(struct g_provider *pp, int dr, int dw, int de)
168129471Spjd{
169129471Spjd	struct g_geom *gp;
170129471Spjd	struct g_consumer *cp;
171129471Spjd	int error;
172129471Spjd
173129471Spjd	gp = pp->geom;
174129471Spjd	cp = LIST_FIRST(&gp->consumer);
175129471Spjd	error = g_access(cp, dr, dw, de);
176129471Spjd
177129471Spjd	return (error);
178129471Spjd}
179129471Spjd
180129471Spjdstatic int
181129471Spjdg_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
182162142Spjd    int ioerror, u_int rfailprob, u_int wfailprob, off_t offset, off_t size,
183289520Strasz    u_int secsize, u_int stripesize, u_int stripeoffset)
184129471Spjd{
185132381Spjd	struct g_nop_softc *sc;
186129471Spjd	struct g_geom *gp;
187129471Spjd	struct g_provider *newpp;
188129471Spjd	struct g_consumer *cp;
189130191Spjd	char name[64];
190129471Spjd	int error;
191238219Strasz	off_t explicitsize;
192129471Spjd
193129471Spjd	g_topology_assert();
194129471Spjd
195129471Spjd	gp = NULL;
196129471Spjd	newpp = NULL;
197129471Spjd	cp = NULL;
198129471Spjd
199132381Spjd	if ((offset % pp->sectorsize) != 0) {
200132381Spjd		gctl_error(req, "Invalid offset for provider %s.", pp->name);
201132381Spjd		return (EINVAL);
202132381Spjd	}
203132381Spjd	if ((size % pp->sectorsize) != 0) {
204132381Spjd		gctl_error(req, "Invalid size for provider %s.", pp->name);
205132381Spjd		return (EINVAL);
206132381Spjd	}
207132381Spjd	if (offset >= pp->mediasize) {
208132381Spjd		gctl_error(req, "Invalid offset for provider %s.", pp->name);
209132381Spjd		return (EINVAL);
210132381Spjd	}
211238219Strasz	explicitsize = size;
212132381Spjd	if (size == 0)
213132381Spjd		size = pp->mediasize - offset;
214132381Spjd	if (offset + size > pp->mediasize) {
215132381Spjd		gctl_error(req, "Invalid size for provider %s.", pp->name);
216132381Spjd		return (EINVAL);
217132381Spjd	}
218132877Spjd	if (secsize == 0)
219132877Spjd		secsize = pp->sectorsize;
220132877Spjd	else if ((secsize % pp->sectorsize) != 0) {
221132877Spjd		gctl_error(req, "Invalid secsize for provider %s.", pp->name);
222132877Spjd		return (EINVAL);
223132877Spjd	}
224217303Sae	if (secsize > MAXPHYS) {
225217303Sae		gctl_error(req, "secsize is too big.");
226217303Sae		return (EINVAL);
227217303Sae	}
228217263Sae	size -= size % secsize;
229289520Strasz	if ((stripesize % pp->sectorsize) != 0) {
230289520Strasz		gctl_error(req, "Invalid stripesize for provider %s.", pp->name);
231289520Strasz		return (EINVAL);
232289520Strasz	}
233289520Strasz	if ((stripeoffset % pp->sectorsize) != 0) {
234289520Strasz		gctl_error(req, "Invalid stripeoffset for provider %s.", pp->name);
235289520Strasz		return (EINVAL);
236289520Strasz	}
237289520Strasz	if (stripesize != 0 && stripeoffset >= stripesize) {
238289520Strasz		gctl_error(req, "stripeoffset is too big.");
239289520Strasz		return (EINVAL);
240289520Strasz	}
241130191Spjd	snprintf(name, sizeof(name), "%s%s", pp->name, G_NOP_SUFFIX);
242130191Spjd	LIST_FOREACH(gp, &mp->geom, geom) {
243130191Spjd		if (strcmp(gp->name, name) == 0) {
244130191Spjd			gctl_error(req, "Provider %s already exists.", name);
245130191Spjd			return (EEXIST);
246130191Spjd		}
247130191Spjd	}
248243333Sjh	gp = g_new_geomf(mp, "%s", name);
249258505Smjg	sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
250132381Spjd	sc->sc_offset = offset;
251238219Strasz	sc->sc_explicitsize = explicitsize;
252289520Strasz	sc->sc_stripesize = stripesize;
253289520Strasz	sc->sc_stripeoffset = stripeoffset;
254162142Spjd	sc->sc_error = ioerror;
255162142Spjd	sc->sc_rfailprob = rfailprob;
256162142Spjd	sc->sc_wfailprob = wfailprob;
257153250Spjd	sc->sc_reads = 0;
258153250Spjd	sc->sc_writes = 0;
259293738Strasz	sc->sc_deletes = 0;
260293738Strasz	sc->sc_getattrs = 0;
261293738Strasz	sc->sc_flushes = 0;
262293738Strasz	sc->sc_cmd0s = 0;
263293738Strasz	sc->sc_cmd1s = 0;
264293738Strasz	sc->sc_cmd2s = 0;
265153250Spjd	sc->sc_readbytes = 0;
266153250Spjd	sc->sc_wrotebytes = 0;
267260385Sscottl	mtx_init(&sc->sc_lock, "gnop lock", NULL, MTX_DEF);
268132381Spjd	gp->softc = sc;
269129471Spjd	gp->start = g_nop_start;
270129471Spjd	gp->orphan = g_nop_orphan;
271238219Strasz	gp->resize = g_nop_resize;
272129471Spjd	gp->access = g_nop_access;
273129471Spjd	gp->dumpconf = g_nop_dumpconf;
274129471Spjd
275243333Sjh	newpp = g_new_providerf(gp, "%s", gp->name);
276260385Sscottl	newpp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
277132381Spjd	newpp->mediasize = size;
278132877Spjd	newpp->sectorsize = secsize;
279289520Strasz	newpp->stripesize = stripesize;
280289520Strasz	newpp->stripeoffset = stripeoffset;
281129471Spjd
282129471Spjd	cp = g_new_consumer(gp);
283260385Sscottl	cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
284129471Spjd	error = g_attach(cp, pp);
285129471Spjd	if (error != 0) {
286129471Spjd		gctl_error(req, "Cannot attach to provider %s.", pp->name);
287129471Spjd		goto fail;
288129471Spjd	}
289129471Spjd
290248721Smav	newpp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED;
291129471Spjd	g_error_provider(newpp, 0);
292129471Spjd	G_NOP_DEBUG(0, "Device %s created.", gp->name);
293129471Spjd	return (0);
294129471Spjdfail:
295220184Sae	if (cp->provider != NULL)
296220184Sae		g_detach(cp);
297220184Sae	g_destroy_consumer(cp);
298220184Sae	g_destroy_provider(newpp);
299260385Sscottl	mtx_destroy(&sc->sc_lock);
300220184Sae	g_free(gp->softc);
301220184Sae	g_destroy_geom(gp);
302129471Spjd	return (error);
303129471Spjd}
304129471Spjd
305129471Spjdstatic int
306129471Spjdg_nop_destroy(struct g_geom *gp, boolean_t force)
307129471Spjd{
308260385Sscottl	struct g_nop_softc *sc;
309129471Spjd	struct g_provider *pp;
310129471Spjd
311129471Spjd	g_topology_assert();
312260385Sscottl	sc = gp->softc;
313260385Sscottl	if (sc == NULL)
314132988Spjd		return (ENXIO);
315129471Spjd	pp = LIST_FIRST(&gp->provider);
316129471Spjd	if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
317129471Spjd		if (force) {
318129471Spjd			G_NOP_DEBUG(0, "Device %s is still open, so it "
319129471Spjd			    "can't be definitely removed.", pp->name);
320129471Spjd		} else {
321129471Spjd			G_NOP_DEBUG(1, "Device %s is still open (r%dw%de%d).",
322129471Spjd			    pp->name, pp->acr, pp->acw, pp->ace);
323129471Spjd			return (EBUSY);
324129471Spjd		}
325129471Spjd	} else {
326129471Spjd		G_NOP_DEBUG(0, "Device %s removed.", gp->name);
327129471Spjd	}
328132381Spjd	gp->softc = NULL;
329260385Sscottl	mtx_destroy(&sc->sc_lock);
330260385Sscottl	g_free(sc);
331129471Spjd	g_wither_geom(gp, ENXIO);
332129471Spjd
333129471Spjd	return (0);
334129471Spjd}
335129471Spjd
336129471Spjdstatic int
337129471Spjdg_nop_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
338129471Spjd{
339129471Spjd
340129471Spjd	return (g_nop_destroy(gp, 0));
341129471Spjd}
342129471Spjd
343129471Spjdstatic void
344129471Spjdg_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
345129471Spjd{
346129471Spjd	struct g_provider *pp;
347289520Strasz	intmax_t *error, *rfailprob, *wfailprob, *offset, *secsize, *size,
348289520Strasz	    *stripesize, *stripeoffset;
349129471Spjd	const char *name;
350129471Spjd	char param[16];
351129471Spjd	int i, *nargs;
352129471Spjd
353129471Spjd	g_topology_assert();
354129471Spjd
355129471Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
356129471Spjd	if (nargs == NULL) {
357129471Spjd		gctl_error(req, "No '%s' argument", "nargs");
358129471Spjd		return;
359129471Spjd	}
360129471Spjd	if (*nargs <= 0) {
361129471Spjd		gctl_error(req, "Missing device(s).");
362129471Spjd		return;
363129471Spjd	}
364162142Spjd	error = gctl_get_paraml(req, "error", sizeof(*error));
365162142Spjd	if (error == NULL) {
366162142Spjd		gctl_error(req, "No '%s' argument", "error");
367129471Spjd		return;
368129471Spjd	}
369162142Spjd	rfailprob = gctl_get_paraml(req, "rfailprob", sizeof(*rfailprob));
370162142Spjd	if (rfailprob == NULL) {
371162142Spjd		gctl_error(req, "No '%s' argument", "rfailprob");
372129471Spjd		return;
373129471Spjd	}
374162142Spjd	if (*rfailprob < -1 || *rfailprob > 100) {
375162142Spjd		gctl_error(req, "Invalid '%s' argument", "rfailprob");
376162142Spjd		return;
377162142Spjd	}
378162142Spjd	wfailprob = gctl_get_paraml(req, "wfailprob", sizeof(*wfailprob));
379162142Spjd	if (wfailprob == NULL) {
380162142Spjd		gctl_error(req, "No '%s' argument", "wfailprob");
381162142Spjd		return;
382162142Spjd	}
383162142Spjd	if (*wfailprob < -1 || *wfailprob > 100) {
384162142Spjd		gctl_error(req, "Invalid '%s' argument", "wfailprob");
385162142Spjd		return;
386162142Spjd	}
387132381Spjd	offset = gctl_get_paraml(req, "offset", sizeof(*offset));
388132381Spjd	if (offset == NULL) {
389132381Spjd		gctl_error(req, "No '%s' argument", "offset");
390132381Spjd		return;
391132381Spjd	}
392132381Spjd	if (*offset < 0) {
393132381Spjd		gctl_error(req, "Invalid '%s' argument", "offset");
394132381Spjd		return;
395132381Spjd	}
396132381Spjd	size = gctl_get_paraml(req, "size", sizeof(*size));
397132381Spjd	if (size == NULL) {
398132381Spjd		gctl_error(req, "No '%s' argument", "size");
399132381Spjd		return;
400132381Spjd	}
401132381Spjd	if (*size < 0) {
402132381Spjd		gctl_error(req, "Invalid '%s' argument", "size");
403132381Spjd		return;
404132381Spjd	}
405132877Spjd	secsize = gctl_get_paraml(req, "secsize", sizeof(*secsize));
406132877Spjd	if (secsize == NULL) {
407132877Spjd		gctl_error(req, "No '%s' argument", "secsize");
408132877Spjd		return;
409132877Spjd	}
410132877Spjd	if (*secsize < 0) {
411132877Spjd		gctl_error(req, "Invalid '%s' argument", "secsize");
412132877Spjd		return;
413132877Spjd	}
414289520Strasz	stripesize = gctl_get_paraml(req, "stripesize", sizeof(*stripesize));
415289520Strasz	if (stripesize == NULL) {
416289520Strasz		gctl_error(req, "No '%s' argument", "stripesize");
417289520Strasz		return;
418289520Strasz	}
419289520Strasz	if (*stripesize < 0) {
420289520Strasz		gctl_error(req, "Invalid '%s' argument", "stripesize");
421289520Strasz		return;
422289520Strasz	}
423289520Strasz	stripeoffset = gctl_get_paraml(req, "stripeoffset", sizeof(*stripeoffset));
424289520Strasz	if (stripeoffset == NULL) {
425289520Strasz		gctl_error(req, "No '%s' argument", "stripeoffset");
426289520Strasz		return;
427289520Strasz	}
428289520Strasz	if (*stripeoffset < 0) {
429289520Strasz		gctl_error(req, "Invalid '%s' argument", "stripeoffset");
430289520Strasz		return;
431289520Strasz	}
432129471Spjd
433129471Spjd	for (i = 0; i < *nargs; i++) {
434129471Spjd		snprintf(param, sizeof(param), "arg%d", i);
435155174Spjd		name = gctl_get_asciiparam(req, param);
436129471Spjd		if (name == NULL) {
437129471Spjd			gctl_error(req, "No 'arg%d' argument", i);
438129471Spjd			return;
439129471Spjd		}
440129471Spjd		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
441129471Spjd			name += strlen("/dev/");
442129471Spjd		pp = g_provider_by_name(name);
443129471Spjd		if (pp == NULL) {
444129471Spjd			G_NOP_DEBUG(1, "Provider %s is invalid.", name);
445129471Spjd			gctl_error(req, "Provider %s is invalid.", name);
446155174Spjd			return;
447129471Spjd		}
448162142Spjd		if (g_nop_create(req, mp, pp,
449162142Spjd		    *error == -1 ? EIO : (int)*error,
450162142Spjd		    *rfailprob == -1 ? 0 : (u_int)*rfailprob,
451162142Spjd		    *wfailprob == -1 ? 0 : (u_int)*wfailprob,
452289520Strasz		    (off_t)*offset, (off_t)*size, (u_int)*secsize,
453289520Strasz		    (u_int)*stripesize, (u_int)*stripeoffset) != 0) {
454129471Spjd			return;
455132381Spjd		}
456129471Spjd	}
457129471Spjd}
458129471Spjd
459129471Spjdstatic void
460129548Spjdg_nop_ctl_configure(struct gctl_req *req, struct g_class *mp)
461129471Spjd{
462132381Spjd	struct g_nop_softc *sc;
463129471Spjd	struct g_provider *pp;
464162142Spjd	intmax_t *error, *rfailprob, *wfailprob;
465129471Spjd	const char *name;
466129471Spjd	char param[16];
467129471Spjd	int i, *nargs;
468129471Spjd
469129471Spjd	g_topology_assert();
470129471Spjd
471129471Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
472129471Spjd	if (nargs == NULL) {
473129471Spjd		gctl_error(req, "No '%s' argument", "nargs");
474129471Spjd		return;
475129471Spjd	}
476129471Spjd	if (*nargs <= 0) {
477129471Spjd		gctl_error(req, "Missing device(s).");
478129471Spjd		return;
479129471Spjd	}
480162142Spjd	error = gctl_get_paraml(req, "error", sizeof(*error));
481162142Spjd	if (error == NULL) {
482162142Spjd		gctl_error(req, "No '%s' argument", "error");
483129471Spjd		return;
484129471Spjd	}
485162142Spjd	rfailprob = gctl_get_paraml(req, "rfailprob", sizeof(*rfailprob));
486162142Spjd	if (rfailprob == NULL) {
487162142Spjd		gctl_error(req, "No '%s' argument", "rfailprob");
488129471Spjd		return;
489129471Spjd	}
490162142Spjd	if (*rfailprob < -1 || *rfailprob > 100) {
491162142Spjd		gctl_error(req, "Invalid '%s' argument", "rfailprob");
492162142Spjd		return;
493162142Spjd	}
494162142Spjd	wfailprob = gctl_get_paraml(req, "wfailprob", sizeof(*wfailprob));
495162142Spjd	if (wfailprob == NULL) {
496162142Spjd		gctl_error(req, "No '%s' argument", "wfailprob");
497162142Spjd		return;
498162142Spjd	}
499162142Spjd	if (*wfailprob < -1 || *wfailprob > 100) {
500162142Spjd		gctl_error(req, "Invalid '%s' argument", "wfailprob");
501162142Spjd		return;
502162142Spjd	}
503129471Spjd
504129471Spjd	for (i = 0; i < *nargs; i++) {
505129471Spjd		snprintf(param, sizeof(param), "arg%d", i);
506155174Spjd		name = gctl_get_asciiparam(req, param);
507129471Spjd		if (name == NULL) {
508129471Spjd			gctl_error(req, "No 'arg%d' argument", i);
509129471Spjd			return;
510129471Spjd		}
511129471Spjd		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
512129471Spjd			name += strlen("/dev/");
513129471Spjd		pp = g_provider_by_name(name);
514129471Spjd		if (pp == NULL || pp->geom->class != mp) {
515129471Spjd			G_NOP_DEBUG(1, "Provider %s is invalid.", name);
516129471Spjd			gctl_error(req, "Provider %s is invalid.", name);
517155174Spjd			return;
518129471Spjd		}
519132381Spjd		sc = pp->geom->softc;
520162142Spjd		if (*error != -1)
521162142Spjd			sc->sc_error = (int)*error;
522162142Spjd		if (*rfailprob != -1)
523162142Spjd			sc->sc_rfailprob = (u_int)*rfailprob;
524162142Spjd		if (*wfailprob != -1)
525162142Spjd			sc->sc_wfailprob = (u_int)*wfailprob;
526129471Spjd	}
527129471Spjd}
528129471Spjd
529129471Spjdstatic struct g_geom *
530129471Spjdg_nop_find_geom(struct g_class *mp, const char *name)
531129471Spjd{
532129471Spjd	struct g_geom *gp;
533129471Spjd
534129471Spjd	LIST_FOREACH(gp, &mp->geom, geom) {
535129471Spjd		if (strcmp(gp->name, name) == 0)
536129471Spjd			return (gp);
537129471Spjd	}
538129471Spjd	return (NULL);
539129471Spjd}
540129471Spjd
541129471Spjdstatic void
542129471Spjdg_nop_ctl_destroy(struct gctl_req *req, struct g_class *mp)
543129471Spjd{
544129471Spjd	int *nargs, *force, error, i;
545129471Spjd	struct g_geom *gp;
546129471Spjd	const char *name;
547129471Spjd	char param[16];
548129471Spjd
549129471Spjd	g_topology_assert();
550129471Spjd
551129471Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
552129471Spjd	if (nargs == NULL) {
553129471Spjd		gctl_error(req, "No '%s' argument", "nargs");
554129471Spjd		return;
555129471Spjd	}
556129471Spjd	if (*nargs <= 0) {
557129471Spjd		gctl_error(req, "Missing device(s).");
558129471Spjd		return;
559129471Spjd	}
560129471Spjd	force = gctl_get_paraml(req, "force", sizeof(*force));
561129471Spjd	if (force == NULL) {
562129471Spjd		gctl_error(req, "No 'force' argument");
563129471Spjd		return;
564129471Spjd	}
565129471Spjd
566129471Spjd	for (i = 0; i < *nargs; i++) {
567129471Spjd		snprintf(param, sizeof(param), "arg%d", i);
568155174Spjd		name = gctl_get_asciiparam(req, param);
569129471Spjd		if (name == NULL) {
570129471Spjd			gctl_error(req, "No 'arg%d' argument", i);
571129471Spjd			return;
572129471Spjd		}
573129471Spjd		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
574129471Spjd			name += strlen("/dev/");
575129471Spjd		gp = g_nop_find_geom(mp, name);
576129471Spjd		if (gp == NULL) {
577129471Spjd			G_NOP_DEBUG(1, "Device %s is invalid.", name);
578129471Spjd			gctl_error(req, "Device %s is invalid.", name);
579155174Spjd			return;
580129471Spjd		}
581129471Spjd		error = g_nop_destroy(gp, *force);
582129471Spjd		if (error != 0) {
583129471Spjd			gctl_error(req, "Cannot destroy device %s (error=%d).",
584129471Spjd			    gp->name, error);
585129471Spjd			return;
586129471Spjd		}
587129471Spjd	}
588129471Spjd}
589129471Spjd
590129471Spjdstatic void
591153250Spjdg_nop_ctl_reset(struct gctl_req *req, struct g_class *mp)
592153250Spjd{
593153250Spjd	struct g_nop_softc *sc;
594153250Spjd	struct g_provider *pp;
595153250Spjd	const char *name;
596153250Spjd	char param[16];
597153250Spjd	int i, *nargs;
598153250Spjd
599153250Spjd	g_topology_assert();
600153250Spjd
601153250Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
602153250Spjd	if (nargs == NULL) {
603153250Spjd		gctl_error(req, "No '%s' argument", "nargs");
604153250Spjd		return;
605153250Spjd	}
606153250Spjd	if (*nargs <= 0) {
607153250Spjd		gctl_error(req, "Missing device(s).");
608153250Spjd		return;
609153250Spjd	}
610153250Spjd
611153250Spjd	for (i = 0; i < *nargs; i++) {
612153250Spjd		snprintf(param, sizeof(param), "arg%d", i);
613155174Spjd		name = gctl_get_asciiparam(req, param);
614153250Spjd		if (name == NULL) {
615153250Spjd			gctl_error(req, "No 'arg%d' argument", i);
616153250Spjd			return;
617153250Spjd		}
618153250Spjd		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
619153250Spjd			name += strlen("/dev/");
620153250Spjd		pp = g_provider_by_name(name);
621153250Spjd		if (pp == NULL || pp->geom->class != mp) {
622153250Spjd			G_NOP_DEBUG(1, "Provider %s is invalid.", name);
623153250Spjd			gctl_error(req, "Provider %s is invalid.", name);
624155174Spjd			return;
625153250Spjd		}
626153250Spjd		sc = pp->geom->softc;
627153250Spjd		sc->sc_reads = 0;
628153250Spjd		sc->sc_writes = 0;
629293738Strasz		sc->sc_deletes = 0;
630293738Strasz		sc->sc_getattrs = 0;
631293738Strasz		sc->sc_flushes = 0;
632293738Strasz		sc->sc_cmd0s = 0;
633293738Strasz		sc->sc_cmd1s = 0;
634293738Strasz		sc->sc_cmd2s = 0;
635153250Spjd		sc->sc_readbytes = 0;
636153250Spjd		sc->sc_wrotebytes = 0;
637153250Spjd	}
638153250Spjd}
639153250Spjd
640153250Spjdstatic void
641129471Spjdg_nop_config(struct gctl_req *req, struct g_class *mp, const char *verb)
642129471Spjd{
643129471Spjd	uint32_t *version;
644129471Spjd
645129471Spjd	g_topology_assert();
646129471Spjd
647129471Spjd	version = gctl_get_paraml(req, "version", sizeof(*version));
648129471Spjd	if (version == NULL) {
649129471Spjd		gctl_error(req, "No '%s' argument.", "version");
650129471Spjd		return;
651129471Spjd	}
652129471Spjd	if (*version != G_NOP_VERSION) {
653129471Spjd		gctl_error(req, "Userland and kernel parts are out of sync.");
654129471Spjd		return;
655129471Spjd	}
656129471Spjd
657129471Spjd	if (strcmp(verb, "create") == 0) {
658129471Spjd		g_nop_ctl_create(req, mp);
659129471Spjd		return;
660129548Spjd	} else if (strcmp(verb, "configure") == 0) {
661129548Spjd		g_nop_ctl_configure(req, mp);
662129471Spjd		return;
663129471Spjd	} else if (strcmp(verb, "destroy") == 0) {
664129471Spjd		g_nop_ctl_destroy(req, mp);
665129471Spjd		return;
666153250Spjd	} else if (strcmp(verb, "reset") == 0) {
667153250Spjd		g_nop_ctl_reset(req, mp);
668153250Spjd		return;
669129471Spjd	}
670129471Spjd
671129471Spjd	gctl_error(req, "Unknown verb.");
672129471Spjd}
673129471Spjd
674129471Spjdstatic void
675129471Spjdg_nop_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
676129471Spjd    struct g_consumer *cp, struct g_provider *pp)
677129471Spjd{
678132381Spjd	struct g_nop_softc *sc;
679129471Spjd
680132665Spjd	if (pp != NULL || cp != NULL)
681132381Spjd		return;
682132381Spjd	sc = gp->softc;
683132665Spjd	sbuf_printf(sb, "%s<Offset>%jd</Offset>\n", indent,
684132381Spjd	    (intmax_t)sc->sc_offset);
685162142Spjd	sbuf_printf(sb, "%s<ReadFailProb>%u</ReadFailProb>\n", indent,
686162142Spjd	    sc->sc_rfailprob);
687162142Spjd	sbuf_printf(sb, "%s<WriteFailProb>%u</WriteFailProb>\n", indent,
688162142Spjd	    sc->sc_wfailprob);
689162153Spjd	sbuf_printf(sb, "%s<Error>%d</Error>\n", indent, sc->sc_error);
690153250Spjd	sbuf_printf(sb, "%s<Reads>%ju</Reads>\n", indent, sc->sc_reads);
691153250Spjd	sbuf_printf(sb, "%s<Writes>%ju</Writes>\n", indent, sc->sc_writes);
692293738Strasz	sbuf_printf(sb, "%s<Deletes>%ju</Deletes>\n", indent, sc->sc_deletes);
693293738Strasz	sbuf_printf(sb, "%s<Getattrs>%ju</Getattrs>\n", indent, sc->sc_getattrs);
694293738Strasz	sbuf_printf(sb, "%s<Flushes>%ju</Flushes>\n", indent, sc->sc_flushes);
695293738Strasz	sbuf_printf(sb, "%s<Cmd0s>%ju</Cmd0s>\n", indent, sc->sc_cmd0s);
696293738Strasz	sbuf_printf(sb, "%s<Cmd1s>%ju</Cmd1s>\n", indent, sc->sc_cmd1s);
697293738Strasz	sbuf_printf(sb, "%s<Cmd2s>%ju</Cmd2s>\n", indent, sc->sc_cmd2s);
698153532Spjd	sbuf_printf(sb, "%s<ReadBytes>%ju</ReadBytes>\n", indent,
699153250Spjd	    sc->sc_readbytes);
700153250Spjd	sbuf_printf(sb, "%s<WroteBytes>%ju</WroteBytes>\n", indent,
701153265Spjd	    sc->sc_wrotebytes);
702129471Spjd}
703129471Spjd
704129471SpjdDECLARE_GEOM_CLASS(g_nop_class, g_nop);
705