g_raid3_ctl.c revision 146117
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 146117 2005-05-11 19:35:43Z 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	sector = g_malloc(pp->sectorsize, M_WAITOK);
453	raid3_metadata_encode(&md, sector);
454	g_topology_unlock();
455	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
456	    pp->sectorsize);
457	g_topology_lock();
458	g_free(sector);
459	if (error != 0)
460		gctl_error(req, "Cannot store metadata on %s.", pp->name);
461end:
462	if (cp != NULL) {
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	}
469	g_destroy_geom(gp);
470}
471
472static void
473g_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp)
474{
475	struct g_raid3_softc *sc;
476	struct g_raid3_disk *disk;
477	const char *name;
478	intmax_t *no;
479	int *nargs;
480
481	g_topology_assert();
482	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
483	if (nargs == NULL) {
484		gctl_error(req, "No '%s' argument.", "nargs");
485		return;
486	}
487	if (*nargs != 1) {
488		gctl_error(req, "Invalid number of arguments.");
489		return;
490	}
491	name = gctl_get_asciiparam(req, "arg0");
492	if (name == NULL) {
493		gctl_error(req, "No 'arg%u' argument.", 0);
494		return;
495	}
496	sc = g_raid3_find_device(mp, name);
497	if (sc == NULL) {
498		gctl_error(req, "No such device: %s.", name);
499		return;
500	}
501	no = gctl_get_paraml(req, "number", sizeof(*no));
502	if (no == NULL) {
503		gctl_error(req, "No '%s' argument.", "no");
504		return;
505	}
506	if (*no >= sc->sc_ndisks) {
507		gctl_error(req, "Invalid component number.");
508		return;
509	}
510	disk = &sc->sc_disks[*no];
511	switch (disk->d_state) {
512	case G_RAID3_DISK_STATE_ACTIVE:
513		/*
514		 * When replacing ACTIVE component, all the rest has to be also
515		 * ACTIVE.
516		 */
517		if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) <
518		    sc->sc_ndisks) {
519			gctl_error(req, "Cannot replace component number %u.",
520			    *no);
521			return;
522		}
523		/* FALLTHROUGH */
524	case G_RAID3_DISK_STATE_STALE:
525	case G_RAID3_DISK_STATE_SYNCHRONIZING:
526		if (g_raid3_clear_metadata(disk) != 0) {
527			gctl_error(req, "Cannot clear metadata on %s.",
528			    g_raid3_get_diskname(disk));
529		} else {
530			g_raid3_event_send(disk,
531			    G_RAID3_DISK_STATE_DISCONNECTED,
532			    G_RAID3_EVENT_WAIT);
533		}
534		break;
535	case G_RAID3_DISK_STATE_NODISK:
536		break;
537	default:
538		gctl_error(req, "Cannot replace component number %u.", *no);
539		return;
540	}
541}
542
543void
544g_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb)
545{
546	uint32_t *version;
547
548	g_topology_assert();
549
550	version = gctl_get_paraml(req, "version", sizeof(*version));
551	if (version == NULL) {
552		gctl_error(req, "No '%s' argument.", "version");
553		return;
554	}
555	if (*version != G_RAID3_VERSION) {
556		gctl_error(req, "Userland and kernel parts are out of sync.");
557		return;
558	}
559
560	if (strcmp(verb, "configure") == 0)
561		g_raid3_ctl_configure(req, mp);
562	else if (strcmp(verb, "insert") == 0)
563		g_raid3_ctl_insert(req, mp);
564	else if (strcmp(verb, "rebuild") == 0)
565		g_raid3_ctl_rebuild(req, mp);
566	else if (strcmp(verb, "remove") == 0)
567		g_raid3_ctl_remove(req, mp);
568	else if (strcmp(verb, "stop") == 0)
569		g_raid3_ctl_stop(req, mp);
570	else
571		gctl_error(req, "Unknown verb.");
572}
573