g_raid3_ctl.c revision 156527
1/*-
2 * Copyright (c) 2004-2005 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: head/sys/geom/raid3/g_raid3_ctl.c 156527 2006-03-10 07:41:31Z pjd $");
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
48static struct g_raid3_softc *
49g_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
69static struct g_raid3_disk *
70g_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
90static void
91g_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 == NULL) {
105		gctl_error(req, "No '%s' argument.", "nargs");
106		return;
107	}
108	if (*nargs != 1) {
109		gctl_error(req, "Invalid number of arguments.");
110		return;
111	}
112	name = gctl_get_asciiparam(req, "arg0");
113	if (name == NULL) {
114		gctl_error(req, "No 'arg%u' argument.", 0);
115		return;
116	}
117	sc = g_raid3_find_device(mp, name);
118	if (sc == NULL) {
119		gctl_error(req, "No such device: %s.", name);
120		return;
121	}
122	if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) {
123		gctl_error(req, "Not all disks connected.");
124		return;
125	}
126	autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync));
127	if (autosync == NULL) {
128		gctl_error(req, "No '%s' argument.", "autosync");
129		return;
130	}
131	noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync));
132	if (noautosync == NULL) {
133		gctl_error(req, "No '%s' argument.", "noautosync");
134		return;
135	}
136	if (*autosync && *noautosync) {
137		gctl_error(req, "'%s' and '%s' specified.", "autosync",
138		    "noautosync");
139		return;
140	}
141	round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin));
142	if (round_robin == NULL) {
143		gctl_error(req, "No '%s' argument.", "round_robin");
144		return;
145	}
146	noround_robin = gctl_get_paraml(req, "noround_robin",
147	    sizeof(*noround_robin));
148	if (noround_robin == NULL) {
149		gctl_error(req, "No '%s' argument.", "noround_robin");
150		return;
151	}
152	if (*round_robin && *noround_robin) {
153		gctl_error(req, "'%s' and '%s' specified.", "round_robin",
154		    "noround_robin");
155		return;
156	}
157	verify = gctl_get_paraml(req, "verify", sizeof(*verify));
158	if (verify == NULL) {
159		gctl_error(req, "No '%s' argument.", "verify");
160		return;
161	}
162	noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify));
163	if (noverify == NULL) {
164		gctl_error(req, "No '%s' argument.", "noverify");
165		return;
166	}
167	if (*verify && *noverify) {
168		gctl_error(req, "'%s' and '%s' specified.", "verify",
169		    "noverify");
170		return;
171	}
172	if (!*autosync && !*noautosync && !*round_robin && !*noround_robin &&
173	    !*verify && !*noverify) {
174		gctl_error(req, "Nothing has changed.");
175		return;
176	}
177	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) {
178		if (*autosync) {
179			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
180			do_sync = 1;
181		}
182	} else {
183		if (*noautosync)
184			sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
185	}
186	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) {
187		if (*noverify)
188			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY;
189	} else {
190		if (*verify)
191			sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY;
192	}
193	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
194		if (*noround_robin)
195			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
196	} else {
197		if (*round_robin)
198			sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
199	}
200	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 &&
201	    (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
202		/*
203		 * VERIFY and ROUND-ROBIN options are mutally exclusive.
204		 */
205		sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
206	}
207	for (n = 0; n < sc->sc_ndisks; n++) {
208		disk = &sc->sc_disks[n];
209		if (do_sync) {
210			if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING)
211				disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC;
212		}
213		g_raid3_update_metadata(disk);
214		if (do_sync) {
215			if (disk->d_state == G_RAID3_DISK_STATE_STALE) {
216				/*
217				 * XXX: This is probably possible that this
218				 *      component will not be retasted.
219				 */
220				g_raid3_event_send(disk,
221				    G_RAID3_DISK_STATE_DISCONNECTED,
222				    G_RAID3_EVENT_DONTWAIT);
223			}
224		}
225	}
226}
227
228static void
229g_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp)
230{
231	struct g_raid3_metadata md;
232	struct g_raid3_softc *sc;
233	struct g_raid3_disk *disk;
234	struct g_provider *pp;
235	const char *name;
236	int error, *nargs;
237
238	g_topology_assert();
239	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
240	if (nargs == NULL) {
241		gctl_error(req, "No '%s' argument.", "nargs");
242		return;
243	}
244	if (*nargs != 2) {
245		gctl_error(req, "Invalid number of arguments.");
246		return;
247	}
248	name = gctl_get_asciiparam(req, "arg0");
249	if (name == NULL) {
250		gctl_error(req, "No 'arg%u' argument.", 0);
251		return;
252	}
253	sc = g_raid3_find_device(mp, name);
254	if (sc == NULL) {
255		gctl_error(req, "No such device: %s.", name);
256		return;
257	}
258	name = gctl_get_asciiparam(req, "arg1");
259	if (name == NULL) {
260		gctl_error(req, "No 'arg%u' argument.", 1);
261		return;
262	}
263	disk = g_raid3_find_disk(sc, name);
264	if (disk == NULL) {
265		gctl_error(req, "No such provider: %s.", name);
266		return;
267	}
268	if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE &&
269	    g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) {
270		gctl_error(req, "There is one stale disk already.", name);
271		return;
272	}
273	/*
274	 * Do rebuild by resetting syncid and disconnecting disk.
275	 * It'll be retasted, connected to the device and synchronized.
276	 */
277	disk->d_sync.ds_syncid = 0;
278	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0)
279		disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC;
280	g_raid3_update_metadata(disk);
281	pp = disk->d_consumer->provider;
282	error = g_raid3_read_metadata(disk->d_consumer, &md);
283	g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED,
284	    G_RAID3_EVENT_WAIT);
285	if (error != 0) {
286		gctl_error(req, "Cannot read metadata from %s.", pp->name);
287		return;
288	}
289	error = g_raid3_add_disk(sc, pp, &md);
290	if (error != 0) {
291		gctl_error(req, "Cannot reconnect component %s.", pp->name);
292		return;
293	}
294}
295
296static void
297g_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp)
298{
299	struct g_raid3_softc *sc;
300	int *force, *nargs, error;
301	const char *name;
302	char param[16];
303	u_int i;
304
305	g_topology_assert();
306
307	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
308	if (nargs == NULL) {
309		gctl_error(req, "No '%s' argument.", "nargs");
310		return;
311	}
312	if (*nargs < 1) {
313		gctl_error(req, "Missing device(s).");
314		return;
315	}
316	force = gctl_get_paraml(req, "force", sizeof(*force));
317	if (force == NULL) {
318		gctl_error(req, "No '%s' argument.", "force");
319		return;
320	}
321
322	for (i = 0; i < (u_int)*nargs; i++) {
323		snprintf(param, sizeof(param), "arg%u", i);
324		name = gctl_get_asciiparam(req, param);
325		if (name == NULL) {
326			gctl_error(req, "No 'arg%u' argument.", i);
327			return;
328		}
329		sc = g_raid3_find_device(mp, name);
330		if (sc == NULL) {
331			gctl_error(req, "No such device: %s.", name);
332			return;
333		}
334		error = g_raid3_destroy(sc, *force);
335		if (error != 0) {
336			gctl_error(req, "Cannot destroy device %s (error=%d).",
337			    sc->sc_geom->name, error);
338			return;
339		}
340	}
341}
342
343static void
344g_raid3_ctl_insert_orphan(struct g_consumer *cp)
345{
346
347	KASSERT(1 == 0, ("%s called while inserting %s.", __func__,
348	    cp->provider->name));
349}
350
351static void
352g_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp)
353{
354	struct g_raid3_metadata md;
355	struct g_raid3_softc *sc;
356	struct g_raid3_disk *disk;
357	struct g_geom *gp;
358	struct g_provider *pp;
359	struct g_consumer *cp;
360	const char *name;
361	u_char *sector;
362	off_t compsize;
363	intmax_t *no;
364	int *hardcode, *nargs, error;
365
366	g_topology_assert();
367	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
368	if (nargs == NULL) {
369		gctl_error(req, "No '%s' argument.", "nargs");
370		return;
371	}
372	if (*nargs != 2) {
373		gctl_error(req, "Invalid number of arguments.");
374		return;
375	}
376	name = gctl_get_asciiparam(req, "arg0");
377	if (name == NULL) {
378		gctl_error(req, "No 'arg%u' argument.", 0);
379		return;
380	}
381	sc = g_raid3_find_device(mp, name);
382	if (sc == NULL) {
383		gctl_error(req, "No such device: %s.", name);
384		return;
385	}
386	no = gctl_get_paraml(req, "number", sizeof(*no));
387	if (no == NULL) {
388		gctl_error(req, "No '%s' argument.", "no");
389		return;
390	}
391	if (*no >= sc->sc_ndisks) {
392		gctl_error(req, "Invalid component number.");
393		return;
394	}
395	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
396	if (hardcode == NULL) {
397		gctl_error(req, "No '%s' argument.", "hardcode");
398		return;
399	}
400	disk = &sc->sc_disks[*no];
401	if (disk->d_state != G_RAID3_DISK_STATE_NODISK) {
402		gctl_error(req, "Component %u is already connected.", *no);
403		return;
404	}
405	name = gctl_get_asciiparam(req, "arg1");
406	if (name == NULL) {
407		gctl_error(req, "No 'arg%u' argument.", 1);
408		return;
409	}
410	pp = g_provider_by_name(name);
411	if (pp == NULL) {
412		gctl_error(req, "Invalid provider.");
413		return;
414	}
415	if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) {
416		gctl_error(req,
417		    "Cannot insert provider %s, because of its sector size.",
418		    pp->name);
419		return;
420	}
421	compsize = sc->sc_mediasize / (sc->sc_ndisks - 1);
422	if (compsize > pp->mediasize - pp->sectorsize) {
423		gctl_error(req, "Provider %s too small.", pp->name);
424		return;
425	}
426	if (compsize < pp->mediasize - pp->sectorsize) {
427		gctl_error(req,
428		    "warning: %s: only %jd bytes from %jd bytes used.",
429		    pp->name, (intmax_t)compsize,
430		    (intmax_t)(pp->mediasize - pp->sectorsize));
431	}
432	gp = g_new_geomf(mp, "raid3:insert");
433	gp->orphan = g_raid3_ctl_insert_orphan;
434	cp = g_new_consumer(gp);
435	error = g_attach(cp, pp);
436	if (error != 0) {
437		gctl_error(req, "Cannot attach to %s.", pp->name);
438		goto end;
439	}
440	error = g_access(cp, 0, 1, 1);
441	if (error != 0) {
442		gctl_error(req, "Cannot access %s.", pp->name);
443		goto end;
444	}
445	g_raid3_fill_metadata(disk, &md);
446	md.md_syncid = 0;
447        md.md_dflags = 0;
448	if (*hardcode)
449                strlcpy(md.md_provider, pp->name, sizeof(md.md_provider));
450        else
451                bzero(md.md_provider, sizeof(md.md_provider));
452	md.md_provsize = pp->mediasize;
453	sector = g_malloc(pp->sectorsize, M_WAITOK);
454	raid3_metadata_encode(&md, sector);
455	g_topology_unlock();
456	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
457	    pp->sectorsize);
458	g_topology_lock();
459	g_free(sector);
460	if (error != 0)
461		gctl_error(req, "Cannot store metadata on %s.", pp->name);
462end:
463	if (cp->acw > 0)
464		g_access(cp, 0, -1, -1);
465	if (cp->provider != NULL)
466		g_detach(cp);
467	g_destroy_consumer(cp);
468	g_destroy_geom(gp);
469}
470
471static void
472g_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp)
473{
474	struct g_raid3_softc *sc;
475	struct g_raid3_disk *disk;
476	const char *name;
477	intmax_t *no;
478	int *nargs;
479
480	g_topology_assert();
481	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
482	if (nargs == NULL) {
483		gctl_error(req, "No '%s' argument.", "nargs");
484		return;
485	}
486	if (*nargs != 1) {
487		gctl_error(req, "Invalid number of arguments.");
488		return;
489	}
490	name = gctl_get_asciiparam(req, "arg0");
491	if (name == NULL) {
492		gctl_error(req, "No 'arg%u' argument.", 0);
493		return;
494	}
495	sc = g_raid3_find_device(mp, name);
496	if (sc == NULL) {
497		gctl_error(req, "No such device: %s.", name);
498		return;
499	}
500	no = gctl_get_paraml(req, "number", sizeof(*no));
501	if (no == NULL) {
502		gctl_error(req, "No '%s' argument.", "no");
503		return;
504	}
505	if (*no >= sc->sc_ndisks) {
506		gctl_error(req, "Invalid component number.");
507		return;
508	}
509	disk = &sc->sc_disks[*no];
510	switch (disk->d_state) {
511	case G_RAID3_DISK_STATE_ACTIVE:
512		/*
513		 * When replacing ACTIVE component, all the rest has to be also
514		 * ACTIVE.
515		 */
516		if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) <
517		    sc->sc_ndisks) {
518			gctl_error(req, "Cannot replace component number %u.",
519			    *no);
520			return;
521		}
522		/* FALLTHROUGH */
523	case G_RAID3_DISK_STATE_STALE:
524	case G_RAID3_DISK_STATE_SYNCHRONIZING:
525		if (g_raid3_clear_metadata(disk) != 0) {
526			gctl_error(req, "Cannot clear metadata on %s.",
527			    g_raid3_get_diskname(disk));
528		} else {
529			g_raid3_event_send(disk,
530			    G_RAID3_DISK_STATE_DISCONNECTED,
531			    G_RAID3_EVENT_WAIT);
532		}
533		break;
534	case G_RAID3_DISK_STATE_NODISK:
535		break;
536	default:
537		gctl_error(req, "Cannot replace component number %u.", *no);
538		return;
539	}
540}
541
542void
543g_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb)
544{
545	uint32_t *version;
546
547	g_topology_assert();
548
549	version = gctl_get_paraml(req, "version", sizeof(*version));
550	if (version == NULL) {
551		gctl_error(req, "No '%s' argument.", "version");
552		return;
553	}
554	if (*version != G_RAID3_VERSION) {
555		gctl_error(req, "Userland and kernel parts are out of sync.");
556		return;
557	}
558
559	if (strcmp(verb, "configure") == 0)
560		g_raid3_ctl_configure(req, mp);
561	else if (strcmp(verb, "insert") == 0)
562		g_raid3_ctl_insert(req, mp);
563	else if (strcmp(verb, "rebuild") == 0)
564		g_raid3_ctl_rebuild(req, mp);
565	else if (strcmp(verb, "remove") == 0)
566		g_raid3_ctl_remove(req, mp);
567	else if (strcmp(verb, "stop") == 0)
568		g_raid3_ctl_stop(req, mp);
569	else
570		gctl_error(req, "Unknown verb.");
571}
572