g_raid3_ctl.c revision 155174
117680Spst/*-
217680Spst * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
317680Spst * All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that the following conditions
717680Spst * are met:
817680Spst * 1. Redistributions of source code must retain the above copyright
917680Spst *    notice, this list of conditions and the following disclaimer.
1017680Spst * 2. Redistributions in binary form must reproduce the above copyright
1117680Spst *    notice, this list of conditions and the following disclaimer in the
1217680Spst *    documentation and/or other materials provided with the distribution.
1317680Spst *
1417680Spst * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1517680Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1617680Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1717680Spst * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
1817680Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1917680Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2026183Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2117680Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2217680Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2356896Sfenner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2456896Sfenner * SUCH DAMAGE.
2517680Spst */
2626183Sfenner
2717680Spst#include <sys/cdefs.h>
28127675Sbms__FBSDID("$FreeBSD: head/sys/geom/raid3/g_raid3_ctl.c 155174 2006-02-01 12:06:01Z pjd $");
29146778Ssam
3017680Spst#include <sys/param.h>
3117680Spst#include <sys/systm.h>
3256896Sfenner#include <sys/kernel.h>
3356896Sfenner#include <sys/module.h>
3456896Sfenner#include <sys/lock.h>
3556896Sfenner#include <sys/mutex.h>
36127675Sbms#include <sys/bio.h>
3717680Spst#include <sys/sysctl.h>
3817680Spst#include <sys/malloc.h>
3917680Spst#include <sys/bitstring.h>
4017680Spst#include <vm/uma.h>
4117680Spst#include <machine/atomic.h>
4217680Spst#include <geom/geom.h>
4317680Spst#include <sys/proc.h>
4417680Spst#include <sys/kthread.h>
4517680Spst#include <geom/raid3/g_raid3.h>
4617680Spst
4717680Spst
4817680Spststatic struct g_raid3_softc *
4917680Spstg_raid3_find_device(struct g_class *mp, const char *name)
5017680Spst{
5117680Spst	struct g_raid3_softc *sc;
5217680Spst	struct g_geom *gp;
5317680Spst
5417680Spst	g_topology_assert();
5517680Spst	LIST_FOREACH(gp, &mp->geom, geom) {
5617680Spst		sc = gp->softc;
5717680Spst		if (sc == NULL)
5817680Spst			continue;
5917680Spst		if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) != 0)
6017680Spst			continue;
61146778Ssam		if (strcmp(gp->name, name) == 0 ||
62146778Ssam		    strcmp(sc->sc_name, name) == 0) {
63146778Ssam			return (sc);
6417680Spst		}
65127675Sbms	}
6617680Spst	return (NULL);
6717680Spst}
6817680Spst
69146778Ssamstatic struct g_raid3_disk *
7017680Spstg_raid3_find_disk(struct g_raid3_softc *sc, const char *name)
7117680Spst{
7217680Spst	struct g_raid3_disk *disk;
7317680Spst	u_int n;
7417680Spst
7517680Spst	g_topology_assert();
7617680Spst	for (n = 0; n < sc->sc_ndisks; n++) {
7717680Spst		disk = &sc->sc_disks[n];
7817680Spst		if (disk->d_state == G_RAID3_DISK_STATE_NODISK)
7917680Spst			continue;
8017680Spst		if (disk->d_consumer == NULL)
8117680Spst			continue;
8217680Spst		if (disk->d_consumer->provider == NULL)
8317680Spst			continue;
8417680Spst		if (strcmp(disk->d_consumer->provider->name, name) == 0)
8517680Spst			return (disk);
8617680Spst	}
8717680Spst	return (NULL);
88127675Sbms}
8917680Spst
9017680Spststatic void
9117680Spstg_raid3_ctl_configure(struct gctl_req *req, struct g_class *mp)
9217680Spst{
9317680Spst	struct g_raid3_softc *sc;
9417680Spst	struct g_raid3_disk *disk;
9517680Spst	const char *name;
9617680Spst	int *nargs, do_sync = 0;
9717680Spst	int *autosync, *noautosync;
9817680Spst	int *round_robin, *noround_robin;
9917680Spst	int *verify, *noverify;
10017680Spst	u_int n;
10117680Spst
102146778Ssam	g_topology_assert();
10317680Spst	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
10417680Spst	if (nargs == NULL) {
10517680Spst		gctl_error(req, "No '%s' argument.", "nargs");
10617680Spst		return;
10717680Spst	}
10817680Spst	if (*nargs != 1) {
10917680Spst		gctl_error(req, "Invalid number of arguments.");
11017680Spst		return;
111146778Ssam	}
11298527Sfenner	name = gctl_get_asciiparam(req, "arg0");
11398527Sfenner	if (name == NULL) {
11498527Sfenner		gctl_error(req, "No 'arg%u' argument.", 0);
11517680Spst		return;
11617680Spst	}
117146778Ssam	sc = g_raid3_find_device(mp, name);
11817680Spst	if (sc == NULL) {
11998527Sfenner		gctl_error(req, "No such device: %s.", name);
120146778Ssam		return;
12198527Sfenner	}
12298527Sfenner	if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) {
12398527Sfenner		gctl_error(req, "Not all disks connected.");
12498527Sfenner		return;
12598527Sfenner	}
126146778Ssam	autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync));
12798527Sfenner	if (autosync == NULL) {
12817680Spst		gctl_error(req, "No '%s' argument.", "autosync");
129146778Ssam		return;
13017680Spst	}
13117680Spst	noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync));
13217680Spst	if (noautosync == NULL) {
13317680Spst		gctl_error(req, "No '%s' argument.", "noautosync");
13417680Spst		return;
13517680Spst	}
13617680Spst	if (*autosync && *noautosync) {
13717680Spst		gctl_error(req, "'%s' and '%s' specified.", "autosync",
13817680Spst		    "noautosync");
13917680Spst		return;
14017680Spst	}
14117680Spst	round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin));
14217680Spst	if (round_robin == NULL) {
14317680Spst		gctl_error(req, "No '%s' argument.", "round_robin");
14417680Spst		return;
14517680Spst	}
14617680Spst	noround_robin = gctl_get_paraml(req, "noround_robin",
14717680Spst	    sizeof(*noround_robin));
14817680Spst	if (noround_robin == NULL) {
14917680Spst		gctl_error(req, "No '%s' argument.", "noround_robin");
15017680Spst		return;
15117680Spst	}
15298527Sfenner	if (*round_robin && *noround_robin) {
153127675Sbms		gctl_error(req, "'%s' and '%s' specified.", "round_robin",
15417680Spst		    "noround_robin");
15517680Spst		return;
15617680Spst	}
15717680Spst	verify = gctl_get_paraml(req, "verify", sizeof(*verify));
15817680Spst	if (verify == NULL) {
15917680Spst		gctl_error(req, "No '%s' argument.", "verify");
16017680Spst		return;
16117680Spst	}
16217680Spst	noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify));
16317680Spst	if (noverify == NULL) {
16498527Sfenner		gctl_error(req, "No '%s' argument.", "noverify");
165127675Sbms		return;
16626183Sfenner	}
16717680Spst	if (*verify && *noverify) {
16817680Spst		gctl_error(req, "'%s' and '%s' specified.", "verify",
16917680Spst		    "noverify");
17017680Spst		return;
17117680Spst	}
17217680Spst	if (!*autosync && !*noautosync && !*round_robin && !*noround_robin &&
17317680Spst	    !*verify && !*noverify) {
17498527Sfenner		gctl_error(req, "Nothing has changed.");
17517680Spst		return;
17617680Spst	}
17798527Sfenner	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) {
17817680Spst		if (*autosync) {
17998527Sfenner			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
18017680Spst			do_sync = 1;
18117680Spst		}
18217680Spst	} else {
18317680Spst		if (*noautosync)
18417680Spst			sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
18517680Spst	}
18617680Spst	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) {
18717680Spst		if (*noverify)
18817680Spst			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY;
18917680Spst	} else {
19017680Spst		if (*verify)
19117680Spst			sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY;
19217680Spst	}
19317680Spst	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
19417680Spst		if (*noround_robin)
19517680Spst			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
19617680Spst	} else {
19717692Spst		if (*round_robin)
19817680Spst			sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
19917680Spst	}
20017680Spst	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 &&
20117680Spst	    (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
20217680Spst		/*
20317680Spst		 * VERIFY and ROUND-ROBIN options are mutally exclusive.
20417680Spst		 */
20517692Spst		sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
20617680Spst	}
20717680Spst	for (n = 0; n < sc->sc_ndisks; n++) {
20817680Spst		disk = &sc->sc_disks[n];
20917680Spst		if (do_sync) {
21017680Spst			if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING)
21117680Spst				disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC;
21217680Spst		}
21398527Sfenner		g_raid3_update_metadata(disk);
21498527Sfenner		if (do_sync) {
21517680Spst			if (disk->d_state == G_RAID3_DISK_STATE_STALE) {
21698527Sfenner				/*
21717680Spst				 * XXX: This is probably possible that this
21898527Sfenner				 *      component will not be retasted.
21917680Spst				 */
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->acw > 0)
463		g_access(cp, 0, -1, -1);
464	if (cp->provider != NULL)
465		g_detach(cp);
466	g_destroy_consumer(cp);
467	g_destroy_geom(gp);
468}
469
470static void
471g_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp)
472{
473	struct g_raid3_softc *sc;
474	struct g_raid3_disk *disk;
475	const char *name;
476	intmax_t *no;
477	int *nargs;
478
479	g_topology_assert();
480	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
481	if (nargs == NULL) {
482		gctl_error(req, "No '%s' argument.", "nargs");
483		return;
484	}
485	if (*nargs != 1) {
486		gctl_error(req, "Invalid number of arguments.");
487		return;
488	}
489	name = gctl_get_asciiparam(req, "arg0");
490	if (name == NULL) {
491		gctl_error(req, "No 'arg%u' argument.", 0);
492		return;
493	}
494	sc = g_raid3_find_device(mp, name);
495	if (sc == NULL) {
496		gctl_error(req, "No such device: %s.", name);
497		return;
498	}
499	no = gctl_get_paraml(req, "number", sizeof(*no));
500	if (no == NULL) {
501		gctl_error(req, "No '%s' argument.", "no");
502		return;
503	}
504	if (*no >= sc->sc_ndisks) {
505		gctl_error(req, "Invalid component number.");
506		return;
507	}
508	disk = &sc->sc_disks[*no];
509	switch (disk->d_state) {
510	case G_RAID3_DISK_STATE_ACTIVE:
511		/*
512		 * When replacing ACTIVE component, all the rest has to be also
513		 * ACTIVE.
514		 */
515		if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) <
516		    sc->sc_ndisks) {
517			gctl_error(req, "Cannot replace component number %u.",
518			    *no);
519			return;
520		}
521		/* FALLTHROUGH */
522	case G_RAID3_DISK_STATE_STALE:
523	case G_RAID3_DISK_STATE_SYNCHRONIZING:
524		if (g_raid3_clear_metadata(disk) != 0) {
525			gctl_error(req, "Cannot clear metadata on %s.",
526			    g_raid3_get_diskname(disk));
527		} else {
528			g_raid3_event_send(disk,
529			    G_RAID3_DISK_STATE_DISCONNECTED,
530			    G_RAID3_EVENT_WAIT);
531		}
532		break;
533	case G_RAID3_DISK_STATE_NODISK:
534		break;
535	default:
536		gctl_error(req, "Cannot replace component number %u.", *no);
537		return;
538	}
539}
540
541void
542g_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb)
543{
544	uint32_t *version;
545
546	g_topology_assert();
547
548	version = gctl_get_paraml(req, "version", sizeof(*version));
549	if (version == NULL) {
550		gctl_error(req, "No '%s' argument.", "version");
551		return;
552	}
553	if (*version != G_RAID3_VERSION) {
554		gctl_error(req, "Userland and kernel parts are out of sync.");
555		return;
556	}
557
558	if (strcmp(verb, "configure") == 0)
559		g_raid3_ctl_configure(req, mp);
560	else if (strcmp(verb, "insert") == 0)
561		g_raid3_ctl_insert(req, mp);
562	else if (strcmp(verb, "rebuild") == 0)
563		g_raid3_ctl_rebuild(req, mp);
564	else if (strcmp(verb, "remove") == 0)
565		g_raid3_ctl_remove(req, mp);
566	else if (strcmp(verb, "stop") == 0)
567		g_raid3_ctl_stop(req, mp);
568	else
569		gctl_error(req, "Unknown verb.");
570}
571