geom_virstor.c revision 181471
1172302Spjd/*- 2172302Spjd * Copyright (c) 2005 Ivan Voras <ivoras@freebsd.org> 3172302Spjd * 4172302Spjd * Redistribution and use in source and binary forms, with or without 5172302Spjd * modification, are permitted provided that the following conditions 6172302Spjd * are met: 7172302Spjd * 1. Redistributions of source code must retain the above copyright 8172302Spjd * notice, this list of conditions and the following disclaimer. 9172302Spjd * 2. Redistributions in binary form must reproduce the above copyright 10172302Spjd * notice, this list of conditions and the following disclaimer in the 11172302Spjd * documentation and/or other materials provided with the distribution. 12172302Spjd * 13172302Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 14172302Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15172302Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16172302Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 17172302Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18172302Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19172302Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20172302Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21172302Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22172302Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23172302Spjd * SUCH DAMAGE. 24172302Spjd */ 25172302Spjd 26172302Spjd#include <sys/cdefs.h> 27172302Spjd__FBSDID("$FreeBSD: head/sbin/geom/class/virstor/geom_virstor.c 181471 2008-08-09 16:47:30Z ivoras $"); 28172302Spjd 29172302Spjd#include <sys/param.h> 30172302Spjd#include <errno.h> 31172302Spjd#include <paths.h> 32172302Spjd#include <stdio.h> 33172302Spjd#include <stdlib.h> 34172302Spjd#include <stdint.h> 35172302Spjd#include <string.h> 36172302Spjd#include <strings.h> 37172302Spjd#include <fcntl.h> 38172302Spjd#include <unistd.h> 39172302Spjd#include <libgeom.h> 40172302Spjd#include <err.h> 41172302Spjd#include <assert.h> 42172302Spjd 43172302Spjd#include <core/geom.h> 44172302Spjd#include <misc/subr.h> 45172302Spjd 46172302Spjd#include <geom/virstor/g_virstor_md.h> 47172302Spjd#include <geom/virstor/g_virstor.h> 48172302Spjd 49172302Spjduint32_t lib_version = G_LIB_VERSION; 50172302Spjduint32_t version = G_VIRSTOR_VERSION; 51172302Spjdstatic intmax_t chunk_size = 4 * 1024 * 1024; /* in kB (default: 4 MB) */ 52172302Spjdstatic intmax_t vir_size = 2ULL << 40; /* in MB (default: 2 TB) */ 53172302Spjd 54172302Spjd#if G_LIB_VERSION == 1 55172302Spjd/* Support RELENG_6 */ 56172302Spjd#define G_TYPE_BOOL G_TYPE_NONE 57172302Spjd#endif 58172302Spjd 59172302Spjd/* 60172302Spjd * virstor_main gets called by the geom(8) utility 61172302Spjd */ 62172302Spjdstatic void virstor_main(struct gctl_req *req, unsigned flags); 63172302Spjd 64172302Spjdstruct g_command class_commands[] = { 65172302Spjd {"clear", G_FLAG_VERBOSE, virstor_main, G_NULL_OPTS, NULL, 66172302Spjd "[-v] prov ..." 67172302Spjd }, 68172302Spjd {"dump", 0, virstor_main, G_NULL_OPTS, NULL, 69172302Spjd "prov ..." 70172302Spjd }, 71172302Spjd {"label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, virstor_main, 72172302Spjd { 73172302Spjd {'h', "hardcode", NULL, G_TYPE_BOOL}, 74172302Spjd {'m', "chunk_size", &chunk_size, G_TYPE_NUMBER}, 75172302Spjd {'s', "vir_size", &vir_size, G_TYPE_NUMBER}, 76172302Spjd G_OPT_SENTINEL 77172302Spjd }, 78172302Spjd NULL, "[-h] [-v] [-m chunk_size] [-s vir_size] name provider0 [provider1 ...]" 79172302Spjd }, 80172302Spjd {"destroy", G_FLAG_VERBOSE, NULL, 81172302Spjd { 82172302Spjd {'f', "force", NULL, G_TYPE_BOOL}, 83172302Spjd G_OPT_SENTINEL 84172302Spjd }, 85172302Spjd NULL, "[-fv] name ..." 86172302Spjd }, 87172302Spjd {"stop", G_FLAG_VERBOSE, NULL, 88172302Spjd { 89172302Spjd {'f', "force", NULL, G_TYPE_BOOL}, 90172302Spjd G_OPT_SENTINEL 91172302Spjd }, 92172302Spjd NULL, "[-fv] name ... (alias for \"destroy\")" 93172302Spjd }, 94172302Spjd {"add", G_FLAG_VERBOSE, NULL, 95172302Spjd { 96172302Spjd {'h', "hardcode", NULL, G_TYPE_BOOL}, 97172302Spjd G_OPT_SENTINEL 98172302Spjd }, 99172302Spjd NULL, "[-vh] name prov [prov ...]" 100172302Spjd }, 101172302Spjd {"remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, NULL, 102172302Spjd "[-v] name ..." 103172302Spjd }, 104172302Spjd G_CMD_SENTINEL 105172302Spjd}; 106172302Spjd 107172302Spjdstatic int verbose = 0; 108172302Spjd 109172302Spjd/* Helper functions' declarations */ 110172302Spjdstatic void virstor_clear(struct gctl_req *req); 111172302Spjdstatic void virstor_dump(struct gctl_req *req); 112172302Spjdstatic void virstor_label(struct gctl_req *req); 113172302Spjd 114172302Spjd/* Dispatcher function (no real work done here, only verbose flag recorder) */ 115172302Spjdstatic void 116172302Spjdvirstor_main(struct gctl_req *req, unsigned flags) 117172302Spjd{ 118172302Spjd const char *name; 119172302Spjd 120172302Spjd if ((flags & G_FLAG_VERBOSE) != 0) 121172302Spjd verbose = 1; 122172302Spjd 123172302Spjd name = gctl_get_ascii(req, "verb"); 124172302Spjd if (name == NULL) { 125172302Spjd gctl_error(req, "No '%s' argument.", "verb"); 126172302Spjd return; 127172302Spjd } 128172302Spjd if (strcmp(name, "label") == 0) 129172302Spjd virstor_label(req); 130172302Spjd else if (strcmp(name, "clear") == 0) 131172302Spjd virstor_clear(req); 132172302Spjd else if (strcmp(name, "dump") == 0) 133172302Spjd virstor_dump(req); 134172302Spjd else 135172302Spjd gctl_error(req, "%s: Unknown command: %s.", __func__, name); 136172302Spjd 137172302Spjd /* No CTASSERT in userland 138172302Spjd CTASSERT(VIRSTOR_MAP_BLOCK_ENTRIES*VIRSTOR_MAP_ENTRY_SIZE == MAXPHYS); 139172302Spjd */ 140172302Spjd} 141172302Spjd 142172302Spjdstatic void 143172302Spjdpathgen(const char *name, char *path, size_t size) 144172302Spjd{ 145172302Spjd 146172302Spjd if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0) 147172302Spjd snprintf(path, size, "%s%s", _PATH_DEV, name); 148172302Spjd else 149172302Spjd strlcpy(path, name, size); 150172302Spjd} 151172302Spjd 152172302Spjdstatic int 153172302Spjdmy_g_metadata_store(const char *name, u_char *md, size_t size) 154172302Spjd{ 155172302Spjd char path[MAXPATHLEN]; 156172302Spjd unsigned sectorsize; 157172302Spjd off_t mediasize; 158172302Spjd u_char *sector; 159172302Spjd int error, fd; 160172302Spjd 161172302Spjd pathgen(name, path, sizeof(path)); 162172302Spjd sector = NULL; 163172302Spjd error = 0; 164172302Spjd 165172302Spjd fd = open(path, O_RDWR); 166172302Spjd if (fd == -1) 167172302Spjd return (errno); 168172302Spjd mediasize = g_get_mediasize(name); 169172302Spjd if (mediasize == 0) { 170172302Spjd error = errno; 171172302Spjd goto out; 172172302Spjd } 173172302Spjd sectorsize = g_get_sectorsize(name); 174172302Spjd if (sectorsize == 0) { 175172302Spjd error = errno; 176172302Spjd goto out; 177172302Spjd } 178172302Spjd assert(sectorsize >= size); 179172302Spjd sector = malloc(sectorsize); 180172302Spjd if (sector == NULL) { 181172302Spjd error = ENOMEM; 182172302Spjd goto out; 183172302Spjd } 184172302Spjd bcopy(md, sector, size); 185181471Sivoras if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 186172302Spjd (ssize_t)sectorsize) { 187172302Spjd error = errno; 188172302Spjd goto out; 189172302Spjd } 190172302Spjdout: 191172302Spjd if (sector != NULL) 192172302Spjd free(sector); 193172302Spjd close(fd); 194172302Spjd return (error); 195172302Spjd} 196172302Spjd 197172302Spjd/* 198172302Spjd * Labels a new geom Meaning: parses and checks the parameters, calculates & 199172302Spjd * writes metadata to the relevant providers so when the next round of 200172302Spjd * "tasting" comes (which will be just after the provider(s) are closed) geom 201172302Spjd * can be instantiated with the tasted metadata. 202172302Spjd */ 203172302Spjdstatic void 204172302Spjdvirstor_label(struct gctl_req *req) 205172302Spjd{ 206172302Spjd struct g_virstor_metadata md; 207172302Spjd off_t msize; 208172302Spjd unsigned char *sect; 209172302Spjd unsigned int i; 210172302Spjd size_t ssize, secsize; 211172302Spjd const char *name; 212172302Spjd char param[32]; 213172302Spjd int hardcode, nargs, error; 214172302Spjd struct virstor_map_entry *map; 215172302Spjd size_t total_chunks; /* We'll run out of memory if 216172302Spjd this needs to be bigger. */ 217172302Spjd unsigned int map_chunks; /* Chunks needed by the map (map size). */ 218172302Spjd size_t map_size; /* In bytes. */ 219172302Spjd ssize_t written; 220172302Spjd int fd; 221172302Spjd 222172302Spjd nargs = gctl_get_int(req, "nargs"); 223172302Spjd if (nargs < 2) { 224172302Spjd gctl_error(req, "Too few arguments (%d): expecting: name " 225172302Spjd "provider0 [provider1 ...]", nargs); 226172302Spjd return; 227172302Spjd } 228172302Spjd 229172302Spjd hardcode = gctl_get_int(req, "hardcode"); 230172302Spjd 231172302Spjd /* 232172302Spjd * Initialize constant parts of metadata: magic signature, version, 233172302Spjd * name. 234172302Spjd */ 235172302Spjd bzero(&md, sizeof(md)); 236172302Spjd strlcpy(md.md_magic, G_VIRSTOR_MAGIC, sizeof(md.md_magic)); 237172302Spjd md.md_version = G_VIRSTOR_VERSION; 238172302Spjd name = gctl_get_ascii(req, "arg0"); 239172302Spjd if (name == NULL) { 240172302Spjd gctl_error(req, "No 'arg%u' argument.", 0); 241172302Spjd return; 242172302Spjd } 243172302Spjd strlcpy(md.md_name, name, sizeof(md.md_name)); 244172302Spjd 245172302Spjd md.md_virsize = (off_t)gctl_get_intmax(req, "vir_size"); 246172302Spjd md.md_chunk_size = gctl_get_intmax(req, "chunk_size"); 247172302Spjd md.md_count = nargs - 1; 248172302Spjd 249172302Spjd if (md.md_virsize == 0 || md.md_chunk_size == 0) { 250172302Spjd gctl_error(req, "Virtual size and chunk size must be non-zero"); 251172302Spjd return; 252172302Spjd } 253172302Spjd 254172302Spjd if (md.md_chunk_size % MAXPHYS != 0) { 255172302Spjd /* XXX: This is not strictly needed, but it's convenient to 256172302Spjd * impose some limitations on it, so why not MAXPHYS. */ 257172302Spjd size_t new_size = (md.md_chunk_size / MAXPHYS) * MAXPHYS; 258172302Spjd if (new_size < md.md_chunk_size) 259172302Spjd new_size += MAXPHYS; 260172302Spjd fprintf(stderr, "Resizing chunk size to be a multiple of " 261172302Spjd "MAXPHYS (%d kB).\n", MAXPHYS / 1024); 262172302Spjd fprintf(stderr, "New chunk size: %zu kB\n", new_size / 1024); 263172302Spjd md.md_chunk_size = new_size; 264172302Spjd } 265172302Spjd 266172302Spjd if (md.md_virsize % md.md_chunk_size != 0) { 267172302Spjd off_t chunk_count = md.md_virsize / md.md_chunk_size; 268172302Spjd md.md_virsize = chunk_count * md.md_chunk_size; 269172302Spjd fprintf(stderr, "Resizing virtual size to be a multiple of " 270172302Spjd "chunk size.\n"); 271172302Spjd fprintf(stderr, "New virtual size: %zu MB\n", 272172302Spjd (size_t)(md.md_virsize/(1024 * 1024))); 273172302Spjd } 274172302Spjd 275181471Sivoras msize = secsize = 0; 276172302Spjd for (i = 1; i < (unsigned)nargs; i++) { 277172302Spjd snprintf(param, sizeof(param), "arg%u", i); 278172302Spjd name = gctl_get_ascii(req, param); 279172302Spjd ssize = g_get_sectorsize(name); 280172302Spjd if (ssize == 0) 281172302Spjd fprintf(stderr, "%s for %s\n", strerror(errno), name); 282172302Spjd msize += g_get_mediasize(name); 283172302Spjd if (secsize == 0) 284172302Spjd secsize = ssize; 285172302Spjd else if (secsize != ssize) { 286172302Spjd gctl_error(req, "Devices need to have same sector size " 287172302Spjd "(%u on %s needs to be %u).", 288172302Spjd (u_int)ssize, name, (u_int)secsize); 289172302Spjd return; 290172302Spjd } 291172302Spjd } 292172302Spjd 293181471Sivoras if (secsize == 0) { 294181471Sivoras gctl_error(req, "Device not specified"); 295181471Sivoras return; 296181471Sivoras } 297181471Sivoras 298172302Spjd if (md.md_chunk_size % secsize != 0) { 299172302Spjd fprintf(stderr, "Error: chunk size is not a multiple of sector " 300172302Spjd "size."); 301172302Spjd gctl_error(req, "Chunk size (in bytes) must be multiple of %u.", 302172302Spjd (unsigned int)secsize); 303172302Spjd return; 304172302Spjd } 305172302Spjd 306172302Spjd total_chunks = md.md_virsize / md.md_chunk_size; 307172302Spjd map_size = total_chunks * sizeof(*map); 308172302Spjd assert(md.md_virsize % md.md_chunk_size == 0); 309172302Spjd 310172302Spjd ssize = map_size % secsize; 311172302Spjd if (ssize != 0) { 312172302Spjd size_t add_chunks = (secsize - ssize) / sizeof(*map); 313172302Spjd total_chunks += add_chunks; 314172302Spjd md.md_virsize = (off_t)total_chunks * (off_t)md.md_chunk_size; 315172302Spjd map_size = total_chunks * sizeof(*map); 316172302Spjd fprintf(stderr, "Resizing virtual size to fit virstor " 317172302Spjd "structures.\n"); 318172302Spjd fprintf(stderr, "New virtual size: %ju MB (%zu new chunks)\n", 319172302Spjd (uintmax_t)(md.md_virsize / (1024 * 1024)), add_chunks); 320172302Spjd } 321172302Spjd 322172302Spjd if (verbose) 323172302Spjd printf("Total virtual chunks: %zu (%zu MB each), %ju MB total " 324172302Spjd "virtual size.\n", 325172302Spjd total_chunks, (size_t)(md.md_chunk_size / (1024 * 1024)), 326172302Spjd md.md_virsize/(1024 * 1024)); 327172302Spjd 328172302Spjd if ((off_t)md.md_virsize < msize) 329172302Spjd fprintf(stderr, "WARNING: Virtual storage size < Physical " 330172302Spjd "available storage (%ju < %ju)\n", md.md_virsize, msize); 331172302Spjd 332172302Spjd /* Clear last sector first to spoil all components if device exists. */ 333172302Spjd if (verbose) 334172302Spjd printf("Clearing metadata on"); 335172302Spjd 336172302Spjd for (i = 1; i < (unsigned)nargs; i++) { 337172302Spjd snprintf(param, sizeof(param), "arg%u", i); 338172302Spjd name = gctl_get_ascii(req, param); 339172302Spjd 340172302Spjd if (verbose) 341172302Spjd printf(" %s", name); 342172302Spjd 343172302Spjd msize = g_get_mediasize(name); 344172302Spjd ssize = g_get_sectorsize(name); 345172302Spjd if (msize == 0 || ssize == 0) { 346172302Spjd gctl_error(req, "Can't retrieve information about " 347172302Spjd "%s: %s.", name, strerror(errno)); 348172302Spjd return; 349172302Spjd } 350173721Sjb if (msize < (off_t) MAX(md.md_chunk_size*4, map_size)) 351172302Spjd gctl_error(req, "Device %s is too small", name); 352172302Spjd error = g_metadata_clear(name, NULL); 353172302Spjd if (error != 0) { 354172302Spjd gctl_error(req, "Can't clear metadata on %s: %s.", name, 355172302Spjd strerror(error)); 356172302Spjd return; 357172302Spjd } 358172302Spjd } 359172302Spjd 360172302Spjd 361172302Spjd /* Write allocation table to the first provider - this needs to be done 362172302Spjd * before metadata is written because when kernel tastes it it's too 363172302Spjd * late */ 364172302Spjd name = gctl_get_ascii(req, "arg1"); /* device with metadata */ 365172302Spjd if (verbose) 366172302Spjd printf(".\nWriting allocation table to %s...", name); 367172302Spjd 368172302Spjd /* How many chunks does the map occupy? */ 369172302Spjd map_chunks = map_size/md.md_chunk_size; 370172302Spjd if (map_size % md.md_chunk_size != 0) 371172302Spjd map_chunks++; 372172302Spjd if (verbose) { 373172302Spjd printf(" (%zu MB, %d chunks) ", map_size/(1024*1024), map_chunks); 374172302Spjd fflush(stdout); 375172302Spjd } 376172302Spjd 377172302Spjd if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) 378172302Spjd fd = open(name, O_RDWR); 379172302Spjd else { 380172302Spjd sprintf(param, "%s%s", _PATH_DEV, name); 381172302Spjd fd = open(param, O_RDWR); 382172302Spjd } 383172302Spjd if (fd < 0) 384172302Spjd gctl_error(req, "Cannot open provider %s to write map", name); 385172302Spjd 386172302Spjd /* Do it with calloc because there might be a need to set up chunk flags 387172302Spjd * in the future */ 388172302Spjd map = calloc(total_chunks, sizeof(*map)); 389172302Spjd if (map == NULL) { 390172302Spjd gctl_error(req, 391172302Spjd "Out of memory (need %zu bytes for allocation map)", 392172302Spjd map_size); 393172302Spjd } 394172302Spjd 395172302Spjd written = pwrite(fd, map, map_size, 0); 396172302Spjd free(map); 397172302Spjd if ((size_t)written != map_size) { 398172302Spjd if (verbose) { 399172302Spjd fprintf(stderr, "\nTried to write %zu, written %zd (%s)\n", 400172302Spjd map_size, written, strerror(errno)); 401172302Spjd } 402172302Spjd gctl_error(req, "Error writing out allocation map!"); 403172302Spjd return; 404172302Spjd } 405172302Spjd close (fd); 406172302Spjd 407172302Spjd if (verbose) 408172302Spjd printf("\nStoring metadata on "); 409172302Spjd 410172302Spjd /* 411172302Spjd * ID is randomly generated, unique for a geom. This is used to 412172302Spjd * recognize all providers belonging to one geom. 413172302Spjd */ 414172302Spjd md.md_id = arc4random(); 415172302Spjd 416172302Spjd /* Ok, store metadata. */ 417172302Spjd for (i = 1; i < (unsigned)nargs; i++) { 418172302Spjd snprintf(param, sizeof(param), "arg%u", i); 419172302Spjd name = gctl_get_ascii(req, param); 420172302Spjd 421172302Spjd msize = g_get_mediasize(name); 422172302Spjd ssize = g_get_sectorsize(name); 423172302Spjd 424172302Spjd if (verbose) 425172302Spjd printf("%s ", name); 426172302Spjd 427172302Spjd /* this provider's position/type in geom */ 428172302Spjd md.no = i - 1; 429172302Spjd /* this provider's size */ 430172302Spjd md.provsize = msize; 431172302Spjd /* chunk allocation info */ 432172302Spjd md.chunk_count = md.provsize / md.md_chunk_size; 433172302Spjd if (verbose) 434172302Spjd printf("(%u chunks) ", md.chunk_count); 435172302Spjd /* Check to make sure last sector is unused */ 436173721Sjb if ((off_t)(md.chunk_count * md.md_chunk_size) > msize-ssize) 437172302Spjd md.chunk_count--; 438172302Spjd md.chunk_next = 0; 439172302Spjd if (i != 1) { 440172302Spjd md.chunk_reserved = 0; 441172302Spjd md.flags = 0; 442172302Spjd } else { 443172302Spjd md.chunk_reserved = map_chunks * 2; 444172302Spjd md.flags = VIRSTOR_PROVIDER_ALLOCATED | 445172302Spjd VIRSTOR_PROVIDER_CURRENT; 446172302Spjd md.chunk_next = md.chunk_reserved; 447172302Spjd if (verbose) 448172302Spjd printf("(%u reserved) ", md.chunk_reserved); 449172302Spjd } 450172302Spjd 451172302Spjd if (!hardcode) 452172302Spjd bzero(md.provider, sizeof(md.provider)); 453172302Spjd else { 454172302Spjd /* convert "/dev/something" to "something" */ 455172302Spjd if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) { 456172302Spjd strlcpy(md.provider, name + strlen(_PATH_DEV), 457172302Spjd sizeof(md.provider)); 458172302Spjd } else 459172302Spjd strlcpy(md.provider, name, sizeof(md.provider)); 460172302Spjd } 461172302Spjd sect = malloc(ssize); 462172302Spjd bzero(sect, ssize); 463172302Spjd if (sect == NULL) 464172302Spjd err(1, "Cannot allocate sector of %zu bytes", ssize); 465172302Spjd virstor_metadata_encode(&md, sect); 466172302Spjd error = my_g_metadata_store(name, sect, ssize); 467172302Spjd free(sect); 468172302Spjd if (error != 0) { 469172302Spjd if (verbose) 470172302Spjd printf("\n"); 471172302Spjd fprintf(stderr, "Can't store metadata on %s: %s.\n", 472172302Spjd name, strerror(error)); 473172302Spjd gctl_error(req, 474172302Spjd "Not fully done (error storing metadata)."); 475172302Spjd return; 476172302Spjd } 477172302Spjd } 478172302Spjd#if 0 479172302Spjd if (verbose) 480172302Spjd printf("\n"); 481172302Spjd#endif 482172302Spjd} 483172302Spjd 484172302Spjd/* Clears metadata on given provider(s) IF it's owned by us */ 485172302Spjdstatic void 486172302Spjdvirstor_clear(struct gctl_req *req) 487172302Spjd{ 488172302Spjd const char *name; 489172302Spjd char param[32]; 490172302Spjd unsigned i; 491172302Spjd int nargs, error; 492172302Spjd int fd; 493172302Spjd 494172302Spjd nargs = gctl_get_int(req, "nargs"); 495172302Spjd if (nargs < 1) { 496172302Spjd gctl_error(req, "Too few arguments."); 497172302Spjd return; 498172302Spjd } 499172302Spjd for (i = 0; i < (unsigned)nargs; i++) { 500172302Spjd snprintf(param, sizeof(param), "arg%u", i); 501172302Spjd name = gctl_get_ascii(req, param); 502172302Spjd 503172302Spjd error = g_metadata_clear(name, G_VIRSTOR_MAGIC); 504172302Spjd if (error != 0) { 505172302Spjd fprintf(stderr, "Can't clear metadata on %s: %s " 506172302Spjd "(do I own it?)\n", name, strerror(error)); 507172302Spjd gctl_error(req, 508172302Spjd "Not fully done (can't clear metadata)."); 509172302Spjd continue; 510172302Spjd } 511172302Spjd if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) 512172302Spjd fd = open(name, O_RDWR); 513172302Spjd else { 514172302Spjd sprintf(param, "%s%s", _PATH_DEV, name); 515172302Spjd fd = open(param, O_RDWR); 516172302Spjd } 517172302Spjd if (fd < 0) { 518172302Spjd gctl_error(req, "Cannot clear header sector for %s", 519172302Spjd name); 520172302Spjd continue; 521172302Spjd } 522172302Spjd if (verbose) 523172302Spjd printf("Metadata cleared on %s.\n", name); 524172302Spjd } 525172302Spjd} 526172302Spjd 527172302Spjd/* Print some metadata information */ 528172302Spjdstatic void 529172302Spjdvirstor_metadata_dump(const struct g_virstor_metadata *md) 530172302Spjd{ 531172302Spjd printf(" Magic string: %s\n", md->md_magic); 532172302Spjd printf(" Metadata version: %u\n", (u_int) md->md_version); 533172302Spjd printf(" Device name: %s\n", md->md_name); 534172302Spjd printf(" Device ID: %u\n", (u_int) md->md_id); 535172302Spjd printf(" Provider index: %u\n", (u_int) md->no); 536172302Spjd printf(" Active providers: %u\n", (u_int) md->md_count); 537172302Spjd printf(" Hardcoded provider: %s\n", 538172302Spjd md->provider[0] != '\0' ? md->provider : "(not hardcoded)"); 539172302Spjd printf(" Virtual size: %u MB\n", 540172302Spjd (unsigned int)(md->md_virsize/(1024 * 1024))); 541172302Spjd printf(" Chunk size: %u kB\n", md->md_chunk_size / 1024); 542172302Spjd printf(" Chunks on provider: %u\n", md->chunk_count); 543172302Spjd printf(" Chunks free: %u\n", md->chunk_count - md->chunk_next); 544172302Spjd printf(" Reserved chunks: %u\n", md->chunk_reserved); 545172302Spjd} 546172302Spjd 547172302Spjd/* Called by geom(8) via gvirstor_main() to dump metadata information */ 548172302Spjdstatic void 549172302Spjdvirstor_dump(struct gctl_req *req) 550172302Spjd{ 551172302Spjd struct g_virstor_metadata md; 552172302Spjd u_char tmpmd[512]; /* temporary buffer */ 553172302Spjd const char *name; 554172302Spjd char param[16]; 555172302Spjd int nargs, error, i; 556172302Spjd 557172302Spjd assert(sizeof(tmpmd) >= sizeof(md)); 558172302Spjd 559172302Spjd nargs = gctl_get_int(req, "nargs"); 560172302Spjd if (nargs < 1) { 561172302Spjd gctl_error(req, "Too few arguments."); 562172302Spjd return; 563172302Spjd } 564172302Spjd for (i = 0; i < nargs; i++) { 565172302Spjd snprintf(param, sizeof(param), "arg%u", i); 566172302Spjd name = gctl_get_ascii(req, param); 567172302Spjd 568172302Spjd error = g_metadata_read(name, (u_char *) & tmpmd, sizeof(tmpmd), 569172302Spjd G_VIRSTOR_MAGIC); 570172302Spjd if (error != 0) { 571172302Spjd fprintf(stderr, "Can't read metadata from %s: %s.\n", 572172302Spjd name, strerror(error)); 573172302Spjd gctl_error(req, 574172302Spjd "Not fully done (error reading metadata)."); 575172302Spjd continue; 576172302Spjd } 577172302Spjd virstor_metadata_decode((u_char *) & tmpmd, &md); 578172302Spjd printf("Metadata on %s:\n", name); 579172302Spjd virstor_metadata_dump(&md); 580172302Spjd printf("\n"); 581172302Spjd } 582172302Spjd} 583