geom_raid3.c revision 134124
1325322Sgordon/*- 2325322Sgordon * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3325322Sgordon * All rights reserved. 4325322Sgordon * 5325322Sgordon * Redistribution and use in source and binary forms, with or without 6325322Sgordon * modification, are permitted provided that the following conditions 7325322Sgordon * are met: 8325322Sgordon * 1. Redistributions of source code must retain the above copyright 9325322Sgordon * notice, this list of conditions and the following disclaimer. 10325322Sgordon * 2. Redistributions in binary form must reproduce the above copyright 11325322Sgordon * notice, this list of conditions and the following disclaimer in the 12325322Sgordon * documentation and/or other materials provided with the distribution. 13325322Sgordon * 14325322Sgordon * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15325322Sgordon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16325322Sgordon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17325322Sgordon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18325322Sgordon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19325322Sgordon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20325322Sgordon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21325322Sgordon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22325322Sgordon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23325322Sgordon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24325322Sgordon * SUCH DAMAGE. 25325322Sgordon */ 26325322Sgordon 27325322Sgordon#include <sys/cdefs.h> 28325322Sgordon__FBSDID("$FreeBSD: head/sbin/geom/class/raid3/geom_raid3.c 134124 2004-08-21 18:11:46Z pjd $"); 29325322Sgordon 30325322Sgordon#include <sys/param.h> 31325322Sgordon#include <errno.h> 32325322Sgordon#include <paths.h> 33325322Sgordon#include <stdio.h> 34325322Sgordon#include <stdlib.h> 35325322Sgordon#include <stdint.h> 36325322Sgordon#include <string.h> 37325322Sgordon#include <strings.h> 38325322Sgordon#include <assert.h> 39325322Sgordon#include <libgeom.h> 40325322Sgordon#include <geom/raid3/g_raid3.h> 41325322Sgordon#include <core/geom.h> 42325322Sgordon#include <misc/subr.h> 43325322Sgordon 44325322Sgordon 45325322Sgordonuint32_t lib_version = G_LIB_VERSION; 46325322Sgordonuint32_t version = G_RAID3_VERSION; 47325322Sgordon 48325322Sgordonstatic void raid3_main(struct gctl_req *req, unsigned f); 49325322Sgordonstatic void raid3_clear(struct gctl_req *req); 50325322Sgordonstatic void raid3_dump(struct gctl_req *req); 51325322Sgordonstatic void raid3_label(struct gctl_req *req); 52325322Sgordon 53325322Sgordonstruct g_command class_commands[] = { 54325322Sgordon { "clear", G_FLAG_VERBOSE, raid3_main, G_NULL_OPTS }, 55330568Sgordon { "configure", G_FLAG_VERBOSE, NULL, 56330568Sgordon { 57330568Sgordon { 'a', "autosync", NULL, G_TYPE_NONE }, 58330568Sgordon { 'd', "dynamic", NULL, G_TYPE_NONE }, 59325322Sgordon { 'h', "hardcode", NULL, G_TYPE_NONE }, 60325322Sgordon { 'n', "noautosync", NULL, G_TYPE_NONE }, 61325322Sgordon { 'r', "round_robin", NULL, G_TYPE_NONE }, 62325322Sgordon { 'R', "noround_robin", NULL, G_TYPE_NONE }, 63325322Sgordon G_OPT_SENTINEL 64325322Sgordon } 65325322Sgordon }, 66325322Sgordon { "dump", 0, raid3_main, G_NULL_OPTS }, 67325322Sgordon { "insert", G_FLAG_VERBOSE, NULL, 68325322Sgordon { 69325322Sgordon { 'h', "hardcode", NULL, G_TYPE_NONE }, 70325322Sgordon { 'n', "number", NULL, G_TYPE_NUMBER }, 71325322Sgordon G_OPT_SENTINEL 72325322Sgordon } 73325322Sgordon }, 74325322Sgordon { "label", G_FLAG_VERBOSE, raid3_main, 75325322Sgordon { 76325322Sgordon { 'h', "hardcode", NULL, G_TYPE_NONE }, 77325322Sgordon { 'n', "noautosync", NULL, G_TYPE_NONE }, 78325322Sgordon { 'r', "round_robin", NULL, G_TYPE_NONE }, 79325322Sgordon G_OPT_SENTINEL 80325322Sgordon } 81325322Sgordon }, 82325322Sgordon { "rebuild", G_FLAG_VERBOSE, NULL, G_NULL_OPTS }, 83325322Sgordon { "remove", G_FLAG_VERBOSE, NULL, 84325322Sgordon { 85325322Sgordon { 'n', "number", NULL, G_TYPE_NUMBER }, 86325322Sgordon G_OPT_SENTINEL 87325322Sgordon } 88325322Sgordon }, 89325322Sgordon { "stop", G_FLAG_VERBOSE, NULL, 90325322Sgordon { 91325322Sgordon { 'f', "force", NULL, G_TYPE_NONE }, 92325322Sgordon G_OPT_SENTINEL 93325322Sgordon } 94325322Sgordon }, 95325322Sgordon G_CMD_SENTINEL 96325322Sgordon}; 97325322Sgordon 98325322Sgordonstatic int verbose = 0; 99325322Sgordon 100325322Sgordonvoid usage(const char *); 101325322Sgordonvoid 102325322Sgordonusage(const char *comm) 103325322Sgordon{ 104325322Sgordon fprintf(stderr, 105325322Sgordon "usage: %s label [-hnrv] name prov prov prov [prov [...]]\n" 106325322Sgordon " %s clear [-v] prov [prov [...]]\n" 107325322Sgordon " %s dump prov [prov [...]]\n" 108325322Sgordon " %s configure [-adhnrRv] name\n" 109325322Sgordon " %s rebuild [-v] name prov\n" 110325322Sgordon " %s insert [-hv] <-n number> name prov\n" 111325322Sgordon " %s remove [-v] <-n number> name\n" 112325322Sgordon " %s stop [-fv] name [...]\n", 113325322Sgordon comm, comm, comm, comm, comm, comm, comm, comm); 114325322Sgordon exit(EXIT_FAILURE); 115325322Sgordon} 116325322Sgordon 117325322Sgordonstatic void 118325322Sgordonraid3_main(struct gctl_req *req, unsigned flags) 119325322Sgordon{ 120325322Sgordon const char *name; 121325322Sgordon 122325322Sgordon if ((flags & G_FLAG_VERBOSE) != 0) 123325322Sgordon verbose = 1; 124325322Sgordon 125325322Sgordon name = gctl_get_asciiparam(req, "verb"); 126325322Sgordon if (name == NULL) { 127325322Sgordon gctl_error(req, "No '%s' argument.", "verb"); 128325322Sgordon return; 129325322Sgordon } 130325322Sgordon if (strcmp(name, "label") == 0) 131325322Sgordon raid3_label(req); 132325322Sgordon else if (strcmp(name, "clear") == 0) 133325322Sgordon raid3_clear(req); 134325322Sgordon else if (strcmp(name, "dump") == 0) 135325322Sgordon raid3_dump(req); 136325322Sgordon else 137325322Sgordon gctl_error(req, "Unknown command: %s.", name); 138325322Sgordon} 139325322Sgordon 140325322Sgordonstatic void 141325322Sgordonraid3_label(struct gctl_req *req) 142325322Sgordon{ 143325322Sgordon struct g_raid3_metadata md; 144325322Sgordon u_char sector[512]; 145325322Sgordon const char *str; 146325322Sgordon char param[16]; 147325322Sgordon int *hardcode, *nargs, *noautosync, *round_robin; 148325322Sgordon int error, i; 149325322Sgordon unsigned sectorsize; 150325322Sgordon off_t mediasize; 151325322Sgordon 152325322Sgordon nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 153325322Sgordon if (nargs == NULL) { 154325322Sgordon gctl_error(req, "No '%s' argument.", "nargs"); 155325322Sgordon return; 156325322Sgordon } 157325322Sgordon if (*nargs < 4) { 158325322Sgordon gctl_error(req, "Too few arguments."); 159325322Sgordon return; 160325322Sgordon } 161325322Sgordon#ifndef BITCOUNT 162325322Sgordon#define BITCOUNT(x) (((BX_(x) + (BX_(x) >> 4)) & 0x0F0F0F0F) % 255) 163325322Sgordon#define BX_(x) ((x) - (((x) >> 1) & 0x77777777) - \ 164325322Sgordon (((x) >> 2) & 0x33333333) - (((x) >> 3) & 0x11111111)) 165325322Sgordon#endif 166325322Sgordon if (BITCOUNT(*nargs - 2) != 1) { 167325322Sgordon gctl_error(req, "Invalid number of components."); 168325322Sgordon return; 169325322Sgordon } 170325322Sgordon 171325322Sgordon strlcpy(md.md_magic, G_RAID3_MAGIC, sizeof(md.md_magic)); 172325322Sgordon md.md_version = G_RAID3_VERSION; 173325322Sgordon str = gctl_get_asciiparam(req, "arg0"); 174325322Sgordon if (str == NULL) { 175325322Sgordon gctl_error(req, "No 'arg%u' argument.", 0); 176325322Sgordon return; 177325322Sgordon } 178325322Sgordon strlcpy(md.md_name, str, sizeof(md.md_name)); 179325322Sgordon md.md_all = *nargs - 1; 180325322Sgordon md.md_mflags = 0; 181325322Sgordon md.md_dflags = 0; 182325322Sgordon md.md_syncid = 1; 183325322Sgordon md.md_sync_offset = 0; 184325322Sgordon noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 185325322Sgordon if (noautosync == NULL) { 186325322Sgordon gctl_error(req, "No '%s' argument.", "noautosync"); 187325322Sgordon return; 188325322Sgordon } 189325322Sgordon if (*noautosync) 190325322Sgordon md.md_mflags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 191325322Sgordon round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin)); 192325322Sgordon if (round_robin == NULL) { 193325322Sgordon gctl_error(req, "No '%s' argument.", "round_robin"); 194325322Sgordon return; 195325322Sgordon } 196325322Sgordon if (*round_robin) 197325322Sgordon md.md_mflags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 198325322Sgordon hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 199325322Sgordon if (hardcode == NULL) { 200325322Sgordon gctl_error(req, "No '%s' argument.", "hardcode"); 201325322Sgordon return; 202325322Sgordon } 203325322Sgordon 204325322Sgordon /* 205325322Sgordon * Calculate sectorsize by finding least common multiple from 206325322Sgordon * sectorsizes of every disk and find the smallest mediasize. 207325322Sgordon */ 208325322Sgordon mediasize = 0; 209325322Sgordon sectorsize = 0; 210325322Sgordon for (i = 1; i < *nargs; i++) { 211325322Sgordon unsigned ssize; 212325322Sgordon off_t msize; 213325322Sgordon 214325322Sgordon snprintf(param, sizeof(param), "arg%u", i); 215325322Sgordon str = gctl_get_asciiparam(req, param); 216325322Sgordon 217325322Sgordon msize = g_get_mediasize(str); 218325322Sgordon ssize = g_get_sectorsize(str); 219325322Sgordon if (msize == 0 || ssize == 0) { 220325322Sgordon gctl_error(req, "Can't get informations about %s: %s.", 221325322Sgordon str, strerror(errno)); 222325322Sgordon return; 223325322Sgordon } 224325322Sgordon msize -= ssize; 225325322Sgordon if (mediasize == 0 || (mediasize > 0 && msize < mediasize)) 226325322Sgordon mediasize = msize; 227325322Sgordon if (sectorsize == 0) 228325322Sgordon sectorsize = ssize; 229325322Sgordon else 230325322Sgordon sectorsize = g_lcm(sectorsize, ssize); 231325322Sgordon } 232325322Sgordon md.md_mediasize = mediasize * (*nargs - 2); 233325322Sgordon md.md_sectorsize = sectorsize * (*nargs - 2); 234325322Sgordon 235325322Sgordon /* 236325322Sgordon * Clear last sector first, to spoil all components if device exists. 237325322Sgordon */ 238325322Sgordon for (i = 1; i < *nargs; i++) { 239325322Sgordon snprintf(param, sizeof(param), "arg%u", i); 240325322Sgordon str = gctl_get_asciiparam(req, param); 241325322Sgordon 242325322Sgordon error = g_metadata_clear(str, NULL); 243325322Sgordon if (error != 0) { 244325322Sgordon gctl_error(req, "Can't store metadata on %s: %s.", str, 245325322Sgordon strerror(error)); 246325322Sgordon return; 247330568Sgordon } 248325322Sgordon } 249325322Sgordon 250325322Sgordon /* 251325322Sgordon * Ok, store metadata (use disk number as priority). 252325322Sgordon */ 253325322Sgordon for (i = 1; i < *nargs; i++) { 254325322Sgordon snprintf(param, sizeof(param), "arg%u", i); 255325322Sgordon str = gctl_get_asciiparam(req, param); 256325322Sgordon 257325322Sgordon md.md_no = i - 1; 258325322Sgordon if (!*hardcode) 259325322Sgordon bzero(md.md_provider, sizeof(md.md_provider)); 260325322Sgordon else { 261325322Sgordon if (strncmp(str, _PATH_DEV, strlen(_PATH_DEV)) == 0) 262325322Sgordon str += strlen(_PATH_DEV); 263325322Sgordon strlcpy(md.md_provider, str, sizeof(md.md_provider)); 264325322Sgordon } 265325322Sgordon raid3_metadata_encode(&md, sector); 266325322Sgordon error = g_metadata_store(str, sector, sizeof(sector)); 267325322Sgordon if (error != 0) { 268325322Sgordon fprintf(stderr, "Can't store metadata on %s: %s.\n", 269325322Sgordon str, strerror(error)); 270325322Sgordon gctl_error(req, "Not fully done."); 271325322Sgordon continue; 272325322Sgordon } 273325322Sgordon if (verbose) 274325322Sgordon printf("Metadata value stored on %s.\n", str); 275325322Sgordon } 276325322Sgordon} 277325322Sgordon 278325322Sgordonstatic void 279325322Sgordonraid3_clear(struct gctl_req *req) 280325322Sgordon{ 281325322Sgordon const char *name; 282325322Sgordon char param[16]; 283325322Sgordon int *nargs, error, i; 284325322Sgordon 285325322Sgordon nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 286330568Sgordon if (nargs == NULL) { 287325322Sgordon gctl_error(req, "No '%s' argument.", "nargs"); 288325322Sgordon return; 289325322Sgordon } 290325322Sgordon if (*nargs < 1) { 291325322Sgordon gctl_error(req, "Too few arguments."); 292325322Sgordon return; 293325322Sgordon } 294325322Sgordon 295325322Sgordon for (i = 0; i < *nargs; i++) { 296325322Sgordon snprintf(param, sizeof(param), "arg%u", i); 297325322Sgordon name = gctl_get_asciiparam(req, param); 298325322Sgordon 299325322Sgordon error = g_metadata_clear(name, G_RAID3_MAGIC); 300325322Sgordon if (error != 0) { 301325322Sgordon fprintf(stderr, "Can't clear metadata on %s: %s.\n", 302325322Sgordon name, strerror(error)); 303325322Sgordon gctl_error(req, "Not fully done."); 304330568Sgordon continue; 305325322Sgordon } 306325322Sgordon if (verbose) 307325322Sgordon printf("Metadata cleared on %s.\n", name); 308325322Sgordon } 309325322Sgordon} 310325322Sgordon 311325322Sgordonstatic void 312325322Sgordonraid3_dump(struct gctl_req *req) 313325322Sgordon{ 314325322Sgordon struct g_raid3_metadata md, tmpmd; 315330568Sgordon const char *name; 316330568Sgordon char param[16]; 317330568Sgordon int *nargs, error, i; 318330568Sgordon 319330568Sgordon nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 320330568Sgordon if (nargs == NULL) { 321330568Sgordon gctl_error(req, "No '%s' argument.", "nargs"); 322330568Sgordon return; 323330568Sgordon } 324330568Sgordon if (*nargs < 1) { 325330568Sgordon gctl_error(req, "Too few arguments."); 326330568Sgordon return; 327330568Sgordon } 328330568Sgordon 329330568Sgordon for (i = 0; i < *nargs; i++) { 330330568Sgordon snprintf(param, sizeof(param), "arg%u", i); 331330568Sgordon name = gctl_get_asciiparam(req, param); 332330568Sgordon 333330568Sgordon error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd), 334330568Sgordon G_RAID3_MAGIC); 335330568Sgordon if (error != 0) { 336330568Sgordon fprintf(stderr, "Can't read metadata from %s: %s.\n", 337330568Sgordon name, strerror(error)); 338330568Sgordon gctl_error(req, "Not fully done."); 339330568Sgordon continue; 340330568Sgordon } 341330568Sgordon if (raid3_metadata_decode((u_char *)&tmpmd, &md) != 0) { 342330568Sgordon fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 343330568Sgordon name); 344330568Sgordon gctl_error(req, "Not fully done."); 345330568Sgordon continue; 346330568Sgordon } 347330568Sgordon printf("Metadata on %s:\n", name); 348330568Sgordon raid3_metadata_dump(&md); 349330568Sgordon printf("\n"); 350330568Sgordon } 351330568Sgordon} 352330568Sgordon