2 * Copyright (c) 2005 Ivan Voras <ivoras@freebsd.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
29 #include <sys/param.h>
43 #include <core/geom.h>
44 #include <misc/subr.h>
46 #include <geom/virstor/g_virstor_md.h>
47 #include <geom/virstor/g_virstor.h>
49 uint32_t lib_version = G_LIB_VERSION;
50 uint32_t version = G_VIRSTOR_VERSION;
51 static intmax_t chunk_size = 4 * 1024 * 1024; /* in kB (default: 4 MB) */
52 static intmax_t vir_size = 2ULL << 40; /* in MB (default: 2 TB) */
54 #if G_LIB_VERSION == 1
55 /* Support RELENG_6 */
56 #define G_TYPE_BOOL G_TYPE_NONE
60 * virstor_main gets called by the geom(8) utility
62 static void virstor_main(struct gctl_req *req, unsigned flags);
64 struct g_command class_commands[] = {
65 {"clear", G_FLAG_VERBOSE, virstor_main, G_NULL_OPTS, NULL,
68 {"dump", 0, virstor_main, G_NULL_OPTS, NULL,
71 {"label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, virstor_main,
73 {'h', "hardcode", NULL, G_TYPE_BOOL},
74 {'m', "chunk_size", &chunk_size, G_TYPE_NUMBER},
75 {'s', "vir_size", &vir_size, G_TYPE_NUMBER},
78 NULL, "[-h] [-v] [-m chunk_size] [-s vir_size] name provider0 [provider1 ...]"
80 {"destroy", G_FLAG_VERBOSE, NULL,
82 {'f', "force", NULL, G_TYPE_BOOL},
85 NULL, "[-fv] name ..."
87 {"stop", G_FLAG_VERBOSE, NULL,
89 {'f', "force", NULL, G_TYPE_BOOL},
92 NULL, "[-fv] name ... (alias for \"destroy\")"
94 {"add", G_FLAG_VERBOSE, NULL,
96 {'h', "hardcode", NULL, G_TYPE_BOOL},
99 NULL, "[-vh] name prov [prov ...]"
101 {"remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, NULL,
107 static int verbose = 0;
109 /* Helper functions' declarations */
110 static void virstor_clear(struct gctl_req *req);
111 static void virstor_dump(struct gctl_req *req);
112 static void virstor_label(struct gctl_req *req);
114 /* Dispatcher function (no real work done here, only verbose flag recorder) */
116 virstor_main(struct gctl_req *req, unsigned flags)
120 if ((flags & G_FLAG_VERBOSE) != 0)
123 name = gctl_get_ascii(req, "verb");
125 gctl_error(req, "No '%s' argument.", "verb");
128 if (strcmp(name, "label") == 0)
130 else if (strcmp(name, "clear") == 0)
132 else if (strcmp(name, "dump") == 0)
135 gctl_error(req, "%s: Unknown command: %s.", __func__, name);
137 /* No CTASSERT in userland
138 CTASSERT(VIRSTOR_MAP_BLOCK_ENTRIES*VIRSTOR_MAP_ENTRY_SIZE == MAXPHYS);
143 pathgen(const char *name, char *path, size_t size)
146 if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0)
147 snprintf(path, size, "%s%s", _PATH_DEV, name);
149 strlcpy(path, name, size);
153 my_g_metadata_store(const char *name, u_char *md, size_t size)
155 char path[MAXPATHLEN];
161 pathgen(name, path, sizeof(path));
165 fd = open(path, O_RDWR);
168 mediasize = g_get_mediasize(name);
169 if (mediasize == 0) {
173 sectorsize = g_get_sectorsize(name);
174 if (sectorsize == 0) {
178 assert(sectorsize >= size);
179 sector = malloc(sectorsize);
180 if (sector == NULL) {
184 bcopy(md, sector, size);
185 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
186 (ssize_t)sectorsize) {
198 * Labels a new geom Meaning: parses and checks the parameters, calculates &
199 * writes metadata to the relevant providers so when the next round of
200 * "tasting" comes (which will be just after the provider(s) are closed) geom
201 * can be instantiated with the tasted metadata.
204 virstor_label(struct gctl_req *req)
206 struct g_virstor_metadata md;
210 size_t ssize, secsize;
213 int hardcode, nargs, error;
214 struct virstor_map_entry *map;
215 size_t total_chunks; /* We'll run out of memory if
216 this needs to be bigger. */
217 unsigned int map_chunks; /* Chunks needed by the map (map size). */
218 size_t map_size; /* In bytes. */
222 nargs = gctl_get_int(req, "nargs");
224 gctl_error(req, "Too few arguments (%d): expecting: name "
225 "provider0 [provider1 ...]", nargs);
229 hardcode = gctl_get_int(req, "hardcode");
232 * Initialize constant parts of metadata: magic signature, version,
235 bzero(&md, sizeof(md));
236 strlcpy(md.md_magic, G_VIRSTOR_MAGIC, sizeof(md.md_magic));
237 md.md_version = G_VIRSTOR_VERSION;
238 name = gctl_get_ascii(req, "arg0");
240 gctl_error(req, "No 'arg%u' argument.", 0);
243 strlcpy(md.md_name, name, sizeof(md.md_name));
245 md.md_virsize = (off_t)gctl_get_intmax(req, "vir_size");
246 md.md_chunk_size = gctl_get_intmax(req, "chunk_size");
247 md.md_count = nargs - 1;
249 if (md.md_virsize == 0 || md.md_chunk_size == 0) {
250 gctl_error(req, "Virtual size and chunk size must be non-zero");
254 if (md.md_chunk_size % MAXPHYS != 0) {
255 /* XXX: This is not strictly needed, but it's convenient to
256 * impose some limitations on it, so why not MAXPHYS. */
257 size_t new_size = (md.md_chunk_size / MAXPHYS) * MAXPHYS;
258 if (new_size < md.md_chunk_size)
260 fprintf(stderr, "Resizing chunk size to be a multiple of "
261 "MAXPHYS (%d kB).\n", MAXPHYS / 1024);
262 fprintf(stderr, "New chunk size: %zu kB\n", new_size / 1024);
263 md.md_chunk_size = new_size;
266 if (md.md_virsize % md.md_chunk_size != 0) {
267 off_t chunk_count = md.md_virsize / md.md_chunk_size;
268 md.md_virsize = chunk_count * md.md_chunk_size;
269 fprintf(stderr, "Resizing virtual size to be a multiple of "
271 fprintf(stderr, "New virtual size: %zu MB\n",
272 (size_t)(md.md_virsize/(1024 * 1024)));
276 for (i = 1; i < (unsigned)nargs; i++) {
277 snprintf(param, sizeof(param), "arg%u", i);
278 name = gctl_get_ascii(req, param);
279 ssize = g_get_sectorsize(name);
281 fprintf(stderr, "%s for %s\n", strerror(errno), name);
282 msize += g_get_mediasize(name);
285 else if (secsize != ssize) {
286 gctl_error(req, "Devices need to have same sector size "
287 "(%u on %s needs to be %u).",
288 (u_int)ssize, name, (u_int)secsize);
294 gctl_error(req, "Device not specified");
298 if (md.md_chunk_size % secsize != 0) {
299 fprintf(stderr, "Error: chunk size is not a multiple of sector "
301 gctl_error(req, "Chunk size (in bytes) must be multiple of %u.",
302 (unsigned int)secsize);
306 total_chunks = md.md_virsize / md.md_chunk_size;
307 map_size = total_chunks * sizeof(*map);
308 assert(md.md_virsize % md.md_chunk_size == 0);
310 ssize = map_size % secsize;
312 size_t add_chunks = (secsize - ssize) / sizeof(*map);
313 total_chunks += add_chunks;
314 md.md_virsize = (off_t)total_chunks * (off_t)md.md_chunk_size;
315 map_size = total_chunks * sizeof(*map);
316 fprintf(stderr, "Resizing virtual size to fit virstor "
318 fprintf(stderr, "New virtual size: %ju MB (%zu new chunks)\n",
319 (uintmax_t)(md.md_virsize / (1024 * 1024)), add_chunks);
323 printf("Total virtual chunks: %zu (%zu MB each), %ju MB total "
325 total_chunks, (size_t)(md.md_chunk_size / (1024 * 1024)),
326 md.md_virsize/(1024 * 1024));
328 if ((off_t)md.md_virsize < msize)
329 fprintf(stderr, "WARNING: Virtual storage size < Physical "
330 "available storage (%ju < %ju)\n", md.md_virsize, msize);
332 /* Clear last sector first to spoil all components if device exists. */
334 printf("Clearing metadata on");
336 for (i = 1; i < (unsigned)nargs; i++) {
337 snprintf(param, sizeof(param), "arg%u", i);
338 name = gctl_get_ascii(req, param);
343 msize = g_get_mediasize(name);
344 ssize = g_get_sectorsize(name);
345 if (msize == 0 || ssize == 0) {
346 gctl_error(req, "Can't retrieve information about "
347 "%s: %s.", name, strerror(errno));
350 if (msize < (off_t) MAX(md.md_chunk_size*4, map_size))
351 gctl_error(req, "Device %s is too small", name);
352 error = g_metadata_clear(name, NULL);
354 gctl_error(req, "Can't clear metadata on %s: %s.", name,
361 /* Write allocation table to the first provider - this needs to be done
362 * before metadata is written because when kernel tastes it it's too
364 name = gctl_get_ascii(req, "arg1"); /* device with metadata */
366 printf(".\nWriting allocation table to %s...", name);
368 /* How many chunks does the map occupy? */
369 map_chunks = map_size/md.md_chunk_size;
370 if (map_size % md.md_chunk_size != 0)
373 printf(" (%zu MB, %d chunks) ", map_size/(1024*1024), map_chunks);
377 if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0)
378 fd = open(name, O_RDWR);
380 sprintf(param, "%s%s", _PATH_DEV, name);
381 fd = open(param, O_RDWR);
384 gctl_error(req, "Cannot open provider %s to write map", name);
386 /* Do it with calloc because there might be a need to set up chunk flags
388 map = calloc(total_chunks, sizeof(*map));
391 "Out of memory (need %zu bytes for allocation map)",
395 written = pwrite(fd, map, map_size, 0);
397 if ((size_t)written != map_size) {
399 fprintf(stderr, "\nTried to write %zu, written %zd (%s)\n",
400 map_size, written, strerror(errno));
402 gctl_error(req, "Error writing out allocation map!");
408 printf("\nStoring metadata on ");
411 * ID is randomly generated, unique for a geom. This is used to
412 * recognize all providers belonging to one geom.
414 md.md_id = arc4random();
416 /* Ok, store metadata. */
417 for (i = 1; i < (unsigned)nargs; i++) {
418 snprintf(param, sizeof(param), "arg%u", i);
419 name = gctl_get_ascii(req, param);
421 msize = g_get_mediasize(name);
422 ssize = g_get_sectorsize(name);
427 /* this provider's position/type in geom */
429 /* this provider's size */
431 /* chunk allocation info */
432 md.chunk_count = md.provsize / md.md_chunk_size;
434 printf("(%u chunks) ", md.chunk_count);
435 /* Check to make sure last sector is unused */
436 if ((off_t)(md.chunk_count * md.md_chunk_size) > msize-ssize)
440 md.chunk_reserved = 0;
443 md.chunk_reserved = map_chunks * 2;
444 md.flags = VIRSTOR_PROVIDER_ALLOCATED |
445 VIRSTOR_PROVIDER_CURRENT;
446 md.chunk_next = md.chunk_reserved;
448 printf("(%u reserved) ", md.chunk_reserved);
452 bzero(md.provider, sizeof(md.provider));
454 /* convert "/dev/something" to "something" */
455 if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) {
456 strlcpy(md.provider, name + strlen(_PATH_DEV),
457 sizeof(md.provider));
459 strlcpy(md.provider, name, sizeof(md.provider));
461 sect = malloc(ssize);
464 err(1, "Cannot allocate sector of %zu bytes", ssize);
465 virstor_metadata_encode(&md, sect);
466 error = my_g_metadata_store(name, sect, ssize);
471 fprintf(stderr, "Can't store metadata on %s: %s.\n",
472 name, strerror(error));
474 "Not fully done (error storing metadata).");
484 /* Clears metadata on given provider(s) IF it's owned by us */
486 virstor_clear(struct gctl_req *req)
494 nargs = gctl_get_int(req, "nargs");
496 gctl_error(req, "Too few arguments.");
499 for (i = 0; i < (unsigned)nargs; i++) {
500 snprintf(param, sizeof(param), "arg%u", i);
501 name = gctl_get_ascii(req, param);
503 error = g_metadata_clear(name, G_VIRSTOR_MAGIC);
505 fprintf(stderr, "Can't clear metadata on %s: %s "
506 "(do I own it?)\n", name, strerror(error));
508 "Not fully done (can't clear metadata).");
511 if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0)
512 fd = open(name, O_RDWR);
514 sprintf(param, "%s%s", _PATH_DEV, name);
515 fd = open(param, O_RDWR);
518 gctl_error(req, "Cannot clear header sector for %s",
523 printf("Metadata cleared on %s.\n", name);
527 /* Print some metadata information */
529 virstor_metadata_dump(const struct g_virstor_metadata *md)
531 printf(" Magic string: %s\n", md->md_magic);
532 printf(" Metadata version: %u\n", (u_int) md->md_version);
533 printf(" Device name: %s\n", md->md_name);
534 printf(" Device ID: %u\n", (u_int) md->md_id);
535 printf(" Provider index: %u\n", (u_int) md->no);
536 printf(" Active providers: %u\n", (u_int) md->md_count);
537 printf(" Hardcoded provider: %s\n",
538 md->provider[0] != '\0' ? md->provider : "(not hardcoded)");
539 printf(" Virtual size: %u MB\n",
540 (unsigned int)(md->md_virsize/(1024 * 1024)));
541 printf(" Chunk size: %u kB\n", md->md_chunk_size / 1024);
542 printf(" Chunks on provider: %u\n", md->chunk_count);
543 printf(" Chunks free: %u\n", md->chunk_count - md->chunk_next);
544 printf(" Reserved chunks: %u\n", md->chunk_reserved);
547 /* Called by geom(8) via gvirstor_main() to dump metadata information */
549 virstor_dump(struct gctl_req *req)
551 struct g_virstor_metadata md;
552 u_char tmpmd[512]; /* temporary buffer */
557 assert(sizeof(tmpmd) >= sizeof(md));
559 nargs = gctl_get_int(req, "nargs");
561 gctl_error(req, "Too few arguments.");
564 for (i = 0; i < nargs; i++) {
565 snprintf(param, sizeof(param), "arg%u", i);
566 name = gctl_get_ascii(req, param);
568 error = g_metadata_read(name, (u_char *) & tmpmd, sizeof(tmpmd),
571 fprintf(stderr, "Can't read metadata from %s: %s.\n",
572 name, strerror(error));
574 "Not fully done (error reading metadata).");
577 virstor_metadata_decode((u_char *) & tmpmd, &md);
578 printf("Metadata on %s:\n", name);
579 virstor_metadata_dump(&md);