1133808Spjd/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4142727Spjd * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 5133808Spjd * All rights reserved. 6133808Spjd * 7133808Spjd * Redistribution and use in source and binary forms, with or without 8133808Spjd * modification, are permitted provided that the following conditions 9133808Spjd * are met: 10133808Spjd * 1. Redistributions of source code must retain the above copyright 11133808Spjd * notice, this list of conditions and the following disclaimer. 12133808Spjd * 2. Redistributions in binary form must reproduce the above copyright 13133808Spjd * notice, this list of conditions and the following disclaimer in the 14133808Spjd * documentation and/or other materials provided with the distribution. 15155175Spjd * 16133808Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17133808Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18133808Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19133808Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20133808Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21133808Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22133808Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23133808Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24133808Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25133808Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26133808Spjd * SUCH DAMAGE. 27133808Spjd */ 28133808Spjd 29133808Spjd#include <sys/cdefs.h> 30133808Spjd__FBSDID("$FreeBSD: stable/11/sbin/geom/class/raid3/geom_raid3.c 330726 2018-03-10 02:15:45Z asomers $"); 31133808Spjd 32133808Spjd#include <sys/param.h> 33133808Spjd#include <errno.h> 34133808Spjd#include <paths.h> 35133808Spjd#include <stdio.h> 36133808Spjd#include <stdlib.h> 37133808Spjd#include <stdint.h> 38133808Spjd#include <string.h> 39133808Spjd#include <strings.h> 40133808Spjd#include <assert.h> 41133808Spjd#include <libgeom.h> 42133808Spjd#include <geom/raid3/g_raid3.h> 43133808Spjd#include <core/geom.h> 44133808Spjd#include <misc/subr.h> 45133808Spjd 46133808Spjd 47133808Spjduint32_t lib_version = G_LIB_VERSION; 48133808Spjduint32_t version = G_RAID3_VERSION; 49133808Spjd 50133808Spjdstatic void raid3_main(struct gctl_req *req, unsigned f); 51133808Spjdstatic void raid3_clear(struct gctl_req *req); 52133808Spjdstatic void raid3_dump(struct gctl_req *req); 53133808Spjdstatic void raid3_label(struct gctl_req *req); 54133808Spjd 55133808Spjdstruct g_command class_commands[] = { 56212554Spjd { "clear", G_FLAG_VERBOSE, raid3_main, G_NULL_OPTS, 57143586Spjd "[-v] prov ..." 58143586Spjd }, 59133808Spjd { "configure", G_FLAG_VERBOSE, NULL, 60133808Spjd { 61162868Spjd { 'a', "autosync", NULL, G_TYPE_BOOL }, 62162868Spjd { 'd', "dynamic", NULL, G_TYPE_BOOL }, 63163888Spjd { 'f', "failsync", NULL, G_TYPE_BOOL }, 64163888Spjd { 'F', "nofailsync", NULL, G_TYPE_BOOL }, 65162868Spjd { 'h', "hardcode", NULL, G_TYPE_BOOL }, 66162868Spjd { 'n', "noautosync", NULL, G_TYPE_BOOL }, 67162868Spjd { 'r', "round_robin", NULL, G_TYPE_BOOL }, 68162868Spjd { 'R', "noround_robin", NULL, G_TYPE_BOOL }, 69162868Spjd { 'w', "verify", NULL, G_TYPE_BOOL }, 70162868Spjd { 'W', "noverify", NULL, G_TYPE_BOOL }, 71133808Spjd G_OPT_SENTINEL 72143586Spjd }, 73212554Spjd "[-adfFhnrRvwW] name" 74133808Spjd }, 75212554Spjd { "dump", 0, raid3_main, G_NULL_OPTS, 76143586Spjd "prov ..." 77143586Spjd }, 78133808Spjd { "insert", G_FLAG_VERBOSE, NULL, 79133808Spjd { 80162868Spjd { 'h', "hardcode", NULL, G_TYPE_BOOL }, 81245456Smav { 'n', "number", G_VAL_OPTIONAL, G_TYPE_NUMBER }, 82133808Spjd G_OPT_SENTINEL 83143586Spjd }, 84212554Spjd "[-hv] <-n number> name prov" 85133808Spjd }, 86133808Spjd { "label", G_FLAG_VERBOSE, raid3_main, 87133808Spjd { 88162868Spjd { 'h', "hardcode", NULL, G_TYPE_BOOL }, 89163888Spjd { 'F', "nofailsync", NULL, G_TYPE_BOOL }, 90162868Spjd { 'n', "noautosync", NULL, G_TYPE_BOOL }, 91162868Spjd { 'r', "round_robin", NULL, G_TYPE_BOOL }, 92212554Spjd { 's', "sectorsize", "0", G_TYPE_NUMBER }, 93162868Spjd { 'w', "verify", NULL, G_TYPE_BOOL }, 94133808Spjd G_OPT_SENTINEL 95143586Spjd }, 96212554Spjd "[-hFnrvw] [-s blocksize] name prov prov prov ..." 97133808Spjd }, 98212554Spjd { "rebuild", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, 99143586Spjd "[-v] name prov" 100143586Spjd }, 101133808Spjd { "remove", G_FLAG_VERBOSE, NULL, 102133808Spjd { 103133808Spjd { 'n', "number", NULL, G_TYPE_NUMBER }, 104133808Spjd G_OPT_SENTINEL 105143586Spjd }, 106212554Spjd "[-v] <-n number> name" 107133808Spjd }, 108133808Spjd { "stop", G_FLAG_VERBOSE, NULL, 109133808Spjd { 110162868Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 111133808Spjd G_OPT_SENTINEL 112143586Spjd }, 113212554Spjd "[-fv] name ..." 114133808Spjd }, 115133808Spjd G_CMD_SENTINEL 116133808Spjd}; 117133808Spjd 118133808Spjdstatic int verbose = 0; 119133808Spjd 120133808Spjdstatic void 121133808Spjdraid3_main(struct gctl_req *req, unsigned flags) 122133808Spjd{ 123133808Spjd const char *name; 124133808Spjd 125133808Spjd if ((flags & G_FLAG_VERBOSE) != 0) 126133808Spjd verbose = 1; 127133808Spjd 128153190Spjd name = gctl_get_ascii(req, "verb"); 129133808Spjd if (name == NULL) { 130133808Spjd gctl_error(req, "No '%s' argument.", "verb"); 131133808Spjd return; 132133808Spjd } 133133808Spjd if (strcmp(name, "label") == 0) 134133808Spjd raid3_label(req); 135133808Spjd else if (strcmp(name, "clear") == 0) 136133808Spjd raid3_clear(req); 137133808Spjd else if (strcmp(name, "dump") == 0) 138133808Spjd raid3_dump(req); 139133808Spjd else 140133808Spjd gctl_error(req, "Unknown command: %s.", name); 141133808Spjd} 142133808Spjd 143133808Spjdstatic void 144133808Spjdraid3_label(struct gctl_req *req) 145133808Spjd{ 146133808Spjd struct g_raid3_metadata md; 147133808Spjd u_char sector[512]; 148133808Spjd const char *str; 149134420Spjd unsigned sectorsize, ssize; 150134420Spjd off_t mediasize, msize; 151163888Spjd int hardcode, round_robin, verify; 152163888Spjd int error, i, nargs; 153133808Spjd 154330726Sasomers bzero(sector, sizeof(sector)); 155153190Spjd nargs = gctl_get_int(req, "nargs"); 156153190Spjd if (nargs < 4) { 157133808Spjd gctl_error(req, "Too few arguments."); 158133808Spjd return; 159133808Spjd } 160153190Spjd if (bitcount32(nargs - 2) != 1) { 161133808Spjd gctl_error(req, "Invalid number of components."); 162133808Spjd return; 163133808Spjd } 164133808Spjd 165133808Spjd strlcpy(md.md_magic, G_RAID3_MAGIC, sizeof(md.md_magic)); 166133808Spjd md.md_version = G_RAID3_VERSION; 167153190Spjd str = gctl_get_ascii(req, "arg0"); 168133808Spjd strlcpy(md.md_name, str, sizeof(md.md_name)); 169147947Spjd md.md_id = arc4random(); 170153190Spjd md.md_all = nargs - 1; 171133808Spjd md.md_mflags = 0; 172133808Spjd md.md_dflags = 0; 173139295Spjd md.md_genid = 0; 174133808Spjd md.md_syncid = 1; 175133808Spjd md.md_sync_offset = 0; 176163888Spjd if (gctl_get_int(req, "noautosync")) 177133808Spjd md.md_mflags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 178163888Spjd if (gctl_get_int(req, "nofailsync")) 179163888Spjd md.md_mflags |= G_RAID3_DEVICE_FLAG_NOFAILSYNC; 180153190Spjd round_robin = gctl_get_int(req, "round_robin"); 181153190Spjd if (round_robin) 182134124Spjd md.md_mflags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 183153190Spjd verify = gctl_get_int(req, "verify"); 184153190Spjd if (verify) 185134168Spjd md.md_mflags |= G_RAID3_DEVICE_FLAG_VERIFY; 186153190Spjd if (round_robin && verify) { 187134168Spjd gctl_error(req, "Both '%c' and '%c' options given.", 'r', 'w'); 188134168Spjd return; 189134168Spjd } 190153190Spjd hardcode = gctl_get_int(req, "hardcode"); 191133808Spjd 192133808Spjd /* 193133808Spjd * Calculate sectorsize by finding least common multiple from 194133808Spjd * sectorsizes of every disk and find the smallest mediasize. 195133808Spjd */ 196133808Spjd mediasize = 0; 197212554Spjd sectorsize = gctl_get_intmax(req, "sectorsize"); 198153190Spjd for (i = 1; i < nargs; i++) { 199153190Spjd str = gctl_get_ascii(req, "arg%d", i); 200133808Spjd msize = g_get_mediasize(str); 201133808Spjd ssize = g_get_sectorsize(str); 202133808Spjd if (msize == 0 || ssize == 0) { 203133808Spjd gctl_error(req, "Can't get informations about %s: %s.", 204133808Spjd str, strerror(errno)); 205133808Spjd return; 206133808Spjd } 207133808Spjd msize -= ssize; 208133808Spjd if (mediasize == 0 || (mediasize > 0 && msize < mediasize)) 209133808Spjd mediasize = msize; 210133808Spjd if (sectorsize == 0) 211133808Spjd sectorsize = ssize; 212133808Spjd else 213133808Spjd sectorsize = g_lcm(sectorsize, ssize); 214133808Spjd } 215153190Spjd md.md_mediasize = mediasize * (nargs - 2); 216153190Spjd md.md_sectorsize = sectorsize * (nargs - 2); 217163204Spjd md.md_mediasize -= (md.md_mediasize % md.md_sectorsize); 218133808Spjd 219217305Sae if (md.md_sectorsize > MAXPHYS) { 220217305Sae gctl_error(req, "The blocksize is too big."); 221217305Sae return; 222217305Sae } 223217305Sae 224133808Spjd /* 225133808Spjd * Clear last sector first, to spoil all components if device exists. 226133808Spjd */ 227153190Spjd for (i = 1; i < nargs; i++) { 228153190Spjd str = gctl_get_ascii(req, "arg%d", i); 229133808Spjd error = g_metadata_clear(str, NULL); 230133808Spjd if (error != 0) { 231133808Spjd gctl_error(req, "Can't store metadata on %s: %s.", str, 232133808Spjd strerror(error)); 233133808Spjd return; 234133808Spjd } 235133808Spjd } 236133808Spjd 237133808Spjd /* 238133808Spjd * Ok, store metadata (use disk number as priority). 239133808Spjd */ 240153190Spjd for (i = 1; i < nargs; i++) { 241153190Spjd str = gctl_get_ascii(req, "arg%d", i); 242142727Spjd msize = g_get_mediasize(str); 243142727Spjd ssize = g_get_sectorsize(str); 244142727Spjd if (mediasize < msize - ssize) { 245134420Spjd fprintf(stderr, 246134420Spjd "warning: %s: only %jd bytes from %jd bytes used.\n", 247142727Spjd str, (intmax_t)mediasize, (intmax_t)(msize - ssize)); 248134420Spjd } 249134420Spjd 250133808Spjd md.md_no = i - 1; 251142727Spjd md.md_provsize = msize; 252153190Spjd if (!hardcode) 253133808Spjd bzero(md.md_provider, sizeof(md.md_provider)); 254133808Spjd else { 255213662Sae if (strncmp(str, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 256213662Sae str += sizeof(_PATH_DEV) - 1; 257133808Spjd strlcpy(md.md_provider, str, sizeof(md.md_provider)); 258133808Spjd } 259153190Spjd if (verify && md.md_no == md.md_all - 1) { 260134539Spjd /* 261134539Spjd * In "verify" mode, force synchronization of parity 262134539Spjd * component on start. 263134539Spjd */ 264134539Spjd md.md_syncid = 0; 265134539Spjd } 266133808Spjd raid3_metadata_encode(&md, sector); 267133808Spjd error = g_metadata_store(str, sector, sizeof(sector)); 268133808Spjd if (error != 0) { 269133808Spjd fprintf(stderr, "Can't store metadata on %s: %s.\n", 270133808Spjd str, strerror(error)); 271133808Spjd gctl_error(req, "Not fully done."); 272133808Spjd continue; 273133808Spjd } 274133808Spjd if (verbose) 275133808Spjd printf("Metadata value stored on %s.\n", str); 276133808Spjd } 277133808Spjd} 278133808Spjd 279133808Spjdstatic void 280133808Spjdraid3_clear(struct gctl_req *req) 281133808Spjd{ 282133808Spjd const char *name; 283153190Spjd int error, i, nargs; 284133808Spjd 285153190Spjd nargs = gctl_get_int(req, "nargs"); 286153190Spjd if (nargs < 1) { 287133808Spjd gctl_error(req, "Too few arguments."); 288133808Spjd return; 289133808Spjd } 290133808Spjd 291153190Spjd for (i = 0; i < nargs; i++) { 292153190Spjd name = gctl_get_ascii(req, "arg%d", i); 293133808Spjd error = g_metadata_clear(name, G_RAID3_MAGIC); 294133808Spjd if (error != 0) { 295133808Spjd fprintf(stderr, "Can't clear metadata on %s: %s.\n", 296133808Spjd name, strerror(error)); 297133808Spjd gctl_error(req, "Not fully done."); 298133808Spjd continue; 299133808Spjd } 300133808Spjd if (verbose) 301155175Spjd printf("Metadata cleared on %s.\n", name); 302133808Spjd } 303133808Spjd} 304133808Spjd 305133808Spjdstatic void 306133808Spjdraid3_dump(struct gctl_req *req) 307133808Spjd{ 308133808Spjd struct g_raid3_metadata md, tmpmd; 309133808Spjd const char *name; 310153190Spjd int error, i, nargs; 311133808Spjd 312153190Spjd nargs = gctl_get_int(req, "nargs"); 313153190Spjd if (nargs < 1) { 314133808Spjd gctl_error(req, "Too few arguments."); 315133808Spjd return; 316133808Spjd } 317133808Spjd 318153190Spjd for (i = 0; i < nargs; i++) { 319153190Spjd name = gctl_get_ascii(req, "arg%d", i); 320133808Spjd error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd), 321133808Spjd G_RAID3_MAGIC); 322133808Spjd if (error != 0) { 323133808Spjd fprintf(stderr, "Can't read metadata from %s: %s.\n", 324133808Spjd name, strerror(error)); 325133808Spjd gctl_error(req, "Not fully done."); 326133808Spjd continue; 327133808Spjd } 328133808Spjd if (raid3_metadata_decode((u_char *)&tmpmd, &md) != 0) { 329133808Spjd fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 330133808Spjd name); 331133808Spjd gctl_error(req, "Not fully done."); 332133808Spjd continue; 333133808Spjd } 334133808Spjd printf("Metadata on %s:\n", name); 335133808Spjd raid3_metadata_dump(&md); 336133808Spjd printf("\n"); 337133808Spjd } 338133808Spjd} 339