xref: /freebsd/lib/geom/stripe/geom_stripe.c (revision 7ef62cebc2f965b0f640263e179276928885e33d)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2004-2005 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/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <errno.h>
34 #include <paths.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <string.h>
39 #include <strings.h>
40 #include <assert.h>
41 #include <libgeom.h>
42 #include <geom/stripe/g_stripe.h>
43 
44 #include "core/geom.h"
45 #include "misc/subr.h"
46 
47 
48 uint32_t lib_version = G_LIB_VERSION;
49 uint32_t version = G_STRIPE_VERSION;
50 
51 #define	GSTRIPE_STRIPESIZE	"65536"
52 
53 static void stripe_main(struct gctl_req *req, unsigned flags);
54 static void stripe_clear(struct gctl_req *req);
55 static void stripe_dump(struct gctl_req *req);
56 static void stripe_label(struct gctl_req *req);
57 
58 struct g_command class_commands[] = {
59 	{ "clear", G_FLAG_VERBOSE, stripe_main, G_NULL_OPTS,
60 	    "[-v] prov ..."
61 	},
62 	{ "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
63 	    {
64 		{ 's', "stripesize", GSTRIPE_STRIPESIZE, G_TYPE_NUMBER },
65 		G_OPT_SENTINEL
66 	    },
67 	    "[-v] [-s stripesize] name prov prov ..."
68 	},
69 	{ "destroy", G_FLAG_VERBOSE, NULL,
70 	    {
71 		{ 'f', "force", NULL, G_TYPE_BOOL },
72 		G_OPT_SENTINEL
73 	    },
74 	    "[-fv] name ..."
75 	},
76 	{ "dump", 0, stripe_main, G_NULL_OPTS,
77 	    "prov ..."
78 	},
79 	{ "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, stripe_main,
80 	    {
81 		{ 'h', "hardcode", NULL, G_TYPE_BOOL },
82 		{ 's', "stripesize", GSTRIPE_STRIPESIZE, G_TYPE_NUMBER },
83 		G_OPT_SENTINEL
84 	    },
85 	    "[-hv] [-s stripesize] name prov prov ..."
86 	},
87 	{ "stop", G_FLAG_VERBOSE, NULL,
88 	    {
89 		{ 'f', "force", NULL, G_TYPE_BOOL },
90 		G_OPT_SENTINEL
91 	    },
92 	    "[-fv] name ..."
93 	},
94 	G_CMD_SENTINEL
95 };
96 
97 static int verbose = 0;
98 
99 static void
100 stripe_main(struct gctl_req *req, unsigned flags)
101 {
102 	const char *name;
103 
104 	if ((flags & G_FLAG_VERBOSE) != 0)
105 		verbose = 1;
106 
107 	name = gctl_get_ascii(req, "verb");
108 	if (name == NULL) {
109 		gctl_error(req, "No '%s' argument.", "verb");
110 		return;
111 	}
112 	if (strcmp(name, "label") == 0)
113 		stripe_label(req);
114 	else if (strcmp(name, "clear") == 0)
115 		stripe_clear(req);
116 	else if (strcmp(name, "dump") == 0)
117 		stripe_dump(req);
118 	else
119 		gctl_error(req, "Unknown command: %s.", name);
120 }
121 
122 static void
123 stripe_label(struct gctl_req *req)
124 {
125 	struct g_stripe_metadata md;
126 	intmax_t stripesize;
127 	off_t compsize, msize;
128 	u_char sector[512];
129 	unsigned ssize, secsize;
130 	const char *name;
131 	int error, i, nargs, hardcode;
132 
133 	bzero(sector, sizeof(sector));
134 	nargs = gctl_get_int(req, "nargs");
135 	if (nargs < 3) {
136 		gctl_error(req, "Too few arguments.");
137 		return;
138 	}
139 	hardcode = gctl_get_int(req, "hardcode");
140 
141 	/*
142 	 * Clear last sector first to spoil all components if device exists.
143 	 */
144 	compsize = 0;
145 	secsize = 0;
146 	for (i = 1; i < nargs; i++) {
147 		name = gctl_get_ascii(req, "arg%d", i);
148 		msize = g_get_mediasize(name);
149 		ssize = g_get_sectorsize(name);
150 		if (msize == 0 || ssize == 0) {
151 			gctl_error(req, "Can't get informations about %s: %s.",
152 			    name, strerror(errno));
153 			return;
154 		}
155 		msize -= ssize;
156 		if (compsize == 0 || (compsize > 0 && msize < compsize))
157 			compsize = msize;
158 		if (secsize == 0)
159 			secsize = ssize;
160 		else
161 			secsize = g_lcm(secsize, ssize);
162 
163 		error = g_metadata_clear(name, NULL);
164 		if (error != 0) {
165 			gctl_error(req, "Can't store metadata on %s: %s.", name,
166 			    strerror(error));
167 			return;
168 		}
169 	}
170 
171 	strlcpy(md.md_magic, G_STRIPE_MAGIC, sizeof(md.md_magic));
172 	md.md_version = G_STRIPE_VERSION;
173 	name = gctl_get_ascii(req, "arg0");
174 	strlcpy(md.md_name, name, sizeof(md.md_name));
175 	md.md_id = arc4random();
176 	md.md_all = nargs - 1;
177 	stripesize = gctl_get_intmax(req, "stripesize");
178 	if ((stripesize % secsize) != 0) {
179 		gctl_error(req, "Stripesize should be multiple of %u.",
180 		    secsize);
181 		return;
182 	}
183 	md.md_stripesize = stripesize;
184 
185 	/*
186 	 * Ok, store metadata.
187 	 */
188 	for (i = 1; i < nargs; i++) {
189 		name = gctl_get_ascii(req, "arg%d", i);
190 		msize = g_get_mediasize(name);
191 		ssize = g_get_sectorsize(name);
192 		if (compsize < msize - ssize) {
193 			fprintf(stderr,
194 			    "warning: %s: only %jd bytes from %jd bytes used.\n",
195 			    name, (intmax_t)compsize, (intmax_t)(msize - ssize));
196 		}
197 
198 		md.md_no = i - 1;
199 		md.md_provsize = msize;
200 		if (!hardcode)
201 			bzero(md.md_provider, sizeof(md.md_provider));
202 		else {
203 			if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
204 				name += sizeof(_PATH_DEV) - 1;
205 			strlcpy(md.md_provider, name, sizeof(md.md_provider));
206 		}
207 		stripe_metadata_encode(&md, sector);
208 		error = g_metadata_store(name, sector, sizeof(sector));
209 		if (error != 0) {
210 			fprintf(stderr, "Can't store metadata on %s: %s.\n",
211 			    name, strerror(error));
212 			gctl_error(req, "Not fully done.");
213 			continue;
214 		}
215 		if (verbose)
216 			printf("Metadata value stored on %s.\n", name);
217 	}
218 }
219 
220 static void
221 stripe_clear(struct gctl_req *req)
222 {
223 	const char *name;
224 	int error, i, nargs;
225 
226 	nargs = gctl_get_int(req, "nargs");
227 	if (nargs < 1) {
228 		gctl_error(req, "Too few arguments.");
229 		return;
230 	}
231 
232 	for (i = 0; i < nargs; i++) {
233 		name = gctl_get_ascii(req, "arg%d", i);
234 		error = g_metadata_clear(name, G_STRIPE_MAGIC);
235 		if (error != 0) {
236 			fprintf(stderr, "Can't clear metadata on %s: %s.\n",
237 			    name, strerror(error));
238 			gctl_error(req, "Not fully done.");
239 			continue;
240 		}
241 		if (verbose)
242 			printf("Metadata cleared on %s.\n", name);
243 	}
244 }
245 
246 static void
247 stripe_metadata_dump(const struct g_stripe_metadata *md)
248 {
249 
250 	printf("         Magic string: %s\n", md->md_magic);
251 	printf("     Metadata version: %u\n", (u_int)md->md_version);
252 	printf("          Device name: %s\n", md->md_name);
253 	printf("            Device ID: %u\n", (u_int)md->md_id);
254 	printf("          Disk number: %u\n", (u_int)md->md_no);
255 	printf("Total number of disks: %u\n", (u_int)md->md_all);
256 	printf("          Stripe size: %u\n", (u_int)md->md_stripesize);
257 	printf("   Hardcoded provider: %s\n", md->md_provider);
258 }
259 
260 static void
261 stripe_dump(struct gctl_req *req)
262 {
263 	struct g_stripe_metadata md, tmpmd;
264 	const char *name;
265 	int error, i, nargs;
266 
267 	nargs = gctl_get_int(req, "nargs");
268 	if (nargs < 1) {
269 		gctl_error(req, "Too few arguments.");
270 		return;
271 	}
272 
273 	for (i = 0; i < nargs; i++) {
274 		name = gctl_get_ascii(req, "arg%d", i);
275 		error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd),
276 		    G_STRIPE_MAGIC);
277 		if (error != 0) {
278 			fprintf(stderr, "Can't read metadata from %s: %s.\n",
279 			    name, strerror(error));
280 			gctl_error(req, "Not fully done.");
281 			continue;
282 		}
283 		stripe_metadata_decode((u_char *)&tmpmd, &md);
284 		printf("Metadata on %s:\n", name);
285 		stripe_metadata_dump(&md);
286 		printf("\n");
287 	}
288 }
289