xref: /freebsd/sys/geom/nop/g_nop.c (revision b91df0e29eff1779edbaf7cf0eae55f869bee7fc)
189aaffecSPawel Jakub Dawidek /*-
289aaffecSPawel Jakub Dawidek  * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
389aaffecSPawel Jakub Dawidek  * All rights reserved.
489aaffecSPawel Jakub Dawidek  *
589aaffecSPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
689aaffecSPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
789aaffecSPawel Jakub Dawidek  * are met:
889aaffecSPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
989aaffecSPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
1089aaffecSPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
1189aaffecSPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
1289aaffecSPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
1389aaffecSPawel Jakub Dawidek  *
1489aaffecSPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1589aaffecSPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1689aaffecSPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1789aaffecSPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
1889aaffecSPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1989aaffecSPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2089aaffecSPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2189aaffecSPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2289aaffecSPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2389aaffecSPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2489aaffecSPawel Jakub Dawidek  * SUCH DAMAGE.
2589aaffecSPawel Jakub Dawidek  */
2689aaffecSPawel Jakub Dawidek 
2789aaffecSPawel Jakub Dawidek #include <sys/cdefs.h>
2889aaffecSPawel Jakub Dawidek __FBSDID("$FreeBSD$");
2989aaffecSPawel Jakub Dawidek 
3089aaffecSPawel Jakub Dawidek #include <sys/param.h>
3189aaffecSPawel Jakub Dawidek #include <sys/systm.h>
3289aaffecSPawel Jakub Dawidek #include <sys/kernel.h>
3389aaffecSPawel Jakub Dawidek #include <sys/module.h>
3489aaffecSPawel Jakub Dawidek #include <sys/lock.h>
3589aaffecSPawel Jakub Dawidek #include <sys/mutex.h>
3689aaffecSPawel Jakub Dawidek #include <sys/bio.h>
3789aaffecSPawel Jakub Dawidek #include <sys/sysctl.h>
3889aaffecSPawel Jakub Dawidek #include <sys/malloc.h>
3989aaffecSPawel Jakub Dawidek #include <geom/geom.h>
4089aaffecSPawel Jakub Dawidek #include <geom/nop/g_nop.h>
4189aaffecSPawel Jakub Dawidek 
4289aaffecSPawel Jakub Dawidek 
4389aaffecSPawel Jakub Dawidek SYSCTL_DECL(_kern_geom);
4489aaffecSPawel Jakub Dawidek SYSCTL_NODE(_kern_geom, OID_AUTO, nop, CTLFLAG_RW, 0, "GEOM_NOP stuff");
4589aaffecSPawel Jakub Dawidek static u_int g_nop_debug = 0;
4689aaffecSPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_nop, OID_AUTO, debug, CTLFLAG_RW, &g_nop_debug, 0,
4789aaffecSPawel Jakub Dawidek     "Debug level");
4889aaffecSPawel Jakub Dawidek 
4989aaffecSPawel Jakub Dawidek static int g_nop_destroy(struct g_geom *gp, boolean_t force);
5089aaffecSPawel Jakub Dawidek static int g_nop_destroy_geom(struct gctl_req *req, struct g_class *mp,
5189aaffecSPawel Jakub Dawidek     struct g_geom *gp);
5289aaffecSPawel Jakub Dawidek static void g_nop_config(struct gctl_req *req, struct g_class *mp,
5389aaffecSPawel Jakub Dawidek     const char *verb);
5489aaffecSPawel Jakub Dawidek static void g_nop_dumpconf(struct sbuf *sb, const char *indent,
5589aaffecSPawel Jakub Dawidek     struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp);
5689aaffecSPawel Jakub Dawidek 
5789aaffecSPawel Jakub Dawidek struct g_class g_nop_class = {
5889aaffecSPawel Jakub Dawidek 	.name = G_NOP_CLASS_NAME,
595721c9c7SPoul-Henning Kamp 	.version = G_VERSION,
6089aaffecSPawel Jakub Dawidek 	.ctlreq = g_nop_config,
6189aaffecSPawel Jakub Dawidek 	.destroy_geom = g_nop_destroy_geom
6289aaffecSPawel Jakub Dawidek };
6389aaffecSPawel Jakub Dawidek 
6489aaffecSPawel Jakub Dawidek 
6589aaffecSPawel Jakub Dawidek static void
6689aaffecSPawel Jakub Dawidek g_nop_orphan(struct g_consumer *cp)
6789aaffecSPawel Jakub Dawidek {
6889aaffecSPawel Jakub Dawidek 
6989aaffecSPawel Jakub Dawidek 	g_topology_assert();
7089aaffecSPawel Jakub Dawidek 	g_nop_destroy(cp->geom, 1);
7189aaffecSPawel Jakub Dawidek }
7289aaffecSPawel Jakub Dawidek 
7389aaffecSPawel Jakub Dawidek static void
7489aaffecSPawel Jakub Dawidek g_nop_start(struct bio *bp)
7589aaffecSPawel Jakub Dawidek {
76e370e911SPawel Jakub Dawidek 	struct g_nop_softc *sc;
7789aaffecSPawel Jakub Dawidek 	struct g_geom *gp;
7889aaffecSPawel Jakub Dawidek 	struct g_provider *pp;
7989aaffecSPawel Jakub Dawidek 	struct bio *cbp;
8089aaffecSPawel Jakub Dawidek 
8189aaffecSPawel Jakub Dawidek 	gp = bp->bio_to->geom;
82e370e911SPawel Jakub Dawidek 	sc = gp->softc;
8389aaffecSPawel Jakub Dawidek 	G_NOP_LOGREQ(bp, "Request received.");
8489aaffecSPawel Jakub Dawidek 	cbp = g_clone_bio(bp);
8589aaffecSPawel Jakub Dawidek 	if (cbp == NULL) {
8689aaffecSPawel Jakub Dawidek 		g_io_deliver(bp, ENOMEM);
8789aaffecSPawel Jakub Dawidek 		return;
8889aaffecSPawel Jakub Dawidek 	}
89df3d5a19SPawel Jakub Dawidek 	switch (bp->bio_cmd) {
90df3d5a19SPawel Jakub Dawidek 	case BIO_READ:
91df3d5a19SPawel Jakub Dawidek 		sc->sc_reads++;
92df3d5a19SPawel Jakub Dawidek 		sc->sc_readbytes += bp->bio_length;
93df3d5a19SPawel Jakub Dawidek 		break;
94df3d5a19SPawel Jakub Dawidek 	case BIO_WRITE:
95df3d5a19SPawel Jakub Dawidek 		sc->sc_writes++;
96df3d5a19SPawel Jakub Dawidek 		sc->sc_wrotebytes += bp->bio_length;
97df3d5a19SPawel Jakub Dawidek 		break;
98df3d5a19SPawel Jakub Dawidek 	}
99e370e911SPawel Jakub Dawidek 	if (sc->sc_failprob > 0) {
10089aaffecSPawel Jakub Dawidek 		u_int rval;
10189aaffecSPawel Jakub Dawidek 
10289aaffecSPawel Jakub Dawidek 		rval = arc4random() % 100;
103e370e911SPawel Jakub Dawidek 		if (rval < sc->sc_failprob) {
10489aaffecSPawel Jakub Dawidek 			g_io_deliver(bp, EIO);
10589aaffecSPawel Jakub Dawidek 			return;
10689aaffecSPawel Jakub Dawidek 		}
10789aaffecSPawel Jakub Dawidek 	}
10889aaffecSPawel Jakub Dawidek 	cbp->bio_done = g_std_done;
109e370e911SPawel Jakub Dawidek 	cbp->bio_offset = bp->bio_offset + sc->sc_offset;
11089aaffecSPawel Jakub Dawidek 	cbp->bio_data = bp->bio_data;
11189aaffecSPawel Jakub Dawidek 	cbp->bio_length = bp->bio_length;
112969ff54dSPawel Jakub Dawidek 	pp = LIST_FIRST(&gp->provider);
113969ff54dSPawel Jakub Dawidek 	KASSERT(pp != NULL, ("NULL pp"));
114969ff54dSPawel Jakub Dawidek 	cbp->bio_to = pp;
11589aaffecSPawel Jakub Dawidek 	G_NOP_LOGREQ(cbp, "Sending request.");
11689aaffecSPawel Jakub Dawidek 	g_io_request(cbp, LIST_FIRST(&gp->consumer));
11789aaffecSPawel Jakub Dawidek }
11889aaffecSPawel Jakub Dawidek 
11989aaffecSPawel Jakub Dawidek static int
12089aaffecSPawel Jakub Dawidek g_nop_access(struct g_provider *pp, int dr, int dw, int de)
12189aaffecSPawel Jakub Dawidek {
12289aaffecSPawel Jakub Dawidek 	struct g_geom *gp;
12389aaffecSPawel Jakub Dawidek 	struct g_consumer *cp;
12489aaffecSPawel Jakub Dawidek 	int error;
12589aaffecSPawel Jakub Dawidek 
12689aaffecSPawel Jakub Dawidek 	gp = pp->geom;
12789aaffecSPawel Jakub Dawidek 	cp = LIST_FIRST(&gp->consumer);
12889aaffecSPawel Jakub Dawidek 	error = g_access(cp, dr, dw, de);
12989aaffecSPawel Jakub Dawidek 
13089aaffecSPawel Jakub Dawidek 	return (error);
13189aaffecSPawel Jakub Dawidek }
13289aaffecSPawel Jakub Dawidek 
13389aaffecSPawel Jakub Dawidek static int
13489aaffecSPawel Jakub Dawidek g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
135d5c96d38SPawel Jakub Dawidek     u_int failprob, off_t offset, off_t size, u_int secsize)
13689aaffecSPawel Jakub Dawidek {
137e370e911SPawel Jakub Dawidek 	struct g_nop_softc *sc;
13889aaffecSPawel Jakub Dawidek 	struct g_geom *gp;
13989aaffecSPawel Jakub Dawidek 	struct g_provider *newpp;
14089aaffecSPawel Jakub Dawidek 	struct g_consumer *cp;
1410e11f0a9SPawel Jakub Dawidek 	char name[64];
14289aaffecSPawel Jakub Dawidek 	int error;
14389aaffecSPawel Jakub Dawidek 
14489aaffecSPawel Jakub Dawidek 	g_topology_assert();
14589aaffecSPawel Jakub Dawidek 
14689aaffecSPawel Jakub Dawidek 	gp = NULL;
14789aaffecSPawel Jakub Dawidek 	newpp = NULL;
14889aaffecSPawel Jakub Dawidek 	cp = NULL;
14989aaffecSPawel Jakub Dawidek 
150e370e911SPawel Jakub Dawidek 	if ((offset % pp->sectorsize) != 0) {
151e370e911SPawel Jakub Dawidek 		gctl_error(req, "Invalid offset for provider %s.", pp->name);
152e370e911SPawel Jakub Dawidek 		return (EINVAL);
153e370e911SPawel Jakub Dawidek 	}
154e370e911SPawel Jakub Dawidek 	if ((size % pp->sectorsize) != 0) {
155e370e911SPawel Jakub Dawidek 		gctl_error(req, "Invalid size for provider %s.", pp->name);
156e370e911SPawel Jakub Dawidek 		return (EINVAL);
157e370e911SPawel Jakub Dawidek 	}
158e370e911SPawel Jakub Dawidek 	if (offset >= pp->mediasize) {
159e370e911SPawel Jakub Dawidek 		gctl_error(req, "Invalid offset for provider %s.", pp->name);
160e370e911SPawel Jakub Dawidek 		return (EINVAL);
161e370e911SPawel Jakub Dawidek 	}
162e370e911SPawel Jakub Dawidek 	if (size == 0)
163e370e911SPawel Jakub Dawidek 		size = pp->mediasize - offset;
164e370e911SPawel Jakub Dawidek 	if (offset + size > pp->mediasize) {
165e370e911SPawel Jakub Dawidek 		gctl_error(req, "Invalid size for provider %s.", pp->name);
166e370e911SPawel Jakub Dawidek 		return (EINVAL);
167e370e911SPawel Jakub Dawidek 	}
168d5c96d38SPawel Jakub Dawidek 	if (secsize == 0)
169d5c96d38SPawel Jakub Dawidek 		secsize = pp->sectorsize;
170d5c96d38SPawel Jakub Dawidek 	else if ((secsize % pp->sectorsize) != 0) {
171d5c96d38SPawel Jakub Dawidek 		gctl_error(req, "Invalid secsize for provider %s.", pp->name);
172d5c96d38SPawel Jakub Dawidek 		return (EINVAL);
173d5c96d38SPawel Jakub Dawidek 	}
1740e11f0a9SPawel Jakub Dawidek 	snprintf(name, sizeof(name), "%s%s", pp->name, G_NOP_SUFFIX);
1750e11f0a9SPawel Jakub Dawidek 	LIST_FOREACH(gp, &mp->geom, geom) {
1760e11f0a9SPawel Jakub Dawidek 		if (strcmp(gp->name, name) == 0) {
1770e11f0a9SPawel Jakub Dawidek 			gctl_error(req, "Provider %s already exists.", name);
1780e11f0a9SPawel Jakub Dawidek 			return (EEXIST);
1790e11f0a9SPawel Jakub Dawidek 		}
1800e11f0a9SPawel Jakub Dawidek 	}
1810e11f0a9SPawel Jakub Dawidek 	gp = g_new_geomf(mp, name);
18289aaffecSPawel Jakub Dawidek 	if (gp == NULL) {
183d462f0a1SPawel Jakub Dawidek 		gctl_error(req, "Cannot create geom %s.", name);
18489aaffecSPawel Jakub Dawidek 		return (ENOMEM);
18589aaffecSPawel Jakub Dawidek 	}
186e370e911SPawel Jakub Dawidek 	sc = g_malloc(sizeof(*sc), M_WAITOK);
187e370e911SPawel Jakub Dawidek 	sc->sc_offset = offset;
188e370e911SPawel Jakub Dawidek 	sc->sc_failprob = failprob;
189df3d5a19SPawel Jakub Dawidek 	sc->sc_reads = 0;
190df3d5a19SPawel Jakub Dawidek 	sc->sc_writes = 0;
191df3d5a19SPawel Jakub Dawidek 	sc->sc_readbytes = 0;
192df3d5a19SPawel Jakub Dawidek 	sc->sc_wrotebytes = 0;
193e370e911SPawel Jakub Dawidek 	gp->softc = sc;
19489aaffecSPawel Jakub Dawidek 	gp->start = g_nop_start;
19589aaffecSPawel Jakub Dawidek 	gp->orphan = g_nop_orphan;
19689aaffecSPawel Jakub Dawidek 	gp->access = g_nop_access;
19789aaffecSPawel Jakub Dawidek 	gp->dumpconf = g_nop_dumpconf;
19889aaffecSPawel Jakub Dawidek 
19989aaffecSPawel Jakub Dawidek 	newpp = g_new_providerf(gp, gp->name);
20089aaffecSPawel Jakub Dawidek 	if (newpp == NULL) {
201d462f0a1SPawel Jakub Dawidek 		gctl_error(req, "Cannot create provider %s.", name);
20289aaffecSPawel Jakub Dawidek 		error = ENOMEM;
20389aaffecSPawel Jakub Dawidek 		goto fail;
20489aaffecSPawel Jakub Dawidek 	}
205e370e911SPawel Jakub Dawidek 	newpp->mediasize = size;
206d5c96d38SPawel Jakub Dawidek 	newpp->sectorsize = secsize;
20789aaffecSPawel Jakub Dawidek 
20889aaffecSPawel Jakub Dawidek 	cp = g_new_consumer(gp);
20989aaffecSPawel Jakub Dawidek 	if (cp == NULL) {
21089aaffecSPawel Jakub Dawidek 		gctl_error(req, "Cannot create consumer for %s.", gp->name);
21189aaffecSPawel Jakub Dawidek 		error = ENOMEM;
21289aaffecSPawel Jakub Dawidek 		goto fail;
21389aaffecSPawel Jakub Dawidek 	}
21489aaffecSPawel Jakub Dawidek 	error = g_attach(cp, pp);
21589aaffecSPawel Jakub Dawidek 	if (error != 0) {
21689aaffecSPawel Jakub Dawidek 		gctl_error(req, "Cannot attach to provider %s.", pp->name);
21789aaffecSPawel Jakub Dawidek 		goto fail;
21889aaffecSPawel Jakub Dawidek 	}
21989aaffecSPawel Jakub Dawidek 
22089aaffecSPawel Jakub Dawidek 	g_error_provider(newpp, 0);
22189aaffecSPawel Jakub Dawidek 	G_NOP_DEBUG(0, "Device %s created.", gp->name);
22289aaffecSPawel Jakub Dawidek 	return (0);
22389aaffecSPawel Jakub Dawidek fail:
22489aaffecSPawel Jakub Dawidek 	if (cp != NULL) {
22589aaffecSPawel Jakub Dawidek 		if (cp->provider != NULL)
22689aaffecSPawel Jakub Dawidek 			g_detach(cp);
22789aaffecSPawel Jakub Dawidek 		g_destroy_consumer(cp);
22889aaffecSPawel Jakub Dawidek 	}
22989aaffecSPawel Jakub Dawidek 	if (newpp != NULL)
230b3f05a2eSMax Khon 		g_destroy_provider(newpp);
231e370e911SPawel Jakub Dawidek 	if (gp != NULL) {
232e370e911SPawel Jakub Dawidek 		if (gp->softc != NULL)
233e370e911SPawel Jakub Dawidek 			g_free(gp->softc);
23489aaffecSPawel Jakub Dawidek 		g_destroy_geom(gp);
235e370e911SPawel Jakub Dawidek 	}
23689aaffecSPawel Jakub Dawidek 	return (error);
23789aaffecSPawel Jakub Dawidek }
23889aaffecSPawel Jakub Dawidek 
23989aaffecSPawel Jakub Dawidek static int
24089aaffecSPawel Jakub Dawidek g_nop_destroy(struct g_geom *gp, boolean_t force)
24189aaffecSPawel Jakub Dawidek {
24289aaffecSPawel Jakub Dawidek 	struct g_provider *pp;
24389aaffecSPawel Jakub Dawidek 
24489aaffecSPawel Jakub Dawidek 	g_topology_assert();
245969ff54dSPawel Jakub Dawidek 	if (gp->softc == NULL)
246969ff54dSPawel Jakub Dawidek 		return (ENXIO);
24789aaffecSPawel Jakub Dawidek 	pp = LIST_FIRST(&gp->provider);
24889aaffecSPawel Jakub Dawidek 	if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
24989aaffecSPawel Jakub Dawidek 		if (force) {
25089aaffecSPawel Jakub Dawidek 			G_NOP_DEBUG(0, "Device %s is still open, so it "
25189aaffecSPawel Jakub Dawidek 			    "can't be definitely removed.", pp->name);
25289aaffecSPawel Jakub Dawidek 		} else {
25389aaffecSPawel Jakub Dawidek 			G_NOP_DEBUG(1, "Device %s is still open (r%dw%de%d).",
25489aaffecSPawel Jakub Dawidek 			    pp->name, pp->acr, pp->acw, pp->ace);
25589aaffecSPawel Jakub Dawidek 			return (EBUSY);
25689aaffecSPawel Jakub Dawidek 		}
25789aaffecSPawel Jakub Dawidek 	} else {
25889aaffecSPawel Jakub Dawidek 		G_NOP_DEBUG(0, "Device %s removed.", gp->name);
25989aaffecSPawel Jakub Dawidek 	}
260e370e911SPawel Jakub Dawidek 	g_free(gp->softc);
261e370e911SPawel Jakub Dawidek 	gp->softc = NULL;
26289aaffecSPawel Jakub Dawidek 	g_wither_geom(gp, ENXIO);
26389aaffecSPawel Jakub Dawidek 
26489aaffecSPawel Jakub Dawidek 	return (0);
26589aaffecSPawel Jakub Dawidek }
26689aaffecSPawel Jakub Dawidek 
26789aaffecSPawel Jakub Dawidek static int
26889aaffecSPawel Jakub Dawidek g_nop_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
26989aaffecSPawel Jakub Dawidek {
27089aaffecSPawel Jakub Dawidek 
27189aaffecSPawel Jakub Dawidek 	return (g_nop_destroy(gp, 0));
27289aaffecSPawel Jakub Dawidek }
27389aaffecSPawel Jakub Dawidek 
27489aaffecSPawel Jakub Dawidek static void
27589aaffecSPawel Jakub Dawidek g_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
27689aaffecSPawel Jakub Dawidek {
27789aaffecSPawel Jakub Dawidek 	struct g_provider *pp;
278d5c96d38SPawel Jakub Dawidek 	intmax_t *failprob, *offset, *secsize, *size;
27989aaffecSPawel Jakub Dawidek 	const char *name;
28089aaffecSPawel Jakub Dawidek 	char param[16];
28189aaffecSPawel Jakub Dawidek 	int i, *nargs;
28289aaffecSPawel Jakub Dawidek 
28389aaffecSPawel Jakub Dawidek 	g_topology_assert();
28489aaffecSPawel Jakub Dawidek 
28589aaffecSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
28689aaffecSPawel Jakub Dawidek 	if (nargs == NULL) {
28789aaffecSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument", "nargs");
28889aaffecSPawel Jakub Dawidek 		return;
28989aaffecSPawel Jakub Dawidek 	}
29089aaffecSPawel Jakub Dawidek 	if (*nargs <= 0) {
29189aaffecSPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
29289aaffecSPawel Jakub Dawidek 		return;
29389aaffecSPawel Jakub Dawidek 	}
29489aaffecSPawel Jakub Dawidek 	failprob = gctl_get_paraml(req, "failprob", sizeof(*failprob));
29589aaffecSPawel Jakub Dawidek 	if (failprob == NULL) {
29689aaffecSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument", "failprob");
29789aaffecSPawel Jakub Dawidek 		return;
29889aaffecSPawel Jakub Dawidek 	}
29989aaffecSPawel Jakub Dawidek 	if (*failprob < 0 || *failprob > 100) {
30089aaffecSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument", "failprob");
30189aaffecSPawel Jakub Dawidek 		return;
30289aaffecSPawel Jakub Dawidek 	}
303e370e911SPawel Jakub Dawidek 	offset = gctl_get_paraml(req, "offset", sizeof(*offset));
304e370e911SPawel Jakub Dawidek 	if (offset == NULL) {
305e370e911SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument", "offset");
306e370e911SPawel Jakub Dawidek 		return;
307e370e911SPawel Jakub Dawidek 	}
308e370e911SPawel Jakub Dawidek 	if (*offset < 0) {
309e370e911SPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument", "offset");
310e370e911SPawel Jakub Dawidek 		return;
311e370e911SPawel Jakub Dawidek 	}
312e370e911SPawel Jakub Dawidek 	size = gctl_get_paraml(req, "size", sizeof(*size));
313e370e911SPawel Jakub Dawidek 	if (size == NULL) {
314e370e911SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument", "size");
315e370e911SPawel Jakub Dawidek 		return;
316e370e911SPawel Jakub Dawidek 	}
317e370e911SPawel Jakub Dawidek 	if (*size < 0) {
318e370e911SPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument", "size");
319e370e911SPawel Jakub Dawidek 		return;
320e370e911SPawel Jakub Dawidek 	}
321d5c96d38SPawel Jakub Dawidek 	secsize = gctl_get_paraml(req, "secsize", sizeof(*secsize));
322d5c96d38SPawel Jakub Dawidek 	if (secsize == NULL) {
323d5c96d38SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument", "secsize");
324d5c96d38SPawel Jakub Dawidek 		return;
325d5c96d38SPawel Jakub Dawidek 	}
326d5c96d38SPawel Jakub Dawidek 	if (*secsize < 0) {
327d5c96d38SPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument", "secsize");
328d5c96d38SPawel Jakub Dawidek 		return;
329d5c96d38SPawel Jakub Dawidek 	}
33089aaffecSPawel Jakub Dawidek 
33189aaffecSPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
33289aaffecSPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
33389aaffecSPawel Jakub Dawidek 		name = gctl_get_asciiparam(req, param);
33489aaffecSPawel Jakub Dawidek 		if (name == NULL) {
33589aaffecSPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument", i);
33689aaffecSPawel Jakub Dawidek 			return;
33789aaffecSPawel Jakub Dawidek 		}
33889aaffecSPawel Jakub Dawidek 		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
33989aaffecSPawel Jakub Dawidek 			name += strlen("/dev/");
34089aaffecSPawel Jakub Dawidek 		pp = g_provider_by_name(name);
34189aaffecSPawel Jakub Dawidek 		if (pp == NULL) {
34289aaffecSPawel Jakub Dawidek 			G_NOP_DEBUG(1, "Provider %s is invalid.", name);
34389aaffecSPawel Jakub Dawidek 			gctl_error(req, "Provider %s is invalid.", name);
34489aaffecSPawel Jakub Dawidek 			return;
34589aaffecSPawel Jakub Dawidek 		}
346e370e911SPawel Jakub Dawidek 		if (g_nop_create(req, mp, pp, (u_int)*failprob, (off_t)*offset,
347d5c96d38SPawel Jakub Dawidek 		    (off_t)*size, (u_int)*secsize) != 0) {
34889aaffecSPawel Jakub Dawidek 			return;
34989aaffecSPawel Jakub Dawidek 		}
35089aaffecSPawel Jakub Dawidek 	}
351e370e911SPawel Jakub Dawidek }
35289aaffecSPawel Jakub Dawidek 
35389aaffecSPawel Jakub Dawidek static void
35402692c51SPawel Jakub Dawidek g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp)
35589aaffecSPawel Jakub Dawidek {
356e370e911SPawel Jakub Dawidek 	struct g_nop_softc *sc;
35789aaffecSPawel Jakub Dawidek 	struct g_provider *pp;
35889aaffecSPawel Jakub Dawidek 	intmax_t *failprob;
35989aaffecSPawel Jakub Dawidek 	const char *name;
36089aaffecSPawel Jakub Dawidek 	char param[16];
36189aaffecSPawel Jakub Dawidek 	int i, *nargs;
36289aaffecSPawel Jakub Dawidek 
36389aaffecSPawel Jakub Dawidek 	g_topology_assert();
36489aaffecSPawel Jakub Dawidek 
36589aaffecSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
36689aaffecSPawel Jakub Dawidek 	if (nargs == NULL) {
36789aaffecSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument", "nargs");
36889aaffecSPawel Jakub Dawidek 		return;
36989aaffecSPawel Jakub Dawidek 	}
37089aaffecSPawel Jakub Dawidek 	if (*nargs <= 0) {
37189aaffecSPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
37289aaffecSPawel Jakub Dawidek 		return;
37389aaffecSPawel Jakub Dawidek 	}
37489aaffecSPawel Jakub Dawidek 	failprob = gctl_get_paraml(req, "failprob", sizeof(*failprob));
37589aaffecSPawel Jakub Dawidek 	if (failprob == NULL) {
37689aaffecSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument", "failprob");
37789aaffecSPawel Jakub Dawidek 		return;
37889aaffecSPawel Jakub Dawidek 	}
37989aaffecSPawel Jakub Dawidek 	if (*failprob < 0 || *failprob > 100) {
38089aaffecSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument", "failprob");
38189aaffecSPawel Jakub Dawidek 		return;
38289aaffecSPawel Jakub Dawidek 	}
38389aaffecSPawel Jakub Dawidek 
38489aaffecSPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
38589aaffecSPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
38689aaffecSPawel Jakub Dawidek 		name = gctl_get_asciiparam(req, param);
38789aaffecSPawel Jakub Dawidek 		if (name == NULL) {
38889aaffecSPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument", i);
38989aaffecSPawel Jakub Dawidek 			return;
39089aaffecSPawel Jakub Dawidek 		}
39189aaffecSPawel Jakub Dawidek 		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
39289aaffecSPawel Jakub Dawidek 			name += strlen("/dev/");
39389aaffecSPawel Jakub Dawidek 		pp = g_provider_by_name(name);
39489aaffecSPawel Jakub Dawidek 		if (pp == NULL || pp->geom->class != mp) {
39589aaffecSPawel Jakub Dawidek 			G_NOP_DEBUG(1, "Provider %s is invalid.", name);
39689aaffecSPawel Jakub Dawidek 			gctl_error(req, "Provider %s is invalid.", name);
39789aaffecSPawel Jakub Dawidek 			return;
39889aaffecSPawel Jakub Dawidek 		}
399e370e911SPawel Jakub Dawidek 		sc = pp->geom->softc;
400e370e911SPawel Jakub Dawidek 		sc->sc_failprob = (u_int)*failprob;
40189aaffecSPawel Jakub Dawidek 	}
40289aaffecSPawel Jakub Dawidek }
40389aaffecSPawel Jakub Dawidek 
40489aaffecSPawel Jakub Dawidek static struct g_geom *
40589aaffecSPawel Jakub Dawidek g_nop_find_geom(struct g_class *mp, const char *name)
40689aaffecSPawel Jakub Dawidek {
40789aaffecSPawel Jakub Dawidek 	struct g_geom *gp;
40889aaffecSPawel Jakub Dawidek 
40989aaffecSPawel Jakub Dawidek 	LIST_FOREACH(gp, &mp->geom, geom) {
41089aaffecSPawel Jakub Dawidek 		if (strcmp(gp->name, name) == 0)
41189aaffecSPawel Jakub Dawidek 			return (gp);
41289aaffecSPawel Jakub Dawidek 	}
41389aaffecSPawel Jakub Dawidek 	return (NULL);
41489aaffecSPawel Jakub Dawidek }
41589aaffecSPawel Jakub Dawidek 
41689aaffecSPawel Jakub Dawidek static void
41789aaffecSPawel Jakub Dawidek g_nop_ctl_destroy(struct gctl_req *req, struct g_class *mp)
41889aaffecSPawel Jakub Dawidek {
41989aaffecSPawel Jakub Dawidek 	int *nargs, *force, error, i;
42089aaffecSPawel Jakub Dawidek 	struct g_geom *gp;
42189aaffecSPawel Jakub Dawidek 	const char *name;
42289aaffecSPawel Jakub Dawidek 	char param[16];
42389aaffecSPawel Jakub Dawidek 
42489aaffecSPawel Jakub Dawidek 	g_topology_assert();
42589aaffecSPawel Jakub Dawidek 
42689aaffecSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
42789aaffecSPawel Jakub Dawidek 	if (nargs == NULL) {
42889aaffecSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument", "nargs");
42989aaffecSPawel Jakub Dawidek 		return;
43089aaffecSPawel Jakub Dawidek 	}
43189aaffecSPawel Jakub Dawidek 	if (*nargs <= 0) {
43289aaffecSPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
43389aaffecSPawel Jakub Dawidek 		return;
43489aaffecSPawel Jakub Dawidek 	}
43589aaffecSPawel Jakub Dawidek 	force = gctl_get_paraml(req, "force", sizeof(*force));
43689aaffecSPawel Jakub Dawidek 	if (force == NULL) {
43789aaffecSPawel Jakub Dawidek 		gctl_error(req, "No 'force' argument");
43889aaffecSPawel Jakub Dawidek 		return;
43989aaffecSPawel Jakub Dawidek 	}
44089aaffecSPawel Jakub Dawidek 
44189aaffecSPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
44289aaffecSPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
44389aaffecSPawel Jakub Dawidek 		name = gctl_get_asciiparam(req, param);
44489aaffecSPawel Jakub Dawidek 		if (name == NULL) {
44589aaffecSPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument", i);
44689aaffecSPawel Jakub Dawidek 			return;
44789aaffecSPawel Jakub Dawidek 		}
44889aaffecSPawel Jakub Dawidek 		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
44989aaffecSPawel Jakub Dawidek 			name += strlen("/dev/");
45089aaffecSPawel Jakub Dawidek 		gp = g_nop_find_geom(mp, name);
45189aaffecSPawel Jakub Dawidek 		if (gp == NULL) {
45289aaffecSPawel Jakub Dawidek 			G_NOP_DEBUG(1, "Device %s is invalid.", name);
45389aaffecSPawel Jakub Dawidek 			gctl_error(req, "Device %s is invalid.", name);
45489aaffecSPawel Jakub Dawidek 			return;
45589aaffecSPawel Jakub Dawidek 		}
45689aaffecSPawel Jakub Dawidek 		error = g_nop_destroy(gp, *force);
45789aaffecSPawel Jakub Dawidek 		if (error != 0) {
45889aaffecSPawel Jakub Dawidek 			gctl_error(req, "Cannot destroy device %s (error=%d).",
45989aaffecSPawel Jakub Dawidek 			    gp->name, error);
46089aaffecSPawel Jakub Dawidek 			return;
46189aaffecSPawel Jakub Dawidek 		}
46289aaffecSPawel Jakub Dawidek 	}
46389aaffecSPawel Jakub Dawidek }
46489aaffecSPawel Jakub Dawidek 
46589aaffecSPawel Jakub Dawidek static void
466df3d5a19SPawel Jakub Dawidek g_nop_ctl_reset(struct gctl_req *req, struct g_class *mp)
467df3d5a19SPawel Jakub Dawidek {
468df3d5a19SPawel Jakub Dawidek 	struct g_nop_softc *sc;
469df3d5a19SPawel Jakub Dawidek 	struct g_provider *pp;
470df3d5a19SPawel Jakub Dawidek 	const char *name;
471df3d5a19SPawel Jakub Dawidek 	char param[16];
472df3d5a19SPawel Jakub Dawidek 	int i, *nargs;
473df3d5a19SPawel Jakub Dawidek 
474df3d5a19SPawel Jakub Dawidek 	g_topology_assert();
475df3d5a19SPawel Jakub Dawidek 
476df3d5a19SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
477df3d5a19SPawel Jakub Dawidek 	if (nargs == NULL) {
478df3d5a19SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument", "nargs");
479df3d5a19SPawel Jakub Dawidek 		return;
480df3d5a19SPawel Jakub Dawidek 	}
481df3d5a19SPawel Jakub Dawidek 	if (*nargs <= 0) {
482df3d5a19SPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
483df3d5a19SPawel Jakub Dawidek 		return;
484df3d5a19SPawel Jakub Dawidek 	}
485df3d5a19SPawel Jakub Dawidek 
486df3d5a19SPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
487df3d5a19SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
488df3d5a19SPawel Jakub Dawidek 		name = gctl_get_asciiparam(req, param);
489df3d5a19SPawel Jakub Dawidek 		if (name == NULL) {
490df3d5a19SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument", i);
491df3d5a19SPawel Jakub Dawidek 			return;
492df3d5a19SPawel Jakub Dawidek 		}
493df3d5a19SPawel Jakub Dawidek 		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
494df3d5a19SPawel Jakub Dawidek 			name += strlen("/dev/");
495df3d5a19SPawel Jakub Dawidek 		pp = g_provider_by_name(name);
496df3d5a19SPawel Jakub Dawidek 		if (pp == NULL || pp->geom->class != mp) {
497df3d5a19SPawel Jakub Dawidek 			G_NOP_DEBUG(1, "Provider %s is invalid.", name);
498df3d5a19SPawel Jakub Dawidek 			gctl_error(req, "Provider %s is invalid.", name);
499df3d5a19SPawel Jakub Dawidek 			return;
500df3d5a19SPawel Jakub Dawidek 		}
501df3d5a19SPawel Jakub Dawidek 		sc = pp->geom->softc;
502df3d5a19SPawel Jakub Dawidek 		sc->sc_reads = 0;
503df3d5a19SPawel Jakub Dawidek 		sc->sc_writes = 0;
504df3d5a19SPawel Jakub Dawidek 		sc->sc_readbytes = 0;
505df3d5a19SPawel Jakub Dawidek 		sc->sc_wrotebytes = 0;
506df3d5a19SPawel Jakub Dawidek 	}
507df3d5a19SPawel Jakub Dawidek }
508df3d5a19SPawel Jakub Dawidek 
509df3d5a19SPawel Jakub Dawidek static void
51089aaffecSPawel Jakub Dawidek g_nop_config(struct gctl_req *req, struct g_class *mp, const char *verb)
51189aaffecSPawel Jakub Dawidek {
51289aaffecSPawel Jakub Dawidek 	uint32_t *version;
51389aaffecSPawel Jakub Dawidek 
51489aaffecSPawel Jakub Dawidek 	g_topology_assert();
51589aaffecSPawel Jakub Dawidek 
51689aaffecSPawel Jakub Dawidek 	version = gctl_get_paraml(req, "version", sizeof(*version));
51789aaffecSPawel Jakub Dawidek 	if (version == NULL) {
51889aaffecSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "version");
51989aaffecSPawel Jakub Dawidek 		return;
52089aaffecSPawel Jakub Dawidek 	}
52189aaffecSPawel Jakub Dawidek 	if (*version != G_NOP_VERSION) {
52289aaffecSPawel Jakub Dawidek 		gctl_error(req, "Userland and kernel parts are out of sync.");
52389aaffecSPawel Jakub Dawidek 		return;
52489aaffecSPawel Jakub Dawidek 	}
52589aaffecSPawel Jakub Dawidek 
52689aaffecSPawel Jakub Dawidek 	if (strcmp(verb, "create") == 0) {
52789aaffecSPawel Jakub Dawidek 		g_nop_ctl_create(req, mp);
52889aaffecSPawel Jakub Dawidek 		return;
52902692c51SPawel Jakub Dawidek 	} else if (strcmp(verb, "configure") == 0) {
53002692c51SPawel Jakub Dawidek 		g_nop_ctl_configure(req, mp);
53189aaffecSPawel Jakub Dawidek 		return;
53289aaffecSPawel Jakub Dawidek 	} else if (strcmp(verb, "destroy") == 0) {
53389aaffecSPawel Jakub Dawidek 		g_nop_ctl_destroy(req, mp);
53489aaffecSPawel Jakub Dawidek 		return;
535df3d5a19SPawel Jakub Dawidek 	} else if (strcmp(verb, "reset") == 0) {
536df3d5a19SPawel Jakub Dawidek 		g_nop_ctl_reset(req, mp);
537df3d5a19SPawel Jakub Dawidek 		return;
53889aaffecSPawel Jakub Dawidek 	}
53989aaffecSPawel Jakub Dawidek 
54089aaffecSPawel Jakub Dawidek 	gctl_error(req, "Unknown verb.");
54189aaffecSPawel Jakub Dawidek }
54289aaffecSPawel Jakub Dawidek 
54389aaffecSPawel Jakub Dawidek static void
54489aaffecSPawel Jakub Dawidek g_nop_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
54589aaffecSPawel Jakub Dawidek     struct g_consumer *cp, struct g_provider *pp)
54689aaffecSPawel Jakub Dawidek {
547e370e911SPawel Jakub Dawidek 	struct g_nop_softc *sc;
54889aaffecSPawel Jakub Dawidek 
5491d723f1dSPawel Jakub Dawidek 	if (pp != NULL || cp != NULL)
550e370e911SPawel Jakub Dawidek 		return;
551e370e911SPawel Jakub Dawidek 	sc = gp->softc;
5521d723f1dSPawel Jakub Dawidek 	sbuf_printf(sb, "%s<Offset>%jd</Offset>\n", indent,
553e370e911SPawel Jakub Dawidek 	    (intmax_t)sc->sc_offset);
554df3d5a19SPawel Jakub Dawidek 	sbuf_printf(sb, "%s<FailProb>%u</FailProb>\n", indent, sc->sc_failprob);
555df3d5a19SPawel Jakub Dawidek 	sbuf_printf(sb, "%s<Reads>%ju</Reads>\n", indent, sc->sc_reads);
556df3d5a19SPawel Jakub Dawidek 	sbuf_printf(sb, "%s<Writes>%ju</Writes>\n", indent, sc->sc_writes);
557b91df0e2SPawel Jakub Dawidek 	sbuf_printf(sb, "%s<ReadBytes>%ju</ReadBytes>\n", indent,
558df3d5a19SPawel Jakub Dawidek 	    sc->sc_readbytes);
559df3d5a19SPawel Jakub Dawidek 	sbuf_printf(sb, "%s<WroteBytes>%ju</WroteBytes>\n", indent,
56064806a73SPawel Jakub Dawidek 	    sc->sc_wrotebytes);
56189aaffecSPawel Jakub Dawidek }
56289aaffecSPawel Jakub Dawidek 
56389aaffecSPawel Jakub Dawidek DECLARE_GEOM_CLASS(g_nop_class, g_nop);
564