geom_raid3.c revision 134168
1279377Simp/*- 2279377Simp * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3279377Simp * All rights reserved. 4279377Simp * 5279377Simp * Redistribution and use in source and binary forms, with or without 6279377Simp * modification, are permitted provided that the following conditions 7279377Simp * are met: 8279377Simp * 1. Redistributions of source code must retain the above copyright 9279377Simp * notice, this list of conditions and the following disclaimer. 10279377Simp * 2. Redistributions in binary form must reproduce the above copyright 11279377Simp * notice, this list of conditions and the following disclaimer in the 12279377Simp * documentation and/or other materials provided with the distribution. 13279377Simp * 14279377Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15279377Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16279377Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17279377Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18279377Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19279377Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20279377Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21279377Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22279377Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23279377Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24279377Simp * SUCH DAMAGE. 25279377Simp */ 26279377Simp 27279377Simp#include <sys/cdefs.h> 28279377Simp__FBSDID("$FreeBSD: head/sbin/geom/class/raid3/geom_raid3.c 134168 2004-08-22 16:21:12Z pjd $"); 29279377Simp 30279377Simp#include <sys/param.h> 31279377Simp#include <errno.h> 32279377Simp#include <paths.h> 33279377Simp#include <stdio.h> 34279377Simp#include <stdlib.h> 35279377Simp#include <stdint.h> 36279377Simp#include <string.h> 37279377Simp#include <strings.h> 38279377Simp#include <assert.h> 39279377Simp#include <libgeom.h> 40279377Simp#include <geom/raid3/g_raid3.h> 41279377Simp#include <core/geom.h> 42279377Simp#include <misc/subr.h> 43279377Simp 44279377Simp 45279377Simpuint32_t lib_version = G_LIB_VERSION; 46279377Simpuint32_t version = G_RAID3_VERSION; 47279377Simp 48279377Simpstatic void raid3_main(struct gctl_req *req, unsigned f); 49279377Simpstatic void raid3_clear(struct gctl_req *req); 50279377Simpstatic void raid3_dump(struct gctl_req *req); 51279377Simpstatic void raid3_label(struct gctl_req *req); 52279377Simp 53279377Simpstruct g_command class_commands[] = { 54279377Simp { "clear", G_FLAG_VERBOSE, raid3_main, G_NULL_OPTS }, 55279377Simp { "configure", G_FLAG_VERBOSE, NULL, 56279377Simp { 57279377Simp { 'a', "autosync", NULL, G_TYPE_NONE }, 58279377Simp { 'd', "dynamic", NULL, G_TYPE_NONE }, 59279377Simp { 'h', "hardcode", NULL, G_TYPE_NONE }, 60279377Simp { 'n', "noautosync", NULL, G_TYPE_NONE }, 61279377Simp { 'r', "round_robin", NULL, G_TYPE_NONE }, 62279377Simp { 'R', "noround_robin", NULL, G_TYPE_NONE }, 63279377Simp { 'w', "verify", NULL, G_TYPE_NONE }, 64279377Simp { 'W', "noverify", NULL, G_TYPE_NONE }, 65279377Simp G_OPT_SENTINEL 66279377Simp } 67279377Simp }, 68279377Simp { "dump", 0, raid3_main, G_NULL_OPTS }, 69279377Simp { "insert", G_FLAG_VERBOSE, NULL, 70279377Simp { 71279377Simp { 'h', "hardcode", NULL, G_TYPE_NONE }, 72279377Simp { 'n', "number", NULL, G_TYPE_NUMBER }, 73279377Simp G_OPT_SENTINEL 74279377Simp } 75279377Simp }, 76279377Simp { "label", G_FLAG_VERBOSE, raid3_main, 77279377Simp { 78279377Simp { 'h', "hardcode", NULL, G_TYPE_NONE }, 79279377Simp { 'n', "noautosync", NULL, G_TYPE_NONE }, 80279377Simp { 'r', "round_robin", NULL, G_TYPE_NONE }, 81279377Simp { 'w', "verify", NULL, G_TYPE_NONE }, 82279377Simp G_OPT_SENTINEL 83279377Simp } 84279377Simp }, 85279377Simp { "rebuild", G_FLAG_VERBOSE, NULL, G_NULL_OPTS }, 86279377Simp { "remove", G_FLAG_VERBOSE, NULL, 87279377Simp { 88279377Simp { 'n', "number", NULL, G_TYPE_NUMBER }, 89279377Simp G_OPT_SENTINEL 90279377Simp } 91279377Simp }, 92279377Simp { "stop", G_FLAG_VERBOSE, NULL, 93279377Simp { 94279377Simp { 'f', "force", NULL, G_TYPE_NONE }, 95279377Simp G_OPT_SENTINEL 96279377Simp } 97279377Simp }, 98279377Simp G_CMD_SENTINEL 99279377Simp}; 100279377Simp 101279377Simpstatic int verbose = 0; 102279377Simp 103279377Simpvoid usage(const char *); 104279377Simpvoid 105279377Simpusage(const char *comm) 106279377Simp{ 107279377Simp fprintf(stderr, 108279377Simp "usage: %s label [-hnrvw] name prov prov prov [prov [...]]\n" 109279377Simp " %s clear [-v] prov [prov [...]]\n" 110279377Simp " %s dump prov [prov [...]]\n" 111279377Simp " %s configure [-adhnrRvwW] name\n" 112279377Simp " %s rebuild [-v] name prov\n" 113279377Simp " %s insert [-hv] <-n number> name prov\n" 114279377Simp " %s remove [-v] <-n number> name\n" 115279377Simp " %s stop [-fv] name [...]\n", 116279377Simp comm, comm, comm, comm, comm, comm, comm, comm); 117279377Simp exit(EXIT_FAILURE); 118279377Simp} 119279377Simp 120279377Simpstatic void 121279377Simpraid3_main(struct gctl_req *req, unsigned flags) 122279377Simp{ 123279377Simp const char *name; 124279377Simp 125279377Simp if ((flags & G_FLAG_VERBOSE) != 0) 126279377Simp verbose = 1; 127279377Simp 128279377Simp name = gctl_get_asciiparam(req, "verb"); 129279377Simp if (name == NULL) { 130279377Simp gctl_error(req, "No '%s' argument.", "verb"); 131279377Simp return; 132279377Simp } 133279377Simp if (strcmp(name, "label") == 0) 134279377Simp raid3_label(req); 135279377Simp else if (strcmp(name, "clear") == 0) 136279377Simp raid3_clear(req); 137279377Simp else if (strcmp(name, "dump") == 0) 138279377Simp raid3_dump(req); 139279377Simp else 140279377Simp gctl_error(req, "Unknown command: %s.", name); 141279377Simp} 142279377Simp 143279377Simpstatic void 144279377Simpraid3_label(struct gctl_req *req) 145279377Simp{ 146279377Simp struct g_raid3_metadata md; 147279377Simp u_char sector[512]; 148279377Simp const char *str; 149279377Simp char param[16]; 150279377Simp int *hardcode, *nargs, *noautosync, *round_robin, *verify; 151279377Simp int error, i; 152279377Simp unsigned sectorsize; 153279377Simp off_t mediasize; 154279377Simp 155279377Simp nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 156279377Simp if (nargs == NULL) { 157279377Simp gctl_error(req, "No '%s' argument.", "nargs"); 158279377Simp return; 159279377Simp } 160279377Simp if (*nargs < 4) { 161279377Simp gctl_error(req, "Too few arguments."); 162279377Simp return; 163279377Simp } 164279377Simp#ifndef BITCOUNT 165279377Simp#define BITCOUNT(x) (((BX_(x) + (BX_(x) >> 4)) & 0x0F0F0F0F) % 255) 166279377Simp#define BX_(x) ((x) - (((x) >> 1) & 0x77777777) - \ 167279377Simp (((x) >> 2) & 0x33333333) - (((x) >> 3) & 0x11111111)) 168279377Simp#endif 169279377Simp if (BITCOUNT(*nargs - 2) != 1) { 170279377Simp gctl_error(req, "Invalid number of components."); 171279377Simp return; 172279377Simp } 173279377Simp 174279377Simp strlcpy(md.md_magic, G_RAID3_MAGIC, sizeof(md.md_magic)); 175279377Simp md.md_version = G_RAID3_VERSION; 176279377Simp str = gctl_get_asciiparam(req, "arg0"); 177279377Simp if (str == NULL) { 178279377Simp gctl_error(req, "No 'arg%u' argument.", 0); 179279377Simp return; 180279377Simp } 181279377Simp strlcpy(md.md_name, str, sizeof(md.md_name)); 182279377Simp md.md_all = *nargs - 1; 183279377Simp md.md_mflags = 0; 184279377Simp md.md_dflags = 0; 185279377Simp md.md_syncid = 1; 186279377Simp md.md_sync_offset = 0; 187279377Simp noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 188279377Simp if (noautosync == NULL) { 189279377Simp gctl_error(req, "No '%s' argument.", "noautosync"); 190279377Simp return; 191279377Simp } 192279377Simp if (*noautosync) 193279377Simp md.md_mflags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 194279377Simp round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin)); 195279377Simp if (round_robin == NULL) { 196279377Simp gctl_error(req, "No '%s' argument.", "round_robin"); 197279377Simp return; 198279377Simp } 199279377Simp if (*round_robin) 200279377Simp md.md_mflags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 201279377Simp verify = gctl_get_paraml(req, "verify", sizeof(*verify)); 202279377Simp if (verify == NULL) { 203279377Simp gctl_error(req, "No '%s' argument.", "verify"); 204279377Simp return; 205279377Simp } 206279377Simp if (*verify) 207279377Simp md.md_mflags |= G_RAID3_DEVICE_FLAG_VERIFY; 208279377Simp if (*round_robin && *verify) { 209279377Simp gctl_error(req, "Both '%c' and '%c' options given.", 'r', 'w'); 210279377Simp return; 211279377Simp } 212279377Simp hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 213279377Simp if (hardcode == NULL) { 214279377Simp gctl_error(req, "No '%s' argument.", "hardcode"); 215279377Simp return; 216279377Simp } 217279377Simp 218279377Simp /* 219279377Simp * Calculate sectorsize by finding least common multiple from 220279377Simp * sectorsizes of every disk and find the smallest mediasize. 221279377Simp */ 222279377Simp mediasize = 0; 223279377Simp sectorsize = 0; 224279377Simp for (i = 1; i < *nargs; i++) { 225279377Simp unsigned ssize; 226279377Simp off_t msize; 227279377Simp 228279377Simp snprintf(param, sizeof(param), "arg%u", i); 229279377Simp str = gctl_get_asciiparam(req, param); 230279377Simp 231279377Simp msize = g_get_mediasize(str); 232279377Simp ssize = g_get_sectorsize(str); 233279377Simp if (msize == 0 || ssize == 0) { 234279377Simp gctl_error(req, "Can't get informations about %s: %s.", 235279377Simp str, strerror(errno)); 236279377Simp return; 237279377Simp } 238279377Simp msize -= ssize; 239279377Simp if (mediasize == 0 || (mediasize > 0 && msize < mediasize)) 240279377Simp mediasize = msize; 241279377Simp if (sectorsize == 0) 242279377Simp sectorsize = ssize; 243279377Simp else 244279377Simp sectorsize = g_lcm(sectorsize, ssize); 245279377Simp } 246279377Simp md.md_mediasize = mediasize * (*nargs - 2); 247279377Simp md.md_sectorsize = sectorsize * (*nargs - 2); 248279377Simp 249279377Simp /* 250279377Simp * Clear last sector first, to spoil all components if device exists. 251279377Simp */ 252279377Simp for (i = 1; i < *nargs; i++) { 253279377Simp snprintf(param, sizeof(param), "arg%u", i); 254279377Simp str = gctl_get_asciiparam(req, param); 255279377Simp 256279377Simp error = g_metadata_clear(str, NULL); 257279377Simp if (error != 0) { 258279377Simp gctl_error(req, "Can't store metadata on %s: %s.", str, 259279377Simp strerror(error)); 260279377Simp return; 261279377Simp } 262279377Simp } 263279377Simp 264279377Simp /* 265279377Simp * Ok, store metadata (use disk number as priority). 266279377Simp */ 267279377Simp for (i = 1; i < *nargs; i++) { 268279377Simp snprintf(param, sizeof(param), "arg%u", i); 269279377Simp str = gctl_get_asciiparam(req, param); 270279377Simp 271279377Simp md.md_no = i - 1; 272279377Simp if (!*hardcode) 273279377Simp bzero(md.md_provider, sizeof(md.md_provider)); 274279377Simp else { 275279377Simp if (strncmp(str, _PATH_DEV, strlen(_PATH_DEV)) == 0) 276279377Simp str += strlen(_PATH_DEV); 277279377Simp strlcpy(md.md_provider, str, sizeof(md.md_provider)); 278279377Simp } 279279377Simp raid3_metadata_encode(&md, sector); 280279377Simp error = g_metadata_store(str, sector, sizeof(sector)); 281279377Simp if (error != 0) { 282279377Simp fprintf(stderr, "Can't store metadata on %s: %s.\n", 283279377Simp str, strerror(error)); 284279377Simp gctl_error(req, "Not fully done."); 285279377Simp continue; 286279377Simp } 287279377Simp if (verbose) 288279377Simp printf("Metadata value stored on %s.\n", str); 289279377Simp } 290279377Simp} 291279377Simp 292279377Simpstatic void 293279377Simpraid3_clear(struct gctl_req *req) 294279377Simp{ 295279377Simp const char *name; 296279377Simp char param[16]; 297279377Simp int *nargs, error, i; 298279377Simp 299279377Simp nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 300279377Simp if (nargs == NULL) { 301279377Simp gctl_error(req, "No '%s' argument.", "nargs"); 302279377Simp return; 303279377Simp } 304279377Simp if (*nargs < 1) { 305279377Simp gctl_error(req, "Too few arguments."); 306279377Simp return; 307279377Simp } 308279377Simp 309279377Simp for (i = 0; i < *nargs; i++) { 310279377Simp snprintf(param, sizeof(param), "arg%u", i); 311279377Simp name = gctl_get_asciiparam(req, param); 312279377Simp 313279377Simp error = g_metadata_clear(name, G_RAID3_MAGIC); 314279377Simp if (error != 0) { 315279377Simp fprintf(stderr, "Can't clear metadata on %s: %s.\n", 316279377Simp name, strerror(error)); 317279377Simp gctl_error(req, "Not fully done."); 318279377Simp continue; 319279377Simp } 320279377Simp if (verbose) 321279377Simp printf("Metadata cleared on %s.\n", name); 322279377Simp } 323279377Simp} 324279377Simp 325279377Simpstatic void 326279377Simpraid3_dump(struct gctl_req *req) 327279377Simp{ 328279377Simp struct g_raid3_metadata md, tmpmd; 329279377Simp const char *name; 330279377Simp char param[16]; 331279377Simp int *nargs, error, i; 332279377Simp 333279377Simp nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 334279377Simp if (nargs == NULL) { 335279377Simp gctl_error(req, "No '%s' argument.", "nargs"); 336279377Simp return; 337279377Simp } 338279377Simp if (*nargs < 1) { 339279377Simp gctl_error(req, "Too few arguments."); 340279377Simp return; 341279377Simp } 342279377Simp 343279377Simp for (i = 0; i < *nargs; i++) { 344279377Simp snprintf(param, sizeof(param), "arg%u", i); 345279377Simp name = gctl_get_asciiparam(req, param); 346279377Simp 347279377Simp error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd), 348279377Simp G_RAID3_MAGIC); 349279377Simp if (error != 0) { 350279377Simp fprintf(stderr, "Can't read metadata from %s: %s.\n", 351279377Simp name, strerror(error)); 352279377Simp gctl_error(req, "Not fully done."); 353279377Simp continue; 354279377Simp } 355279377Simp if (raid3_metadata_decode((u_char *)&tmpmd, &md) != 0) { 356279377Simp fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 357279377Simp name); 358279377Simp gctl_error(req, "Not fully done."); 359279377Simp continue; 360279377Simp } 361279377Simp printf("Metadata on %s:\n", name); 362279377Simp raid3_metadata_dump(&md); 363279377Simp printf("\n"); 364279377Simp } 365279377Simp} 366279377Simp