geom_raid3.c revision 133808
1133808Spjd/*-
2133808Spjd * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3133808Spjd * All rights reserved.
4133808Spjd *
5133808Spjd * Redistribution and use in source and binary forms, with or without
6133808Spjd * modification, are permitted provided that the following conditions
7133808Spjd * are met:
8133808Spjd * 1. Redistributions of source code must retain the above copyright
9133808Spjd *    notice, this list of conditions and the following disclaimer.
10133808Spjd * 2. Redistributions in binary form must reproduce the above copyright
11133808Spjd *    notice, this list of conditions and the following disclaimer in the
12133808Spjd *    documentation and/or other materials provided with the distribution.
13133808Spjd *
14133808Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15133808Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16133808Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17133808Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18133808Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19133808Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20133808Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21133808Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22133808Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23133808Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24133808Spjd * SUCH DAMAGE.
25133808Spjd */
26133808Spjd
27133808Spjd#include <sys/cdefs.h>
28133808Spjd__FBSDID("$FreeBSD: head/sbin/geom/class/raid3/geom_raid3.c 133808 2004-08-16 06:23:14Z pjd $");
29133808Spjd
30133808Spjd#include <sys/param.h>
31133808Spjd#include <errno.h>
32133808Spjd#include <paths.h>
33133808Spjd#include <stdio.h>
34133808Spjd#include <stdlib.h>
35133808Spjd#include <stdint.h>
36133808Spjd#include <string.h>
37133808Spjd#include <strings.h>
38133808Spjd#include <assert.h>
39133808Spjd#include <libgeom.h>
40133808Spjd#include <geom/raid3/g_raid3.h>
41133808Spjd#include <core/geom.h>
42133808Spjd#include <misc/subr.h>
43133808Spjd
44133808Spjd
45133808Spjduint32_t lib_version = G_LIB_VERSION;
46133808Spjduint32_t version = G_RAID3_VERSION;
47133808Spjd
48133808Spjdstatic void raid3_main(struct gctl_req *req, unsigned f);
49133808Spjdstatic void raid3_clear(struct gctl_req *req);
50133808Spjdstatic void raid3_dump(struct gctl_req *req);
51133808Spjdstatic void raid3_label(struct gctl_req *req);
52133808Spjd
53133808Spjdstruct g_command class_commands[] = {
54133808Spjd	{ "clear", G_FLAG_VERBOSE, raid3_main, G_NULL_OPTS },
55133808Spjd	{ "configure", G_FLAG_VERBOSE, NULL,
56133808Spjd	    {
57133808Spjd		{ 'a', "autosync", NULL, G_TYPE_NONE },
58133808Spjd		{ 'd', "dynamic", NULL, G_TYPE_NONE },
59133808Spjd		{ 'h', "hardcode", NULL, G_TYPE_NONE },
60133808Spjd		{ 'n', "noautosync", NULL, G_TYPE_NONE },
61133808Spjd		G_OPT_SENTINEL
62133808Spjd	    }
63133808Spjd	},
64133808Spjd	{ "dump", 0, raid3_main, G_NULL_OPTS },
65133808Spjd	{ "insert", G_FLAG_VERBOSE, NULL,
66133808Spjd	    {
67133808Spjd		{ 'h', "hardcode", NULL, G_TYPE_NONE },
68133808Spjd		{ 'n', "number", NULL, G_TYPE_NUMBER },
69133808Spjd		G_OPT_SENTINEL
70133808Spjd	    }
71133808Spjd	},
72133808Spjd	{ "label", G_FLAG_VERBOSE, raid3_main,
73133808Spjd	    {
74133808Spjd		{ 'h', "hardcode", NULL, G_TYPE_NONE },
75133808Spjd		{ 'n', "noautosync", NULL, G_TYPE_NONE },
76133808Spjd		G_OPT_SENTINEL
77133808Spjd	    }
78133808Spjd	},
79133808Spjd	{ "rebuild", G_FLAG_VERBOSE, NULL, G_NULL_OPTS },
80133808Spjd	{ "remove", G_FLAG_VERBOSE, NULL,
81133808Spjd	    {
82133808Spjd		{ 'n', "number", NULL, G_TYPE_NUMBER },
83133808Spjd		G_OPT_SENTINEL
84133808Spjd	    }
85133808Spjd	},
86133808Spjd	{ "stop", G_FLAG_VERBOSE, NULL,
87133808Spjd	    {
88133808Spjd		{ 'f', "force", NULL, G_TYPE_NONE },
89133808Spjd		G_OPT_SENTINEL
90133808Spjd	    }
91133808Spjd	},
92133808Spjd	G_CMD_SENTINEL
93133808Spjd};
94133808Spjd
95133808Spjdstatic int verbose = 0;
96133808Spjd
97133808Spjdvoid usage(const char *);
98133808Spjdvoid
99133808Spjdusage(const char *comm)
100133808Spjd{
101133808Spjd	fprintf(stderr,
102133808Spjd	    "usage: %s label [-hnv] name prov prov prov [prov [...]]\n"
103133808Spjd	    "       %s clear [-v] prov [prov [...]]\n"
104133808Spjd	    "       %s dump prov [prov [...]]\n"
105133808Spjd	    "       %s configure [-adhnv] name\n"
106133808Spjd	    "       %s rebuild [-v] name prov\n"
107133808Spjd	    "       %s insert [-hv] <-n number> name prov\n"
108133808Spjd	    "       %s remove [-v] <-n number> name\n"
109133808Spjd	    "       %s stop [-fv] name\n",
110133808Spjd	    comm, comm, comm, comm, comm, comm, comm, comm);
111133808Spjd	exit(EXIT_FAILURE);
112133808Spjd}
113133808Spjd
114133808Spjdstatic void
115133808Spjdraid3_main(struct gctl_req *req, unsigned flags)
116133808Spjd{
117133808Spjd	const char *name;
118133808Spjd
119133808Spjd	if ((flags & G_FLAG_VERBOSE) != 0)
120133808Spjd		verbose = 1;
121133808Spjd
122133808Spjd	name = gctl_get_asciiparam(req, "verb");
123133808Spjd	if (name == NULL) {
124133808Spjd		gctl_error(req, "No '%s' argument.", "verb");
125133808Spjd		return;
126133808Spjd	}
127133808Spjd	if (strcmp(name, "label") == 0)
128133808Spjd		raid3_label(req);
129133808Spjd	else if (strcmp(name, "clear") == 0)
130133808Spjd		raid3_clear(req);
131133808Spjd	else if (strcmp(name, "dump") == 0)
132133808Spjd		raid3_dump(req);
133133808Spjd	else
134133808Spjd		gctl_error(req, "Unknown command: %s.", name);
135133808Spjd}
136133808Spjd
137133808Spjdstatic void
138133808Spjdraid3_label(struct gctl_req *req)
139133808Spjd{
140133808Spjd	struct g_raid3_metadata md;
141133808Spjd	u_char sector[512];
142133808Spjd	const char *str;
143133808Spjd	char param[16];
144133808Spjd	int *hardcode, *nargs, *noautosync, error, i;
145133808Spjd	unsigned sectorsize;
146133808Spjd	off_t mediasize;
147133808Spjd
148133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
149133808Spjd	if (nargs == NULL) {
150133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
151133808Spjd		return;
152133808Spjd	}
153133808Spjd	if (*nargs < 4) {
154133808Spjd		gctl_error(req, "Too few arguments.");
155133808Spjd		return;
156133808Spjd	}
157133808Spjd#ifndef BITCOUNT
158133808Spjd#define	BITCOUNT(x)	(((BX_(x) + (BX_(x) >> 4)) & 0x0F0F0F0F) % 255)
159133808Spjd#define	BX_(x)		((x) - (((x) >> 1) & 0x77777777) -		\
160133808Spjd			 (((x) >> 2) & 0x33333333) - (((x) >> 3) & 0x11111111))
161133808Spjd#endif
162133808Spjd	if (BITCOUNT(*nargs - 2) != 1) {
163133808Spjd		gctl_error(req, "Invalid number of components.");
164133808Spjd		return;
165133808Spjd	}
166133808Spjd
167133808Spjd	strlcpy(md.md_magic, G_RAID3_MAGIC, sizeof(md.md_magic));
168133808Spjd	md.md_version = G_RAID3_VERSION;
169133808Spjd	str = gctl_get_asciiparam(req, "arg0");
170133808Spjd	if (str == NULL) {
171133808Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
172133808Spjd		return;
173133808Spjd	}
174133808Spjd	strlcpy(md.md_name, str, sizeof(md.md_name));
175133808Spjd	md.md_all = *nargs - 1;
176133808Spjd	md.md_mflags = 0;
177133808Spjd	md.md_dflags = 0;
178133808Spjd	md.md_syncid = 1;
179133808Spjd	md.md_sync_offset = 0;
180133808Spjd	noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync));
181133808Spjd	if (noautosync == NULL) {
182133808Spjd		gctl_error(req, "No '%s' argument.", "noautosync");
183133808Spjd		return;
184133808Spjd	}
185133808Spjd	if (*noautosync)
186133808Spjd		md.md_mflags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
187133808Spjd	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
188133808Spjd	if (hardcode == NULL) {
189133808Spjd		gctl_error(req, "No '%s' argument.", "hardcode");
190133808Spjd		return;
191133808Spjd	}
192133808Spjd
193133808Spjd	/*
194133808Spjd	 * Calculate sectorsize by finding least common multiple from
195133808Spjd	 * sectorsizes of every disk and find the smallest mediasize.
196133808Spjd	 */
197133808Spjd	mediasize = 0;
198133808Spjd	sectorsize = 0;
199133808Spjd	for (i = 1; i < *nargs; i++) {
200133808Spjd		unsigned ssize;
201133808Spjd		off_t msize;
202133808Spjd
203133808Spjd		snprintf(param, sizeof(param), "arg%u", i);
204133808Spjd		str = gctl_get_asciiparam(req, param);
205133808Spjd
206133808Spjd		msize = g_get_mediasize(str);
207133808Spjd		ssize = g_get_sectorsize(str);
208133808Spjd		if (msize == 0 || ssize == 0) {
209133808Spjd			gctl_error(req, "Can't get informations about %s: %s.",
210133808Spjd			    str, strerror(errno));
211133808Spjd			return;
212133808Spjd		}
213133808Spjd		msize -= ssize;
214133808Spjd		if (mediasize == 0 || (mediasize > 0 && msize < mediasize))
215133808Spjd			mediasize = msize;
216133808Spjd		if (sectorsize == 0)
217133808Spjd			sectorsize = ssize;
218133808Spjd		else
219133808Spjd			sectorsize = g_lcm(sectorsize, ssize);
220133808Spjd	}
221133808Spjd	md.md_mediasize = mediasize * (*nargs - 2);
222133808Spjd	md.md_sectorsize = sectorsize * (*nargs - 2);
223133808Spjd
224133808Spjd	/*
225133808Spjd	 * Clear last sector first, to spoil all components if device exists.
226133808Spjd	 */
227133808Spjd	for (i = 1; i < *nargs; i++) {
228133808Spjd		snprintf(param, sizeof(param), "arg%u", i);
229133808Spjd		str = gctl_get_asciiparam(req, param);
230133808Spjd
231133808Spjd		error = g_metadata_clear(str, NULL);
232133808Spjd		if (error != 0) {
233133808Spjd			gctl_error(req, "Can't store metadata on %s: %s.", str,
234133808Spjd			    strerror(error));
235133808Spjd			return;
236133808Spjd		}
237133808Spjd	}
238133808Spjd
239133808Spjd	/*
240133808Spjd	 * Ok, store metadata (use disk number as priority).
241133808Spjd	 */
242133808Spjd	for (i = 1; i < *nargs; i++) {
243133808Spjd		snprintf(param, sizeof(param), "arg%u", i);
244133808Spjd		str = gctl_get_asciiparam(req, param);
245133808Spjd
246133808Spjd		md.md_no = i - 1;
247133808Spjd		if (!*hardcode)
248133808Spjd			bzero(md.md_provider, sizeof(md.md_provider));
249133808Spjd		else {
250133808Spjd			if (strncmp(str, _PATH_DEV, strlen(_PATH_DEV)) == 0)
251133808Spjd				str += strlen(_PATH_DEV);
252133808Spjd			strlcpy(md.md_provider, str, sizeof(md.md_provider));
253133808Spjd		}
254133808Spjd		raid3_metadata_encode(&md, sector);
255133808Spjd		error = g_metadata_store(str, sector, sizeof(sector));
256133808Spjd		if (error != 0) {
257133808Spjd			fprintf(stderr, "Can't store metadata on %s: %s.\n",
258133808Spjd			    str, strerror(error));
259133808Spjd			gctl_error(req, "Not fully done.");
260133808Spjd			continue;
261133808Spjd		}
262133808Spjd		if (verbose)
263133808Spjd			printf("Metadata value stored on %s.\n", str);
264133808Spjd	}
265133808Spjd}
266133808Spjd
267133808Spjdstatic void
268133808Spjdraid3_clear(struct gctl_req *req)
269133808Spjd{
270133808Spjd	const char *name;
271133808Spjd	char param[16];
272133808Spjd	int *nargs, error, i;
273133808Spjd
274133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
275133808Spjd	if (nargs == NULL) {
276133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
277133808Spjd		return;
278133808Spjd	}
279133808Spjd	if (*nargs < 1) {
280133808Spjd		gctl_error(req, "Too few arguments.");
281133808Spjd		return;
282133808Spjd	}
283133808Spjd
284133808Spjd	for (i = 0; i < *nargs; i++) {
285133808Spjd		snprintf(param, sizeof(param), "arg%u", i);
286133808Spjd		name = gctl_get_asciiparam(req, param);
287133808Spjd
288133808Spjd		error = g_metadata_clear(name, G_RAID3_MAGIC);
289133808Spjd		if (error != 0) {
290133808Spjd			fprintf(stderr, "Can't clear metadata on %s: %s.\n",
291133808Spjd			    name, strerror(error));
292133808Spjd			gctl_error(req, "Not fully done.");
293133808Spjd			continue;
294133808Spjd		}
295133808Spjd		if (verbose)
296133808Spjd			printf("Metadata cleared on %s.\n", name);
297133808Spjd	}
298133808Spjd}
299133808Spjd
300133808Spjdstatic void
301133808Spjdraid3_dump(struct gctl_req *req)
302133808Spjd{
303133808Spjd	struct g_raid3_metadata md, tmpmd;
304133808Spjd	const char *name;
305133808Spjd	char param[16];
306133808Spjd	int *nargs, error, i;
307133808Spjd
308133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
309133808Spjd	if (nargs == NULL) {
310133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
311133808Spjd		return;
312133808Spjd	}
313133808Spjd	if (*nargs < 1) {
314133808Spjd		gctl_error(req, "Too few arguments.");
315133808Spjd		return;
316133808Spjd	}
317133808Spjd
318133808Spjd	for (i = 0; i < *nargs; i++) {
319133808Spjd		snprintf(param, sizeof(param), "arg%u", i);
320133808Spjd		name = gctl_get_asciiparam(req, param);
321133808Spjd
322133808Spjd		error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd),
323133808Spjd		    G_RAID3_MAGIC);
324133808Spjd		if (error != 0) {
325133808Spjd			fprintf(stderr, "Can't read metadata from %s: %s.\n",
326133808Spjd			    name, strerror(error));
327133808Spjd			gctl_error(req, "Not fully done.");
328133808Spjd			continue;
329133808Spjd		}
330133808Spjd		if (raid3_metadata_decode((u_char *)&tmpmd, &md) != 0) {
331133808Spjd			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
332133808Spjd			    name);
333133808Spjd			gctl_error(req, "Not fully done.");
334133808Spjd			continue;
335133808Spjd		}
336133808Spjd		printf("Metadata on %s:\n", name);
337133808Spjd		raid3_metadata_dump(&md);
338133808Spjd		printf("\n");
339133808Spjd	}
340133808Spjd}
341