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