g_raid3_ctl.c revision 160330
1133808Spjd/*-
2156878Spjd * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3133808Spjd * All rights reserved.
4133808Spjd *
5133808Spjd * Redistribution and use in source and binary forms, with or without
6133808Spjd * modification, are permitted provided that the following conditions
7133808Spjd * are met:
8133808Spjd * 1. Redistributions of source code must retain the above copyright
9133808Spjd *    notice, this list of conditions and the following disclaimer.
10133808Spjd * 2. Redistributions in binary form must reproduce the above copyright
11133808Spjd *    notice, this list of conditions and the following disclaimer in the
12133808Spjd *    documentation and/or other materials provided with the distribution.
13155174Spjd *
14133808Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15133808Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16133808Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17133808Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18133808Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19133808Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20133808Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21133808Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22133808Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23133808Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24133808Spjd * SUCH DAMAGE.
25133808Spjd */
26133808Spjd
27133808Spjd#include <sys/cdefs.h>
28133808Spjd__FBSDID("$FreeBSD: head/sys/geom/raid3/g_raid3_ctl.c 160330 2006-07-13 20:37:59Z pjd $");
29133808Spjd
30133808Spjd#include <sys/param.h>
31133808Spjd#include <sys/systm.h>
32133808Spjd#include <sys/kernel.h>
33133808Spjd#include <sys/module.h>
34133808Spjd#include <sys/lock.h>
35133808Spjd#include <sys/mutex.h>
36133808Spjd#include <sys/bio.h>
37133808Spjd#include <sys/sysctl.h>
38133808Spjd#include <sys/malloc.h>
39133808Spjd#include <sys/bitstring.h>
40133808Spjd#include <vm/uma.h>
41133808Spjd#include <machine/atomic.h>
42133808Spjd#include <geom/geom.h>
43133808Spjd#include <sys/proc.h>
44133808Spjd#include <sys/kthread.h>
45133808Spjd#include <geom/raid3/g_raid3.h>
46133808Spjd
47133808Spjd
48133808Spjdstatic struct g_raid3_softc *
49133808Spjdg_raid3_find_device(struct g_class *mp, const char *name)
50133808Spjd{
51133808Spjd	struct g_raid3_softc *sc;
52133808Spjd	struct g_geom *gp;
53133808Spjd
54156612Spjd	g_topology_lock();
55133808Spjd	LIST_FOREACH(gp, &mp->geom, geom) {
56133808Spjd		sc = gp->softc;
57133808Spjd		if (sc == NULL)
58133808Spjd			continue;
59133808Spjd		if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) != 0)
60133808Spjd			continue;
61133808Spjd		if (strcmp(gp->name, name) == 0 ||
62133808Spjd		    strcmp(sc->sc_name, name) == 0) {
63156612Spjd			g_topology_unlock();
64156612Spjd			sx_xlock(&sc->sc_lock);
65133808Spjd			return (sc);
66133808Spjd		}
67133808Spjd	}
68156612Spjd	g_topology_unlock();
69133808Spjd	return (NULL);
70133808Spjd}
71133808Spjd
72133808Spjdstatic struct g_raid3_disk *
73133808Spjdg_raid3_find_disk(struct g_raid3_softc *sc, const char *name)
74133808Spjd{
75133808Spjd	struct g_raid3_disk *disk;
76133808Spjd	u_int n;
77133808Spjd
78156612Spjd	sx_assert(&sc->sc_lock, SX_XLOCKED);
79160330Spjd	if (strncmp(name, "/dev/", 5) == 0)
80160330Spjd		name += 5;
81133808Spjd	for (n = 0; n < sc->sc_ndisks; n++) {
82133808Spjd		disk = &sc->sc_disks[n];
83133808Spjd		if (disk->d_state == G_RAID3_DISK_STATE_NODISK)
84133808Spjd			continue;
85133808Spjd		if (disk->d_consumer == NULL)
86133808Spjd			continue;
87133808Spjd		if (disk->d_consumer->provider == NULL)
88133808Spjd			continue;
89133808Spjd		if (strcmp(disk->d_consumer->provider->name, name) == 0)
90133808Spjd			return (disk);
91133808Spjd	}
92133808Spjd	return (NULL);
93133808Spjd}
94133808Spjd
95133808Spjdstatic void
96133808Spjdg_raid3_ctl_configure(struct gctl_req *req, struct g_class *mp)
97133808Spjd{
98133808Spjd	struct g_raid3_softc *sc;
99133808Spjd	struct g_raid3_disk *disk;
100133808Spjd	const char *name;
101134124Spjd	int *nargs, do_sync = 0;
102134168Spjd	int *autosync, *noautosync;
103134168Spjd	int *round_robin, *noround_robin;
104134168Spjd	int *verify, *noverify;
105133808Spjd	u_int n;
106133808Spjd
107133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
108144142Spjd	if (nargs == NULL) {
109144142Spjd		gctl_error(req, "No '%s' argument.", "nargs");
110144142Spjd		return;
111144142Spjd	}
112133808Spjd	if (*nargs != 1) {
113133808Spjd		gctl_error(req, "Invalid number of arguments.");
114133808Spjd		return;
115133808Spjd	}
116133808Spjd	autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync));
117133808Spjd	if (autosync == NULL) {
118133808Spjd		gctl_error(req, "No '%s' argument.", "autosync");
119133808Spjd		return;
120133808Spjd	}
121133808Spjd	noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync));
122133808Spjd	if (noautosync == NULL) {
123133808Spjd		gctl_error(req, "No '%s' argument.", "noautosync");
124133808Spjd		return;
125133808Spjd	}
126133808Spjd	if (*autosync && *noautosync) {
127133808Spjd		gctl_error(req, "'%s' and '%s' specified.", "autosync",
128133808Spjd		    "noautosync");
129133808Spjd		return;
130133808Spjd	}
131134124Spjd	round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin));
132134124Spjd	if (round_robin == NULL) {
133134124Spjd		gctl_error(req, "No '%s' argument.", "round_robin");
134134124Spjd		return;
135134124Spjd	}
136134124Spjd	noround_robin = gctl_get_paraml(req, "noround_robin",
137134124Spjd	    sizeof(*noround_robin));
138134124Spjd	if (noround_robin == NULL) {
139134124Spjd		gctl_error(req, "No '%s' argument.", "noround_robin");
140134124Spjd		return;
141134124Spjd	}
142134124Spjd	if (*round_robin && *noround_robin) {
143134124Spjd		gctl_error(req, "'%s' and '%s' specified.", "round_robin",
144134124Spjd		    "noround_robin");
145134124Spjd		return;
146134124Spjd	}
147134168Spjd	verify = gctl_get_paraml(req, "verify", sizeof(*verify));
148134168Spjd	if (verify == NULL) {
149134168Spjd		gctl_error(req, "No '%s' argument.", "verify");
150134168Spjd		return;
151134168Spjd	}
152134168Spjd	noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify));
153134168Spjd	if (noverify == NULL) {
154134168Spjd		gctl_error(req, "No '%s' argument.", "noverify");
155134168Spjd		return;
156134168Spjd	}
157134168Spjd	if (*verify && *noverify) {
158134168Spjd		gctl_error(req, "'%s' and '%s' specified.", "verify",
159134168Spjd		    "noverify");
160134168Spjd		return;
161134168Spjd	}
162134168Spjd	if (!*autosync && !*noautosync && !*round_robin && !*noround_robin &&
163134168Spjd	    !*verify && !*noverify) {
164134124Spjd		gctl_error(req, "Nothing has changed.");
165134124Spjd		return;
166134124Spjd	}
167156612Spjd	name = gctl_get_asciiparam(req, "arg0");
168156612Spjd	if (name == NULL) {
169156612Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
170156612Spjd		return;
171156612Spjd	}
172156612Spjd	sc = g_raid3_find_device(mp, name);
173156612Spjd	if (sc == NULL) {
174156612Spjd		gctl_error(req, "No such device: %s.", name);
175156612Spjd		return;
176156612Spjd	}
177156612Spjd	if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) {
178156612Spjd		gctl_error(req, "Not all disks connected.");
179156612Spjd		sx_xunlock(&sc->sc_lock);
180156612Spjd		return;
181156612Spjd	}
182133808Spjd	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) {
183133808Spjd		if (*autosync) {
184133808Spjd			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
185133808Spjd			do_sync = 1;
186133808Spjd		}
187133808Spjd	} else {
188133808Spjd		if (*noautosync)
189133808Spjd			sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
190133808Spjd	}
191134168Spjd	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) {
192134168Spjd		if (*noverify)
193134168Spjd			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY;
194134168Spjd	} else {
195134168Spjd		if (*verify)
196134168Spjd			sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY;
197134168Spjd	}
198134124Spjd	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
199134124Spjd		if (*noround_robin)
200134124Spjd			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
201134124Spjd	} else {
202134124Spjd		if (*round_robin)
203134124Spjd			sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
204134124Spjd	}
205134168Spjd	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 &&
206134168Spjd	    (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
207134168Spjd		/*
208134168Spjd		 * VERIFY and ROUND-ROBIN options are mutally exclusive.
209134168Spjd		 */
210134168Spjd		sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
211134168Spjd	}
212133808Spjd	for (n = 0; n < sc->sc_ndisks; n++) {
213133808Spjd		disk = &sc->sc_disks[n];
214133808Spjd		if (do_sync) {
215133808Spjd			if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING)
216133808Spjd				disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC;
217133808Spjd		}
218133808Spjd		g_raid3_update_metadata(disk);
219133808Spjd		if (do_sync) {
220133808Spjd			if (disk->d_state == G_RAID3_DISK_STATE_STALE) {
221133808Spjd				/*
222133808Spjd				 * XXX: This is probably possible that this
223133808Spjd				 *      component will not be retasted.
224133808Spjd				 */
225133808Spjd				g_raid3_event_send(disk,
226133808Spjd				    G_RAID3_DISK_STATE_DISCONNECTED,
227133808Spjd				    G_RAID3_EVENT_DONTWAIT);
228133808Spjd			}
229133808Spjd		}
230133808Spjd	}
231156612Spjd	sx_xunlock(&sc->sc_lock);
232133808Spjd}
233133808Spjd
234133808Spjdstatic void
235133808Spjdg_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp)
236133808Spjd{
237139671Spjd	struct g_raid3_metadata md;
238133808Spjd	struct g_raid3_softc *sc;
239133808Spjd	struct g_raid3_disk *disk;
240139671Spjd	struct g_provider *pp;
241133808Spjd	const char *name;
242139671Spjd	int error, *nargs;
243133808Spjd
244133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
245133808Spjd	if (nargs == NULL) {
246133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
247133808Spjd		return;
248133808Spjd	}
249133808Spjd	if (*nargs != 2) {
250133808Spjd		gctl_error(req, "Invalid number of arguments.");
251133808Spjd		return;
252133808Spjd	}
253133808Spjd	name = gctl_get_asciiparam(req, "arg0");
254133808Spjd	if (name == NULL) {
255133808Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
256133808Spjd		return;
257133808Spjd	}
258133808Spjd	sc = g_raid3_find_device(mp, name);
259133808Spjd	if (sc == NULL) {
260133808Spjd		gctl_error(req, "No such device: %s.", name);
261133808Spjd		return;
262133808Spjd	}
263133808Spjd	name = gctl_get_asciiparam(req, "arg1");
264133808Spjd	if (name == NULL) {
265133808Spjd		gctl_error(req, "No 'arg%u' argument.", 1);
266156612Spjd		sx_xunlock(&sc->sc_lock);
267133808Spjd		return;
268133808Spjd	}
269133808Spjd	disk = g_raid3_find_disk(sc, name);
270133808Spjd	if (disk == NULL) {
271133808Spjd		gctl_error(req, "No such provider: %s.", name);
272156612Spjd		sx_xunlock(&sc->sc_lock);
273133808Spjd		return;
274133808Spjd	}
275133808Spjd	if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE &&
276133808Spjd	    g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) {
277133808Spjd		gctl_error(req, "There is one stale disk already.", name);
278156612Spjd		sx_xunlock(&sc->sc_lock);
279133808Spjd		return;
280133808Spjd	}
281133808Spjd	/*
282133808Spjd	 * Do rebuild by resetting syncid and disconnecting disk.
283133808Spjd	 * It'll be retasted, connected to the device and synchronized.
284133808Spjd	 */
285133808Spjd	disk->d_sync.ds_syncid = 0;
286133808Spjd	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0)
287133808Spjd		disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC;
288133808Spjd	g_raid3_update_metadata(disk);
289139671Spjd	pp = disk->d_consumer->provider;
290156612Spjd	g_topology_lock();
291139671Spjd	error = g_raid3_read_metadata(disk->d_consumer, &md);
292156612Spjd	g_topology_unlock();
293133808Spjd	g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED,
294133808Spjd	    G_RAID3_EVENT_WAIT);
295139671Spjd	if (error != 0) {
296139671Spjd		gctl_error(req, "Cannot read metadata from %s.", pp->name);
297156612Spjd		sx_xunlock(&sc->sc_lock);
298139671Spjd		return;
299139671Spjd	}
300139671Spjd	error = g_raid3_add_disk(sc, pp, &md);
301156612Spjd	if (error != 0)
302139671Spjd		gctl_error(req, "Cannot reconnect component %s.", pp->name);
303156612Spjd	sx_xunlock(&sc->sc_lock);
304133808Spjd}
305133808Spjd
306133808Spjdstatic void
307133808Spjdg_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp)
308133808Spjd{
309133808Spjd	struct g_raid3_softc *sc;
310133808Spjd	int *force, *nargs, error;
311133808Spjd	const char *name;
312133808Spjd	char param[16];
313133808Spjd	u_int i;
314157630Spjd	int how;
315133808Spjd
316133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
317133808Spjd	if (nargs == NULL) {
318133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
319133808Spjd		return;
320133808Spjd	}
321133808Spjd	if (*nargs < 1) {
322133808Spjd		gctl_error(req, "Missing device(s).");
323133808Spjd		return;
324133808Spjd	}
325133808Spjd	force = gctl_get_paraml(req, "force", sizeof(*force));
326133808Spjd	if (force == NULL) {
327133808Spjd		gctl_error(req, "No '%s' argument.", "force");
328133808Spjd		return;
329133808Spjd	}
330157630Spjd	if (*force)
331157630Spjd		how = G_RAID3_DESTROY_HARD;
332157630Spjd	else
333157630Spjd		how = G_RAID3_DESTROY_SOFT;
334133808Spjd
335133808Spjd	for (i = 0; i < (u_int)*nargs; i++) {
336133808Spjd		snprintf(param, sizeof(param), "arg%u", i);
337133808Spjd		name = gctl_get_asciiparam(req, param);
338133808Spjd		if (name == NULL) {
339133808Spjd			gctl_error(req, "No 'arg%u' argument.", i);
340133808Spjd			return;
341133808Spjd		}
342133808Spjd		sc = g_raid3_find_device(mp, name);
343133808Spjd		if (sc == NULL) {
344133808Spjd			gctl_error(req, "No such device: %s.", name);
345133808Spjd			return;
346133808Spjd		}
347157630Spjd		g_cancel_event(sc);
348157630Spjd		error = g_raid3_destroy(sc, how);
349133808Spjd		if (error != 0) {
350133808Spjd			gctl_error(req, "Cannot destroy device %s (error=%d).",
351133808Spjd			    sc->sc_geom->name, error);
352156612Spjd			sx_xunlock(&sc->sc_lock);
353133808Spjd			return;
354133808Spjd		}
355156612Spjd		/* No need to unlock, because lock is already dead. */
356133808Spjd	}
357133808Spjd}
358133808Spjd
359133808Spjdstatic void
360133808Spjdg_raid3_ctl_insert_orphan(struct g_consumer *cp)
361133808Spjd{
362133808Spjd
363133808Spjd	KASSERT(1 == 0, ("%s called while inserting %s.", __func__,
364133808Spjd	    cp->provider->name));
365133808Spjd}
366133808Spjd
367133808Spjdstatic void
368133808Spjdg_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp)
369133808Spjd{
370133808Spjd	struct g_raid3_metadata md;
371133808Spjd	struct g_raid3_softc *sc;
372133808Spjd	struct g_raid3_disk *disk;
373133808Spjd	struct g_geom *gp;
374133808Spjd	struct g_provider *pp;
375133808Spjd	struct g_consumer *cp;
376133808Spjd	const char *name;
377133808Spjd	u_char *sector;
378134420Spjd	off_t compsize;
379133808Spjd	intmax_t *no;
380133808Spjd	int *hardcode, *nargs, error;
381133808Spjd
382133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
383133808Spjd	if (nargs == NULL) {
384133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
385133808Spjd		return;
386133808Spjd	}
387133808Spjd	if (*nargs != 2) {
388133808Spjd		gctl_error(req, "Invalid number of arguments.");
389133808Spjd		return;
390133808Spjd	}
391156612Spjd	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
392156612Spjd	if (hardcode == NULL) {
393156612Spjd		gctl_error(req, "No '%s' argument.", "hardcode");
394133808Spjd		return;
395133808Spjd	}
396156612Spjd	name = gctl_get_asciiparam(req, "arg1");
397156612Spjd	if (name == NULL) {
398156612Spjd		gctl_error(req, "No 'arg%u' argument.", 1);
399133808Spjd		return;
400133808Spjd	}
401133808Spjd	no = gctl_get_paraml(req, "number", sizeof(*no));
402133808Spjd	if (no == NULL) {
403133808Spjd		gctl_error(req, "No '%s' argument.", "no");
404133808Spjd		return;
405133808Spjd	}
406160330Spjd	if (strncmp(name, "/dev/", 5) == 0)
407160330Spjd		name += 5;
408156612Spjd	g_topology_lock();
409156612Spjd	pp = g_provider_by_name(name);
410156612Spjd	if (pp == NULL) {
411156612Spjd		g_topology_unlock();
412156612Spjd		gctl_error(req, "Invalid provider.");
413156612Spjd		return;
414156612Spjd	}
415156612Spjd	gp = g_new_geomf(mp, "raid3:insert");
416156612Spjd	gp->orphan = g_raid3_ctl_insert_orphan;
417156612Spjd	cp = g_new_consumer(gp);
418156612Spjd	error = g_attach(cp, pp);
419156612Spjd	if (error != 0) {
420156612Spjd		g_topology_unlock();
421156612Spjd		gctl_error(req, "Cannot attach to %s.", pp->name);
422156612Spjd		goto end;
423156612Spjd	}
424156612Spjd	error = g_access(cp, 0, 1, 1);
425156612Spjd	if (error != 0) {
426156612Spjd		g_topology_unlock();
427156612Spjd		gctl_error(req, "Cannot access %s.", pp->name);
428156612Spjd		goto end;
429156612Spjd	}
430156612Spjd	g_topology_unlock();
431156612Spjd	name = gctl_get_asciiparam(req, "arg0");
432156612Spjd	if (name == NULL) {
433156612Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
434156612Spjd		goto end;
435156612Spjd	}
436156612Spjd	sc = g_raid3_find_device(mp, name);
437156612Spjd	if (sc == NULL) {
438156612Spjd		gctl_error(req, "No such device: %s.", name);
439156612Spjd		goto end;
440156612Spjd	}
441133808Spjd	if (*no >= sc->sc_ndisks) {
442156612Spjd		sx_xunlock(&sc->sc_lock);
443133808Spjd		gctl_error(req, "Invalid component number.");
444156612Spjd		goto end;
445133808Spjd	}
446133808Spjd	disk = &sc->sc_disks[*no];
447133808Spjd	if (disk->d_state != G_RAID3_DISK_STATE_NODISK) {
448156612Spjd		sx_xunlock(&sc->sc_lock);
449133808Spjd		gctl_error(req, "Component %u is already connected.", *no);
450156612Spjd		goto end;
451133808Spjd	}
452133808Spjd	if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) {
453156612Spjd		sx_xunlock(&sc->sc_lock);
454133808Spjd		gctl_error(req,
455133808Spjd		    "Cannot insert provider %s, because of its sector size.",
456133808Spjd		    pp->name);
457156612Spjd		goto end;
458133808Spjd	}
459134420Spjd	compsize = sc->sc_mediasize / (sc->sc_ndisks - 1);
460134420Spjd	if (compsize > pp->mediasize - pp->sectorsize) {
461156612Spjd		sx_xunlock(&sc->sc_lock);
462134420Spjd		gctl_error(req, "Provider %s too small.", pp->name);
463156612Spjd		goto end;
464134420Spjd	}
465134420Spjd	if (compsize < pp->mediasize - pp->sectorsize) {
466134420Spjd		gctl_error(req,
467134420Spjd		    "warning: %s: only %jd bytes from %jd bytes used.",
468134420Spjd		    pp->name, (intmax_t)compsize,
469134420Spjd		    (intmax_t)(pp->mediasize - pp->sectorsize));
470134420Spjd	}
471133808Spjd	g_raid3_fill_metadata(disk, &md);
472156612Spjd	sx_xunlock(&sc->sc_lock);
473133808Spjd	md.md_syncid = 0;
474133808Spjd        md.md_dflags = 0;
475133808Spjd	if (*hardcode)
476133808Spjd                strlcpy(md.md_provider, pp->name, sizeof(md.md_provider));
477133808Spjd        else
478133808Spjd                bzero(md.md_provider, sizeof(md.md_provider));
479156527Spjd	md.md_provsize = pp->mediasize;
480133808Spjd	sector = g_malloc(pp->sectorsize, M_WAITOK);
481133808Spjd	raid3_metadata_encode(&md, sector);
482133808Spjd	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
483133808Spjd	    pp->sectorsize);
484133808Spjd	g_free(sector);
485133808Spjd	if (error != 0)
486133808Spjd		gctl_error(req, "Cannot store metadata on %s.", pp->name);
487133808Spjdend:
488156612Spjd	g_topology_lock();
489146118Spjd	if (cp->acw > 0)
490146118Spjd		g_access(cp, 0, -1, -1);
491146118Spjd	if (cp->provider != NULL)
492146118Spjd		g_detach(cp);
493146118Spjd	g_destroy_consumer(cp);
494146117Spjd	g_destroy_geom(gp);
495156612Spjd	g_topology_unlock();
496133808Spjd}
497133808Spjd
498133808Spjdstatic void
499133808Spjdg_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp)
500133808Spjd{
501133808Spjd	struct g_raid3_softc *sc;
502133808Spjd	struct g_raid3_disk *disk;
503133808Spjd	const char *name;
504133808Spjd	intmax_t *no;
505133808Spjd	int *nargs;
506133808Spjd
507133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
508133808Spjd	if (nargs == NULL) {
509133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
510133808Spjd		return;
511133808Spjd	}
512133808Spjd	if (*nargs != 1) {
513133808Spjd		gctl_error(req, "Invalid number of arguments.");
514133808Spjd		return;
515133808Spjd	}
516156612Spjd	no = gctl_get_paraml(req, "number", sizeof(*no));
517156612Spjd	if (no == NULL) {
518156612Spjd		gctl_error(req, "No '%s' argument.", "no");
519156612Spjd		return;
520156612Spjd	}
521133808Spjd	name = gctl_get_asciiparam(req, "arg0");
522133808Spjd	if (name == NULL) {
523133808Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
524133808Spjd		return;
525133808Spjd	}
526133808Spjd	sc = g_raid3_find_device(mp, name);
527133808Spjd	if (sc == NULL) {
528133808Spjd		gctl_error(req, "No such device: %s.", name);
529133808Spjd		return;
530133808Spjd	}
531133808Spjd	if (*no >= sc->sc_ndisks) {
532156612Spjd		sx_xunlock(&sc->sc_lock);
533133808Spjd		gctl_error(req, "Invalid component number.");
534133808Spjd		return;
535133808Spjd	}
536133808Spjd	disk = &sc->sc_disks[*no];
537133808Spjd	switch (disk->d_state) {
538133808Spjd	case G_RAID3_DISK_STATE_ACTIVE:
539133808Spjd		/*
540133808Spjd		 * When replacing ACTIVE component, all the rest has to be also
541133808Spjd		 * ACTIVE.
542133808Spjd		 */
543133808Spjd		if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) <
544133808Spjd		    sc->sc_ndisks) {
545133808Spjd			gctl_error(req, "Cannot replace component number %u.",
546133808Spjd			    *no);
547156612Spjd			break;
548133808Spjd		}
549133808Spjd		/* FALLTHROUGH */
550133808Spjd	case G_RAID3_DISK_STATE_STALE:
551133808Spjd	case G_RAID3_DISK_STATE_SYNCHRONIZING:
552133808Spjd		if (g_raid3_clear_metadata(disk) != 0) {
553133808Spjd			gctl_error(req, "Cannot clear metadata on %s.",
554133808Spjd			    g_raid3_get_diskname(disk));
555139295Spjd		} else {
556139295Spjd			g_raid3_event_send(disk,
557139295Spjd			    G_RAID3_DISK_STATE_DISCONNECTED,
558156612Spjd			    G_RAID3_EVENT_DONTWAIT);
559133808Spjd		}
560133808Spjd		break;
561133808Spjd	case G_RAID3_DISK_STATE_NODISK:
562133808Spjd		break;
563133808Spjd	default:
564133808Spjd		gctl_error(req, "Cannot replace component number %u.", *no);
565156612Spjd		break;
566133808Spjd	}
567156612Spjd	sx_xunlock(&sc->sc_lock);
568133808Spjd}
569133808Spjd
570133808Spjdvoid
571133808Spjdg_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb)
572133808Spjd{
573133808Spjd	uint32_t *version;
574133808Spjd
575133808Spjd	g_topology_assert();
576133808Spjd
577133808Spjd	version = gctl_get_paraml(req, "version", sizeof(*version));
578133808Spjd	if (version == NULL) {
579133808Spjd		gctl_error(req, "No '%s' argument.", "version");
580133808Spjd		return;
581133808Spjd	}
582133808Spjd	if (*version != G_RAID3_VERSION) {
583133808Spjd		gctl_error(req, "Userland and kernel parts are out of sync.");
584133808Spjd		return;
585133808Spjd	}
586133808Spjd
587156612Spjd	g_topology_unlock();
588133808Spjd	if (strcmp(verb, "configure") == 0)
589133808Spjd		g_raid3_ctl_configure(req, mp);
590133808Spjd	else if (strcmp(verb, "insert") == 0)
591133808Spjd		g_raid3_ctl_insert(req, mp);
592133808Spjd	else if (strcmp(verb, "rebuild") == 0)
593133808Spjd		g_raid3_ctl_rebuild(req, mp);
594133808Spjd	else if (strcmp(verb, "remove") == 0)
595133808Spjd		g_raid3_ctl_remove(req, mp);
596133808Spjd	else if (strcmp(verb, "stop") == 0)
597133808Spjd		g_raid3_ctl_stop(req, mp);
598133808Spjd	else
599133808Spjd		gctl_error(req, "Unknown verb.");
600156612Spjd	g_topology_lock();
601133808Spjd}
602