xref: /freebsd/sys/geom/raid3/g_raid3_ctl.c (revision 6af83ee0d2941d18880b6aaa2b4facd1d30c6106)
1 /*-
2  * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
34 #include <sys/lock.h>
35 #include <sys/mutex.h>
36 #include <sys/bio.h>
37 #include <sys/sysctl.h>
38 #include <sys/malloc.h>
39 #include <sys/bitstring.h>
40 #include <vm/uma.h>
41 #include <machine/atomic.h>
42 #include <geom/geom.h>
43 #include <sys/proc.h>
44 #include <sys/kthread.h>
45 #include <geom/raid3/g_raid3.h>
46 
47 
48 static struct g_raid3_softc *
49 g_raid3_find_device(struct g_class *mp, const char *name)
50 {
51 	struct g_raid3_softc *sc;
52 	struct g_geom *gp;
53 
54 	g_topology_assert();
55 	LIST_FOREACH(gp, &mp->geom, geom) {
56 		sc = gp->softc;
57 		if (sc == NULL)
58 			continue;
59 		if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) != 0)
60 			continue;
61 		if (strcmp(gp->name, name) == 0 ||
62 		    strcmp(sc->sc_name, name) == 0) {
63 			return (sc);
64 		}
65 	}
66 	return (NULL);
67 }
68 
69 static struct g_raid3_disk *
70 g_raid3_find_disk(struct g_raid3_softc *sc, const char *name)
71 {
72 	struct g_raid3_disk *disk;
73 	u_int n;
74 
75 	g_topology_assert();
76 	for (n = 0; n < sc->sc_ndisks; n++) {
77 		disk = &sc->sc_disks[n];
78 		if (disk->d_state == G_RAID3_DISK_STATE_NODISK)
79 			continue;
80 		if (disk->d_consumer == NULL)
81 			continue;
82 		if (disk->d_consumer->provider == NULL)
83 			continue;
84 		if (strcmp(disk->d_consumer->provider->name, name) == 0)
85 			return (disk);
86 	}
87 	return (NULL);
88 }
89 
90 static void
91 g_raid3_ctl_configure(struct gctl_req *req, struct g_class *mp)
92 {
93 	struct g_raid3_softc *sc;
94 	struct g_raid3_disk *disk;
95 	const char *name;
96 	int *nargs, do_sync = 0;
97 	int *autosync, *noautosync;
98 	int *round_robin, *noround_robin;
99 	int *verify, *noverify;
100 	u_int n;
101 
102 	g_topology_assert();
103 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
104 	if (*nargs != 1) {
105 		gctl_error(req, "Invalid number of arguments.");
106 		return;
107 	}
108 	name = gctl_get_asciiparam(req, "arg0");
109 	sc = g_raid3_find_device(mp, name);
110 	if (sc == NULL) {
111 		gctl_error(req, "No such device: %s.", name);
112 		return;
113 	}
114 	if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) {
115 		gctl_error(req, "Not all disks connected.");
116 		return;
117 	}
118 	autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync));
119 	if (autosync == NULL) {
120 		gctl_error(req, "No '%s' argument.", "autosync");
121 		return;
122 	}
123 	noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync));
124 	if (noautosync == NULL) {
125 		gctl_error(req, "No '%s' argument.", "noautosync");
126 		return;
127 	}
128 	if (*autosync && *noautosync) {
129 		gctl_error(req, "'%s' and '%s' specified.", "autosync",
130 		    "noautosync");
131 		return;
132 	}
133 	round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin));
134 	if (round_robin == NULL) {
135 		gctl_error(req, "No '%s' argument.", "round_robin");
136 		return;
137 	}
138 	noround_robin = gctl_get_paraml(req, "noround_robin",
139 	    sizeof(*noround_robin));
140 	if (noround_robin == NULL) {
141 		gctl_error(req, "No '%s' argument.", "noround_robin");
142 		return;
143 	}
144 	if (*round_robin && *noround_robin) {
145 		gctl_error(req, "'%s' and '%s' specified.", "round_robin",
146 		    "noround_robin");
147 		return;
148 	}
149 	verify = gctl_get_paraml(req, "verify", sizeof(*verify));
150 	if (verify == NULL) {
151 		gctl_error(req, "No '%s' argument.", "verify");
152 		return;
153 	}
154 	noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify));
155 	if (noverify == NULL) {
156 		gctl_error(req, "No '%s' argument.", "noverify");
157 		return;
158 	}
159 	if (*verify && *noverify) {
160 		gctl_error(req, "'%s' and '%s' specified.", "verify",
161 		    "noverify");
162 		return;
163 	}
164 	if (!*autosync && !*noautosync && !*round_robin && !*noround_robin &&
165 	    !*verify && !*noverify) {
166 		gctl_error(req, "Nothing has changed.");
167 		return;
168 	}
169 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) {
170 		if (*autosync) {
171 			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
172 			do_sync = 1;
173 		}
174 	} else {
175 		if (*noautosync)
176 			sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
177 	}
178 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) {
179 		if (*noverify)
180 			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY;
181 	} else {
182 		if (*verify)
183 			sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY;
184 	}
185 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
186 		if (*noround_robin)
187 			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
188 	} else {
189 		if (*round_robin)
190 			sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
191 	}
192 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 &&
193 	    (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
194 		/*
195 		 * VERIFY and ROUND-ROBIN options are mutally exclusive.
196 		 */
197 		sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
198 	}
199 	for (n = 0; n < sc->sc_ndisks; n++) {
200 		disk = &sc->sc_disks[n];
201 		if (do_sync) {
202 			if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING)
203 				disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC;
204 		}
205 		g_raid3_update_metadata(disk);
206 		if (do_sync) {
207 			if (disk->d_state == G_RAID3_DISK_STATE_STALE) {
208 				/*
209 				 * XXX: This is probably possible that this
210 				 *      component will not be retasted.
211 				 */
212 				g_raid3_event_send(disk,
213 				    G_RAID3_DISK_STATE_DISCONNECTED,
214 				    G_RAID3_EVENT_DONTWAIT);
215 			}
216 		}
217 	}
218 }
219 
220 static void
221 g_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp)
222 {
223 	struct g_raid3_metadata md;
224 	struct g_raid3_softc *sc;
225 	struct g_raid3_disk *disk;
226 	struct g_provider *pp;
227 	const char *name;
228 	int error, *nargs;
229 
230 	g_topology_assert();
231 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
232 	if (nargs == NULL) {
233 		gctl_error(req, "No '%s' argument.", "nargs");
234 		return;
235 	}
236 	if (*nargs != 2) {
237 		gctl_error(req, "Invalid number of arguments.");
238 		return;
239 	}
240 	name = gctl_get_asciiparam(req, "arg0");
241 	if (name == NULL) {
242 		gctl_error(req, "No 'arg%u' argument.", 0);
243 		return;
244 	}
245 	sc = g_raid3_find_device(mp, name);
246 	if (sc == NULL) {
247 		gctl_error(req, "No such device: %s.", name);
248 		return;
249 	}
250 	name = gctl_get_asciiparam(req, "arg1");
251 	if (name == NULL) {
252 		gctl_error(req, "No 'arg%u' argument.", 1);
253 		return;
254 	}
255 	disk = g_raid3_find_disk(sc, name);
256 	if (disk == NULL) {
257 		gctl_error(req, "No such provider: %s.", name);
258 		return;
259 	}
260 	if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE &&
261 	    g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) {
262 		gctl_error(req, "There is one stale disk already.", name);
263 		return;
264 	}
265 	/*
266 	 * Do rebuild by resetting syncid and disconnecting disk.
267 	 * It'll be retasted, connected to the device and synchronized.
268 	 */
269 	disk->d_sync.ds_syncid = 0;
270 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0)
271 		disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC;
272 	g_raid3_update_metadata(disk);
273 	pp = disk->d_consumer->provider;
274 	error = g_raid3_read_metadata(disk->d_consumer, &md);
275 	g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED,
276 	    G_RAID3_EVENT_WAIT);
277 	if (error != 0) {
278 		gctl_error(req, "Cannot read metadata from %s.", pp->name);
279 		return;
280 	}
281 	error = g_raid3_add_disk(sc, pp, &md);
282 	if (error != 0) {
283 		gctl_error(req, "Cannot reconnect component %s.", pp->name);
284 		return;
285 	}
286 }
287 
288 static void
289 g_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp)
290 {
291 	struct g_raid3_softc *sc;
292 	int *force, *nargs, error;
293 	const char *name;
294 	char param[16];
295 	u_int i;
296 
297 	g_topology_assert();
298 
299 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
300 	if (nargs == NULL) {
301 		gctl_error(req, "No '%s' argument.", "nargs");
302 		return;
303 	}
304 	if (*nargs < 1) {
305 		gctl_error(req, "Missing device(s).");
306 		return;
307 	}
308 	force = gctl_get_paraml(req, "force", sizeof(*force));
309 	if (force == NULL) {
310 		gctl_error(req, "No '%s' argument.", "force");
311 		return;
312 	}
313 
314 	for (i = 0; i < (u_int)*nargs; i++) {
315 		snprintf(param, sizeof(param), "arg%u", i);
316 		name = gctl_get_asciiparam(req, param);
317 		if (name == NULL) {
318 			gctl_error(req, "No 'arg%u' argument.", i);
319 			return;
320 		}
321 		sc = g_raid3_find_device(mp, name);
322 		if (sc == NULL) {
323 			gctl_error(req, "No such device: %s.", name);
324 			return;
325 		}
326 		error = g_raid3_destroy(sc, *force);
327 		if (error != 0) {
328 			gctl_error(req, "Cannot destroy device %s (error=%d).",
329 			    sc->sc_geom->name, error);
330 			return;
331 		}
332 	}
333 }
334 
335 static void
336 g_raid3_ctl_insert_orphan(struct g_consumer *cp)
337 {
338 
339 	KASSERT(1 == 0, ("%s called while inserting %s.", __func__,
340 	    cp->provider->name));
341 }
342 
343 static void
344 g_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp)
345 {
346 	struct g_raid3_metadata md;
347 	struct g_raid3_softc *sc;
348 	struct g_raid3_disk *disk;
349 	struct g_geom *gp;
350 	struct g_provider *pp;
351 	struct g_consumer *cp;
352 	const char *name;
353 	u_char *sector;
354 	off_t compsize;
355 	intmax_t *no;
356 	int *hardcode, *nargs, error;
357 
358 	g_topology_assert();
359 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
360 	if (nargs == NULL) {
361 		gctl_error(req, "No '%s' argument.", "nargs");
362 		return;
363 	}
364 	if (*nargs != 2) {
365 		gctl_error(req, "Invalid number of arguments.");
366 		return;
367 	}
368 	name = gctl_get_asciiparam(req, "arg0");
369 	if (name == NULL) {
370 		gctl_error(req, "No 'arg%u' argument.", 0);
371 		return;
372 	}
373 	sc = g_raid3_find_device(mp, name);
374 	if (sc == NULL) {
375 		gctl_error(req, "No such device: %s.", name);
376 		return;
377 	}
378 	no = gctl_get_paraml(req, "number", sizeof(*no));
379 	if (no == NULL) {
380 		gctl_error(req, "No '%s' argument.", "no");
381 		return;
382 	}
383 	if (*no >= sc->sc_ndisks) {
384 		gctl_error(req, "Invalid component number.");
385 		return;
386 	}
387 	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
388 	if (hardcode == NULL) {
389 		gctl_error(req, "No '%s' argument.", "hardcode");
390 		return;
391 	}
392 	disk = &sc->sc_disks[*no];
393 	if (disk->d_state != G_RAID3_DISK_STATE_NODISK) {
394 		gctl_error(req, "Component %u is already connected.", *no);
395 		return;
396 	}
397 	name = gctl_get_asciiparam(req, "arg1");
398 	if (name == NULL) {
399 		gctl_error(req, "No 'arg%u' argument.", 1);
400 		return;
401 	}
402 	pp = g_provider_by_name(name);
403 	if (pp == NULL) {
404 		gctl_error(req, "Invalid provider.");
405 		return;
406 	}
407 	if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) {
408 		gctl_error(req,
409 		    "Cannot insert provider %s, because of its sector size.",
410 		    pp->name);
411 		return;
412 	}
413 	compsize = sc->sc_mediasize / (sc->sc_ndisks - 1);
414 	if (compsize > pp->mediasize - pp->sectorsize) {
415 		gctl_error(req, "Provider %s too small.", pp->name);
416 		return;
417 	}
418 	if (compsize < pp->mediasize - pp->sectorsize) {
419 		gctl_error(req,
420 		    "warning: %s: only %jd bytes from %jd bytes used.",
421 		    pp->name, (intmax_t)compsize,
422 		    (intmax_t)(pp->mediasize - pp->sectorsize));
423 	}
424 	gp = g_new_geomf(mp, "raid3:insert");
425 	gp->orphan = g_raid3_ctl_insert_orphan;
426 	cp = g_new_consumer(gp);
427 	error = g_attach(cp, pp);
428 	if (error != 0) {
429 		gctl_error(req, "Cannot attach to %s.", pp->name);
430 		goto end;
431 	}
432 	error = g_access(cp, 0, 1, 1);
433 	if (error != 0) {
434 		gctl_error(req, "Cannot access %s.", pp->name);
435 		goto end;
436 	}
437 	g_raid3_fill_metadata(disk, &md);
438 	md.md_syncid = 0;
439         md.md_dflags = 0;
440 	if (*hardcode)
441                 strlcpy(md.md_provider, pp->name, sizeof(md.md_provider));
442         else
443                 bzero(md.md_provider, sizeof(md.md_provider));
444 	sector = g_malloc(pp->sectorsize, M_WAITOK);
445 	raid3_metadata_encode(&md, sector);
446 	g_topology_unlock();
447 	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
448 	    pp->sectorsize);
449 	g_topology_lock();
450 	g_free(sector);
451 	if (error != 0)
452 		gctl_error(req, "Cannot store metadata on %s.", pp->name);
453 end:
454 	if (gp != NULL) {
455 		if (cp != NULL) {
456 			if (cp->acw > 0)
457 				g_access(cp, 0, -1, -1);
458 			if (cp->provider != NULL)
459 				g_detach(cp);
460 			g_destroy_consumer(cp);
461 		}
462 		g_destroy_geom(gp);
463 	}
464 }
465 
466 static void
467 g_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp)
468 {
469 	struct g_raid3_softc *sc;
470 	struct g_raid3_disk *disk;
471 	const char *name;
472 	intmax_t *no;
473 	int *nargs;
474 
475 	g_topology_assert();
476 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
477 	if (nargs == NULL) {
478 		gctl_error(req, "No '%s' argument.", "nargs");
479 		return;
480 	}
481 	if (*nargs != 1) {
482 		gctl_error(req, "Invalid number of arguments.");
483 		return;
484 	}
485 	name = gctl_get_asciiparam(req, "arg0");
486 	if (name == NULL) {
487 		gctl_error(req, "No 'arg%u' argument.", 0);
488 		return;
489 	}
490 	sc = g_raid3_find_device(mp, name);
491 	if (sc == NULL) {
492 		gctl_error(req, "No such device: %s.", name);
493 		return;
494 	}
495 	no = gctl_get_paraml(req, "number", sizeof(*no));
496 	if (no == NULL) {
497 		gctl_error(req, "No '%s' argument.", "no");
498 		return;
499 	}
500 	if (*no >= sc->sc_ndisks) {
501 		gctl_error(req, "Invalid component number.");
502 		return;
503 	}
504 	disk = &sc->sc_disks[*no];
505 	switch (disk->d_state) {
506 	case G_RAID3_DISK_STATE_ACTIVE:
507 		/*
508 		 * When replacing ACTIVE component, all the rest has to be also
509 		 * ACTIVE.
510 		 */
511 		if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) <
512 		    sc->sc_ndisks) {
513 			gctl_error(req, "Cannot replace component number %u.",
514 			    *no);
515 			return;
516 		}
517 		/* FALLTHROUGH */
518 	case G_RAID3_DISK_STATE_STALE:
519 	case G_RAID3_DISK_STATE_SYNCHRONIZING:
520 		if (g_raid3_clear_metadata(disk) != 0) {
521 			gctl_error(req, "Cannot clear metadata on %s.",
522 			    g_raid3_get_diskname(disk));
523 		} else {
524 			g_raid3_event_send(disk,
525 			    G_RAID3_DISK_STATE_DISCONNECTED,
526 			    G_RAID3_EVENT_WAIT);
527 		}
528 		break;
529 	case G_RAID3_DISK_STATE_NODISK:
530 		break;
531 	default:
532 		gctl_error(req, "Cannot replace component number %u.", *no);
533 		return;
534 	}
535 }
536 
537 void
538 g_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb)
539 {
540 	uint32_t *version;
541 
542 	g_topology_assert();
543 
544 	version = gctl_get_paraml(req, "version", sizeof(*version));
545 	if (version == NULL) {
546 		gctl_error(req, "No '%s' argument.", "version");
547 		return;
548 	}
549 	if (*version != G_RAID3_VERSION) {
550 		gctl_error(req, "Userland and kernel parts are out of sync.");
551 		return;
552 	}
553 
554 	if (strcmp(verb, "configure") == 0)
555 		g_raid3_ctl_configure(req, mp);
556 	else if (strcmp(verb, "insert") == 0)
557 		g_raid3_ctl_insert(req, mp);
558 	else if (strcmp(verb, "rebuild") == 0)
559 		g_raid3_ctl_rebuild(req, mp);
560 	else if (strcmp(verb, "remove") == 0)
561 		g_raid3_ctl_remove(req, mp);
562 	else if (strcmp(verb, "stop") == 0)
563 		g_raid3_ctl_stop(req, mp);
564 	else
565 		gctl_error(req, "Unknown verb.");
566 }
567