geom_virstor.c revision 213662
1250661Sdavidcs/*- 2250661Sdavidcs * Copyright (c) 2005 Ivan Voras <ivoras@freebsd.org> 3250661Sdavidcs * 4250661Sdavidcs * Redistribution and use in source and binary forms, with or without 5250661Sdavidcs * modification, are permitted provided that the following conditions 6250661Sdavidcs * are met: 7250661Sdavidcs * 1. Redistributions of source code must retain the above copyright 8250661Sdavidcs * notice, this list of conditions and the following disclaimer. 9250661Sdavidcs * 2. Redistributions in binary form must reproduce the above copyright 10250661Sdavidcs * notice, this list of conditions and the following disclaimer in the 11250661Sdavidcs * documentation and/or other materials provided with the distribution. 12250661Sdavidcs * 13250661Sdavidcs * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 14250661Sdavidcs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15250661Sdavidcs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16250661Sdavidcs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 17250661Sdavidcs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18250661Sdavidcs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19250661Sdavidcs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20250661Sdavidcs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21250661Sdavidcs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22250661Sdavidcs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23250661Sdavidcs * SUCH DAMAGE. 24250661Sdavidcs */ 25250661Sdavidcs 26250661Sdavidcs#include <sys/cdefs.h> 27250661Sdavidcs__FBSDID("$FreeBSD: head/sbin/geom/class/virstor/geom_virstor.c 213662 2010-10-09 20:20:27Z ae $"); 28250661Sdavidcs 29250661Sdavidcs#include <sys/param.h> 30250661Sdavidcs#include <errno.h> 31250661Sdavidcs#include <paths.h> 32250661Sdavidcs#include <stdio.h> 33250661Sdavidcs#include <stdlib.h> 34250661Sdavidcs#include <stdint.h> 35250661Sdavidcs#include <string.h> 36250661Sdavidcs#include <strings.h> 37250661Sdavidcs#include <fcntl.h> 38250661Sdavidcs#include <unistd.h> 39250661Sdavidcs#include <libgeom.h> 40250661Sdavidcs#include <err.h> 41250661Sdavidcs#include <assert.h> 42250661Sdavidcs 43250661Sdavidcs#include <core/geom.h> 44250661Sdavidcs#include <misc/subr.h> 45250661Sdavidcs 46250661Sdavidcs#include <geom/virstor/g_virstor_md.h> 47250661Sdavidcs#include <geom/virstor/g_virstor.h> 48250661Sdavidcs 49250661Sdavidcsuint32_t lib_version = G_LIB_VERSION; 50250661Sdavidcsuint32_t version = G_VIRSTOR_VERSION; 51250661Sdavidcs 52250661Sdavidcs#define GVIRSTOR_CHUNK_SIZE "4M" 53250661Sdavidcs#define GVIRSTOR_VIR_SIZE "2T" 54250661Sdavidcs 55250661Sdavidcs#if G_LIB_VERSION == 1 56250661Sdavidcs/* Support RELENG_6 */ 57250661Sdavidcs#define G_TYPE_BOOL G_TYPE_NONE 58250661Sdavidcs#endif 59250661Sdavidcs 60250661Sdavidcs/* 61250661Sdavidcs * virstor_main gets called by the geom(8) utility 62250661Sdavidcs */ 63250661Sdavidcsstatic void virstor_main(struct gctl_req *req, unsigned flags); 64250661Sdavidcs 65250661Sdavidcsstruct g_command class_commands[] = { 66250661Sdavidcs { "clear", G_FLAG_VERBOSE, virstor_main, G_NULL_OPTS, 67250661Sdavidcs "[-v] prov ..." 68250661Sdavidcs }, 69250661Sdavidcs { "dump", 0, virstor_main, G_NULL_OPTS, 70250661Sdavidcs "prov ..." 71250661Sdavidcs }, 72250661Sdavidcs { "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, virstor_main, 73250661Sdavidcs { 74250661Sdavidcs { 'h', "hardcode", NULL, G_TYPE_BOOL}, 75250661Sdavidcs { 'm', "chunk_size", GVIRSTOR_CHUNK_SIZE, G_TYPE_NUMBER}, 76250661Sdavidcs { 's', "vir_size", GVIRSTOR_VIR_SIZE, G_TYPE_NUMBER}, 77250661Sdavidcs G_OPT_SENTINEL 78250661Sdavidcs }, 79250661Sdavidcs "[-h] [-v] [-m chunk_size] [-s vir_size] name provider0 [provider1 ...]" 80250661Sdavidcs }, 81250661Sdavidcs { "destroy", G_FLAG_VERBOSE, NULL, 82250661Sdavidcs { 83250661Sdavidcs { 'f', "force", NULL, G_TYPE_BOOL}, 84250661Sdavidcs G_OPT_SENTINEL 85250661Sdavidcs }, 86250661Sdavidcs "[-fv] name ..." 87250661Sdavidcs }, 88250661Sdavidcs { "stop", G_FLAG_VERBOSE, NULL, 89250661Sdavidcs { 90250661Sdavidcs { 'f', "force", NULL, G_TYPE_BOOL}, 91250661Sdavidcs G_OPT_SENTINEL 92250661Sdavidcs }, 93250661Sdavidcs "[-fv] name ... (alias for \"destroy\")" 94250661Sdavidcs }, 95250661Sdavidcs { "add", G_FLAG_VERBOSE, NULL, 96250661Sdavidcs { 97250661Sdavidcs { 'h', "hardcode", NULL, G_TYPE_BOOL}, 98250661Sdavidcs G_OPT_SENTINEL 99250661Sdavidcs }, 100250661Sdavidcs "[-vh] name prov [prov ...]" 101250661Sdavidcs }, 102250661Sdavidcs { "remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, 103250661Sdavidcs "[-v] name ..." 104250661Sdavidcs }, 105250661Sdavidcs G_CMD_SENTINEL 106250661Sdavidcs}; 107250661Sdavidcs 108250661Sdavidcsstatic int verbose = 0; 109250661Sdavidcs 110250661Sdavidcs/* Helper functions' declarations */ 111250661Sdavidcsstatic void virstor_clear(struct gctl_req *req); 112250661Sdavidcsstatic void virstor_dump(struct gctl_req *req); 113250661Sdavidcsstatic void virstor_label(struct gctl_req *req); 114250661Sdavidcs 115250661Sdavidcs/* Dispatcher function (no real work done here, only verbose flag recorder) */ 116250661Sdavidcsstatic void 117250661Sdavidcsvirstor_main(struct gctl_req *req, unsigned flags) 118250661Sdavidcs{ 119250661Sdavidcs const char *name; 120250661Sdavidcs 121250661Sdavidcs if ((flags & G_FLAG_VERBOSE) != 0) 122250661Sdavidcs verbose = 1; 123250661Sdavidcs 124250661Sdavidcs name = gctl_get_ascii(req, "verb"); 125250661Sdavidcs if (name == NULL) { 126250661Sdavidcs gctl_error(req, "No '%s' argument.", "verb"); 127250661Sdavidcs return; 128250661Sdavidcs } 129250661Sdavidcs if (strcmp(name, "label") == 0) 130250661Sdavidcs virstor_label(req); 131250661Sdavidcs else if (strcmp(name, "clear") == 0) 132250661Sdavidcs virstor_clear(req); 133250661Sdavidcs else if (strcmp(name, "dump") == 0) 134250661Sdavidcs virstor_dump(req); 135250661Sdavidcs else 136250661Sdavidcs gctl_error(req, "%s: Unknown command: %s.", __func__, name); 137250661Sdavidcs 138250661Sdavidcs /* No CTASSERT in userland 139250661Sdavidcs CTASSERT(VIRSTOR_MAP_BLOCK_ENTRIES*VIRSTOR_MAP_ENTRY_SIZE == MAXPHYS); 140250661Sdavidcs */ 141250661Sdavidcs} 142250661Sdavidcs 143250661Sdavidcsstatic void 144250661Sdavidcspathgen(const char *name, char *path, size_t size) 145250661Sdavidcs{ 146250661Sdavidcs 147250661Sdavidcs if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) != 0) 148250661Sdavidcs snprintf(path, size, "%s%s", _PATH_DEV, name); 149250661Sdavidcs else 150250661Sdavidcs strlcpy(path, name, size); 151250661Sdavidcs} 152250661Sdavidcs 153250661Sdavidcsstatic int 154250661Sdavidcsmy_g_metadata_store(const char *name, u_char *md, size_t size) 155250661Sdavidcs{ 156250661Sdavidcs char path[MAXPATHLEN]; 157250661Sdavidcs unsigned sectorsize; 158250661Sdavidcs off_t mediasize; 159250661Sdavidcs u_char *sector; 160250661Sdavidcs int error, fd; 161250661Sdavidcs 162250661Sdavidcs pathgen(name, path, sizeof(path)); 163250661Sdavidcs sector = NULL; 164250661Sdavidcs error = 0; 165250661Sdavidcs 166250661Sdavidcs fd = open(path, O_RDWR); 167250661Sdavidcs if (fd == -1) 168250661Sdavidcs return (errno); 169250661Sdavidcs mediasize = g_get_mediasize(name); 170250661Sdavidcs if (mediasize == 0) { 171250661Sdavidcs error = errno; 172250661Sdavidcs goto out; 173250661Sdavidcs } 174250661Sdavidcs sectorsize = g_get_sectorsize(name); 175250661Sdavidcs if (sectorsize == 0) { 176250661Sdavidcs error = errno; 177250661Sdavidcs goto out; 178250661Sdavidcs } 179250661Sdavidcs assert(sectorsize >= size); 180250661Sdavidcs sector = malloc(sectorsize); 181250661Sdavidcs if (sector == NULL) { 182250661Sdavidcs error = ENOMEM; 183250661Sdavidcs goto out; 184250661Sdavidcs } 185250661Sdavidcs bcopy(md, sector, size); 186250661Sdavidcs if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 187250661Sdavidcs (ssize_t)sectorsize) { 188250661Sdavidcs error = errno; 189250661Sdavidcs goto out; 190250661Sdavidcs } 191250661Sdavidcsout: 192250661Sdavidcs if (sector != NULL) 193250661Sdavidcs free(sector); 194250661Sdavidcs close(fd); 195250661Sdavidcs return (error); 196250661Sdavidcs} 197250661Sdavidcs 198250661Sdavidcs/* 199250661Sdavidcs * Labels a new geom Meaning: parses and checks the parameters, calculates & 200250661Sdavidcs * writes metadata to the relevant providers so when the next round of 201250661Sdavidcs * "tasting" comes (which will be just after the provider(s) are closed) geom 202250661Sdavidcs * can be instantiated with the tasted metadata. 203250661Sdavidcs */ 204250661Sdavidcsstatic void 205250661Sdavidcsvirstor_label(struct gctl_req *req) 206250661Sdavidcs{ 207250661Sdavidcs struct g_virstor_metadata md; 208250661Sdavidcs off_t msize; 209250661Sdavidcs unsigned char *sect; 210250661Sdavidcs unsigned int i; 211250661Sdavidcs size_t ssize, secsize; 212250661Sdavidcs const char *name; 213250661Sdavidcs char param[32]; 214250661Sdavidcs int hardcode, nargs, error; 215250661Sdavidcs struct virstor_map_entry *map; 216250661Sdavidcs size_t total_chunks; /* We'll run out of memory if 217250661Sdavidcs this needs to be bigger. */ 218250661Sdavidcs unsigned int map_chunks; /* Chunks needed by the map (map size). */ 219250661Sdavidcs size_t map_size; /* In bytes. */ 220250661Sdavidcs ssize_t written; 221250661Sdavidcs int fd; 222250661Sdavidcs 223250661Sdavidcs nargs = gctl_get_int(req, "nargs"); 224250661Sdavidcs if (nargs < 2) { 225250661Sdavidcs gctl_error(req, "Too few arguments (%d): expecting: name " 226250661Sdavidcs "provider0 [provider1 ...]", nargs); 227250661Sdavidcs return; 228250661Sdavidcs } 229250661Sdavidcs 230250661Sdavidcs hardcode = gctl_get_int(req, "hardcode"); 231250661Sdavidcs 232250661Sdavidcs /* 233250661Sdavidcs * Initialize constant parts of metadata: magic signature, version, 234250661Sdavidcs * name. 235250661Sdavidcs */ 236250661Sdavidcs bzero(&md, sizeof(md)); 237250661Sdavidcs strlcpy(md.md_magic, G_VIRSTOR_MAGIC, sizeof(md.md_magic)); 238250661Sdavidcs md.md_version = G_VIRSTOR_VERSION; 239250661Sdavidcs name = gctl_get_ascii(req, "arg0"); 240250661Sdavidcs if (name == NULL) { 241250661Sdavidcs gctl_error(req, "No 'arg%u' argument.", 0); 242250661Sdavidcs return; 243250661Sdavidcs } 244250661Sdavidcs strlcpy(md.md_name, name, sizeof(md.md_name)); 245250661Sdavidcs 246250661Sdavidcs md.md_virsize = (off_t)gctl_get_intmax(req, "vir_size"); 247250661Sdavidcs md.md_chunk_size = gctl_get_intmax(req, "chunk_size"); 248250661Sdavidcs md.md_count = nargs - 1; 249250661Sdavidcs 250250661Sdavidcs if (md.md_virsize == 0 || md.md_chunk_size == 0) { 251250661Sdavidcs gctl_error(req, "Virtual size and chunk size must be non-zero"); 252250661Sdavidcs return; 253250661Sdavidcs } 254250661Sdavidcs 255250661Sdavidcs if (md.md_chunk_size % MAXPHYS != 0) { 256250661Sdavidcs /* XXX: This is not strictly needed, but it's convenient to 257250661Sdavidcs * impose some limitations on it, so why not MAXPHYS. */ 258250661Sdavidcs size_t new_size = (md.md_chunk_size / MAXPHYS) * MAXPHYS; 259250661Sdavidcs if (new_size < md.md_chunk_size) 260250661Sdavidcs new_size += MAXPHYS; 261250661Sdavidcs fprintf(stderr, "Resizing chunk size to be a multiple of " 262250661Sdavidcs "MAXPHYS (%d kB).\n", MAXPHYS / 1024); 263250661Sdavidcs fprintf(stderr, "New chunk size: %zu kB\n", new_size / 1024); 264250661Sdavidcs md.md_chunk_size = new_size; 265250661Sdavidcs } 266250661Sdavidcs 267250661Sdavidcs if (md.md_virsize % md.md_chunk_size != 0) { 268250661Sdavidcs off_t chunk_count = md.md_virsize / md.md_chunk_size; 269250661Sdavidcs md.md_virsize = chunk_count * md.md_chunk_size; 270250661Sdavidcs fprintf(stderr, "Resizing virtual size to be a multiple of " 271250661Sdavidcs "chunk size.\n"); 272250661Sdavidcs fprintf(stderr, "New virtual size: %zu MB\n", 273250661Sdavidcs (size_t)(md.md_virsize/(1024 * 1024))); 274250661Sdavidcs } 275250661Sdavidcs 276250661Sdavidcs msize = secsize = 0; 277250661Sdavidcs for (i = 1; i < (unsigned)nargs; i++) { 278250661Sdavidcs snprintf(param, sizeof(param), "arg%u", i); 279250661Sdavidcs name = gctl_get_ascii(req, param); 280250661Sdavidcs ssize = g_get_sectorsize(name); 281250661Sdavidcs if (ssize == 0) 282250661Sdavidcs fprintf(stderr, "%s for %s\n", strerror(errno), name); 283250661Sdavidcs msize += g_get_mediasize(name); 284250661Sdavidcs if (secsize == 0) 285250661Sdavidcs secsize = ssize; 286250661Sdavidcs else if (secsize != ssize) { 287250661Sdavidcs gctl_error(req, "Devices need to have same sector size " 288250661Sdavidcs "(%u on %s needs to be %u).", 289250661Sdavidcs (u_int)ssize, name, (u_int)secsize); 290250661Sdavidcs return; 291250661Sdavidcs } 292250661Sdavidcs } 293250661Sdavidcs 294250661Sdavidcs if (secsize == 0) { 295250661Sdavidcs gctl_error(req, "Device not specified"); 296250661Sdavidcs return; 297250661Sdavidcs } 298250661Sdavidcs 299250661Sdavidcs if (md.md_chunk_size % secsize != 0) { 300250661Sdavidcs fprintf(stderr, "Error: chunk size is not a multiple of sector " 301250661Sdavidcs "size."); 302250661Sdavidcs gctl_error(req, "Chunk size (in bytes) must be multiple of %u.", 303250661Sdavidcs (unsigned int)secsize); 304250661Sdavidcs return; 305250661Sdavidcs } 306250661Sdavidcs 307250661Sdavidcs total_chunks = md.md_virsize / md.md_chunk_size; 308250661Sdavidcs map_size = total_chunks * sizeof(*map); 309250661Sdavidcs assert(md.md_virsize % md.md_chunk_size == 0); 310250661Sdavidcs 311250661Sdavidcs ssize = map_size % secsize; 312250661Sdavidcs if (ssize != 0) { 313250661Sdavidcs size_t add_chunks = (secsize - ssize) / sizeof(*map); 314250661Sdavidcs total_chunks += add_chunks; 315250661Sdavidcs md.md_virsize = (off_t)total_chunks * (off_t)md.md_chunk_size; 316250661Sdavidcs map_size = total_chunks * sizeof(*map); 317250661Sdavidcs fprintf(stderr, "Resizing virtual size to fit virstor " 318250661Sdavidcs "structures.\n"); 319250661Sdavidcs fprintf(stderr, "New virtual size: %ju MB (%zu new chunks)\n", 320250661Sdavidcs (uintmax_t)(md.md_virsize / (1024 * 1024)), add_chunks); 321250661Sdavidcs } 322250661Sdavidcs 323250661Sdavidcs if (verbose) 324250661Sdavidcs printf("Total virtual chunks: %zu (%zu MB each), %ju MB total " 325250661Sdavidcs "virtual size.\n", 326250661Sdavidcs total_chunks, (size_t)(md.md_chunk_size / (1024 * 1024)), 327250661Sdavidcs md.md_virsize/(1024 * 1024)); 328250661Sdavidcs 329250661Sdavidcs if ((off_t)md.md_virsize < msize) 330250661Sdavidcs fprintf(stderr, "WARNING: Virtual storage size < Physical " 331250661Sdavidcs "available storage (%ju < %ju)\n", md.md_virsize, msize); 332250661Sdavidcs 333250661Sdavidcs /* Clear last sector first to spoil all components if device exists. */ 334250661Sdavidcs if (verbose) 335250661Sdavidcs printf("Clearing metadata on"); 336250661Sdavidcs 337250661Sdavidcs for (i = 1; i < (unsigned)nargs; i++) { 338250661Sdavidcs snprintf(param, sizeof(param), "arg%u", i); 339250661Sdavidcs name = gctl_get_ascii(req, param); 340250661Sdavidcs 341250661Sdavidcs if (verbose) 342250661Sdavidcs printf(" %s", name); 343250661Sdavidcs 344250661Sdavidcs msize = g_get_mediasize(name); 345250661Sdavidcs ssize = g_get_sectorsize(name); 346250661Sdavidcs if (msize == 0 || ssize == 0) { 347250661Sdavidcs gctl_error(req, "Can't retrieve information about " 348250661Sdavidcs "%s: %s.", name, strerror(errno)); 349250661Sdavidcs return; 350250661Sdavidcs } 351250661Sdavidcs if (msize < (off_t) MAX(md.md_chunk_size*4, map_size)) 352250661Sdavidcs gctl_error(req, "Device %s is too small", name); 353250661Sdavidcs error = g_metadata_clear(name, NULL); 354250661Sdavidcs if (error != 0) { 355250661Sdavidcs gctl_error(req, "Can't clear metadata on %s: %s.", name, 356250661Sdavidcs strerror(error)); 357250661Sdavidcs return; 358250661Sdavidcs } 359250661Sdavidcs } 360250661Sdavidcs 361250661Sdavidcs 362250661Sdavidcs /* Write allocation table to the first provider - this needs to be done 363250661Sdavidcs * before metadata is written because when kernel tastes it it's too 364250661Sdavidcs * late */ 365250661Sdavidcs name = gctl_get_ascii(req, "arg1"); /* device with metadata */ 366250661Sdavidcs if (verbose) 367250661Sdavidcs printf(".\nWriting allocation table to %s...", name); 368250661Sdavidcs 369250661Sdavidcs /* How many chunks does the map occupy? */ 370250661Sdavidcs map_chunks = map_size/md.md_chunk_size; 371250661Sdavidcs if (map_size % md.md_chunk_size != 0) 372250661Sdavidcs map_chunks++; 373250661Sdavidcs if (verbose) { 374250661Sdavidcs printf(" (%zu MB, %d chunks) ", map_size/(1024*1024), map_chunks); 375250661Sdavidcs fflush(stdout); 376250661Sdavidcs } 377250661Sdavidcs 378250661Sdavidcs if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 379250661Sdavidcs fd = open(name, O_RDWR); 380250661Sdavidcs else { 381250661Sdavidcs sprintf(param, "%s%s", _PATH_DEV, name); 382250661Sdavidcs fd = open(param, O_RDWR); 383250661Sdavidcs } 384250661Sdavidcs if (fd < 0) 385250661Sdavidcs gctl_error(req, "Cannot open provider %s to write map", name); 386250661Sdavidcs 387250661Sdavidcs /* Do it with calloc because there might be a need to set up chunk flags 388250661Sdavidcs * in the future */ 389250661Sdavidcs map = calloc(total_chunks, sizeof(*map)); 390250661Sdavidcs if (map == NULL) { 391250661Sdavidcs gctl_error(req, 392250661Sdavidcs "Out of memory (need %zu bytes for allocation map)", 393250661Sdavidcs map_size); 394250661Sdavidcs } 395250661Sdavidcs 396250661Sdavidcs written = pwrite(fd, map, map_size, 0); 397250661Sdavidcs free(map); 398250661Sdavidcs if ((size_t)written != map_size) { 399250661Sdavidcs if (verbose) { 400250661Sdavidcs fprintf(stderr, "\nTried to write %zu, written %zd (%s)\n", 401250661Sdavidcs map_size, written, strerror(errno)); 402250661Sdavidcs } 403250661Sdavidcs gctl_error(req, "Error writing out allocation map!"); 404250661Sdavidcs return; 405250661Sdavidcs } 406250661Sdavidcs close (fd); 407250661Sdavidcs 408250661Sdavidcs if (verbose) 409250661Sdavidcs printf("\nStoring metadata on "); 410250661Sdavidcs 411250661Sdavidcs /* 412250661Sdavidcs * ID is randomly generated, unique for a geom. This is used to 413250661Sdavidcs * recognize all providers belonging to one geom. 414250661Sdavidcs */ 415250661Sdavidcs md.md_id = arc4random(); 416250661Sdavidcs 417250661Sdavidcs /* Ok, store metadata. */ 418250661Sdavidcs for (i = 1; i < (unsigned)nargs; i++) { 419250661Sdavidcs snprintf(param, sizeof(param), "arg%u", i); 420250661Sdavidcs name = gctl_get_ascii(req, param); 421250661Sdavidcs 422250661Sdavidcs msize = g_get_mediasize(name); 423250661Sdavidcs ssize = g_get_sectorsize(name); 424250661Sdavidcs 425250661Sdavidcs if (verbose) 426250661Sdavidcs printf("%s ", name); 427250661Sdavidcs 428250661Sdavidcs /* this provider's position/type in geom */ 429250661Sdavidcs md.no = i - 1; 430250661Sdavidcs /* this provider's size */ 431250661Sdavidcs md.provsize = msize; 432250661Sdavidcs /* chunk allocation info */ 433250661Sdavidcs md.chunk_count = md.provsize / md.md_chunk_size; 434250661Sdavidcs if (verbose) 435250661Sdavidcs printf("(%u chunks) ", md.chunk_count); 436250661Sdavidcs /* Check to make sure last sector is unused */ 437250661Sdavidcs if ((off_t)(md.chunk_count * md.md_chunk_size) > msize-ssize) 438250661Sdavidcs md.chunk_count--; 439250661Sdavidcs md.chunk_next = 0; 440250661Sdavidcs if (i != 1) { 441250661Sdavidcs md.chunk_reserved = 0; 442250661Sdavidcs md.flags = 0; 443250661Sdavidcs } else { 444250661Sdavidcs md.chunk_reserved = map_chunks * 2; 445250661Sdavidcs md.flags = VIRSTOR_PROVIDER_ALLOCATED | 446250661Sdavidcs VIRSTOR_PROVIDER_CURRENT; 447250661Sdavidcs md.chunk_next = md.chunk_reserved; 448250661Sdavidcs if (verbose) 449250661Sdavidcs printf("(%u reserved) ", md.chunk_reserved); 450250661Sdavidcs } 451250661Sdavidcs 452250661Sdavidcs if (!hardcode) 453250661Sdavidcs bzero(md.provider, sizeof(md.provider)); 454250661Sdavidcs else { 455250661Sdavidcs /* convert "/dev/something" to "something" */ 456250661Sdavidcs if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) { 457250661Sdavidcs strlcpy(md.provider, name + sizeof(_PATH_DEV) - 1, 458250661Sdavidcs sizeof(md.provider)); 459250661Sdavidcs } else 460250661Sdavidcs strlcpy(md.provider, name, sizeof(md.provider)); 461250661Sdavidcs } 462250661Sdavidcs sect = malloc(ssize); 463250661Sdavidcs if (sect == NULL) 464250661Sdavidcs err(1, "Cannot allocate sector of %zu bytes", ssize); 465250661Sdavidcs bzero(sect, ssize); 466250661Sdavidcs virstor_metadata_encode(&md, sect); 467250661Sdavidcs error = my_g_metadata_store(name, sect, ssize); 468250661Sdavidcs free(sect); 469250661Sdavidcs if (error != 0) { 470250661Sdavidcs if (verbose) 471250661Sdavidcs printf("\n"); 472250661Sdavidcs fprintf(stderr, "Can't store metadata on %s: %s.\n", 473250661Sdavidcs name, strerror(error)); 474250661Sdavidcs gctl_error(req, 475250661Sdavidcs "Not fully done (error storing metadata)."); 476250661Sdavidcs return; 477250661Sdavidcs } 478250661Sdavidcs } 479250661Sdavidcs#if 0 480250661Sdavidcs if (verbose) 481250661Sdavidcs printf("\n"); 482250661Sdavidcs#endif 483250661Sdavidcs} 484250661Sdavidcs 485250661Sdavidcs/* Clears metadata on given provider(s) IF it's owned by us */ 486250661Sdavidcsstatic void 487250661Sdavidcsvirstor_clear(struct gctl_req *req) 488250661Sdavidcs{ 489250661Sdavidcs const char *name; 490250661Sdavidcs char param[32]; 491250661Sdavidcs unsigned i; 492250661Sdavidcs int nargs, error; 493250661Sdavidcs int fd; 494250661Sdavidcs 495250661Sdavidcs nargs = gctl_get_int(req, "nargs"); 496250661Sdavidcs if (nargs < 1) { 497250661Sdavidcs gctl_error(req, "Too few arguments."); 498250661Sdavidcs return; 499250661Sdavidcs } 500250661Sdavidcs for (i = 0; i < (unsigned)nargs; i++) { 501250661Sdavidcs snprintf(param, sizeof(param), "arg%u", i); 502250661Sdavidcs name = gctl_get_ascii(req, param); 503250661Sdavidcs 504250661Sdavidcs error = g_metadata_clear(name, G_VIRSTOR_MAGIC); 505250661Sdavidcs if (error != 0) { 506250661Sdavidcs fprintf(stderr, "Can't clear metadata on %s: %s " 507250661Sdavidcs "(do I own it?)\n", name, strerror(error)); 508250661Sdavidcs gctl_error(req, 509250661Sdavidcs "Not fully done (can't clear metadata)."); 510250661Sdavidcs continue; 511250661Sdavidcs } 512250661Sdavidcs if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 513250661Sdavidcs fd = open(name, O_RDWR); 514250661Sdavidcs else { 515250661Sdavidcs sprintf(param, "%s%s", _PATH_DEV, name); 516250661Sdavidcs fd = open(param, O_RDWR); 517250661Sdavidcs } 518250661Sdavidcs if (fd < 0) { 519250661Sdavidcs gctl_error(req, "Cannot clear header sector for %s", 520250661Sdavidcs name); 521250661Sdavidcs continue; 522250661Sdavidcs } 523250661Sdavidcs if (verbose) 524250661Sdavidcs printf("Metadata cleared on %s.\n", name); 525250661Sdavidcs } 526250661Sdavidcs} 527250661Sdavidcs 528250661Sdavidcs/* Print some metadata information */ 529250661Sdavidcsstatic void 530250661Sdavidcsvirstor_metadata_dump(const struct g_virstor_metadata *md) 531250661Sdavidcs{ 532250661Sdavidcs printf(" Magic string: %s\n", md->md_magic); 533250661Sdavidcs printf(" Metadata version: %u\n", (u_int) md->md_version); 534250661Sdavidcs printf(" Device name: %s\n", md->md_name); 535250661Sdavidcs printf(" Device ID: %u\n", (u_int) md->md_id); 536250661Sdavidcs printf(" Provider index: %u\n", (u_int) md->no); 537250661Sdavidcs printf(" Active providers: %u\n", (u_int) md->md_count); 538250661Sdavidcs printf(" Hardcoded provider: %s\n", 539250661Sdavidcs md->provider[0] != '\0' ? md->provider : "(not hardcoded)"); 540250661Sdavidcs printf(" Virtual size: %u MB\n", 541250661Sdavidcs (unsigned int)(md->md_virsize/(1024 * 1024))); 542250661Sdavidcs printf(" Chunk size: %u kB\n", md->md_chunk_size / 1024); 543250661Sdavidcs printf(" Chunks on provider: %u\n", md->chunk_count); 544250661Sdavidcs printf(" Chunks free: %u\n", md->chunk_count - md->chunk_next); 545250661Sdavidcs printf(" Reserved chunks: %u\n", md->chunk_reserved); 546250661Sdavidcs} 547250661Sdavidcs 548250661Sdavidcs/* Called by geom(8) via gvirstor_main() to dump metadata information */ 549250661Sdavidcsstatic void 550250661Sdavidcsvirstor_dump(struct gctl_req *req) 551250661Sdavidcs{ 552250661Sdavidcs struct g_virstor_metadata md; 553250661Sdavidcs u_char tmpmd[512]; /* temporary buffer */ 554250661Sdavidcs const char *name; 555250661Sdavidcs char param[16]; 556250661Sdavidcs int nargs, error, i; 557250661Sdavidcs 558250661Sdavidcs assert(sizeof(tmpmd) >= sizeof(md)); 559250661Sdavidcs 560250661Sdavidcs nargs = gctl_get_int(req, "nargs"); 561250661Sdavidcs if (nargs < 1) { 562250661Sdavidcs gctl_error(req, "Too few arguments."); 563250661Sdavidcs return; 564250661Sdavidcs } 565250661Sdavidcs for (i = 0; i < nargs; i++) { 566250661Sdavidcs snprintf(param, sizeof(param), "arg%u", i); 567250661Sdavidcs name = gctl_get_ascii(req, param); 568250661Sdavidcs 569250661Sdavidcs error = g_metadata_read(name, (u_char *) & tmpmd, sizeof(tmpmd), 570250661Sdavidcs G_VIRSTOR_MAGIC); 571250661Sdavidcs if (error != 0) { 572250661Sdavidcs fprintf(stderr, "Can't read metadata from %s: %s.\n", 573250661Sdavidcs name, strerror(error)); 574250661Sdavidcs gctl_error(req, 575250661Sdavidcs "Not fully done (error reading metadata)."); 576250661Sdavidcs continue; 577250661Sdavidcs } 578250661Sdavidcs virstor_metadata_decode((u_char *) & tmpmd, &md); 579250661Sdavidcs printf("Metadata on %s:\n", name); 580250661Sdavidcs virstor_metadata_dump(&md); 581250661Sdavidcs printf("\n"); 582250661Sdavidcs } 583250661Sdavidcs} 584250661Sdavidcs