g_raid3_ctl.c revision 155174
1133808Spjd/*- 2141994Spjd * 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. 13155174Spjd * 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: head/sys/geom/raid3/g_raid3_ctl.c 155174 2006-02-01 12:06:01Z pjd $"); 29133808Spjd 30133808Spjd#include <sys/param.h> 31133808Spjd#include <sys/systm.h> 32133808Spjd#include <sys/kernel.h> 33133808Spjd#include <sys/module.h> 34133808Spjd#include <sys/lock.h> 35133808Spjd#include <sys/mutex.h> 36133808Spjd#include <sys/bio.h> 37133808Spjd#include <sys/sysctl.h> 38133808Spjd#include <sys/malloc.h> 39133808Spjd#include <sys/bitstring.h> 40133808Spjd#include <vm/uma.h> 41133808Spjd#include <machine/atomic.h> 42133808Spjd#include <geom/geom.h> 43133808Spjd#include <sys/proc.h> 44133808Spjd#include <sys/kthread.h> 45133808Spjd#include <geom/raid3/g_raid3.h> 46133808Spjd 47133808Spjd 48133808Spjdstatic struct g_raid3_softc * 49133808Spjdg_raid3_find_device(struct g_class *mp, const char *name) 50133808Spjd{ 51133808Spjd struct g_raid3_softc *sc; 52133808Spjd struct g_geom *gp; 53133808Spjd 54133808Spjd g_topology_assert(); 55133808Spjd LIST_FOREACH(gp, &mp->geom, geom) { 56133808Spjd sc = gp->softc; 57133808Spjd if (sc == NULL) 58133808Spjd continue; 59133808Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) != 0) 60133808Spjd continue; 61133808Spjd if (strcmp(gp->name, name) == 0 || 62133808Spjd strcmp(sc->sc_name, name) == 0) { 63133808Spjd return (sc); 64133808Spjd } 65133808Spjd } 66133808Spjd return (NULL); 67133808Spjd} 68133808Spjd 69133808Spjdstatic struct g_raid3_disk * 70133808Spjdg_raid3_find_disk(struct g_raid3_softc *sc, const char *name) 71133808Spjd{ 72133808Spjd struct g_raid3_disk *disk; 73133808Spjd u_int n; 74133808Spjd 75133808Spjd g_topology_assert(); 76133808Spjd for (n = 0; n < sc->sc_ndisks; n++) { 77133808Spjd disk = &sc->sc_disks[n]; 78133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 79133808Spjd continue; 80133808Spjd if (disk->d_consumer == NULL) 81133808Spjd continue; 82133808Spjd if (disk->d_consumer->provider == NULL) 83133808Spjd continue; 84133808Spjd if (strcmp(disk->d_consumer->provider->name, name) == 0) 85133808Spjd return (disk); 86133808Spjd } 87133808Spjd return (NULL); 88133808Spjd} 89133808Spjd 90133808Spjdstatic void 91133808Spjdg_raid3_ctl_configure(struct gctl_req *req, struct g_class *mp) 92133808Spjd{ 93133808Spjd struct g_raid3_softc *sc; 94133808Spjd struct g_raid3_disk *disk; 95133808Spjd const char *name; 96134124Spjd int *nargs, do_sync = 0; 97134168Spjd int *autosync, *noautosync; 98134168Spjd int *round_robin, *noround_robin; 99134168Spjd int *verify, *noverify; 100133808Spjd u_int n; 101133808Spjd 102133808Spjd g_topology_assert(); 103133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 104144142Spjd if (nargs == NULL) { 105144142Spjd gctl_error(req, "No '%s' argument.", "nargs"); 106144142Spjd return; 107144142Spjd } 108133808Spjd if (*nargs != 1) { 109133808Spjd gctl_error(req, "Invalid number of arguments."); 110133808Spjd return; 111133808Spjd } 112133808Spjd name = gctl_get_asciiparam(req, "arg0"); 113144142Spjd if (name == NULL) { 114144142Spjd gctl_error(req, "No 'arg%u' argument.", 0); 115144142Spjd return; 116144142Spjd } 117133808Spjd sc = g_raid3_find_device(mp, name); 118133808Spjd if (sc == NULL) { 119133808Spjd gctl_error(req, "No such device: %s.", name); 120133808Spjd return; 121133808Spjd } 122133808Spjd if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) { 123133808Spjd gctl_error(req, "Not all disks connected."); 124133808Spjd return; 125133808Spjd } 126133808Spjd autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync)); 127133808Spjd if (autosync == NULL) { 128133808Spjd gctl_error(req, "No '%s' argument.", "autosync"); 129133808Spjd return; 130133808Spjd } 131133808Spjd noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 132133808Spjd if (noautosync == NULL) { 133133808Spjd gctl_error(req, "No '%s' argument.", "noautosync"); 134133808Spjd return; 135133808Spjd } 136133808Spjd if (*autosync && *noautosync) { 137133808Spjd gctl_error(req, "'%s' and '%s' specified.", "autosync", 138133808Spjd "noautosync"); 139133808Spjd return; 140133808Spjd } 141134124Spjd round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin)); 142134124Spjd if (round_robin == NULL) { 143134124Spjd gctl_error(req, "No '%s' argument.", "round_robin"); 144134124Spjd return; 145134124Spjd } 146134124Spjd noround_robin = gctl_get_paraml(req, "noround_robin", 147134124Spjd sizeof(*noround_robin)); 148134124Spjd if (noround_robin == NULL) { 149134124Spjd gctl_error(req, "No '%s' argument.", "noround_robin"); 150134124Spjd return; 151134124Spjd } 152134124Spjd if (*round_robin && *noround_robin) { 153134124Spjd gctl_error(req, "'%s' and '%s' specified.", "round_robin", 154134124Spjd "noround_robin"); 155134124Spjd return; 156134124Spjd } 157134168Spjd verify = gctl_get_paraml(req, "verify", sizeof(*verify)); 158134168Spjd if (verify == NULL) { 159134168Spjd gctl_error(req, "No '%s' argument.", "verify"); 160134168Spjd return; 161134168Spjd } 162134168Spjd noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify)); 163134168Spjd if (noverify == NULL) { 164134168Spjd gctl_error(req, "No '%s' argument.", "noverify"); 165134168Spjd return; 166134168Spjd } 167134168Spjd if (*verify && *noverify) { 168134168Spjd gctl_error(req, "'%s' and '%s' specified.", "verify", 169134168Spjd "noverify"); 170134168Spjd return; 171134168Spjd } 172134168Spjd if (!*autosync && !*noautosync && !*round_robin && !*noround_robin && 173134168Spjd !*verify && !*noverify) { 174134124Spjd gctl_error(req, "Nothing has changed."); 175134124Spjd return; 176134124Spjd } 177133808Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) { 178133808Spjd if (*autosync) { 179133808Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 180133808Spjd do_sync = 1; 181133808Spjd } 182133808Spjd } else { 183133808Spjd if (*noautosync) 184133808Spjd sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 185133808Spjd } 186134168Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) { 187134168Spjd if (*noverify) 188134168Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY; 189134168Spjd } else { 190134168Spjd if (*verify) 191134168Spjd sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY; 192134168Spjd } 193134124Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 194134124Spjd if (*noround_robin) 195134124Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 196134124Spjd } else { 197134124Spjd if (*round_robin) 198134124Spjd sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 199134124Spjd } 200134168Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && 201134168Spjd (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 202134168Spjd /* 203134168Spjd * VERIFY and ROUND-ROBIN options are mutally exclusive. 204134168Spjd */ 205134168Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 206134168Spjd } 207133808Spjd for (n = 0; n < sc->sc_ndisks; n++) { 208133808Spjd disk = &sc->sc_disks[n]; 209133808Spjd if (do_sync) { 210133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) 211133808Spjd disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC; 212133808Spjd } 213133808Spjd g_raid3_update_metadata(disk); 214133808Spjd if (do_sync) { 215133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_STALE) { 216133808Spjd /* 217133808Spjd * XXX: This is probably possible that this 218133808Spjd * component will not be retasted. 219133808Spjd */ 220133808Spjd g_raid3_event_send(disk, 221133808Spjd G_RAID3_DISK_STATE_DISCONNECTED, 222133808Spjd G_RAID3_EVENT_DONTWAIT); 223133808Spjd } 224133808Spjd } 225133808Spjd } 226133808Spjd} 227133808Spjd 228133808Spjdstatic void 229133808Spjdg_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp) 230133808Spjd{ 231139671Spjd struct g_raid3_metadata md; 232133808Spjd struct g_raid3_softc *sc; 233133808Spjd struct g_raid3_disk *disk; 234139671Spjd struct g_provider *pp; 235133808Spjd const char *name; 236139671Spjd int error, *nargs; 237133808Spjd 238133808Spjd g_topology_assert(); 239133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 240133808Spjd if (nargs == NULL) { 241133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 242133808Spjd return; 243133808Spjd } 244133808Spjd if (*nargs != 2) { 245133808Spjd gctl_error(req, "Invalid number of arguments."); 246133808Spjd return; 247133808Spjd } 248133808Spjd name = gctl_get_asciiparam(req, "arg0"); 249133808Spjd if (name == NULL) { 250133808Spjd gctl_error(req, "No 'arg%u' argument.", 0); 251133808Spjd return; 252133808Spjd } 253133808Spjd sc = g_raid3_find_device(mp, name); 254133808Spjd if (sc == NULL) { 255133808Spjd gctl_error(req, "No such device: %s.", name); 256133808Spjd return; 257133808Spjd } 258133808Spjd name = gctl_get_asciiparam(req, "arg1"); 259133808Spjd if (name == NULL) { 260133808Spjd gctl_error(req, "No 'arg%u' argument.", 1); 261133808Spjd return; 262133808Spjd } 263133808Spjd disk = g_raid3_find_disk(sc, name); 264133808Spjd if (disk == NULL) { 265133808Spjd gctl_error(req, "No such provider: %s.", name); 266133808Spjd return; 267133808Spjd } 268133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE && 269133808Spjd g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) { 270133808Spjd gctl_error(req, "There is one stale disk already.", name); 271133808Spjd return; 272133808Spjd } 273133808Spjd /* 274133808Spjd * Do rebuild by resetting syncid and disconnecting disk. 275133808Spjd * It'll be retasted, connected to the device and synchronized. 276133808Spjd */ 277133808Spjd disk->d_sync.ds_syncid = 0; 278133808Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) 279133808Spjd disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC; 280133808Spjd g_raid3_update_metadata(disk); 281139671Spjd pp = disk->d_consumer->provider; 282139671Spjd error = g_raid3_read_metadata(disk->d_consumer, &md); 283133808Spjd g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 284133808Spjd G_RAID3_EVENT_WAIT); 285139671Spjd if (error != 0) { 286139671Spjd gctl_error(req, "Cannot read metadata from %s.", pp->name); 287139671Spjd return; 288139671Spjd } 289139671Spjd error = g_raid3_add_disk(sc, pp, &md); 290139671Spjd if (error != 0) { 291139671Spjd gctl_error(req, "Cannot reconnect component %s.", pp->name); 292139671Spjd return; 293139671Spjd } 294133808Spjd} 295133808Spjd 296133808Spjdstatic void 297133808Spjdg_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp) 298133808Spjd{ 299133808Spjd struct g_raid3_softc *sc; 300133808Spjd int *force, *nargs, error; 301133808Spjd const char *name; 302133808Spjd char param[16]; 303133808Spjd u_int i; 304133808Spjd 305133808Spjd g_topology_assert(); 306133808Spjd 307133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 308133808Spjd if (nargs == NULL) { 309133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 310133808Spjd return; 311133808Spjd } 312133808Spjd if (*nargs < 1) { 313133808Spjd gctl_error(req, "Missing device(s)."); 314133808Spjd return; 315133808Spjd } 316133808Spjd force = gctl_get_paraml(req, "force", sizeof(*force)); 317133808Spjd if (force == NULL) { 318133808Spjd gctl_error(req, "No '%s' argument.", "force"); 319133808Spjd return; 320133808Spjd } 321133808Spjd 322133808Spjd for (i = 0; i < (u_int)*nargs; i++) { 323133808Spjd snprintf(param, sizeof(param), "arg%u", i); 324133808Spjd name = gctl_get_asciiparam(req, param); 325133808Spjd if (name == NULL) { 326133808Spjd gctl_error(req, "No 'arg%u' argument.", i); 327133808Spjd return; 328133808Spjd } 329133808Spjd sc = g_raid3_find_device(mp, name); 330133808Spjd if (sc == NULL) { 331133808Spjd gctl_error(req, "No such device: %s.", name); 332133808Spjd return; 333133808Spjd } 334133808Spjd error = g_raid3_destroy(sc, *force); 335133808Spjd if (error != 0) { 336133808Spjd gctl_error(req, "Cannot destroy device %s (error=%d).", 337133808Spjd sc->sc_geom->name, error); 338133808Spjd return; 339133808Spjd } 340133808Spjd } 341133808Spjd} 342133808Spjd 343133808Spjdstatic void 344133808Spjdg_raid3_ctl_insert_orphan(struct g_consumer *cp) 345133808Spjd{ 346133808Spjd 347133808Spjd KASSERT(1 == 0, ("%s called while inserting %s.", __func__, 348133808Spjd cp->provider->name)); 349133808Spjd} 350133808Spjd 351133808Spjdstatic void 352133808Spjdg_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp) 353133808Spjd{ 354133808Spjd struct g_raid3_metadata md; 355133808Spjd struct g_raid3_softc *sc; 356133808Spjd struct g_raid3_disk *disk; 357133808Spjd struct g_geom *gp; 358133808Spjd struct g_provider *pp; 359133808Spjd struct g_consumer *cp; 360133808Spjd const char *name; 361133808Spjd u_char *sector; 362134420Spjd off_t compsize; 363133808Spjd intmax_t *no; 364133808Spjd int *hardcode, *nargs, error; 365133808Spjd 366133808Spjd g_topology_assert(); 367133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 368133808Spjd if (nargs == NULL) { 369133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 370133808Spjd return; 371133808Spjd } 372133808Spjd if (*nargs != 2) { 373133808Spjd gctl_error(req, "Invalid number of arguments."); 374133808Spjd return; 375133808Spjd } 376133808Spjd name = gctl_get_asciiparam(req, "arg0"); 377133808Spjd if (name == NULL) { 378133808Spjd gctl_error(req, "No 'arg%u' argument.", 0); 379133808Spjd return; 380133808Spjd } 381133808Spjd sc = g_raid3_find_device(mp, name); 382133808Spjd if (sc == NULL) { 383133808Spjd gctl_error(req, "No such device: %s.", name); 384133808Spjd return; 385133808Spjd } 386133808Spjd no = gctl_get_paraml(req, "number", sizeof(*no)); 387133808Spjd if (no == NULL) { 388133808Spjd gctl_error(req, "No '%s' argument.", "no"); 389133808Spjd return; 390133808Spjd } 391133808Spjd if (*no >= sc->sc_ndisks) { 392133808Spjd gctl_error(req, "Invalid component number."); 393133808Spjd return; 394133808Spjd } 395133808Spjd hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 396133808Spjd if (hardcode == NULL) { 397133808Spjd gctl_error(req, "No '%s' argument.", "hardcode"); 398133808Spjd return; 399133808Spjd } 400133808Spjd disk = &sc->sc_disks[*no]; 401133808Spjd if (disk->d_state != G_RAID3_DISK_STATE_NODISK) { 402133808Spjd gctl_error(req, "Component %u is already connected.", *no); 403133808Spjd return; 404133808Spjd } 405133808Spjd name = gctl_get_asciiparam(req, "arg1"); 406133808Spjd if (name == NULL) { 407133808Spjd gctl_error(req, "No 'arg%u' argument.", 1); 408133808Spjd return; 409133808Spjd } 410133808Spjd pp = g_provider_by_name(name); 411133808Spjd if (pp == NULL) { 412133808Spjd gctl_error(req, "Invalid provider."); 413133808Spjd return; 414133808Spjd } 415133808Spjd if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) { 416133808Spjd gctl_error(req, 417133808Spjd "Cannot insert provider %s, because of its sector size.", 418133808Spjd pp->name); 419133808Spjd return; 420133808Spjd } 421134420Spjd compsize = sc->sc_mediasize / (sc->sc_ndisks - 1); 422134420Spjd if (compsize > pp->mediasize - pp->sectorsize) { 423134420Spjd gctl_error(req, "Provider %s too small.", pp->name); 424134420Spjd return; 425134420Spjd } 426134420Spjd if (compsize < pp->mediasize - pp->sectorsize) { 427134420Spjd gctl_error(req, 428134420Spjd "warning: %s: only %jd bytes from %jd bytes used.", 429134420Spjd pp->name, (intmax_t)compsize, 430134420Spjd (intmax_t)(pp->mediasize - pp->sectorsize)); 431134420Spjd } 432133808Spjd gp = g_new_geomf(mp, "raid3:insert"); 433133808Spjd gp->orphan = g_raid3_ctl_insert_orphan; 434133808Spjd cp = g_new_consumer(gp); 435133808Spjd error = g_attach(cp, pp); 436133808Spjd if (error != 0) { 437133808Spjd gctl_error(req, "Cannot attach to %s.", pp->name); 438133808Spjd goto end; 439133808Spjd } 440133808Spjd error = g_access(cp, 0, 1, 1); 441133808Spjd if (error != 0) { 442133808Spjd gctl_error(req, "Cannot access %s.", pp->name); 443133808Spjd goto end; 444133808Spjd } 445133808Spjd g_raid3_fill_metadata(disk, &md); 446133808Spjd md.md_syncid = 0; 447133808Spjd md.md_dflags = 0; 448133808Spjd if (*hardcode) 449133808Spjd strlcpy(md.md_provider, pp->name, sizeof(md.md_provider)); 450133808Spjd else 451133808Spjd bzero(md.md_provider, sizeof(md.md_provider)); 452133808Spjd sector = g_malloc(pp->sectorsize, M_WAITOK); 453133808Spjd raid3_metadata_encode(&md, sector); 454133808Spjd g_topology_unlock(); 455133808Spjd error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 456133808Spjd pp->sectorsize); 457133808Spjd g_topology_lock(); 458133808Spjd g_free(sector); 459133808Spjd if (error != 0) 460133808Spjd gctl_error(req, "Cannot store metadata on %s.", pp->name); 461133808Spjdend: 462146118Spjd if (cp->acw > 0) 463146118Spjd g_access(cp, 0, -1, -1); 464146118Spjd if (cp->provider != NULL) 465146118Spjd g_detach(cp); 466146118Spjd g_destroy_consumer(cp); 467146117Spjd g_destroy_geom(gp); 468133808Spjd} 469133808Spjd 470133808Spjdstatic void 471133808Spjdg_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp) 472133808Spjd{ 473133808Spjd struct g_raid3_softc *sc; 474133808Spjd struct g_raid3_disk *disk; 475133808Spjd const char *name; 476133808Spjd intmax_t *no; 477133808Spjd int *nargs; 478133808Spjd 479133808Spjd g_topology_assert(); 480133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 481133808Spjd if (nargs == NULL) { 482133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 483133808Spjd return; 484133808Spjd } 485133808Spjd if (*nargs != 1) { 486133808Spjd gctl_error(req, "Invalid number of arguments."); 487133808Spjd return; 488133808Spjd } 489133808Spjd name = gctl_get_asciiparam(req, "arg0"); 490133808Spjd if (name == NULL) { 491133808Spjd gctl_error(req, "No 'arg%u' argument.", 0); 492133808Spjd return; 493133808Spjd } 494133808Spjd sc = g_raid3_find_device(mp, name); 495133808Spjd if (sc == NULL) { 496133808Spjd gctl_error(req, "No such device: %s.", name); 497133808Spjd return; 498133808Spjd } 499133808Spjd no = gctl_get_paraml(req, "number", sizeof(*no)); 500133808Spjd if (no == NULL) { 501133808Spjd gctl_error(req, "No '%s' argument.", "no"); 502133808Spjd return; 503133808Spjd } 504133808Spjd if (*no >= sc->sc_ndisks) { 505133808Spjd gctl_error(req, "Invalid component number."); 506133808Spjd return; 507133808Spjd } 508133808Spjd disk = &sc->sc_disks[*no]; 509133808Spjd switch (disk->d_state) { 510133808Spjd case G_RAID3_DISK_STATE_ACTIVE: 511133808Spjd /* 512133808Spjd * When replacing ACTIVE component, all the rest has to be also 513133808Spjd * ACTIVE. 514133808Spjd */ 515133808Spjd if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < 516133808Spjd sc->sc_ndisks) { 517133808Spjd gctl_error(req, "Cannot replace component number %u.", 518133808Spjd *no); 519133808Spjd return; 520133808Spjd } 521133808Spjd /* FALLTHROUGH */ 522133808Spjd case G_RAID3_DISK_STATE_STALE: 523133808Spjd case G_RAID3_DISK_STATE_SYNCHRONIZING: 524133808Spjd if (g_raid3_clear_metadata(disk) != 0) { 525133808Spjd gctl_error(req, "Cannot clear metadata on %s.", 526133808Spjd g_raid3_get_diskname(disk)); 527139295Spjd } else { 528139295Spjd g_raid3_event_send(disk, 529139295Spjd G_RAID3_DISK_STATE_DISCONNECTED, 530139295Spjd G_RAID3_EVENT_WAIT); 531133808Spjd } 532133808Spjd break; 533133808Spjd case G_RAID3_DISK_STATE_NODISK: 534133808Spjd break; 535133808Spjd default: 536133808Spjd gctl_error(req, "Cannot replace component number %u.", *no); 537133808Spjd return; 538133808Spjd } 539133808Spjd} 540133808Spjd 541133808Spjdvoid 542133808Spjdg_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb) 543133808Spjd{ 544133808Spjd uint32_t *version; 545133808Spjd 546133808Spjd g_topology_assert(); 547133808Spjd 548133808Spjd version = gctl_get_paraml(req, "version", sizeof(*version)); 549133808Spjd if (version == NULL) { 550133808Spjd gctl_error(req, "No '%s' argument.", "version"); 551133808Spjd return; 552133808Spjd } 553133808Spjd if (*version != G_RAID3_VERSION) { 554133808Spjd gctl_error(req, "Userland and kernel parts are out of sync."); 555133808Spjd return; 556133808Spjd } 557133808Spjd 558133808Spjd if (strcmp(verb, "configure") == 0) 559133808Spjd g_raid3_ctl_configure(req, mp); 560133808Spjd else if (strcmp(verb, "insert") == 0) 561133808Spjd g_raid3_ctl_insert(req, mp); 562133808Spjd else if (strcmp(verb, "rebuild") == 0) 563133808Spjd g_raid3_ctl_rebuild(req, mp); 564133808Spjd else if (strcmp(verb, "remove") == 0) 565133808Spjd g_raid3_ctl_remove(req, mp); 566133808Spjd else if (strcmp(verb, "stop") == 0) 567133808Spjd g_raid3_ctl_stop(req, mp); 568133808Spjd else 569133808Spjd gctl_error(req, "Unknown verb."); 570133808Spjd} 571