1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2004-2006 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/param.h>
30#include <sys/systm.h>
31#include <sys/kernel.h>
32#include <sys/module.h>
33#include <sys/lock.h>
34#include <sys/mutex.h>
35#include <sys/bio.h>
36#include <sys/sysctl.h>
37#include <sys/malloc.h>
38#include <sys/bitstring.h>
39#include <vm/uma.h>
40#include <machine/atomic.h>
41#include <geom/geom.h>
42#include <sys/proc.h>
43#include <sys/kthread.h>
44#include <geom/raid3/g_raid3.h>
45
46static struct g_raid3_softc *
47g_raid3_find_device(struct g_class *mp, const char *name)
48{
49	struct g_raid3_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_RAID3_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
70static struct g_raid3_disk *
71g_raid3_find_disk(struct g_raid3_softc *sc, const char *name)
72{
73	struct g_raid3_disk *disk;
74	u_int n;
75
76	sx_assert(&sc->sc_lock, SX_XLOCKED);
77	if (strncmp(name, _PATH_DEV, 5) == 0)
78		name += 5;
79	for (n = 0; n < sc->sc_ndisks; n++) {
80		disk = &sc->sc_disks[n];
81		if (disk->d_state == G_RAID3_DISK_STATE_NODISK)
82			continue;
83		if (disk->d_consumer == NULL)
84			continue;
85		if (disk->d_consumer->provider == NULL)
86			continue;
87		if (strcmp(disk->d_consumer->provider->name, name) == 0)
88			return (disk);
89	}
90	return (NULL);
91}
92
93static void
94g_raid3_ctl_configure(struct gctl_req *req, struct g_class *mp)
95{
96	struct g_raid3_softc *sc;
97	struct g_raid3_disk *disk;
98	const char *name;
99	int *nargs, do_sync = 0, dirty = 1;
100	int *autosync, *noautosync;
101	int *failsync, *nofailsync;
102	int *round_robin, *noround_robin;
103	int *verify, *noverify;
104	u_int n;
105
106	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
107	if (nargs == NULL) {
108		gctl_error(req, "No '%s' argument.", "nargs");
109		return;
110	}
111	if (*nargs != 1) {
112		gctl_error(req, "Invalid number of arguments.");
113		return;
114	}
115	autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync));
116	if (autosync == NULL) {
117		gctl_error(req, "No '%s' argument.", "autosync");
118		return;
119	}
120	noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync));
121	if (noautosync == NULL) {
122		gctl_error(req, "No '%s' argument.", "noautosync");
123		return;
124	}
125	if (*autosync && *noautosync) {
126		gctl_error(req, "'%s' and '%s' specified.", "autosync",
127		    "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	if (*failsync && *nofailsync) {
141		gctl_error(req, "'%s' and '%s' specified.", "failsync",
142		    "nofailsync");
143		return;
144	}
145	round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin));
146	if (round_robin == NULL) {
147		gctl_error(req, "No '%s' argument.", "round_robin");
148		return;
149	}
150	noround_robin = gctl_get_paraml(req, "noround_robin",
151	    sizeof(*noround_robin));
152	if (noround_robin == NULL) {
153		gctl_error(req, "No '%s' argument.", "noround_robin");
154		return;
155	}
156	if (*round_robin && *noround_robin) {
157		gctl_error(req, "'%s' and '%s' specified.", "round_robin",
158		    "noround_robin");
159		return;
160	}
161	verify = gctl_get_paraml(req, "verify", sizeof(*verify));
162	if (verify == NULL) {
163		gctl_error(req, "No '%s' argument.", "verify");
164		return;
165	}
166	noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify));
167	if (noverify == NULL) {
168		gctl_error(req, "No '%s' argument.", "noverify");
169		return;
170	}
171	if (*verify && *noverify) {
172		gctl_error(req, "'%s' and '%s' specified.", "verify",
173		    "noverify");
174		return;
175	}
176	if (!*autosync && !*noautosync && !*failsync && !*nofailsync &&
177	    !*round_robin && !*noround_robin && !*verify && !*noverify) {
178		gctl_error(req, "Nothing has changed.");
179		return;
180	}
181	name = gctl_get_asciiparam(req, "arg0");
182	if (name == NULL) {
183		gctl_error(req, "No 'arg%u' argument.", 0);
184		return;
185	}
186	sc = g_raid3_find_device(mp, name);
187	if (sc == NULL) {
188		gctl_error(req, "No such device: %s.", name);
189		return;
190	}
191	if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) {
192		gctl_error(req, "Not all disks connected.");
193		sx_xunlock(&sc->sc_lock);
194		return;
195	}
196	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) {
197		if (*autosync) {
198			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
199			do_sync = 1;
200		}
201	} else {
202		if (*noautosync)
203			sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
204	}
205	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOFAILSYNC) != 0) {
206		if (*failsync)
207			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOFAILSYNC;
208	} else {
209		if (*nofailsync) {
210			sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOFAILSYNC;
211			dirty = 0;
212		}
213	}
214	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) {
215		if (*noverify)
216			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY;
217	} else {
218		if (*verify)
219			sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY;
220	}
221	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
222		if (*noround_robin)
223			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
224	} else {
225		if (*round_robin)
226			sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
227	}
228	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 &&
229	    (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
230		/*
231		 * VERIFY and ROUND-ROBIN options are mutally exclusive.
232		 */
233		sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
234	}
235	for (n = 0; n < sc->sc_ndisks; n++) {
236		disk = &sc->sc_disks[n];
237		if (do_sync) {
238			if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING)
239				disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC;
240		}
241		if (!dirty)
242			disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY;
243		g_raid3_update_metadata(disk);
244		if (do_sync) {
245			if (disk->d_state == G_RAID3_DISK_STATE_STALE) {
246				/*
247				 * XXX: This is probably possible that this
248				 *      component will not be retasted.
249				 */
250				g_raid3_event_send(disk,
251				    G_RAID3_DISK_STATE_DISCONNECTED,
252				    G_RAID3_EVENT_DONTWAIT);
253			}
254		}
255	}
256	sx_xunlock(&sc->sc_lock);
257}
258
259static void
260g_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp)
261{
262	struct g_raid3_metadata md;
263	struct g_raid3_softc *sc;
264	struct g_raid3_disk *disk;
265	struct g_provider *pp;
266	const char *name;
267	int error, *nargs;
268
269	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
270	if (nargs == NULL) {
271		gctl_error(req, "No '%s' argument.", "nargs");
272		return;
273	}
274	if (*nargs != 2) {
275		gctl_error(req, "Invalid number of arguments.");
276		return;
277	}
278	name = gctl_get_asciiparam(req, "arg0");
279	if (name == NULL) {
280		gctl_error(req, "No 'arg%u' argument.", 0);
281		return;
282	}
283	sc = g_raid3_find_device(mp, name);
284	if (sc == NULL) {
285		gctl_error(req, "No such device: %s.", name);
286		return;
287	}
288	name = gctl_get_asciiparam(req, "arg1");
289	if (name == NULL) {
290		gctl_error(req, "No 'arg%u' argument.", 1);
291		sx_xunlock(&sc->sc_lock);
292		return;
293	}
294	disk = g_raid3_find_disk(sc, name);
295	if (disk == NULL) {
296		gctl_error(req, "No such provider: %s.", name);
297		sx_xunlock(&sc->sc_lock);
298		return;
299	}
300	if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE &&
301	    g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) {
302		gctl_error(req, "There is one stale disk already.");
303		sx_xunlock(&sc->sc_lock);
304		return;
305	}
306	/*
307	 * Do rebuild by resetting syncid and disconnecting disk.
308	 * It'll be retasted, connected to the device and synchronized.
309	 */
310	disk->d_sync.ds_syncid = 0;
311	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0)
312		disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC;
313	g_raid3_update_metadata(disk);
314	pp = disk->d_consumer->provider;
315	g_topology_lock();
316	error = g_raid3_read_metadata(disk->d_consumer, &md);
317	g_topology_unlock();
318	g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED,
319	    G_RAID3_EVENT_WAIT);
320	if (error != 0) {
321		gctl_error(req, "Cannot read metadata from %s.", pp->name);
322		sx_xunlock(&sc->sc_lock);
323		return;
324	}
325	error = g_raid3_add_disk(sc, pp, &md);
326	if (error != 0)
327		gctl_error(req, "Cannot reconnect component %s.", pp->name);
328	sx_xunlock(&sc->sc_lock);
329}
330
331static void
332g_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp)
333{
334	struct g_raid3_softc *sc;
335	int *force, *nargs, error;
336	const char *name;
337	char param[16];
338	u_int i;
339	int how;
340
341	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
342	if (nargs == NULL) {
343		gctl_error(req, "No '%s' argument.", "nargs");
344		return;
345	}
346	if (*nargs < 1) {
347		gctl_error(req, "Missing device(s).");
348		return;
349	}
350	force = gctl_get_paraml(req, "force", sizeof(*force));
351	if (force == NULL) {
352		gctl_error(req, "No '%s' argument.", "force");
353		return;
354	}
355	if (*force)
356		how = G_RAID3_DESTROY_HARD;
357	else
358		how = G_RAID3_DESTROY_SOFT;
359
360	for (i = 0; i < (u_int)*nargs; i++) {
361		snprintf(param, sizeof(param), "arg%u", i);
362		name = gctl_get_asciiparam(req, param);
363		if (name == NULL) {
364			gctl_error(req, "No 'arg%u' argument.", i);
365			return;
366		}
367		sc = g_raid3_find_device(mp, name);
368		if (sc == NULL) {
369			gctl_error(req, "No such device: %s.", name);
370			return;
371		}
372		g_cancel_event(sc);
373		error = g_raid3_destroy(sc, how);
374		if (error != 0) {
375			gctl_error(req, "Cannot destroy device %s (error=%d).",
376			    sc->sc_geom->name, error);
377			sx_xunlock(&sc->sc_lock);
378			return;
379		}
380		/* No need to unlock, because lock is already dead. */
381	}
382}
383
384static void
385g_raid3_ctl_insert_orphan(struct g_consumer *cp)
386{
387
388	KASSERT(1 == 0, ("%s called while inserting %s.", __func__,
389	    cp->provider->name));
390}
391
392static void
393g_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp)
394{
395	struct g_raid3_metadata md;
396	struct g_raid3_softc *sc;
397	struct g_raid3_disk *disk;
398	struct g_geom *gp;
399	struct g_provider *pp;
400	struct g_consumer *cp;
401	const char *name;
402	u_char *sector;
403	off_t compsize;
404	intmax_t *no;
405	int *hardcode, *nargs, error, autono;
406
407	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
408	if (nargs == NULL) {
409		gctl_error(req, "No '%s' argument.", "nargs");
410		return;
411	}
412	if (*nargs != 2) {
413		gctl_error(req, "Invalid number of arguments.");
414		return;
415	}
416	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
417	if (hardcode == NULL) {
418		gctl_error(req, "No '%s' argument.", "hardcode");
419		return;
420	}
421	pp = gctl_get_provider(req, "arg1");
422	if (pp == NULL)
423		return;
424	if (gctl_get_param(req, "number", NULL) != NULL)
425		no = gctl_get_paraml(req, "number", sizeof(*no));
426	else
427		no = NULL;
428	gp = g_new_geomf(mp, "raid3:insert");
429	gp->orphan = g_raid3_ctl_insert_orphan;
430	cp = g_new_consumer(gp);
431	error = g_attach(cp, pp);
432	if (error != 0) {
433		g_topology_unlock();
434		gctl_error(req, "Cannot attach to %s.", pp->name);
435		goto end;
436	}
437	error = g_access(cp, 0, 1, 1);
438	if (error != 0) {
439		g_topology_unlock();
440		gctl_error(req, "Cannot access %s.", pp->name);
441		goto end;
442	}
443	g_topology_unlock();
444	name = gctl_get_asciiparam(req, "arg0");
445	if (name == NULL) {
446		gctl_error(req, "No 'arg%u' argument.", 0);
447		goto end;
448	}
449	sc = g_raid3_find_device(mp, name);
450	if (sc == NULL) {
451		gctl_error(req, "No such device: %s.", name);
452		goto end;
453	}
454	if (no != NULL) {
455		if (*no < 0 || *no >= sc->sc_ndisks) {
456			sx_xunlock(&sc->sc_lock);
457			gctl_error(req, "Invalid component number.");
458			goto end;
459		}
460		disk = &sc->sc_disks[*no];
461		if (disk->d_state != G_RAID3_DISK_STATE_NODISK) {
462			sx_xunlock(&sc->sc_lock);
463			gctl_error(req, "Component %jd is already connected.",
464			    *no);
465			goto end;
466		}
467	} else {
468		disk = NULL;
469		for (autono = 0; autono < sc->sc_ndisks && disk == NULL; autono++)
470			if (sc->sc_disks[autono].d_state ==
471			    G_RAID3_DISK_STATE_NODISK)
472				disk = &sc->sc_disks[autono];
473		if (disk == NULL) {
474			sx_xunlock(&sc->sc_lock);
475			gctl_error(req, "No disconnected components.");
476			goto end;
477		}
478	}
479	if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) {
480		sx_xunlock(&sc->sc_lock);
481		gctl_error(req,
482		    "Cannot insert provider %s, because of its sector size.",
483		    pp->name);
484		goto end;
485	}
486	compsize = sc->sc_mediasize / (sc->sc_ndisks - 1);
487	if (compsize > pp->mediasize - pp->sectorsize) {
488		sx_xunlock(&sc->sc_lock);
489		gctl_error(req, "Provider %s too small.", pp->name);
490		goto end;
491	}
492	if (compsize < pp->mediasize - pp->sectorsize) {
493		gctl_error(req,
494		    "warning: %s: only %jd bytes from %jd bytes used.",
495		    pp->name, (intmax_t)compsize,
496		    (intmax_t)(pp->mediasize - pp->sectorsize));
497	}
498	g_raid3_fill_metadata(disk, &md);
499	sx_xunlock(&sc->sc_lock);
500	md.md_syncid = 0;
501	md.md_dflags = 0;
502	if (*hardcode)
503		strlcpy(md.md_provider, pp->name, sizeof(md.md_provider));
504	else
505		bzero(md.md_provider, sizeof(md.md_provider));
506	md.md_provsize = pp->mediasize;
507	sector = g_malloc(pp->sectorsize, M_WAITOK);
508	raid3_metadata_encode(&md, sector);
509	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
510	    pp->sectorsize);
511	g_free(sector);
512	if (error != 0)
513		gctl_error(req, "Cannot store metadata on %s.", pp->name);
514end:
515	g_topology_lock();
516	if (cp->acw > 0)
517		g_access(cp, 0, -1, -1);
518	if (cp->provider != NULL)
519		g_detach(cp);
520	g_destroy_consumer(cp);
521	g_destroy_geom(gp);
522	g_topology_unlock();
523}
524
525static void
526g_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp)
527{
528	struct g_raid3_softc *sc;
529	struct g_raid3_disk *disk;
530	const char *name;
531	intmax_t *no;
532	int *nargs;
533
534	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
535	if (nargs == NULL) {
536		gctl_error(req, "No '%s' argument.", "nargs");
537		return;
538	}
539	if (*nargs != 1) {
540		gctl_error(req, "Invalid number of arguments.");
541		return;
542	}
543	no = gctl_get_paraml(req, "number", sizeof(*no));
544	if (no == NULL) {
545		gctl_error(req, "No '%s' argument.", "no");
546		return;
547	}
548	name = gctl_get_asciiparam(req, "arg0");
549	if (name == NULL) {
550		gctl_error(req, "No 'arg%u' argument.", 0);
551		return;
552	}
553	sc = g_raid3_find_device(mp, name);
554	if (sc == NULL) {
555		gctl_error(req, "No such device: %s.", name);
556		return;
557	}
558	if (*no >= sc->sc_ndisks) {
559		sx_xunlock(&sc->sc_lock);
560		gctl_error(req, "Invalid component number.");
561		return;
562	}
563	disk = &sc->sc_disks[*no];
564	switch (disk->d_state) {
565	case G_RAID3_DISK_STATE_ACTIVE:
566		/*
567		 * When replacing ACTIVE component, all the rest has to be also
568		 * ACTIVE.
569		 */
570		if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) <
571		    sc->sc_ndisks) {
572			gctl_error(req, "Cannot replace component number %jd.",
573			    *no);
574			break;
575		}
576		/* FALLTHROUGH */
577	case G_RAID3_DISK_STATE_STALE:
578	case G_RAID3_DISK_STATE_SYNCHRONIZING:
579		if (g_raid3_clear_metadata(disk) != 0) {
580			gctl_error(req, "Cannot clear metadata on %s.",
581			    g_raid3_get_diskname(disk));
582		} else {
583			g_raid3_event_send(disk,
584			    G_RAID3_DISK_STATE_DISCONNECTED,
585			    G_RAID3_EVENT_DONTWAIT);
586		}
587		break;
588	case G_RAID3_DISK_STATE_NODISK:
589		break;
590	default:
591		gctl_error(req, "Cannot replace component number %jd.", *no);
592		break;
593	}
594	sx_xunlock(&sc->sc_lock);
595}
596
597void
598g_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb)
599{
600	uint32_t *version;
601
602	g_topology_assert();
603
604	version = gctl_get_paraml(req, "version", sizeof(*version));
605	if (version == NULL) {
606		gctl_error(req, "No '%s' argument.", "version");
607		return;
608	}
609	if (*version != G_RAID3_VERSION) {
610		gctl_error(req, "Userland and kernel parts are out of sync.");
611		return;
612	}
613
614	g_topology_unlock();
615	if (strcmp(verb, "configure") == 0)
616		g_raid3_ctl_configure(req, mp);
617	else if (strcmp(verb, "insert") == 0)
618		g_raid3_ctl_insert(req, mp);
619	else if (strcmp(verb, "rebuild") == 0)
620		g_raid3_ctl_rebuild(req, mp);
621	else if (strcmp(verb, "remove") == 0)
622		g_raid3_ctl_remove(req, mp);
623	else if (strcmp(verb, "stop") == 0)
624		g_raid3_ctl_stop(req, mp);
625	else
626		gctl_error(req, "Unknown verb.");
627	g_topology_lock();
628}
629