1133808Spjd/*- 2142727Spjd * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3133808Spjd * All rights reserved. 4133808Spjd * 5133808Spjd * Redistribution and use in source and binary forms, with or without 6133808Spjd * modification, are permitted provided that the following conditions 7133808Spjd * are met: 8133808Spjd * 1. Redistributions of source code must retain the above copyright 9133808Spjd * notice, this list of conditions and the following disclaimer. 10133808Spjd * 2. Redistributions in binary form must reproduce the above copyright 11133808Spjd * notice, this list of conditions and the following disclaimer in the 12133808Spjd * documentation and/or other materials provided with the distribution. 13155175Spjd * 14133808Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15133808Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16133808Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17133808Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18133808Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19133808Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20133808Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21133808Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22133808Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23133808Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24133808Spjd * SUCH DAMAGE. 25133808Spjd */ 26133808Spjd 27133808Spjd#include <sys/cdefs.h> 28133808Spjd__FBSDID("$FreeBSD$"); 29133808Spjd 30133808Spjd#include <sys/param.h> 31133808Spjd#include <errno.h> 32133808Spjd#include <paths.h> 33133808Spjd#include <stdio.h> 34133808Spjd#include <stdlib.h> 35133808Spjd#include <stdint.h> 36133808Spjd#include <string.h> 37133808Spjd#include <strings.h> 38133808Spjd#include <assert.h> 39133808Spjd#include <libgeom.h> 40133808Spjd#include <geom/raid3/g_raid3.h> 41133808Spjd#include <core/geom.h> 42133808Spjd#include <misc/subr.h> 43133808Spjd 44133808Spjd 45133808Spjduint32_t lib_version = G_LIB_VERSION; 46133808Spjduint32_t version = G_RAID3_VERSION; 47133808Spjd 48133808Spjdstatic void raid3_main(struct gctl_req *req, unsigned f); 49133808Spjdstatic void raid3_clear(struct gctl_req *req); 50133808Spjdstatic void raid3_dump(struct gctl_req *req); 51133808Spjdstatic void raid3_label(struct gctl_req *req); 52133808Spjd 53133808Spjdstruct g_command class_commands[] = { 54212554Spjd { "clear", G_FLAG_VERBOSE, raid3_main, G_NULL_OPTS, 55143586Spjd "[-v] prov ..." 56143586Spjd }, 57133808Spjd { "configure", G_FLAG_VERBOSE, NULL, 58133808Spjd { 59162868Spjd { 'a', "autosync", NULL, G_TYPE_BOOL }, 60162868Spjd { 'd', "dynamic", NULL, G_TYPE_BOOL }, 61163888Spjd { 'f', "failsync", NULL, G_TYPE_BOOL }, 62163888Spjd { 'F', "nofailsync", NULL, G_TYPE_BOOL }, 63162868Spjd { 'h', "hardcode", NULL, G_TYPE_BOOL }, 64162868Spjd { 'n', "noautosync", NULL, G_TYPE_BOOL }, 65162868Spjd { 'r', "round_robin", NULL, G_TYPE_BOOL }, 66162868Spjd { 'R', "noround_robin", NULL, G_TYPE_BOOL }, 67162868Spjd { 'w', "verify", NULL, G_TYPE_BOOL }, 68162868Spjd { 'W', "noverify", NULL, G_TYPE_BOOL }, 69133808Spjd G_OPT_SENTINEL 70143586Spjd }, 71212554Spjd "[-adfFhnrRvwW] name" 72133808Spjd }, 73212554Spjd { "dump", 0, raid3_main, G_NULL_OPTS, 74143586Spjd "prov ..." 75143586Spjd }, 76133808Spjd { "insert", G_FLAG_VERBOSE, NULL, 77133808Spjd { 78162868Spjd { 'h', "hardcode", NULL, G_TYPE_BOOL }, 79246081Smav { 'n', "number", G_VAL_OPTIONAL, G_TYPE_NUMBER }, 80133808Spjd G_OPT_SENTINEL 81143586Spjd }, 82212554Spjd "[-hv] <-n number> name prov" 83133808Spjd }, 84133808Spjd { "label", G_FLAG_VERBOSE, raid3_main, 85133808Spjd { 86162868Spjd { 'h', "hardcode", NULL, G_TYPE_BOOL }, 87163888Spjd { 'F', "nofailsync", NULL, G_TYPE_BOOL }, 88162868Spjd { 'n', "noautosync", NULL, G_TYPE_BOOL }, 89162868Spjd { 'r', "round_robin", NULL, G_TYPE_BOOL }, 90212554Spjd { 's', "sectorsize", "0", G_TYPE_NUMBER }, 91162868Spjd { 'w', "verify", NULL, G_TYPE_BOOL }, 92133808Spjd G_OPT_SENTINEL 93143586Spjd }, 94212554Spjd "[-hFnrvw] [-s blocksize] name prov prov prov ..." 95133808Spjd }, 96212554Spjd { "rebuild", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, 97143586Spjd "[-v] name prov" 98143586Spjd }, 99133808Spjd { "remove", G_FLAG_VERBOSE, NULL, 100133808Spjd { 101133808Spjd { 'n', "number", NULL, G_TYPE_NUMBER }, 102133808Spjd G_OPT_SENTINEL 103143586Spjd }, 104212554Spjd "[-v] <-n number> name" 105133808Spjd }, 106133808Spjd { "stop", G_FLAG_VERBOSE, NULL, 107133808Spjd { 108162868Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 109133808Spjd G_OPT_SENTINEL 110143586Spjd }, 111212554Spjd "[-fv] name ..." 112133808Spjd }, 113133808Spjd G_CMD_SENTINEL 114133808Spjd}; 115133808Spjd 116133808Spjdstatic int verbose = 0; 117133808Spjd 118133808Spjdstatic void 119133808Spjdraid3_main(struct gctl_req *req, unsigned flags) 120133808Spjd{ 121133808Spjd const char *name; 122133808Spjd 123133808Spjd if ((flags & G_FLAG_VERBOSE) != 0) 124133808Spjd verbose = 1; 125133808Spjd 126153190Spjd name = gctl_get_ascii(req, "verb"); 127133808Spjd if (name == NULL) { 128133808Spjd gctl_error(req, "No '%s' argument.", "verb"); 129133808Spjd return; 130133808Spjd } 131133808Spjd if (strcmp(name, "label") == 0) 132133808Spjd raid3_label(req); 133133808Spjd else if (strcmp(name, "clear") == 0) 134133808Spjd raid3_clear(req); 135133808Spjd else if (strcmp(name, "dump") == 0) 136133808Spjd raid3_dump(req); 137133808Spjd else 138133808Spjd gctl_error(req, "Unknown command: %s.", name); 139133808Spjd} 140133808Spjd 141133808Spjdstatic void 142133808Spjdraid3_label(struct gctl_req *req) 143133808Spjd{ 144133808Spjd struct g_raid3_metadata md; 145133808Spjd u_char sector[512]; 146133808Spjd const char *str; 147134420Spjd unsigned sectorsize, ssize; 148134420Spjd off_t mediasize, msize; 149163888Spjd int hardcode, round_robin, verify; 150163888Spjd int error, i, nargs; 151133808Spjd 152153190Spjd nargs = gctl_get_int(req, "nargs"); 153153190Spjd if (nargs < 4) { 154133808Spjd gctl_error(req, "Too few arguments."); 155133808Spjd return; 156133808Spjd } 157153190Spjd if (bitcount32(nargs - 2) != 1) { 158133808Spjd gctl_error(req, "Invalid number of components."); 159133808Spjd return; 160133808Spjd } 161133808Spjd 162133808Spjd strlcpy(md.md_magic, G_RAID3_MAGIC, sizeof(md.md_magic)); 163133808Spjd md.md_version = G_RAID3_VERSION; 164153190Spjd str = gctl_get_ascii(req, "arg0"); 165133808Spjd strlcpy(md.md_name, str, sizeof(md.md_name)); 166147947Spjd md.md_id = arc4random(); 167153190Spjd md.md_all = nargs - 1; 168133808Spjd md.md_mflags = 0; 169133808Spjd md.md_dflags = 0; 170139295Spjd md.md_genid = 0; 171133808Spjd md.md_syncid = 1; 172133808Spjd md.md_sync_offset = 0; 173163888Spjd if (gctl_get_int(req, "noautosync")) 174133808Spjd md.md_mflags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 175163888Spjd if (gctl_get_int(req, "nofailsync")) 176163888Spjd md.md_mflags |= G_RAID3_DEVICE_FLAG_NOFAILSYNC; 177153190Spjd round_robin = gctl_get_int(req, "round_robin"); 178153190Spjd if (round_robin) 179134124Spjd md.md_mflags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 180153190Spjd verify = gctl_get_int(req, "verify"); 181153190Spjd if (verify) 182134168Spjd md.md_mflags |= G_RAID3_DEVICE_FLAG_VERIFY; 183153190Spjd if (round_robin && verify) { 184134168Spjd gctl_error(req, "Both '%c' and '%c' options given.", 'r', 'w'); 185134168Spjd return; 186134168Spjd } 187153190Spjd hardcode = gctl_get_int(req, "hardcode"); 188133808Spjd 189133808Spjd /* 190133808Spjd * Calculate sectorsize by finding least common multiple from 191133808Spjd * sectorsizes of every disk and find the smallest mediasize. 192133808Spjd */ 193133808Spjd mediasize = 0; 194212554Spjd sectorsize = gctl_get_intmax(req, "sectorsize"); 195153190Spjd for (i = 1; i < nargs; i++) { 196153190Spjd str = gctl_get_ascii(req, "arg%d", i); 197133808Spjd msize = g_get_mediasize(str); 198133808Spjd ssize = g_get_sectorsize(str); 199133808Spjd if (msize == 0 || ssize == 0) { 200133808Spjd gctl_error(req, "Can't get informations about %s: %s.", 201133808Spjd str, strerror(errno)); 202133808Spjd return; 203133808Spjd } 204133808Spjd msize -= ssize; 205133808Spjd if (mediasize == 0 || (mediasize > 0 && msize < mediasize)) 206133808Spjd mediasize = msize; 207133808Spjd if (sectorsize == 0) 208133808Spjd sectorsize = ssize; 209133808Spjd else 210133808Spjd sectorsize = g_lcm(sectorsize, ssize); 211133808Spjd } 212153190Spjd md.md_mediasize = mediasize * (nargs - 2); 213153190Spjd md.md_sectorsize = sectorsize * (nargs - 2); 214163204Spjd md.md_mediasize -= (md.md_mediasize % md.md_sectorsize); 215133808Spjd 216217305Sae if (md.md_sectorsize > MAXPHYS) { 217217305Sae gctl_error(req, "The blocksize is too big."); 218217305Sae return; 219217305Sae } 220217305Sae 221133808Spjd /* 222133808Spjd * Clear last sector first, to spoil all components if device exists. 223133808Spjd */ 224153190Spjd for (i = 1; i < nargs; i++) { 225153190Spjd str = gctl_get_ascii(req, "arg%d", i); 226133808Spjd error = g_metadata_clear(str, NULL); 227133808Spjd if (error != 0) { 228133808Spjd gctl_error(req, "Can't store metadata on %s: %s.", str, 229133808Spjd strerror(error)); 230133808Spjd return; 231133808Spjd } 232133808Spjd } 233133808Spjd 234133808Spjd /* 235133808Spjd * Ok, store metadata (use disk number as priority). 236133808Spjd */ 237153190Spjd for (i = 1; i < nargs; i++) { 238153190Spjd str = gctl_get_ascii(req, "arg%d", i); 239142727Spjd msize = g_get_mediasize(str); 240142727Spjd ssize = g_get_sectorsize(str); 241142727Spjd if (mediasize < msize - ssize) { 242134420Spjd fprintf(stderr, 243134420Spjd "warning: %s: only %jd bytes from %jd bytes used.\n", 244142727Spjd str, (intmax_t)mediasize, (intmax_t)(msize - ssize)); 245134420Spjd } 246134420Spjd 247133808Spjd md.md_no = i - 1; 248142727Spjd md.md_provsize = msize; 249153190Spjd if (!hardcode) 250133808Spjd bzero(md.md_provider, sizeof(md.md_provider)); 251133808Spjd else { 252213662Sae if (strncmp(str, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 253213662Sae str += sizeof(_PATH_DEV) - 1; 254133808Spjd strlcpy(md.md_provider, str, sizeof(md.md_provider)); 255133808Spjd } 256153190Spjd if (verify && md.md_no == md.md_all - 1) { 257134539Spjd /* 258134539Spjd * In "verify" mode, force synchronization of parity 259134539Spjd * component on start. 260134539Spjd */ 261134539Spjd md.md_syncid = 0; 262134539Spjd } 263133808Spjd raid3_metadata_encode(&md, sector); 264133808Spjd error = g_metadata_store(str, sector, sizeof(sector)); 265133808Spjd if (error != 0) { 266133808Spjd fprintf(stderr, "Can't store metadata on %s: %s.\n", 267133808Spjd str, strerror(error)); 268133808Spjd gctl_error(req, "Not fully done."); 269133808Spjd continue; 270133808Spjd } 271133808Spjd if (verbose) 272133808Spjd printf("Metadata value stored on %s.\n", str); 273133808Spjd } 274133808Spjd} 275133808Spjd 276133808Spjdstatic void 277133808Spjdraid3_clear(struct gctl_req *req) 278133808Spjd{ 279133808Spjd const char *name; 280153190Spjd int error, i, nargs; 281133808Spjd 282153190Spjd nargs = gctl_get_int(req, "nargs"); 283153190Spjd if (nargs < 1) { 284133808Spjd gctl_error(req, "Too few arguments."); 285133808Spjd return; 286133808Spjd } 287133808Spjd 288153190Spjd for (i = 0; i < nargs; i++) { 289153190Spjd name = gctl_get_ascii(req, "arg%d", i); 290133808Spjd error = g_metadata_clear(name, G_RAID3_MAGIC); 291133808Spjd if (error != 0) { 292133808Spjd fprintf(stderr, "Can't clear metadata on %s: %s.\n", 293133808Spjd name, strerror(error)); 294133808Spjd gctl_error(req, "Not fully done."); 295133808Spjd continue; 296133808Spjd } 297133808Spjd if (verbose) 298155175Spjd printf("Metadata cleared on %s.\n", name); 299133808Spjd } 300133808Spjd} 301133808Spjd 302133808Spjdstatic void 303133808Spjdraid3_dump(struct gctl_req *req) 304133808Spjd{ 305133808Spjd struct g_raid3_metadata md, tmpmd; 306133808Spjd const char *name; 307153190Spjd int error, i, nargs; 308133808Spjd 309153190Spjd nargs = gctl_get_int(req, "nargs"); 310153190Spjd if (nargs < 1) { 311133808Spjd gctl_error(req, "Too few arguments."); 312133808Spjd return; 313133808Spjd } 314133808Spjd 315153190Spjd for (i = 0; i < nargs; i++) { 316153190Spjd name = gctl_get_ascii(req, "arg%d", i); 317133808Spjd error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd), 318133808Spjd G_RAID3_MAGIC); 319133808Spjd if (error != 0) { 320133808Spjd fprintf(stderr, "Can't read metadata from %s: %s.\n", 321133808Spjd name, strerror(error)); 322133808Spjd gctl_error(req, "Not fully done."); 323133808Spjd continue; 324133808Spjd } 325133808Spjd if (raid3_metadata_decode((u_char *)&tmpmd, &md) != 0) { 326133808Spjd fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 327133808Spjd name); 328133808Spjd gctl_error(req, "Not fully done."); 329133808Spjd continue; 330133808Spjd } 331133808Spjd printf("Metadata on %s:\n", name); 332133808Spjd raid3_metadata_dump(&md); 333133808Spjd printf("\n"); 334133808Spjd } 335133808Spjd} 336