]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/geom/mirror/geom_mirror.c
Merge OpenSSL 1.0.2p.
[FreeBSD/FreeBSD.git] / lib / geom / mirror / geom_mirror.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004-2009 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 <err.h>
34 #include <errno.h>
35 #include <paths.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdint.h>
39 #include <string.h>
40 #include <strings.h>
41 #include <assert.h>
42 #include <libgeom.h>
43 #include <geom/mirror/g_mirror.h>
44 #include <core/geom.h>
45 #include <misc/subr.h>
46
47 uint32_t lib_version = G_LIB_VERSION;
48 uint32_t version = G_MIRROR_VERSION;
49
50 #define GMIRROR_BALANCE         "load"
51 #define GMIRROR_SLICE           "4096"
52 #define GMIRROR_PRIORITY        "0"
53
54 static void mirror_main(struct gctl_req *req, unsigned flags);
55 static void mirror_activate(struct gctl_req *req);
56 static void mirror_clear(struct gctl_req *req);
57 static void mirror_dump(struct gctl_req *req);
58 static void mirror_label(struct gctl_req *req);
59 static void mirror_resize(struct gctl_req *req, unsigned flags);
60
61 struct g_command class_commands[] = {
62         { "activate", G_FLAG_VERBOSE, mirror_main, G_NULL_OPTS,
63             "[-v] name prov ..."
64         },
65         { "clear", G_FLAG_VERBOSE, mirror_main, G_NULL_OPTS,
66             "[-v] prov ..."
67         },
68         { "configure", G_FLAG_VERBOSE, NULL,
69             {
70                 { 'a', "autosync", NULL, G_TYPE_BOOL },
71                 { 'b', "balance", "", G_TYPE_STRING },
72                 { 'd', "dynamic", NULL, G_TYPE_BOOL },
73                 { 'f', "failsync", NULL, G_TYPE_BOOL },
74                 { 'F', "nofailsync", NULL, G_TYPE_BOOL },
75                 { 'h', "hardcode", NULL, G_TYPE_BOOL },
76                 { 'n', "noautosync", NULL, G_TYPE_BOOL },
77                 { 'p', "priority", "-1", G_TYPE_NUMBER },
78                 { 's', "slice", "-1", G_TYPE_NUMBER },
79                 G_OPT_SENTINEL
80             },
81             "[-adfFhnv] [-b balance] [-s slice] name\n"
82             "[-v] -p priority name prov"
83         },
84         { "create", G_FLAG_VERBOSE, NULL,
85             {
86                 { 'b', "balance", GMIRROR_BALANCE, G_TYPE_STRING },
87                 { 'F', "nofailsync", NULL, G_TYPE_BOOL },
88                 { 'n', "noautosync", NULL, G_TYPE_BOOL },
89                 { 's', "slice", GMIRROR_SLICE, G_TYPE_NUMBER },
90                 G_OPT_SENTINEL
91             },
92             "[-Fnv] [-b balance] [-s slice] name prov ..."
93         },
94         { "deactivate", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
95             "[-v] name prov ..."
96         },
97         { "destroy", G_FLAG_VERBOSE, NULL,
98             {
99                 { 'f', "force", NULL, G_TYPE_BOOL },
100                 G_OPT_SENTINEL
101             },
102             "[-fv] name ..."
103         },
104         { "dump", 0, mirror_main, G_NULL_OPTS,
105             "prov ..."
106         },
107         { "forget", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
108             "name ..."
109         },
110         { "label", G_FLAG_VERBOSE, mirror_main,
111             {
112                 { 'b', "balance", GMIRROR_BALANCE, G_TYPE_STRING },
113                 { 'F', "nofailsync", NULL, G_TYPE_BOOL },
114                 { 'h', "hardcode", NULL, G_TYPE_BOOL },
115                 { 'n', "noautosync", NULL, G_TYPE_BOOL },
116                 { 's', "slice", GMIRROR_SLICE, G_TYPE_NUMBER },
117                 G_OPT_SENTINEL
118             },
119             "[-Fhnv] [-b balance] [-s slice] name prov ..."
120         },
121         { "insert", G_FLAG_VERBOSE, NULL,
122             {
123                 { 'h', "hardcode", NULL, G_TYPE_BOOL },
124                 { 'i', "inactive", NULL, G_TYPE_BOOL },
125                 { 'p', "priority", GMIRROR_PRIORITY, G_TYPE_NUMBER },
126                 G_OPT_SENTINEL
127             },
128             "[-hiv] [-p priority] name prov ..."
129         },
130         { "rebuild", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
131             "[-v] name prov ..."
132         },
133         { "remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
134             "[-v] name prov ..."
135         },
136         { "resize", G_FLAG_VERBOSE, mirror_resize,
137             {
138                 { 's', "size", "*", G_TYPE_STRING },
139                 G_OPT_SENTINEL
140             },
141             "[-s size] [-v] name"
142         },
143         { "stop", G_FLAG_VERBOSE, NULL,
144             {
145                 { 'f', "force", NULL, G_TYPE_BOOL },
146                 G_OPT_SENTINEL
147             },
148             "[-fv] name ..."
149         },
150         G_CMD_SENTINEL
151 };
152
153 static int verbose = 0;
154
155 static void
156 mirror_main(struct gctl_req *req, unsigned flags)
157 {
158         const char *name;
159
160         if ((flags & G_FLAG_VERBOSE) != 0)
161                 verbose = 1;
162
163         name = gctl_get_ascii(req, "verb");
164         if (name == NULL) {
165                 gctl_error(req, "No '%s' argument.", "verb");
166                 return;
167         }
168         if (strcmp(name, "label") == 0)
169                 mirror_label(req);
170         else if (strcmp(name, "clear") == 0)
171                 mirror_clear(req);
172         else if (strcmp(name, "dump") == 0)
173                 mirror_dump(req);
174         else if (strcmp(name, "activate") == 0)
175                 mirror_activate(req);
176         else
177                 gctl_error(req, "Unknown command: %s.", name);
178 }
179
180 static void
181 mirror_label(struct gctl_req *req)
182 {
183         struct g_mirror_metadata md;
184         u_char sector[512];
185         const char *str;
186         unsigned sectorsize;
187         off_t mediasize;
188         intmax_t val;
189         int error, i, nargs, bal, hardcode;
190
191         bzero(sector, sizeof(sector));
192         nargs = gctl_get_int(req, "nargs");
193         if (nargs < 2) {
194                 gctl_error(req, "Too few arguments.");
195                 return;
196         }
197
198         strlcpy(md.md_magic, G_MIRROR_MAGIC, sizeof(md.md_magic));
199         md.md_version = G_MIRROR_VERSION;
200         str = gctl_get_ascii(req, "arg0");
201         strlcpy(md.md_name, str, sizeof(md.md_name));
202         md.md_mid = arc4random();
203         md.md_all = nargs - 1;
204         md.md_mflags = 0;
205         md.md_dflags = 0;
206         md.md_genid = 0;
207         md.md_syncid = 1;
208         md.md_sync_offset = 0;
209         val = gctl_get_intmax(req, "slice");
210         md.md_slice = val;
211         str = gctl_get_ascii(req, "balance");
212         bal = balance_id(str);
213         if (bal == -1) {
214                 gctl_error(req, "Invalid balance algorithm.");
215                 return;
216         }
217         md.md_balance = bal;
218         if (gctl_get_int(req, "noautosync"))
219                 md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC;
220         if (gctl_get_int(req, "nofailsync"))
221                 md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOFAILSYNC;
222         hardcode = gctl_get_int(req, "hardcode");
223
224         /*
225          * Calculate sectorsize by finding least common multiple from
226          * sectorsizes of every disk and find the smallest mediasize.
227          */
228         mediasize = 0;
229         sectorsize = 0;
230         for (i = 1; i < nargs; i++) {
231                 unsigned ssize;
232                 off_t msize;
233
234                 str = gctl_get_ascii(req, "arg%d", i);
235                 msize = g_get_mediasize(str);
236                 ssize = g_get_sectorsize(str);
237                 if (msize == 0 || ssize == 0) {
238                         gctl_error(req, "Can't get informations about %s: %s.",
239                             str, strerror(errno));
240                         return;
241                 }
242                 msize -= ssize;
243                 if (mediasize == 0 || (mediasize > 0 && msize < mediasize))
244                         mediasize = msize;
245                 if (sectorsize == 0)
246                         sectorsize = ssize;
247                 else
248                         sectorsize = g_lcm(sectorsize, ssize);
249         }
250         md.md_mediasize = mediasize;
251         md.md_sectorsize = sectorsize;
252         md.md_mediasize -= (md.md_mediasize % md.md_sectorsize);
253
254         /*
255          * Clear last sector first, to spoil all components if device exists.
256          */
257         for (i = 1; i < nargs; i++) {
258                 str = gctl_get_ascii(req, "arg%d", i);
259                 error = g_metadata_clear(str, NULL);
260                 if (error != 0) {
261                         gctl_error(req, "Can't store metadata on %s: %s.", str,
262                             strerror(error));
263                         return;
264                 }
265         }
266
267         /*
268          * Ok, store metadata (use disk number as priority).
269          */
270         for (i = 1; i < nargs; i++) {
271                 str = gctl_get_ascii(req, "arg%d", i);
272                 md.md_did = arc4random();
273                 md.md_priority = i - 1;
274                 md.md_provsize = g_get_mediasize(str);
275                 assert(md.md_provsize != 0);
276                 if (!hardcode)
277                         bzero(md.md_provider, sizeof(md.md_provider));
278                 else {
279                         if (strncmp(str, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
280                                 str += sizeof(_PATH_DEV) - 1;
281                         strlcpy(md.md_provider, str, sizeof(md.md_provider));
282                 }
283                 mirror_metadata_encode(&md, sector);
284                 error = g_metadata_store(str, sector, sizeof(sector));
285                 if (error != 0) {
286                         fprintf(stderr, "Can't store metadata on %s: %s.\n",
287                             str, strerror(error));
288                         gctl_error(req, "Not fully done.");
289                         continue;
290                 }
291                 if (verbose)
292                         printf("Metadata value stored on %s.\n", str);
293         }
294 }
295
296 static void
297 mirror_clear(struct gctl_req *req)
298 {
299         const char *name;
300         int error, i, nargs;
301
302         nargs = gctl_get_int(req, "nargs");
303         if (nargs < 1) {
304                 gctl_error(req, "Too few arguments.");
305                 return;
306         }
307
308         for (i = 0; i < nargs; i++) {
309                 name = gctl_get_ascii(req, "arg%d", i);
310                 error = g_metadata_clear(name, G_MIRROR_MAGIC);
311                 if (error != 0) {
312                         fprintf(stderr, "Can't clear metadata on %s: %s.\n",
313                             name, strerror(error));
314                         gctl_error(req, "Not fully done.");
315                         continue;
316                 }
317                 if (verbose)
318                         printf("Metadata cleared on %s.\n", name);
319         }
320 }
321
322 static void
323 mirror_dump(struct gctl_req *req)
324 {
325         struct g_mirror_metadata md, tmpmd;
326         const char *name;
327         int error, i, nargs;
328
329         nargs = gctl_get_int(req, "nargs");
330         if (nargs < 1) {
331                 gctl_error(req, "Too few arguments.");
332                 return;
333         }
334
335         for (i = 0; i < nargs; i++) {
336                 name = gctl_get_ascii(req, "arg%d", i);
337                 error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd),
338                     G_MIRROR_MAGIC);
339                 if (error != 0) {
340                         fprintf(stderr, "Can't read metadata from %s: %s.\n",
341                             name, strerror(error));
342                         gctl_error(req, "Not fully done.");
343                         continue;
344                 }
345                 if (mirror_metadata_decode((u_char *)&tmpmd, &md) != 0) {
346                         fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
347                             name);
348                         gctl_error(req, "Not fully done.");
349                         continue;
350                 }
351                 printf("Metadata on %s:\n", name);
352                 mirror_metadata_dump(&md);
353                 printf("\n");
354         }
355 }
356
357 static void
358 mirror_activate(struct gctl_req *req)
359 {
360         struct g_mirror_metadata md, tmpmd;
361         const char *name, *path;
362         int error, i, nargs;
363
364         nargs = gctl_get_int(req, "nargs");
365         if (nargs < 2) {
366                 gctl_error(req, "Too few arguments.");
367                 return;
368         }
369         name = gctl_get_ascii(req, "arg0");
370
371         for (i = 1; i < nargs; i++) {
372                 path = gctl_get_ascii(req, "arg%d", i);
373                 error = g_metadata_read(path, (u_char *)&tmpmd, sizeof(tmpmd),
374                     G_MIRROR_MAGIC);
375                 if (error != 0) {
376                         fprintf(stderr, "Cannot read metadata from %s: %s.\n",
377                             path, strerror(error));
378                         gctl_error(req, "Not fully done.");
379                         continue;
380                 }
381                 if (mirror_metadata_decode((u_char *)&tmpmd, &md) != 0) {
382                         fprintf(stderr,
383                             "MD5 hash mismatch for provider %s, skipping.\n",
384                             path);
385                         gctl_error(req, "Not fully done.");
386                         continue;
387                 }
388                 if (strcmp(md.md_name, name) != 0) {
389                         fprintf(stderr,
390                             "Provider %s is not the mirror %s component.\n",
391                             path, name);
392                         gctl_error(req, "Not fully done.");
393                         continue;
394                 }
395                 md.md_dflags &= ~G_MIRROR_DISK_FLAG_INACTIVE;
396                 mirror_metadata_encode(&md, (u_char *)&tmpmd);
397                 error = g_metadata_store(path, (u_char *)&tmpmd, sizeof(tmpmd));
398                 if (error != 0) {
399                         fprintf(stderr, "Cannot write metadata from %s: %s.\n",
400                             path, strerror(error));
401                         gctl_error(req, "Not fully done.");
402                         continue;
403                 }
404                 if (verbose)
405                         printf("Provider %s activated.\n", path);
406         }
407 }
408
409 static struct gclass *
410 find_class(struct gmesh *mesh, const char *name)
411 {
412         struct gclass *classp;
413
414         LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
415                 if (strcmp(classp->lg_name, name) == 0)
416                         return (classp);
417         }
418         return (NULL);
419 }
420
421 static struct ggeom *
422 find_geom(struct gclass *classp, const char *name)
423 {
424         struct ggeom *gp;
425
426         LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
427                 if (strcmp(gp->lg_name, name) == 0)
428                         return (gp);
429         }
430         return (NULL);
431 }
432
433 static void
434 mirror_resize(struct gctl_req *req, unsigned flags __unused)
435 {
436         struct gmesh mesh;
437         struct gclass *classp;
438         struct ggeom *gp;
439         struct gprovider *pp;
440         struct gconsumer *cp;
441         off_t size;
442         int error, nargs;
443         const char *name;
444         char ssize[30];
445
446         nargs = gctl_get_int(req, "nargs");
447         if (nargs < 1) {
448                 gctl_error(req, "Too few arguments.");
449                 return;
450         }
451         error = geom_gettree(&mesh);
452         if (error)
453                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
454         name = gctl_get_ascii(req, "class");
455         if (name == NULL)
456                 abort();
457         classp = find_class(&mesh, name);
458         if (classp == NULL)
459                 errx(EXIT_FAILURE, "Class %s not found.", name);
460         name = gctl_get_ascii(req, "arg0");
461         if (name == NULL)
462                 abort();
463         gp = find_geom(classp, name);
464         if (gp == NULL)
465                 errx(EXIT_FAILURE, "No such geom: %s.", name);
466         pp = LIST_FIRST(&gp->lg_provider);
467         if (pp == NULL)
468                 errx(EXIT_FAILURE, "Provider of geom %s not found.", name);
469         size = pp->lg_mediasize;
470         name = gctl_get_ascii(req, "size");
471         if (name == NULL)
472                 errx(EXIT_FAILURE, "The size is not specified.");
473         if (*name == '*') {
474 #define CSZ(c)  ((c)->lg_provider->lg_mediasize - \
475     (c)->lg_provider->lg_sectorsize)
476                 /* Find the maximum possible size */
477                 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
478                         if (CSZ(cp) > size)
479                                 size = CSZ(cp);
480                 }
481                 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
482                         if (CSZ(cp) < size)
483                                 size = CSZ(cp);
484                 }
485 #undef CSZ
486                 if (size == pp->lg_mediasize)
487                         errx(EXIT_FAILURE,
488                             "Cannot expand provider %s\n",
489                             pp->lg_name);
490         } else {
491                 error = g_parse_lba(name, pp->lg_sectorsize, &size);
492                 if (error)
493                         errc(EXIT_FAILURE, error, "Invalid size param");
494                 size *= pp->lg_sectorsize;
495         }
496         snprintf(ssize, sizeof(ssize), "%ju", (uintmax_t)size);
497         gctl_change_param(req, "size", -1, ssize);
498         geom_deletetree(&mesh);
499         gctl_issue(req);
500 }