]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sbin/geom/class/mirror/geom_mirror.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sbin / geom / class / mirror / geom_mirror.c
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$");
29
30 #include <sys/param.h>
31 #include <errno.h>
32 #include <paths.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stdint.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <assert.h>
39 #include <libgeom.h>
40 #include <geom/mirror/g_mirror.h>
41 #include <core/geom.h>
42 #include <misc/subr.h>
43
44
45 uint32_t lib_version = G_LIB_VERSION;
46 uint32_t version = G_MIRROR_VERSION;
47
48 static char label_balance[] = "split", configure_balance[] = "none";
49 static intmax_t label_slice = 4096, configure_slice = -1;
50 static intmax_t insert_priority = 0;
51
52 static void mirror_main(struct gctl_req *req, unsigned flags);
53 static void mirror_activate(struct gctl_req *req);
54 static void mirror_clear(struct gctl_req *req);
55 static void mirror_dump(struct gctl_req *req);
56 static void mirror_label(struct gctl_req *req);
57
58 struct g_command class_commands[] = {
59         { "activate", G_FLAG_VERBOSE, mirror_main, G_NULL_OPTS, NULL,
60             "[-v] name prov ..."
61         },
62         { "clear", G_FLAG_VERBOSE, mirror_main, G_NULL_OPTS, NULL,
63             "[-v] prov ..."
64         },
65         { "configure", G_FLAG_VERBOSE, NULL,
66             {
67                 { 'a', "autosync", NULL, G_TYPE_BOOL },
68                 { 'b', "balance", configure_balance, G_TYPE_STRING },
69                 { 'd', "dynamic", NULL, G_TYPE_BOOL },
70                 { 'f', "failsync", NULL, G_TYPE_BOOL },
71                 { 'F', "nofailsync", NULL, G_TYPE_BOOL },
72                 { 'h', "hardcode", NULL, G_TYPE_BOOL },
73                 { 'n', "noautosync", NULL, G_TYPE_BOOL },
74                 { 's', "slice", &configure_slice, G_TYPE_NUMBER },
75                 G_OPT_SENTINEL
76             },
77             NULL, "[-adfFhnv] [-b balance] [-s slice] name"
78         },
79         { "deactivate", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, NULL,
80             "[-v] name prov ..."
81         },
82         { "dump", 0, mirror_main, G_NULL_OPTS, NULL,
83             "prov ..."
84         },
85         { "forget", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, NULL,
86             "name ..."
87         },
88         { "label", G_FLAG_VERBOSE, mirror_main,
89             {
90                 { 'b', "balance", label_balance, G_TYPE_STRING },
91                 { 'F', "nofailsync", NULL, G_TYPE_BOOL },
92                 { 'h', "hardcode", NULL, G_TYPE_BOOL },
93                 { 'n', "noautosync", NULL, G_TYPE_BOOL },
94                 { 's', "slice", &label_slice, G_TYPE_NUMBER },
95                 G_OPT_SENTINEL
96             },
97             NULL, "[-Fhnv] [-b balance] [-s slice] name prov ..."
98         },
99         { "insert", G_FLAG_VERBOSE, NULL,
100             {
101                 { 'h', "hardcode", NULL, G_TYPE_BOOL },
102                 { 'i', "inactive", NULL, G_TYPE_BOOL },
103                 { 'p', "priority", &insert_priority, G_TYPE_NUMBER },
104                 G_OPT_SENTINEL
105             },
106             NULL, "[-hiv] [-p priority] name prov ..."
107         },
108         { "rebuild", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, NULL,
109             "[-v] name prov ..."
110         },
111         { "remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, NULL,
112             "[-v] name prov ..."
113         },
114         { "stop", G_FLAG_VERBOSE, NULL,
115             {
116                 { 'f', "force", NULL, G_TYPE_BOOL },
117                 G_OPT_SENTINEL
118             },
119             NULL, "[-fv] name ..."
120         },
121         G_CMD_SENTINEL
122 };
123
124 static int verbose = 0;
125
126 static void
127 mirror_main(struct gctl_req *req, unsigned flags)
128 {
129         const char *name;
130
131         if ((flags & G_FLAG_VERBOSE) != 0)
132                 verbose = 1;
133
134         name = gctl_get_ascii(req, "verb");
135         if (name == NULL) {
136                 gctl_error(req, "No '%s' argument.", "verb");
137                 return;
138         }
139         if (strcmp(name, "label") == 0)
140                 mirror_label(req);
141         else if (strcmp(name, "clear") == 0)
142                 mirror_clear(req);
143         else if (strcmp(name, "dump") == 0)
144                 mirror_dump(req);
145         else if (strcmp(name, "activate") == 0)
146                 mirror_activate(req);
147         else
148                 gctl_error(req, "Unknown command: %s.", name);
149 }
150
151 static void
152 mirror_label(struct gctl_req *req)
153 {
154         struct g_mirror_metadata md;
155         u_char sector[512];
156         const char *str;
157         unsigned sectorsize;
158         off_t mediasize;
159         intmax_t val;
160         int error, i, nargs, bal, hardcode;
161
162         nargs = gctl_get_int(req, "nargs");
163         if (nargs < 2) {
164                 gctl_error(req, "Too few arguments.");
165                 return;
166         }
167
168         strlcpy(md.md_magic, G_MIRROR_MAGIC, sizeof(md.md_magic));
169         md.md_version = G_MIRROR_VERSION;
170         str = gctl_get_ascii(req, "arg0");
171         strlcpy(md.md_name, str, sizeof(md.md_name));
172         md.md_mid = arc4random();
173         md.md_all = nargs - 1;
174         md.md_mflags = 0;
175         md.md_dflags = 0;
176         md.md_genid = 0;
177         md.md_syncid = 1;
178         md.md_sync_offset = 0;
179         val = gctl_get_intmax(req, "slice");
180         md.md_slice = val;
181         str = gctl_get_ascii(req, "balance");
182         bal = balance_id(str);
183         if (bal == -1) {
184                 gctl_error(req, "Invalid balance algorithm.");
185                 return;
186         }
187         md.md_balance = bal;
188         if (gctl_get_int(req, "noautosync"))
189                 md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC;
190         if (gctl_get_int(req, "nofailsync"))
191                 md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOFAILSYNC;
192         hardcode = gctl_get_int(req, "hardcode");
193
194         /*
195          * Calculate sectorsize by finding least common multiple from
196          * sectorsizes of every disk and find the smallest mediasize.
197          */
198         mediasize = 0;
199         sectorsize = 0;
200         for (i = 1; i < nargs; i++) {
201                 unsigned ssize;
202                 off_t msize;
203
204                 str = gctl_get_ascii(req, "arg%d", i);
205                 msize = g_get_mediasize(str);
206                 ssize = g_get_sectorsize(str);
207                 if (msize == 0 || ssize == 0) {
208                         gctl_error(req, "Can't get informations about %s: %s.",
209                             str, strerror(errno));
210                         return;
211                 }
212                 msize -= ssize;
213                 if (mediasize == 0 || (mediasize > 0 && msize < mediasize))
214                         mediasize = msize;
215                 if (sectorsize == 0)
216                         sectorsize = ssize;
217                 else
218                         sectorsize = g_lcm(sectorsize, ssize);
219         }
220         md.md_mediasize = mediasize;
221         md.md_sectorsize = sectorsize;
222         md.md_mediasize -= (md.md_mediasize % md.md_sectorsize);
223
224         /*
225          * Clear last sector first, to spoil all components if device exists.
226          */
227         for (i = 1; i < nargs; i++) {
228                 str = gctl_get_ascii(req, "arg%d", i);
229                 error = g_metadata_clear(str, NULL);
230                 if (error != 0) {
231                         gctl_error(req, "Can't store metadata on %s: %s.", str,
232                             strerror(error));
233                         return;
234                 }
235         }
236
237         /*
238          * Ok, store metadata (use disk number as priority).
239          */
240         for (i = 1; i < nargs; i++) {
241                 str = gctl_get_ascii(req, "arg%d", i);
242                 md.md_did = arc4random();
243                 md.md_priority = i - 1;
244                 md.md_provsize = g_get_mediasize(str);
245                 assert(md.md_provsize != 0);
246                 if (!hardcode)
247                         bzero(md.md_provider, sizeof(md.md_provider));
248                 else {
249                         if (strncmp(str, _PATH_DEV, strlen(_PATH_DEV)) == 0)
250                                 str += strlen(_PATH_DEV);
251                         strlcpy(md.md_provider, str, sizeof(md.md_provider));
252                 }
253                 mirror_metadata_encode(&md, sector);
254                 error = g_metadata_store(str, sector, sizeof(sector));
255                 if (error != 0) {
256                         fprintf(stderr, "Can't store metadata on %s: %s.\n",
257                             str, strerror(error));
258                         gctl_error(req, "Not fully done.");
259                         continue;
260                 }
261                 if (verbose)
262                         printf("Metadata value stored on %s.\n", str);
263         }
264 }
265
266 static void
267 mirror_clear(struct gctl_req *req)
268 {
269         const char *name;
270         int error, i, nargs;
271
272         nargs = gctl_get_int(req, "nargs");
273         if (nargs < 1) {
274                 gctl_error(req, "Too few arguments.");
275                 return;
276         }
277
278         for (i = 0; i < nargs; i++) {
279                 name = gctl_get_ascii(req, "arg%d", i);
280                 error = g_metadata_clear(name, G_MIRROR_MAGIC);
281                 if (error != 0) {
282                         fprintf(stderr, "Can't clear metadata on %s: %s.\n",
283                             name, strerror(error));
284                         gctl_error(req, "Not fully done.");
285                         continue;
286                 }
287                 if (verbose)
288                         printf("Metadata cleared on %s.\n", name);
289         }
290 }
291
292 static void
293 mirror_dump(struct gctl_req *req)
294 {
295         struct g_mirror_metadata md, tmpmd;
296         const char *name;
297         int error, i, nargs;
298
299         nargs = gctl_get_int(req, "nargs");
300         if (nargs < 1) {
301                 gctl_error(req, "Too few arguments.");
302                 return;
303         }
304
305         for (i = 0; i < nargs; i++) {
306                 name = gctl_get_ascii(req, "arg%d", i);
307                 error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd),
308                     G_MIRROR_MAGIC);
309                 if (error != 0) {
310                         fprintf(stderr, "Can't read metadata from %s: %s.\n",
311                             name, strerror(error));
312                         gctl_error(req, "Not fully done.");
313                         continue;
314                 }
315                 if (mirror_metadata_decode((u_char *)&tmpmd, &md) != 0) {
316                         fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
317                             name);
318                         gctl_error(req, "Not fully done.");
319                         continue;
320                 }
321                 printf("Metadata on %s:\n", name);
322                 mirror_metadata_dump(&md);
323                 printf("\n");
324         }
325 }
326
327 static void
328 mirror_activate(struct gctl_req *req)
329 {
330         struct g_mirror_metadata md, tmpmd;
331         const char *name, *path;
332         int error, i, nargs;
333
334         nargs = gctl_get_int(req, "nargs");
335         if (nargs < 2) {
336                 gctl_error(req, "Too few arguments.");
337                 return;
338         }
339         name = gctl_get_ascii(req, "arg0");
340
341         for (i = 1; i < nargs; i++) {
342                 path = gctl_get_ascii(req, "arg%d", i);
343                 error = g_metadata_read(path, (u_char *)&tmpmd, sizeof(tmpmd),
344                     G_MIRROR_MAGIC);
345                 if (error != 0) {
346                         fprintf(stderr, "Cannot read metadata from %s: %s.\n",
347                             path, strerror(error));
348                         gctl_error(req, "Not fully done.");
349                         continue;
350                 }
351                 if (mirror_metadata_decode((u_char *)&tmpmd, &md) != 0) {
352                         fprintf(stderr,
353                             "MD5 hash mismatch for provider %s, skipping.\n",
354                             path);
355                         gctl_error(req, "Not fully done.");
356                         continue;
357                 }
358                 if (strcmp(md.md_name, name) != 0) {
359                         fprintf(stderr,
360                             "Provider %s is not the mirror %s component.\n",
361                             path, name);
362                         gctl_error(req, "Not fully done.");
363                         continue;
364                 }
365                 md.md_dflags &= ~G_MIRROR_DISK_FLAG_INACTIVE;
366                 mirror_metadata_encode(&md, (u_char *)&tmpmd);
367                 error = g_metadata_store(path, (u_char *)&tmpmd, sizeof(tmpmd));
368                 if (error != 0) {
369                         fprintf(stderr, "Cannot write metadata from %s: %s.\n",
370                             path, strerror(error));
371                         gctl_error(req, "Not fully done.");
372                         continue;
373                 }
374                 if (verbose)
375                         printf("Provider %s activated.\n", path);
376         }
377 }