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