xref: /freebsd/sys/geom/mirror/g_mirror_ctl.c (revision 97cb52fa9aefd90fad38790fded50905aeeb9b9e)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004-2009 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36 #include <sys/limits.h>
37 #include <sys/lock.h>
38 #include <sys/mutex.h>
39 #include <sys/bio.h>
40 #include <sys/sbuf.h>
41 #include <sys/sysctl.h>
42 #include <sys/malloc.h>
43 #include <sys/bitstring.h>
44 #include <vm/uma.h>
45 #include <machine/atomic.h>
46 #include <geom/geom.h>
47 #include <geom/geom_int.h>
48 #include <sys/proc.h>
49 #include <sys/kthread.h>
50 #include <geom/mirror/g_mirror.h>
51 
52 
53 static struct g_mirror_softc *
54 g_mirror_find_device(struct g_class *mp, const char *name)
55 {
56 	struct g_mirror_softc *sc;
57 	struct g_geom *gp;
58 
59 	g_topology_lock();
60 	LIST_FOREACH(gp, &mp->geom, geom) {
61 		sc = gp->softc;
62 		if (sc == NULL)
63 			continue;
64 		if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0)
65 			continue;
66 		if (strcmp(gp->name, name) == 0 ||
67 		    strcmp(sc->sc_name, name) == 0) {
68 			g_topology_unlock();
69 			sx_xlock(&sc->sc_lock);
70 			return (sc);
71 		}
72 	}
73 	g_topology_unlock();
74 	return (NULL);
75 }
76 
77 static struct g_mirror_disk *
78 g_mirror_find_disk(struct g_mirror_softc *sc, const char *name)
79 {
80 	struct g_mirror_disk *disk;
81 
82 	sx_assert(&sc->sc_lock, SX_XLOCKED);
83 	if (strncmp(name, "/dev/", 5) == 0)
84 		name += 5;
85 	LIST_FOREACH(disk, &sc->sc_disks, d_next) {
86 		if (disk->d_consumer == NULL)
87 			continue;
88 		if (disk->d_consumer->provider == NULL)
89 			continue;
90 		if (strcmp(disk->d_consumer->provider->name, name) == 0)
91 			return (disk);
92 	}
93 	return (NULL);
94 }
95 
96 static void
97 g_mirror_ctl_configure(struct gctl_req *req, struct g_class *mp)
98 {
99 	struct g_mirror_softc *sc;
100 	struct g_mirror_disk *disk;
101 	const char *name, *balancep, *prov;
102 	intmax_t *slicep, *priority;
103 	uint32_t slice;
104 	uint8_t balance;
105 	int *autosync, *noautosync, *failsync, *nofailsync, *hardcode, *dynamic;
106 	int *nargs, do_sync = 0, dirty = 1, do_priority = 0;
107 
108 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
109 	if (nargs == NULL) {
110 		gctl_error(req, "No '%s' argument.", "nargs");
111 		return;
112 	}
113 	if (*nargs != 1 && *nargs != 2) {
114 		gctl_error(req, "Invalid number of arguments.");
115 		return;
116 	}
117 	name = gctl_get_asciiparam(req, "arg0");
118 	if (name == NULL) {
119 		gctl_error(req, "No 'arg%u' argument.", 0);
120 		return;
121 	}
122 	balancep = gctl_get_asciiparam(req, "balance");
123 	if (balancep == NULL) {
124 		gctl_error(req, "No '%s' argument.", "balance");
125 		return;
126 	}
127 	autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync));
128 	if (autosync == NULL) {
129 		gctl_error(req, "No '%s' argument.", "autosync");
130 		return;
131 	}
132 	noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync));
133 	if (noautosync == NULL) {
134 		gctl_error(req, "No '%s' argument.", "noautosync");
135 		return;
136 	}
137 	failsync = gctl_get_paraml(req, "failsync", sizeof(*failsync));
138 	if (failsync == NULL) {
139 		gctl_error(req, "No '%s' argument.", "failsync");
140 		return;
141 	}
142 	nofailsync = gctl_get_paraml(req, "nofailsync", sizeof(*nofailsync));
143 	if (nofailsync == NULL) {
144 		gctl_error(req, "No '%s' argument.", "nofailsync");
145 		return;
146 	}
147 	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
148 	if (hardcode == NULL) {
149 		gctl_error(req, "No '%s' argument.", "hardcode");
150 		return;
151 	}
152 	dynamic = gctl_get_paraml(req, "dynamic", sizeof(*dynamic));
153 	if (dynamic == NULL) {
154 		gctl_error(req, "No '%s' argument.", "dynamic");
155 		return;
156 	}
157 	priority = gctl_get_paraml(req, "priority", sizeof(*priority));
158 	if (priority == NULL) {
159 		gctl_error(req, "No '%s' argument.", "priority");
160 		return;
161 	}
162 	if (*priority < -1 || *priority > 255) {
163 		gctl_error(req, "Priority range is 0 to 255, %jd given",
164 		    *priority);
165 		return;
166 	}
167 	/*
168 	 * Since we have a priority, we also need a provider now.
169 	 * Note: be WARNS safe, by always assigning prov and only throw an
170 	 * error if *priority != -1.
171 	 */
172 	prov = gctl_get_asciiparam(req, "arg1");
173 	if (*priority > -1) {
174 		if (prov == NULL) {
175 			gctl_error(req, "Priority needs a disk name");
176 			return;
177 		}
178 		do_priority = 1;
179 	}
180 	if (*autosync && *noautosync) {
181 		gctl_error(req, "'%s' and '%s' specified.", "autosync",
182 		    "noautosync");
183 		return;
184 	}
185 	if (*failsync && *nofailsync) {
186 		gctl_error(req, "'%s' and '%s' specified.", "failsync",
187 		    "nofailsync");
188 		return;
189 	}
190 	if (*hardcode && *dynamic) {
191 		gctl_error(req, "'%s' and '%s' specified.", "hardcode",
192 		    "dynamic");
193 		return;
194 	}
195 	sc = g_mirror_find_device(mp, name);
196 	if (sc == NULL) {
197 		gctl_error(req, "No such device: %s.", name);
198 		return;
199 	}
200 	if (*balancep == '\0')
201 		balance = sc->sc_balance;
202 	else {
203 		if (balance_id(balancep) == -1) {
204 			gctl_error(req, "Invalid balance algorithm.");
205 			sx_xunlock(&sc->sc_lock);
206 			return;
207 		}
208 		balance = balance_id(balancep);
209 	}
210 	slicep = gctl_get_paraml(req, "slice", sizeof(*slicep));
211 	if (slicep == NULL) {
212 		gctl_error(req, "No '%s' argument.", "slice");
213 		sx_xunlock(&sc->sc_lock);
214 		return;
215 	}
216 	if (*slicep == -1)
217 		slice = sc->sc_slice;
218 	else
219 		slice = *slicep;
220 	/* Enforce usage() of -p not allowing any other options. */
221 	if (do_priority && (*autosync || *noautosync || *failsync ||
222 	    *nofailsync || *hardcode || *dynamic || *slicep != -1 ||
223 	    *balancep != '\0')) {
224 		sx_xunlock(&sc->sc_lock);
225 		gctl_error(req, "only -p accepted when setting priority");
226 		return;
227 	}
228 	if (sc->sc_balance == balance && sc->sc_slice == slice && !*autosync &&
229 	    !*noautosync && !*failsync && !*nofailsync && !*hardcode &&
230 	    !*dynamic && !do_priority) {
231 		sx_xunlock(&sc->sc_lock);
232 		gctl_error(req, "Nothing has changed.");
233 		return;
234 	}
235 	if ((!do_priority && *nargs != 1) || (do_priority && *nargs != 2)) {
236 		sx_xunlock(&sc->sc_lock);
237 		gctl_error(req, "Invalid number of arguments.");
238 		return;
239 	}
240 	if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) {
241 		sx_xunlock(&sc->sc_lock);
242 		gctl_error(req, "Not all disks connected. Try 'forget' command "
243 		    "first.");
244 		return;
245 	}
246 	sc->sc_balance = balance;
247 	sc->sc_slice = slice;
248 	if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0) {
249 		if (*autosync) {
250 			sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_NOAUTOSYNC;
251 			do_sync = 1;
252 		}
253 	} else {
254 		if (*noautosync)
255 			sc->sc_flags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC;
256 	}
257 	if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOFAILSYNC) != 0) {
258 		if (*failsync)
259 			sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_NOFAILSYNC;
260 	} else {
261 		if (*nofailsync) {
262 			sc->sc_flags |= G_MIRROR_DEVICE_FLAG_NOFAILSYNC;
263 			dirty = 0;
264 		}
265 	}
266 	LIST_FOREACH(disk, &sc->sc_disks, d_next) {
267 		/*
268 		 * Handle priority first, since we only need one disk, do one
269 		 * operation on it and then we're done. No need to check other
270 		 * flags, as usage doesn't allow it.
271 		 */
272 		if (do_priority) {
273 			if (strcmp(disk->d_name, prov) == 0) {
274 				if (disk->d_priority == *priority)
275 					gctl_error(req, "Nothing has changed.");
276 				else {
277 					disk->d_priority = *priority;
278 					g_mirror_update_metadata(disk);
279 				}
280 				break;
281 			}
282 			continue;
283 		}
284 		if (do_sync) {
285 			if (disk->d_state == G_MIRROR_DISK_STATE_SYNCHRONIZING)
286 				disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC;
287 		}
288 		if (*hardcode)
289 			disk->d_flags |= G_MIRROR_DISK_FLAG_HARDCODED;
290 		else if (*dynamic)
291 			disk->d_flags &= ~G_MIRROR_DISK_FLAG_HARDCODED;
292 		if (!dirty)
293 			disk->d_flags &= ~G_MIRROR_DISK_FLAG_DIRTY;
294 		g_mirror_update_metadata(disk);
295 		if (do_sync) {
296 			if (disk->d_state == G_MIRROR_DISK_STATE_STALE) {
297 				g_mirror_event_send(disk,
298 				    G_MIRROR_DISK_STATE_DISCONNECTED,
299 				    G_MIRROR_EVENT_DONTWAIT);
300 			}
301 		}
302 	}
303 	sx_xunlock(&sc->sc_lock);
304 }
305 
306 static void
307 g_mirror_create_orphan(struct g_consumer *cp)
308 {
309 
310 	KASSERT(1 == 0, ("%s called while creating %s.", __func__,
311 	    cp->provider->name));
312 }
313 
314 static void
315 g_mirror_ctl_create(struct gctl_req *req, struct g_class *mp)
316 {
317 	struct g_mirror_metadata md;
318 	struct g_geom *gp;
319 	struct g_consumer *cp;
320 	struct g_provider *pp;
321 	struct g_mirror_softc *sc;
322 	struct sbuf *sb;
323 	const char *name;
324 	char param[16];
325 	int *nargs;
326 	intmax_t *val;
327 	int *ival;
328 	const char *sval;
329 	int bal;
330 	unsigned attached, no, sectorsize;
331 	off_t mediasize;
332 
333 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
334 	if (nargs == NULL) {
335 		gctl_error(req, "No '%s' argument.", "nargs");
336 		return;
337 	}
338 	if (*nargs <= 2) {
339 		gctl_error(req, "Too few arguments.");
340 		return;
341 	}
342 
343 	strlcpy(md.md_magic, G_MIRROR_MAGIC, sizeof(md.md_magic));
344 	md.md_version = G_MIRROR_VERSION;
345 	name = gctl_get_asciiparam(req, "arg0");
346 	if (name == NULL) {
347 		gctl_error(req, "No 'arg%u' argument.", 0);
348 		return;
349 	}
350 	strlcpy(md.md_name, name, sizeof(md.md_name));
351 	md.md_mid = arc4random();
352 	md.md_all = *nargs - 1;
353 	md.md_genid = 0;
354 	md.md_syncid = 1;
355 	md.md_sync_offset = 0;
356 	val = gctl_get_paraml(req, "slice", sizeof(*val));
357 	if (val == NULL) {
358 		gctl_error(req, "No slice argument.");
359 		return;
360 	}
361 	md.md_slice = *val;
362 	sval = gctl_get_asciiparam(req, "balance");
363 	if (sval == NULL) {
364 		gctl_error(req, "No balance argument.");
365 		return;
366 	}
367 	bal = balance_id(sval);
368 	if (bal < 0) {
369 		gctl_error(req, "Invalid balance algorithm.");
370 		return;
371 	}
372 	md.md_balance = bal;
373 	md.md_mflags = 0;
374 	md.md_dflags = 0;
375 	ival = gctl_get_paraml(req, "noautosync", sizeof(*ival));
376 	if (ival != NULL && *ival)
377 		md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC;
378 	ival = gctl_get_paraml(req, "nofailsync", sizeof(*ival));
379 	if (ival != NULL && *ival)
380 		md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOFAILSYNC;
381 	/* These fields not used in manual mode. */
382 	bzero(md.md_provider, sizeof(md.md_provider));
383 	md.md_provsize = 0;
384 
385 	g_topology_lock();
386 	mediasize = OFF_MAX;
387 	sectorsize = 0;
388 	gp = g_new_geomf(mp, "%s", md.md_name);
389 	gp->orphan = g_mirror_create_orphan;
390 	cp = g_new_consumer(gp);
391 	for (no = 1; no < *nargs; no++) {
392 		snprintf(param, sizeof(param), "arg%u", no);
393 		name = gctl_get_asciiparam(req, param);
394 		if (name == NULL) {
395 			gctl_error(req, "No 'arg%u' argument.", no);
396 err:
397 			g_destroy_consumer(cp);
398 			g_destroy_geom(gp);
399 			g_topology_unlock();
400 			return;
401 		}
402 		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
403 			name += strlen("/dev/");
404 		pp = g_provider_by_name(name);
405 		if (pp == NULL) {
406 			G_MIRROR_DEBUG(1, "Disk %s is invalid.", name);
407 			gctl_error(req, "Disk %s is invalid.", name);
408 			goto err;
409 		}
410 		g_attach(cp, pp);
411 		if (g_access(cp, 1, 0, 0) != 0) {
412 			G_MIRROR_DEBUG(1, "Can't open disk %s.", name);
413 			gctl_error(req, "Can't open disk %s.", name);
414 err2:
415 			g_detach(cp);
416 			goto err;
417 		}
418 		if (pp->mediasize == 0 || pp->sectorsize == 0) {
419 			G_MIRROR_DEBUG(1, "Disk %s has no media.", name);
420 			gctl_error(req, "Disk %s has no media.", name);
421 			g_access(cp, -1, 0, 0);
422 			goto err2;
423 		}
424 		if (pp->mediasize < mediasize)
425 			mediasize = pp->mediasize;
426 		if (pp->sectorsize > sectorsize)
427 			sectorsize = pp->sectorsize;
428 		g_access(cp, -1, 0, 0);
429 		g_detach(cp);
430 	}
431 	g_destroy_consumer(cp);
432 	g_destroy_geom(gp);
433 	md.md_mediasize = mediasize;
434 	md.md_sectorsize = sectorsize;
435 	md.md_mediasize -= (md.md_mediasize % md.md_sectorsize);
436 
437 	gp = g_mirror_create(mp, &md, G_MIRROR_TYPE_MANUAL);
438 	if (gp == NULL) {
439 		gctl_error(req, "Can't create %s.", md.md_name);
440 		g_topology_unlock();
441 		return;
442 	}
443 
444 	sc = gp->softc;
445 	g_topology_unlock();
446 	sx_xlock(&sc->sc_lock);
447 	sc->sc_flags |= G_MIRROR_DEVICE_FLAG_TASTING;
448 	sb = sbuf_new_auto();
449 	sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name);
450 	for (attached = 0, no = 1; no < *nargs; no++) {
451 		snprintf(param, sizeof(param), "arg%u", no);
452 		name = gctl_get_asciiparam(req, param);
453 		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
454 			name += strlen("/dev/");
455 		pp = g_provider_by_name(name);
456 		if (pp == NULL) {
457 			G_MIRROR_DEBUG(1, "Provider %s disappear?!", name);
458 			sbuf_printf(sb, " %s", name);
459 			continue;
460 		}
461 		md.md_did = arc4random();
462 		md.md_priority = no - 1;
463 		if (g_mirror_add_disk(sc, pp, &md) != 0) {
464 			G_MIRROR_DEBUG(1, "Disk %u (%s) not attached to %s.",
465 			    no, pp->name, gp->name);
466 			sbuf_printf(sb, " %s", pp->name);
467 			continue;
468 		}
469 		attached++;
470 	}
471 	sbuf_finish(sb);
472 	sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_TASTING;
473 	if (md.md_all != attached ||
474 	    (sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) {
475 		g_mirror_destroy(gp->softc, G_MIRROR_DESTROY_HARD);
476 		gctl_error(req, "%s", sbuf_data(sb));
477 	} else
478 		sx_xunlock(&sc->sc_lock);
479 	sbuf_delete(sb);
480 }
481 
482 static void
483 g_mirror_ctl_rebuild(struct gctl_req *req, struct g_class *mp)
484 {
485 	struct g_mirror_metadata md;
486 	struct g_mirror_softc *sc;
487 	struct g_mirror_disk *disk;
488 	struct g_provider *pp;
489 	const char *name;
490 	char param[16];
491 	int error, *nargs;
492 	u_int i;
493 
494 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
495 	if (nargs == NULL) {
496 		gctl_error(req, "No '%s' argument.", "nargs");
497 		return;
498 	}
499 	if (*nargs < 2) {
500 		gctl_error(req, "Too few arguments.");
501 		return;
502 	}
503 	name = gctl_get_asciiparam(req, "arg0");
504 	if (name == NULL) {
505 		gctl_error(req, "No 'arg%u' argument.", 0);
506 		return;
507 	}
508 	sc = g_mirror_find_device(mp, name);
509 	if (sc == NULL) {
510 		gctl_error(req, "No such device: %s.", name);
511 		return;
512 	}
513 	for (i = 1; i < (u_int)*nargs; i++) {
514 		snprintf(param, sizeof(param), "arg%u", i);
515 		name = gctl_get_asciiparam(req, param);
516 		if (name == NULL) {
517 			gctl_error(req, "No 'arg%u' argument.", i);
518 			continue;
519 		}
520 		disk = g_mirror_find_disk(sc, name);
521 		if (disk == NULL) {
522 			gctl_error(req, "No such provider: %s.", name);
523 			continue;
524 		}
525 		if (g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) == 1 &&
526 		    disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) {
527 			/*
528 			 * This is the last active disk. There will be nothing
529 			 * to rebuild it from, so deny this request.
530 			 */
531 			gctl_error(req,
532 			    "Provider %s is the last active provider in %s.",
533 			    name, sc->sc_geom->name);
534 			break;
535 		}
536 		/*
537 		 * Do rebuild by resetting syncid, disconnecting the disk and
538 		 * connecting it again.
539 		 */
540 		disk->d_sync.ds_syncid = 0;
541 		if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0)
542 			disk->d_flags |= G_MIRROR_DISK_FLAG_FORCE_SYNC;
543 		g_mirror_update_metadata(disk);
544 		pp = disk->d_consumer->provider;
545 		g_topology_lock();
546 		error = g_mirror_read_metadata(disk->d_consumer, &md);
547 		g_topology_unlock();
548 		g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED,
549 		    G_MIRROR_EVENT_WAIT);
550 		if (error != 0) {
551 			gctl_error(req, "Cannot read metadata from %s.",
552 			    pp->name);
553 			continue;
554 		}
555 		error = g_mirror_add_disk(sc, pp, &md);
556 		if (error != 0) {
557 			gctl_error(req, "Cannot reconnect component %s.",
558 			    pp->name);
559 			continue;
560 		}
561 	}
562 	sx_xunlock(&sc->sc_lock);
563 }
564 
565 static void
566 g_mirror_ctl_insert(struct gctl_req *req, struct g_class *mp)
567 {
568 	struct g_mirror_softc *sc;
569 	struct g_mirror_disk *disk;
570 	struct g_mirror_metadata md;
571 	struct g_provider *pp;
572 	struct g_consumer *cp;
573 	intmax_t *priority;
574 	const char *name;
575 	char param[16];
576 	u_char *sector;
577 	u_int i, n;
578 	int error, *nargs, *hardcode, *inactive;
579 	struct {
580 		struct g_provider	*provider;
581 		struct g_consumer	*consumer;
582 	} *disks;
583 	off_t mdsize;
584 
585 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
586 	if (nargs == NULL) {
587 		gctl_error(req, "No '%s' argument.", "nargs");
588 		return;
589 	}
590 	if (*nargs < 2) {
591 		gctl_error(req, "Too few arguments.");
592 		return;
593 	}
594 	priority = gctl_get_paraml(req, "priority", sizeof(*priority));
595 	if (priority == NULL) {
596 		gctl_error(req, "No '%s' argument.", "priority");
597 		return;
598 	}
599 	inactive = gctl_get_paraml(req, "inactive", sizeof(*inactive));
600 	if (inactive == NULL) {
601 		gctl_error(req, "No '%s' argument.", "inactive");
602 		return;
603 	}
604 	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
605 	if (hardcode == NULL) {
606 		gctl_error(req, "No '%s' argument.", "hardcode");
607 		return;
608 	}
609 	name = gctl_get_asciiparam(req, "arg0");
610 	if (name == NULL) {
611 		gctl_error(req, "No 'arg%u' argument.", 0);
612 		return;
613 	}
614 	sc = g_mirror_find_device(mp, name);
615 	if (sc == NULL) {
616 		gctl_error(req, "No such device: %s.", name);
617 		return;
618 	}
619 	if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) {
620 		gctl_error(req, "Not all disks connected.");
621 		sx_xunlock(&sc->sc_lock);
622 		return;
623 	}
624 
625 	disks = g_malloc(sizeof(*disks) * (*nargs), M_WAITOK | M_ZERO);
626 	g_topology_lock();
627 	for (i = 1, n = 0; i < (u_int)*nargs; i++) {
628 		snprintf(param, sizeof(param), "arg%u", i);
629 		name = gctl_get_asciiparam(req, param);
630 		if (name == NULL) {
631 			gctl_error(req, "No 'arg%u' argument.", i);
632 			continue;
633 		}
634 		if (g_mirror_find_disk(sc, name) != NULL) {
635 			gctl_error(req, "Provider %s already inserted.", name);
636 			continue;
637 		}
638 		if (strncmp(name, "/dev/", 5) == 0)
639 			name += 5;
640 		pp = g_provider_by_name(name);
641 		if (pp == NULL) {
642 			gctl_error(req, "Unknown provider %s.", name);
643 			continue;
644 		}
645 		cp = g_new_consumer(sc->sc_geom);
646 		if (g_attach(cp, pp) != 0) {
647 			g_destroy_consumer(cp);
648 			gctl_error(req, "Cannot attach to provider %s.", name);
649 			continue;
650 		}
651 		if (g_access(cp, 0, 1, 1) != 0) {
652 			gctl_error(req, "Cannot access provider %s.", name);
653 err:
654 			g_detach(cp);
655 			g_destroy_consumer(cp);
656 			continue;
657 		}
658 		mdsize = (sc->sc_type == G_MIRROR_TYPE_AUTOMATIC) ?
659 		    pp->sectorsize : 0;
660 		if (sc->sc_provider->mediasize > pp->mediasize - mdsize) {
661 			gctl_error(req, "Provider %s too small.", name);
662 err2:
663 			g_access(cp, 0, -1, -1);
664 			goto err;
665 		}
666 		if ((sc->sc_provider->sectorsize % pp->sectorsize) != 0) {
667 			gctl_error(req, "Invalid sectorsize of provider %s.",
668 			    name);
669 			goto err2;
670 		}
671 		if (sc->sc_type != G_MIRROR_TYPE_AUTOMATIC) {
672 			g_access(cp, 0, -1, -1);
673 			g_detach(cp);
674 			g_destroy_consumer(cp);
675 			g_topology_unlock();
676 			sc->sc_ndisks++;
677 			g_mirror_fill_metadata(sc, NULL, &md);
678 			md.md_priority = *priority;
679 			if (*inactive)
680 				md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE;
681 			if (g_mirror_add_disk(sc, pp, &md) != 0) {
682 				sc->sc_ndisks--;
683 				gctl_error(req, "Disk %s not inserted.", name);
684 			}
685 			g_topology_lock();
686 			continue;
687 		}
688 		disks[n].provider = pp;
689 		disks[n].consumer = cp;
690 		n++;
691 	}
692 	if (n == 0) {
693 		g_topology_unlock();
694 		sx_xunlock(&sc->sc_lock);
695 		g_free(disks);
696 		return;
697 	}
698 	sc->sc_ndisks += n;
699 again:
700 	for (i = 0; i < n; i++) {
701 		if (disks[i].consumer == NULL)
702 			continue;
703 		g_mirror_fill_metadata(sc, NULL, &md);
704 		md.md_priority = *priority;
705 		if (*inactive)
706 			md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE;
707 		pp = disks[i].provider;
708 		if (*hardcode) {
709 			strlcpy(md.md_provider, pp->name,
710 			    sizeof(md.md_provider));
711 		} else {
712 			bzero(md.md_provider, sizeof(md.md_provider));
713 		}
714 		md.md_provsize = pp->mediasize;
715 		sector = g_malloc(pp->sectorsize, M_WAITOK);
716 		mirror_metadata_encode(&md, sector);
717 		error = g_write_data(disks[i].consumer,
718 		    pp->mediasize - pp->sectorsize, sector, pp->sectorsize);
719 		g_free(sector);
720 		if (error != 0) {
721 			gctl_error(req, "Cannot store metadata on %s.",
722 			    pp->name);
723 			g_access(disks[i].consumer, 0, -1, -1);
724 			g_detach(disks[i].consumer);
725 			g_destroy_consumer(disks[i].consumer);
726 			disks[i].consumer = NULL;
727 			disks[i].provider = NULL;
728 			sc->sc_ndisks--;
729 			goto again;
730 		}
731 	}
732 	g_topology_unlock();
733 	if (i == 0) {
734 		/* All writes failed. */
735 		sx_xunlock(&sc->sc_lock);
736 		g_free(disks);
737 		return;
738 	}
739 	LIST_FOREACH(disk, &sc->sc_disks, d_next) {
740 		g_mirror_update_metadata(disk);
741 	}
742 	/*
743 	 * Release provider and wait for retaste.
744 	 */
745 	g_topology_lock();
746 	for (i = 0; i < n; i++) {
747 		if (disks[i].consumer == NULL)
748 			continue;
749 		g_access(disks[i].consumer, 0, -1, -1);
750 		g_detach(disks[i].consumer);
751 		g_destroy_consumer(disks[i].consumer);
752 	}
753 	g_topology_unlock();
754 	sx_xunlock(&sc->sc_lock);
755 	g_free(disks);
756 }
757 
758 static void
759 g_mirror_ctl_remove(struct gctl_req *req, struct g_class *mp)
760 {
761 	struct g_mirror_softc *sc;
762 	struct g_mirror_disk *disk;
763 	const char *name;
764 	char param[16];
765 	int *nargs;
766 	u_int i, active;
767 
768 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
769 	if (nargs == NULL) {
770 		gctl_error(req, "No '%s' argument.", "nargs");
771 		return;
772 	}
773 	if (*nargs < 2) {
774 		gctl_error(req, "Too few arguments.");
775 		return;
776 	}
777 	name = gctl_get_asciiparam(req, "arg0");
778 	if (name == NULL) {
779 		gctl_error(req, "No 'arg%u' argument.", 0);
780 		return;
781 	}
782 	sc = g_mirror_find_device(mp, name);
783 	if (sc == NULL) {
784 		gctl_error(req, "No such device: %s.", name);
785 		return;
786 	}
787 	if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) {
788 		sx_xunlock(&sc->sc_lock);
789 		gctl_error(req, "Not all disks connected. Try 'forget' command "
790 		    "first.");
791 		return;
792 	}
793 	active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE);
794 	for (i = 1; i < (u_int)*nargs; i++) {
795 		snprintf(param, sizeof(param), "arg%u", i);
796 		name = gctl_get_asciiparam(req, param);
797 		if (name == NULL) {
798 			gctl_error(req, "No 'arg%u' argument.", i);
799 			continue;
800 		}
801 		disk = g_mirror_find_disk(sc, name);
802 		if (disk == NULL) {
803 			gctl_error(req, "No such provider: %s.", name);
804 			continue;
805 		}
806 		if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) {
807 			if (active > 1)
808 				active--;
809 			else {
810 				gctl_error(req, "%s: Can't remove the last "
811 				    "ACTIVE component %s.", sc->sc_geom->name,
812 				    name);
813 				continue;
814 			}
815 		}
816 		g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DESTROY,
817 		    G_MIRROR_EVENT_DONTWAIT);
818 	}
819 	sx_xunlock(&sc->sc_lock);
820 }
821 
822 static void
823 g_mirror_ctl_resize(struct gctl_req *req, struct g_class *mp)
824 {
825 	struct g_mirror_softc *sc;
826 	struct g_mirror_disk *disk;
827 	uint64_t mediasize;
828 	const char *name, *s;
829 	char *x;
830 	int *nargs;
831 
832 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
833 	if (nargs == NULL) {
834 		gctl_error(req, "No '%s' argument.", "nargs");
835 		return;
836 	}
837 	if (*nargs != 1) {
838 		gctl_error(req, "Missing device.");
839 		return;
840 	}
841 	name = gctl_get_asciiparam(req, "arg0");
842 	if (name == NULL) {
843 		gctl_error(req, "No 'arg%u' argument.", 0);
844 		return;
845 	}
846 	s = gctl_get_asciiparam(req, "size");
847 	if (s == NULL) {
848 		gctl_error(req, "No '%s' argument.", "size");
849 		return;
850 	}
851 	mediasize = strtouq(s, &x, 0);
852 	if (*x != '\0' || mediasize == 0) {
853 		gctl_error(req, "Invalid '%s' argument.", "size");
854 		return;
855 	}
856 	sc = g_mirror_find_device(mp, name);
857 	if (sc == NULL) {
858 		gctl_error(req, "No such device: %s.", name);
859 		return;
860 	}
861 	/* Deny shrinking of an opened provider */
862 	if ((g_debugflags & 16) == 0 && sc->sc_provider_open > 0) {
863 		if (sc->sc_mediasize > mediasize) {
864 			gctl_error(req, "Device %s is busy.",
865 			    sc->sc_provider->name);
866 			sx_xunlock(&sc->sc_lock);
867 			return;
868 		}
869 	}
870 	LIST_FOREACH(disk, &sc->sc_disks, d_next) {
871 		if (mediasize > disk->d_consumer->provider->mediasize -
872 		    disk->d_consumer->provider->sectorsize) {
873 			gctl_error(req, "Provider %s is too small.",
874 			    disk->d_name);
875 			sx_xunlock(&sc->sc_lock);
876 			return;
877 		}
878 	}
879 	/* Update the size. */
880 	sc->sc_mediasize = mediasize;
881 	LIST_FOREACH(disk, &sc->sc_disks, d_next) {
882 		g_mirror_update_metadata(disk);
883 	}
884 	g_topology_lock();
885 	g_resize_provider(sc->sc_provider, mediasize);
886 	g_topology_unlock();
887 	sx_xunlock(&sc->sc_lock);
888 }
889 
890 static void
891 g_mirror_ctl_deactivate(struct gctl_req *req, struct g_class *mp)
892 {
893 	struct g_mirror_softc *sc;
894 	struct g_mirror_disk *disk;
895 	const char *name;
896 	char param[16];
897 	int *nargs;
898 	u_int i, active;
899 
900 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
901 	if (nargs == NULL) {
902 		gctl_error(req, "No '%s' argument.", "nargs");
903 		return;
904 	}
905 	if (*nargs < 2) {
906 		gctl_error(req, "Too few arguments.");
907 		return;
908 	}
909 	name = gctl_get_asciiparam(req, "arg0");
910 	if (name == NULL) {
911 		gctl_error(req, "No 'arg%u' argument.", 0);
912 		return;
913 	}
914 	sc = g_mirror_find_device(mp, name);
915 	if (sc == NULL) {
916 		gctl_error(req, "No such device: %s.", name);
917 		return;
918 	}
919 	active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE);
920 	for (i = 1; i < (u_int)*nargs; i++) {
921 		snprintf(param, sizeof(param), "arg%u", i);
922 		name = gctl_get_asciiparam(req, param);
923 		if (name == NULL) {
924 			gctl_error(req, "No 'arg%u' argument.", i);
925 			continue;
926 		}
927 		disk = g_mirror_find_disk(sc, name);
928 		if (disk == NULL) {
929 			gctl_error(req, "No such provider: %s.", name);
930 			continue;
931 		}
932 		if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) {
933 			if (active > 1)
934 				active--;
935 			else {
936 				gctl_error(req, "%s: Can't deactivate the "
937 				    "last ACTIVE component %s.",
938 				    sc->sc_geom->name, name);
939 				continue;
940 			}
941 		}
942 		disk->d_flags |= G_MIRROR_DISK_FLAG_INACTIVE;
943 		disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC;
944 		g_mirror_update_metadata(disk);
945 		sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID;
946 		g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED,
947 		    G_MIRROR_EVENT_DONTWAIT);
948 	}
949 	sx_xunlock(&sc->sc_lock);
950 }
951 
952 static void
953 g_mirror_ctl_forget(struct gctl_req *req, struct g_class *mp)
954 {
955 	struct g_mirror_softc *sc;
956 	struct g_mirror_disk *disk;
957 	const char *name;
958 	char param[16];
959 	int *nargs;
960 	u_int i;
961 
962 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
963 	if (nargs == NULL) {
964 		gctl_error(req, "No '%s' argument.", "nargs");
965 		return;
966 	}
967 	if (*nargs < 1) {
968 		gctl_error(req, "Missing device(s).");
969 		return;
970 	}
971 
972 	for (i = 0; i < (u_int)*nargs; i++) {
973 		snprintf(param, sizeof(param), "arg%u", i);
974 		name = gctl_get_asciiparam(req, param);
975 		if (name == NULL) {
976 			gctl_error(req, "No 'arg%u' argument.", i);
977 			return;
978 		}
979 		sc = g_mirror_find_device(mp, name);
980 		if (sc == NULL) {
981 			gctl_error(req, "No such device: %s.", name);
982 			return;
983 		}
984 		if (g_mirror_ndisks(sc, -1) == sc->sc_ndisks) {
985 			sx_xunlock(&sc->sc_lock);
986 			G_MIRROR_DEBUG(1,
987 			    "All disks connected in %s, skipping.",
988 			    sc->sc_name);
989 			continue;
990 		}
991 		sc->sc_ndisks = g_mirror_ndisks(sc, -1);
992 		LIST_FOREACH(disk, &sc->sc_disks, d_next) {
993 			g_mirror_update_metadata(disk);
994 		}
995 		sx_xunlock(&sc->sc_lock);
996 	}
997 }
998 
999 static void
1000 g_mirror_ctl_stop(struct gctl_req *req, struct g_class *mp, int wipe)
1001 {
1002 	struct g_mirror_softc *sc;
1003 	int *force, *nargs, error;
1004 	const char *name;
1005 	char param[16];
1006 	u_int i;
1007 	int how;
1008 
1009 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1010 	if (nargs == NULL) {
1011 		gctl_error(req, "No '%s' argument.", "nargs");
1012 		return;
1013 	}
1014 	if (*nargs < 1) {
1015 		gctl_error(req, "Missing device(s).");
1016 		return;
1017 	}
1018 	force = gctl_get_paraml(req, "force", sizeof(*force));
1019 	if (force == NULL) {
1020 		gctl_error(req, "No '%s' argument.", "force");
1021 		return;
1022 	}
1023 	if (*force)
1024 		how = G_MIRROR_DESTROY_HARD;
1025 	else
1026 		how = G_MIRROR_DESTROY_SOFT;
1027 
1028 	for (i = 0; i < (u_int)*nargs; i++) {
1029 		snprintf(param, sizeof(param), "arg%u", i);
1030 		name = gctl_get_asciiparam(req, param);
1031 		if (name == NULL) {
1032 			gctl_error(req, "No 'arg%u' argument.", i);
1033 			return;
1034 		}
1035 		sc = g_mirror_find_device(mp, name);
1036 		if (sc == NULL) {
1037 			gctl_error(req, "No such device: %s.", name);
1038 			return;
1039 		}
1040 		g_cancel_event(sc);
1041 		if (wipe)
1042 			sc->sc_flags |= G_MIRROR_DEVICE_FLAG_WIPE;
1043 		error = g_mirror_destroy(sc, how);
1044 		if (error != 0) {
1045 			gctl_error(req, "Cannot destroy device %s (error=%d).",
1046 			    sc->sc_geom->name, error);
1047 			if (wipe)
1048 				sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_WIPE;
1049 			sx_xunlock(&sc->sc_lock);
1050 			return;
1051 		}
1052 		/* No need to unlock, because lock is already dead. */
1053 	}
1054 }
1055 
1056 void
1057 g_mirror_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1058 {
1059 	uint32_t *version;
1060 
1061 	g_topology_assert();
1062 
1063 	version = gctl_get_paraml(req, "version", sizeof(*version));
1064 	if (version == NULL) {
1065 		gctl_error(req, "No '%s' argument.", "version");
1066 		return;
1067 	}
1068 	if (*version != G_MIRROR_VERSION) {
1069 		gctl_error(req, "Userland and kernel parts are out of sync.");
1070 		return;
1071 	}
1072 
1073 	g_topology_unlock();
1074 	if (strcmp(verb, "configure") == 0)
1075 		g_mirror_ctl_configure(req, mp);
1076 	else if (strcmp(verb, "create") == 0)
1077 		g_mirror_ctl_create(req, mp);
1078 	else if (strcmp(verb, "rebuild") == 0)
1079 		g_mirror_ctl_rebuild(req, mp);
1080 	else if (strcmp(verb, "insert") == 0)
1081 		g_mirror_ctl_insert(req, mp);
1082 	else if (strcmp(verb, "remove") == 0)
1083 		g_mirror_ctl_remove(req, mp);
1084 	else if (strcmp(verb, "resize") == 0)
1085 		g_mirror_ctl_resize(req, mp);
1086 	else if (strcmp(verb, "deactivate") == 0)
1087 		g_mirror_ctl_deactivate(req, mp);
1088 	else if (strcmp(verb, "forget") == 0)
1089 		g_mirror_ctl_forget(req, mp);
1090 	else if (strcmp(verb, "stop") == 0)
1091 		g_mirror_ctl_stop(req, mp, 0);
1092 	else if (strcmp(verb, "destroy") == 0)
1093 		g_mirror_ctl_stop(req, mp, 1);
1094 	else
1095 		gctl_error(req, "Unknown verb.");
1096 	g_topology_lock();
1097 }
1098