geom_raid3.c revision 142727
1139743Simp/*- 254122Smarcel * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 354122Smarcel * All rights reserved. 454122Smarcel * 554122Smarcel * Redistribution and use in source and binary forms, with or without 654122Smarcel * modification, are permitted provided that the following conditions 754122Smarcel * are met: 854122Smarcel * 1. Redistributions of source code must retain the above copyright 954122Smarcel * notice, this list of conditions and the following disclaimer. 1054122Smarcel * 2. Redistributions in binary form must reproduce the above copyright 1154122Smarcel * notice, this list of conditions and the following disclaimer in the 1254122Smarcel * documentation and/or other materials provided with the distribution. 1354122Smarcel * 1454122Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1565067Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1654122Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1754122Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 1854122Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1954122Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2054122Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2154122Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2254122Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2354122Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2454122Smarcel * SUCH DAMAGE. 2554122Smarcel */ 2654122Smarcel 2754122Smarcel#include <sys/cdefs.h> 2854122Smarcel__FBSDID("$FreeBSD: head/sbin/geom/class/raid3/geom_raid3.c 142727 2005-02-27 23:07:47Z pjd $"); 2954122Smarcel 3054122Smarcel#include <sys/param.h> 3154122Smarcel#include <errno.h> 3254122Smarcel#include <paths.h> 3354122Smarcel#include <stdio.h> 3454122Smarcel#include <stdlib.h> 35221426Snetchild#include <stdint.h> 36221426Snetchild#include <string.h> 37221426Snetchild#include <strings.h> 38221426Snetchild#include <assert.h> 39221426Snetchild#include <libgeom.h> 40221426Snetchild#include <geom/raid3/g_raid3.h> 41221426Snetchild#include <core/geom.h> 42221426Snetchild#include <misc/subr.h> 43221426Snetchild 44221426Snetchild 45221426Snetchilduint32_t lib_version = G_LIB_VERSION; 4657858Snsayeruint32_t version = G_RAID3_VERSION; 4757858Snsayer 4857998Snsayerstatic void raid3_main(struct gctl_req *req, unsigned f); 4957998Snsayerstatic void raid3_clear(struct gctl_req *req); 5057998Snsayerstatic void raid3_dump(struct gctl_req *req); 5157998Snsayerstatic void raid3_label(struct gctl_req *req); 5257998Snsayer 5357998Snsayerstruct g_command class_commands[] = { 5457998Snsayer { "clear", G_FLAG_VERBOSE, raid3_main, G_NULL_OPTS }, 5557998Snsayer { "configure", G_FLAG_VERBOSE, NULL, 5657998Snsayer { 5757998Snsayer { 'a', "autosync", NULL, G_TYPE_NONE }, 5857998Snsayer { 'd', "dynamic", NULL, G_TYPE_NONE }, 5957998Snsayer { 'h', "hardcode", NULL, G_TYPE_NONE }, 6057858Snsayer { 'n', "noautosync", NULL, G_TYPE_NONE }, 61130453Sphk { 'r', "round_robin", NULL, G_TYPE_NONE }, 62130453Sphk { 'R', "noround_robin", NULL, G_TYPE_NONE }, 6357858Snsayer { 'w', "verify", NULL, G_TYPE_NONE }, 6457858Snsayer { 'W', "noverify", NULL, G_TYPE_NONE }, 65130453Sphk G_OPT_SENTINEL 66130453Sphk } 67130453Sphk }, 68130453Sphk { "dump", 0, raid3_main, G_NULL_OPTS }, 69130453Sphk { "insert", G_FLAG_VERBOSE, NULL, 70130453Sphk { 71130453Sphk { 'h', "hardcode", NULL, G_TYPE_NONE }, 72130453Sphk { 'n', "number", NULL, G_TYPE_NUMBER }, 73130453Sphk G_OPT_SENTINEL 74130453Sphk } 7554122Smarcel }, 7654122Smarcel { "label", G_FLAG_VERBOSE, raid3_main, 7786555Smarcel { 7886555Smarcel { 'h', "hardcode", NULL, G_TYPE_NONE }, 7986555Smarcel { 'n', "noautosync", NULL, G_TYPE_NONE }, 8086555Smarcel { 'r', "round_robin", NULL, G_TYPE_NONE }, 8186555Smarcel { 'w', "verify", NULL, G_TYPE_NONE }, 8286555Smarcel G_OPT_SENTINEL 8386555Smarcel } 8486555Smarcel }, 8586555Smarcel { "rebuild", G_FLAG_VERBOSE, NULL, G_NULL_OPTS }, 8686555Smarcel { "remove", G_FLAG_VERBOSE, NULL, 8786555Smarcel { 8886555Smarcel { 'n', "number", NULL, G_TYPE_NUMBER }, 8986555Smarcel G_OPT_SENTINEL 9086555Smarcel } 9186555Smarcel }, 9286555Smarcel { "stop", G_FLAG_VERBOSE, NULL, 9386555Smarcel { 9486555Smarcel { 'f', "force", NULL, G_TYPE_NONE }, 9586555Smarcel G_OPT_SENTINEL 9686555Smarcel } 9786555Smarcel }, 9886555Smarcel G_CMD_SENTINEL 9986555Smarcel}; 10086555Smarcel 10186555Smarcelstatic int verbose = 0; 10286555Smarcel 10386555Smarcelvoid usage(const char *); 10486555Smarcelvoid 10586555Smarcelusage(const char *comm) 10686555Smarcel{ 10786555Smarcel fprintf(stderr, 10886555Smarcel "usage: %s label [-hnrvw] name prov prov prov ...\n" 10986555Smarcel " %s clear [-v] prov ...\n" 11086555Smarcel " %s dump prov ...\n" 11186555Smarcel " %s configure [-adhnrRvwW] name\n" 11286555Smarcel " %s rebuild [-v] name prov\n" 11386555Smarcel " %s insert [-hv] <-n number> name prov\n" 11486555Smarcel " %s remove [-v] <-n number> name\n" 11586555Smarcel " %s stop [-fv] name ...\n", 11686555Smarcel comm, comm, comm, comm, comm, comm, comm, comm); 117168477Sscottl} 118168477Sscottl 11986555Smarcelstatic void 12086555Smarcelraid3_main(struct gctl_req *req, unsigned flags) 12186555Smarcel{ 12286555Smarcel const char *name; 12386555Smarcel 12486555Smarcel if ((flags & G_FLAG_VERBOSE) != 0) 12554122Smarcel verbose = 1; 12654122Smarcel 12786555Smarcel name = gctl_get_asciiparam(req, "verb"); 12854122Smarcel if (name == NULL) { 12954122Smarcel gctl_error(req, "No '%s' argument.", "verb"); 13054122Smarcel return; 13154122Smarcel } 13286555Smarcel if (strcmp(name, "label") == 0) 13386555Smarcel raid3_label(req); 13486555Smarcel else if (strcmp(name, "clear") == 0) 13586555Smarcel raid3_clear(req); 13686555Smarcel else if (strcmp(name, "dump") == 0) 13786555Smarcel raid3_dump(req); 13886555Smarcel else 13986555Smarcel gctl_error(req, "Unknown command: %s.", name); 14086555Smarcel} 14186555Smarcel 14286555Smarcelstatic void 14386555Smarcelraid3_label(struct gctl_req *req) 14486555Smarcel{ 14554122Smarcel struct g_raid3_metadata md; 146168477Sscottl u_char sector[512]; 147168477Sscottl const char *str; 148168602Sscottl char param[16]; 149168602Sscottl int *hardcode, *nargs, *noautosync, *round_robin, *verify; 150168602Sscottl int error, i; 151168602Sscottl unsigned sectorsize, ssize; 152168602Sscottl off_t mediasize, msize; 153168602Sscottl 154168602Sscottl nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 155168602Sscottl if (nargs == NULL) { 156168602Sscottl gctl_error(req, "No '%s' argument.", "nargs"); 157168602Sscottl return; 158168602Sscottl } 159168602Sscottl if (*nargs < 4) { 160168602Sscottl gctl_error(req, "Too few arguments."); 161168602Sscottl return; 162168602Sscottl } 163168602Sscottl#ifndef BITCOUNT 164168602Sscottl#define BITCOUNT(x) (((BX_(x) + (BX_(x) >> 4)) & 0x0F0F0F0F) % 255) 165168602Sscottl#define BX_(x) ((x) - (((x) >> 1) & 0x77777777) - \ 166168602Sscottl (((x) >> 2) & 0x33333333) - (((x) >> 3) & 0x11111111)) 167168602Sscottl#endif 168168602Sscottl if (BITCOUNT(*nargs - 2) != 1) { 169168602Sscottl gctl_error(req, "Invalid number of components."); 170168602Sscottl return; 171168602Sscottl } 172168602Sscottl 173168477Sscottl strlcpy(md.md_magic, G_RAID3_MAGIC, sizeof(md.md_magic)); 174168602Sscottl md.md_version = G_RAID3_VERSION; 175168602Sscottl str = gctl_get_asciiparam(req, "arg0"); 176168477Sscottl if (str == NULL) { 177168477Sscottl gctl_error(req, "No 'arg%u' argument.", 0); 178104893Ssobomax return; 179104893Ssobomax } 180104893Ssobomax strlcpy(md.md_name, str, sizeof(md.md_name)); 181104893Ssobomax md.md_all = *nargs - 1; 182104893Ssobomax md.md_mflags = 0; 183104893Ssobomax md.md_dflags = 0; 184104893Ssobomax md.md_genid = 0; 185104893Ssobomax md.md_syncid = 1; 18654122Smarcel md.md_sync_offset = 0; 18754122Smarcel noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 18854122Smarcel if (noautosync == NULL) { 18954122Smarcel gctl_error(req, "No '%s' argument.", "noautosync"); 19054122Smarcel return; 19154122Smarcel } 19254122Smarcel if (*noautosync) 19354122Smarcel md.md_mflags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 19454122Smarcel round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin)); 19554122Smarcel if (round_robin == NULL) { 19654122Smarcel gctl_error(req, "No '%s' argument.", "round_robin"); 19754122Smarcel return; 19854122Smarcel } 19954122Smarcel if (*round_robin) 20054122Smarcel md.md_mflags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 20154122Smarcel verify = gctl_get_paraml(req, "verify", sizeof(*verify)); 20254122Smarcel if (verify == NULL) { 20354122Smarcel gctl_error(req, "No '%s' argument.", "verify"); 20454122Smarcel return; 20554122Smarcel } 20654122Smarcel if (*verify) 20754122Smarcel md.md_mflags |= G_RAID3_DEVICE_FLAG_VERIFY; 20854122Smarcel if (*round_robin && *verify) { 20954122Smarcel gctl_error(req, "Both '%c' and '%c' options given.", 'r', 'w'); 21054122Smarcel return; 21154122Smarcel } 21254122Smarcel hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 21354122Smarcel if (hardcode == NULL) { 21454122Smarcel gctl_error(req, "No '%s' argument.", "hardcode"); 21554122Smarcel return; 21654122Smarcel } 21754122Smarcel 21854122Smarcel /* 21954122Smarcel * Calculate sectorsize by finding least common multiple from 22054122Smarcel * sectorsizes of every disk and find the smallest mediasize. 22154122Smarcel */ 22254122Smarcel mediasize = 0; 22354122Smarcel sectorsize = 0; 22454122Smarcel for (i = 1; i < *nargs; i++) { 22554122Smarcel snprintf(param, sizeof(param), "arg%u", i); 22654122Smarcel str = gctl_get_asciiparam(req, param); 22754122Smarcel 22854122Smarcel msize = g_get_mediasize(str); 22954122Smarcel ssize = g_get_sectorsize(str); 23054122Smarcel if (msize == 0 || ssize == 0) { 23154122Smarcel gctl_error(req, "Can't get informations about %s: %s.", 23286607Siedowse str, strerror(errno)); 23354122Smarcel return; 23454122Smarcel } 23554122Smarcel msize -= ssize; 23685203Sdes if (mediasize == 0 || (mediasize > 0 && msize < mediasize)) 23785203Sdes mediasize = msize; 23885203Sdes if (sectorsize == 0) 23985203Sdes sectorsize = ssize; 24085203Sdes else 24154122Smarcel sectorsize = g_lcm(sectorsize, ssize); 24254122Smarcel } 24354122Smarcel md.md_mediasize = mediasize * (*nargs - 2); 244173422Skib md.md_sectorsize = sectorsize * (*nargs - 2); 245173422Skib 246173422Skib /* 24754122Smarcel * Clear last sector first, to spoil all components if device exists. 24854122Smarcel */ 249173422Skib for (i = 1; i < *nargs; i++) { 25054122Smarcel snprintf(param, sizeof(param), "arg%u", i); 25154122Smarcel str = gctl_get_asciiparam(req, param); 25285127Sdes 25385127Sdes error = g_metadata_clear(str, NULL); 25485127Sdes if (error != 0) { 25585127Sdes gctl_error(req, "Can't store metadata on %s: %s.", str, 25685127Sdes strerror(error)); 25785127Sdes return; 25885127Sdes } 25954122Smarcel } 26054122Smarcel 26154122Smarcel /* 26254122Smarcel * Ok, store metadata (use disk number as priority). 26354122Smarcel */ 26454122Smarcel for (i = 1; i < *nargs; i++) { 26554122Smarcel snprintf(param, sizeof(param), "arg%u", i); 26654122Smarcel str = gctl_get_asciiparam(req, param); 26754122Smarcel 26854122Smarcel msize = g_get_mediasize(str); 26954122Smarcel ssize = g_get_sectorsize(str); 27054122Smarcel if (mediasize < msize - ssize) { 27154122Smarcel fprintf(stderr, 27254122Smarcel "warning: %s: only %jd bytes from %jd bytes used.\n", 27354122Smarcel str, (intmax_t)mediasize, (intmax_t)(msize - ssize)); 27454122Smarcel } 27554122Smarcel 27654122Smarcel md.md_no = i - 1; 27754122Smarcel md.md_provsize = msize; 278130689Sbms if (!*hardcode) 27954122Smarcel bzero(md.md_provider, sizeof(md.md_provider)); 280104893Ssobomax else { 281216813Sscf if (strncmp(str, _PATH_DEV, strlen(_PATH_DEV)) == 0) 282130691Sbms str += strlen(_PATH_DEV); 28354122Smarcel strlcpy(md.md_provider, str, sizeof(md.md_provider)); 28486540Smarcel } 28554122Smarcel if (*verify && md.md_no == md.md_all - 1) { 28654122Smarcel /* 28754122Smarcel * In "verify" mode, force synchronization of parity 28854122Smarcel * component on start. 28954122Smarcel */ 29054122Smarcel md.md_syncid = 0; 29154122Smarcel } 29254122Smarcel raid3_metadata_encode(&md, sector); 29354122Smarcel error = g_metadata_store(str, sector, sizeof(sector)); 29454122Smarcel if (error != 0) { 29554122Smarcel fprintf(stderr, "Can't store metadata on %s: %s.\n", 29654122Smarcel str, strerror(error)); 29754122Smarcel gctl_error(req, "Not fully done."); 29854122Smarcel continue; 29954122Smarcel } 30054122Smarcel if (verbose) 30154122Smarcel printf("Metadata value stored on %s.\n", str); 30254122Smarcel } 30354122Smarcel} 30454122Smarcel 30554122Smarcelstatic void 306131461Snetchildraid3_clear(struct gctl_req *req) 30754122Smarcel{ 30854122Smarcel const char *name; 30954122Smarcel char param[16]; 31054122Smarcel int *nargs, error, i; 31154122Smarcel 31254122Smarcel nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 31354122Smarcel if (nargs == NULL) { 31454122Smarcel gctl_error(req, "No '%s' argument.", "nargs"); 31554122Smarcel return; 31654122Smarcel } 31754122Smarcel if (*nargs < 1) { 31854122Smarcel gctl_error(req, "Too few arguments."); 31954122Smarcel return; 32054122Smarcel } 32154122Smarcel 32254122Smarcel for (i = 0; i < *nargs; i++) { 32354122Smarcel snprintf(param, sizeof(param), "arg%u", i); 32454122Smarcel name = gctl_get_asciiparam(req, param); 32554122Smarcel 32654122Smarcel error = g_metadata_clear(name, G_RAID3_MAGIC); 32754122Smarcel if (error != 0) { 32854122Smarcel fprintf(stderr, "Can't clear metadata on %s: %s.\n", 32954122Smarcel name, strerror(error)); 33054122Smarcel gctl_error(req, "Not fully done."); 33154122Smarcel continue; 33254122Smarcel } 33354122Smarcel if (verbose) 33454122Smarcel printf("Metadata cleared on %s.\n", name); 33554122Smarcel } 33654122Smarcel} 33754122Smarcel 33854122Smarcelstatic void 33954122Smarcelraid3_dump(struct gctl_req *req) 34054122Smarcel{ 34185139Smarcel struct g_raid3_metadata md, tmpmd; 34254122Smarcel const char *name; 34354122Smarcel char param[16]; 34454122Smarcel int *nargs, error, i; 34585139Smarcel 34654122Smarcel nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 34754122Smarcel if (nargs == NULL) { 34885139Smarcel gctl_error(req, "No '%s' argument.", "nargs"); 34954122Smarcel return; 35054122Smarcel } 35185139Smarcel if (*nargs < 1) { 35254122Smarcel gctl_error(req, "Too few arguments."); 35354122Smarcel return; 35485139Smarcel } 35554122Smarcel 35654122Smarcel for (i = 0; i < *nargs; i++) { 35754122Smarcel snprintf(param, sizeof(param), "arg%u", i); 35854122Smarcel name = gctl_get_asciiparam(req, param); 35954122Smarcel 36054122Smarcel error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd), 36185139Smarcel G_RAID3_MAGIC); 36254122Smarcel if (error != 0) { 36385139Smarcel fprintf(stderr, "Can't read metadata from %s: %s.\n", 36454122Smarcel name, strerror(error)); 36554122Smarcel gctl_error(req, "Not fully done."); 36654122Smarcel continue; 36754122Smarcel } 36854122Smarcel if (raid3_metadata_decode((u_char *)&tmpmd, &md) != 0) { 36954122Smarcel fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 37085139Smarcel name); 37154122Smarcel gctl_error(req, "Not fully done."); 37285139Smarcel continue; 37354122Smarcel } 37454122Smarcel printf("Metadata on %s:\n", name); 37554122Smarcel raid3_metadata_dump(&md); 37654122Smarcel printf("\n"); 37754122Smarcel } 37885139Smarcel} 379125997Sbms