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