1133808Spjd/*- 2156878Spjd * Copyright (c) 2004-2006 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$"); 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 54156612Spjd g_topology_lock(); 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) { 63156612Spjd g_topology_unlock(); 64156612Spjd sx_xlock(&sc->sc_lock); 65133808Spjd return (sc); 66133808Spjd } 67133808Spjd } 68156612Spjd g_topology_unlock(); 69133808Spjd return (NULL); 70133808Spjd} 71133808Spjd 72133808Spjdstatic struct g_raid3_disk * 73133808Spjdg_raid3_find_disk(struct g_raid3_softc *sc, const char *name) 74133808Spjd{ 75133808Spjd struct g_raid3_disk *disk; 76133808Spjd u_int n; 77133808Spjd 78156612Spjd sx_assert(&sc->sc_lock, SX_XLOCKED); 79160330Spjd if (strncmp(name, "/dev/", 5) == 0) 80160330Spjd name += 5; 81133808Spjd for (n = 0; n < sc->sc_ndisks; n++) { 82133808Spjd disk = &sc->sc_disks[n]; 83133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 84133808Spjd continue; 85133808Spjd if (disk->d_consumer == NULL) 86133808Spjd continue; 87133808Spjd if (disk->d_consumer->provider == NULL) 88133808Spjd continue; 89133808Spjd if (strcmp(disk->d_consumer->provider->name, name) == 0) 90133808Spjd return (disk); 91133808Spjd } 92133808Spjd return (NULL); 93133808Spjd} 94133808Spjd 95133808Spjdstatic void 96133808Spjdg_raid3_ctl_configure(struct gctl_req *req, struct g_class *mp) 97133808Spjd{ 98133808Spjd struct g_raid3_softc *sc; 99133808Spjd struct g_raid3_disk *disk; 100133808Spjd const char *name; 101163888Spjd int *nargs, do_sync = 0, dirty = 1; 102134168Spjd int *autosync, *noautosync; 103163888Spjd int *failsync, *nofailsync; 104134168Spjd int *round_robin, *noround_robin; 105134168Spjd int *verify, *noverify; 106133808Spjd u_int n; 107133808Spjd 108133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 109144142Spjd if (nargs == NULL) { 110144142Spjd gctl_error(req, "No '%s' argument.", "nargs"); 111144142Spjd return; 112144142Spjd } 113133808Spjd if (*nargs != 1) { 114133808Spjd gctl_error(req, "Invalid number of arguments."); 115133808Spjd return; 116133808Spjd } 117133808Spjd autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync)); 118133808Spjd if (autosync == NULL) { 119133808Spjd gctl_error(req, "No '%s' argument.", "autosync"); 120133808Spjd return; 121133808Spjd } 122133808Spjd noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 123133808Spjd if (noautosync == NULL) { 124133808Spjd gctl_error(req, "No '%s' argument.", "noautosync"); 125133808Spjd return; 126133808Spjd } 127133808Spjd if (*autosync && *noautosync) { 128133808Spjd gctl_error(req, "'%s' and '%s' specified.", "autosync", 129133808Spjd "noautosync"); 130133808Spjd return; 131133808Spjd } 132163888Spjd failsync = gctl_get_paraml(req, "failsync", sizeof(*failsync)); 133163888Spjd if (failsync == NULL) { 134163888Spjd gctl_error(req, "No '%s' argument.", "failsync"); 135163888Spjd return; 136163888Spjd } 137163888Spjd nofailsync = gctl_get_paraml(req, "nofailsync", sizeof(*nofailsync)); 138163888Spjd if (nofailsync == NULL) { 139163888Spjd gctl_error(req, "No '%s' argument.", "nofailsync"); 140163888Spjd return; 141163888Spjd } 142163888Spjd if (*failsync && *nofailsync) { 143163888Spjd gctl_error(req, "'%s' and '%s' specified.", "failsync", 144163888Spjd "nofailsync"); 145163888Spjd return; 146163888Spjd } 147134124Spjd round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin)); 148134124Spjd if (round_robin == NULL) { 149134124Spjd gctl_error(req, "No '%s' argument.", "round_robin"); 150134124Spjd return; 151134124Spjd } 152134124Spjd noround_robin = gctl_get_paraml(req, "noround_robin", 153134124Spjd sizeof(*noround_robin)); 154134124Spjd if (noround_robin == NULL) { 155134124Spjd gctl_error(req, "No '%s' argument.", "noround_robin"); 156134124Spjd return; 157134124Spjd } 158134124Spjd if (*round_robin && *noround_robin) { 159134124Spjd gctl_error(req, "'%s' and '%s' specified.", "round_robin", 160134124Spjd "noround_robin"); 161134124Spjd return; 162134124Spjd } 163134168Spjd verify = gctl_get_paraml(req, "verify", sizeof(*verify)); 164134168Spjd if (verify == NULL) { 165134168Spjd gctl_error(req, "No '%s' argument.", "verify"); 166134168Spjd return; 167134168Spjd } 168134168Spjd noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify)); 169134168Spjd if (noverify == NULL) { 170134168Spjd gctl_error(req, "No '%s' argument.", "noverify"); 171134168Spjd return; 172134168Spjd } 173134168Spjd if (*verify && *noverify) { 174134168Spjd gctl_error(req, "'%s' and '%s' specified.", "verify", 175134168Spjd "noverify"); 176134168Spjd return; 177134168Spjd } 178163888Spjd if (!*autosync && !*noautosync && !*failsync && !*nofailsync && 179163888Spjd !*round_robin && !*noround_robin && !*verify && !*noverify) { 180134124Spjd gctl_error(req, "Nothing has changed."); 181134124Spjd return; 182134124Spjd } 183156612Spjd name = gctl_get_asciiparam(req, "arg0"); 184156612Spjd if (name == NULL) { 185156612Spjd gctl_error(req, "No 'arg%u' argument.", 0); 186156612Spjd return; 187156612Spjd } 188156612Spjd sc = g_raid3_find_device(mp, name); 189156612Spjd if (sc == NULL) { 190156612Spjd gctl_error(req, "No such device: %s.", name); 191156612Spjd return; 192156612Spjd } 193156612Spjd if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) { 194156612Spjd gctl_error(req, "Not all disks connected."); 195156612Spjd sx_xunlock(&sc->sc_lock); 196156612Spjd return; 197156612Spjd } 198133808Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) { 199133808Spjd if (*autosync) { 200133808Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 201133808Spjd do_sync = 1; 202133808Spjd } 203133808Spjd } else { 204133808Spjd if (*noautosync) 205133808Spjd sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 206133808Spjd } 207163888Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOFAILSYNC) != 0) { 208163888Spjd if (*failsync) 209163888Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOFAILSYNC; 210163888Spjd } else { 211163888Spjd if (*nofailsync) { 212163888Spjd sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOFAILSYNC; 213163888Spjd dirty = 0; 214163888Spjd } 215163888Spjd } 216134168Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) { 217134168Spjd if (*noverify) 218134168Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY; 219134168Spjd } else { 220134168Spjd if (*verify) 221134168Spjd sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY; 222134168Spjd } 223134124Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 224134124Spjd if (*noround_robin) 225134124Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 226134124Spjd } else { 227134124Spjd if (*round_robin) 228134124Spjd sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 229134124Spjd } 230134168Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && 231134168Spjd (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 232134168Spjd /* 233134168Spjd * VERIFY and ROUND-ROBIN options are mutally exclusive. 234134168Spjd */ 235134168Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 236134168Spjd } 237133808Spjd for (n = 0; n < sc->sc_ndisks; n++) { 238133808Spjd disk = &sc->sc_disks[n]; 239133808Spjd if (do_sync) { 240133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) 241133808Spjd disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC; 242133808Spjd } 243163888Spjd if (!dirty) 244163888Spjd disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 245133808Spjd g_raid3_update_metadata(disk); 246133808Spjd if (do_sync) { 247133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_STALE) { 248133808Spjd /* 249133808Spjd * XXX: This is probably possible that this 250133808Spjd * component will not be retasted. 251133808Spjd */ 252133808Spjd g_raid3_event_send(disk, 253133808Spjd G_RAID3_DISK_STATE_DISCONNECTED, 254133808Spjd G_RAID3_EVENT_DONTWAIT); 255133808Spjd } 256133808Spjd } 257133808Spjd } 258156612Spjd sx_xunlock(&sc->sc_lock); 259133808Spjd} 260133808Spjd 261133808Spjdstatic void 262133808Spjdg_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp) 263133808Spjd{ 264139671Spjd struct g_raid3_metadata md; 265133808Spjd struct g_raid3_softc *sc; 266133808Spjd struct g_raid3_disk *disk; 267139671Spjd struct g_provider *pp; 268133808Spjd const char *name; 269139671Spjd int error, *nargs; 270133808Spjd 271133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 272133808Spjd if (nargs == NULL) { 273133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 274133808Spjd return; 275133808Spjd } 276133808Spjd if (*nargs != 2) { 277133808Spjd gctl_error(req, "Invalid number of arguments."); 278133808Spjd return; 279133808Spjd } 280133808Spjd name = gctl_get_asciiparam(req, "arg0"); 281133808Spjd if (name == NULL) { 282133808Spjd gctl_error(req, "No 'arg%u' argument.", 0); 283133808Spjd return; 284133808Spjd } 285133808Spjd sc = g_raid3_find_device(mp, name); 286133808Spjd if (sc == NULL) { 287133808Spjd gctl_error(req, "No such device: %s.", name); 288133808Spjd return; 289133808Spjd } 290133808Spjd name = gctl_get_asciiparam(req, "arg1"); 291133808Spjd if (name == NULL) { 292133808Spjd gctl_error(req, "No 'arg%u' argument.", 1); 293156612Spjd sx_xunlock(&sc->sc_lock); 294133808Spjd return; 295133808Spjd } 296133808Spjd disk = g_raid3_find_disk(sc, name); 297133808Spjd if (disk == NULL) { 298133808Spjd gctl_error(req, "No such provider: %s.", name); 299156612Spjd sx_xunlock(&sc->sc_lock); 300133808Spjd return; 301133808Spjd } 302133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE && 303133808Spjd g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) { 304162350Spjd gctl_error(req, "There is one stale disk already."); 305156612Spjd sx_xunlock(&sc->sc_lock); 306133808Spjd return; 307133808Spjd } 308133808Spjd /* 309133808Spjd * Do rebuild by resetting syncid and disconnecting disk. 310133808Spjd * It'll be retasted, connected to the device and synchronized. 311133808Spjd */ 312133808Spjd disk->d_sync.ds_syncid = 0; 313133808Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) 314133808Spjd disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC; 315133808Spjd g_raid3_update_metadata(disk); 316139671Spjd pp = disk->d_consumer->provider; 317156612Spjd g_topology_lock(); 318139671Spjd error = g_raid3_read_metadata(disk->d_consumer, &md); 319156612Spjd g_topology_unlock(); 320133808Spjd g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 321133808Spjd G_RAID3_EVENT_WAIT); 322139671Spjd if (error != 0) { 323139671Spjd gctl_error(req, "Cannot read metadata from %s.", pp->name); 324156612Spjd sx_xunlock(&sc->sc_lock); 325139671Spjd return; 326139671Spjd } 327139671Spjd error = g_raid3_add_disk(sc, pp, &md); 328156612Spjd if (error != 0) 329139671Spjd gctl_error(req, "Cannot reconnect component %s.", pp->name); 330156612Spjd sx_xunlock(&sc->sc_lock); 331133808Spjd} 332133808Spjd 333133808Spjdstatic void 334133808Spjdg_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp) 335133808Spjd{ 336133808Spjd struct g_raid3_softc *sc; 337133808Spjd int *force, *nargs, error; 338133808Spjd const char *name; 339133808Spjd char param[16]; 340133808Spjd u_int i; 341157630Spjd int how; 342133808Spjd 343133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 344133808Spjd if (nargs == NULL) { 345133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 346133808Spjd return; 347133808Spjd } 348133808Spjd if (*nargs < 1) { 349133808Spjd gctl_error(req, "Missing device(s)."); 350133808Spjd return; 351133808Spjd } 352133808Spjd force = gctl_get_paraml(req, "force", sizeof(*force)); 353133808Spjd if (force == NULL) { 354133808Spjd gctl_error(req, "No '%s' argument.", "force"); 355133808Spjd return; 356133808Spjd } 357157630Spjd if (*force) 358157630Spjd how = G_RAID3_DESTROY_HARD; 359157630Spjd else 360157630Spjd how = G_RAID3_DESTROY_SOFT; 361133808Spjd 362133808Spjd for (i = 0; i < (u_int)*nargs; i++) { 363133808Spjd snprintf(param, sizeof(param), "arg%u", i); 364133808Spjd name = gctl_get_asciiparam(req, param); 365133808Spjd if (name == NULL) { 366133808Spjd gctl_error(req, "No 'arg%u' argument.", i); 367133808Spjd return; 368133808Spjd } 369133808Spjd sc = g_raid3_find_device(mp, name); 370133808Spjd if (sc == NULL) { 371133808Spjd gctl_error(req, "No such device: %s.", name); 372133808Spjd return; 373133808Spjd } 374157630Spjd g_cancel_event(sc); 375157630Spjd error = g_raid3_destroy(sc, how); 376133808Spjd if (error != 0) { 377133808Spjd gctl_error(req, "Cannot destroy device %s (error=%d).", 378133808Spjd sc->sc_geom->name, error); 379156612Spjd sx_xunlock(&sc->sc_lock); 380133808Spjd return; 381133808Spjd } 382156612Spjd /* No need to unlock, because lock is already dead. */ 383133808Spjd } 384133808Spjd} 385133808Spjd 386133808Spjdstatic void 387133808Spjdg_raid3_ctl_insert_orphan(struct g_consumer *cp) 388133808Spjd{ 389133808Spjd 390133808Spjd KASSERT(1 == 0, ("%s called while inserting %s.", __func__, 391133808Spjd cp->provider->name)); 392133808Spjd} 393133808Spjd 394133808Spjdstatic void 395133808Spjdg_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp) 396133808Spjd{ 397133808Spjd struct g_raid3_metadata md; 398133808Spjd struct g_raid3_softc *sc; 399133808Spjd struct g_raid3_disk *disk; 400133808Spjd struct g_geom *gp; 401133808Spjd struct g_provider *pp; 402133808Spjd struct g_consumer *cp; 403133808Spjd const char *name; 404133808Spjd u_char *sector; 405134420Spjd off_t compsize; 406133808Spjd intmax_t *no; 407245456Smav int *hardcode, *nargs, error, autono; 408133808Spjd 409133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 410133808Spjd if (nargs == NULL) { 411133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 412133808Spjd return; 413133808Spjd } 414133808Spjd if (*nargs != 2) { 415133808Spjd gctl_error(req, "Invalid number of arguments."); 416133808Spjd return; 417133808Spjd } 418156612Spjd hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 419156612Spjd if (hardcode == NULL) { 420156612Spjd gctl_error(req, "No '%s' argument.", "hardcode"); 421133808Spjd return; 422133808Spjd } 423156612Spjd name = gctl_get_asciiparam(req, "arg1"); 424156612Spjd if (name == NULL) { 425156612Spjd gctl_error(req, "No 'arg%u' argument.", 1); 426133808Spjd return; 427133808Spjd } 428245456Smav if (gctl_get_param(req, "number", NULL) != NULL) 429245456Smav no = gctl_get_paraml(req, "number", sizeof(*no)); 430245456Smav else 431245456Smav no = NULL; 432160330Spjd if (strncmp(name, "/dev/", 5) == 0) 433160330Spjd name += 5; 434156612Spjd g_topology_lock(); 435156612Spjd pp = g_provider_by_name(name); 436156612Spjd if (pp == NULL) { 437156612Spjd g_topology_unlock(); 438156612Spjd gctl_error(req, "Invalid provider."); 439156612Spjd return; 440156612Spjd } 441156612Spjd gp = g_new_geomf(mp, "raid3:insert"); 442156612Spjd gp->orphan = g_raid3_ctl_insert_orphan; 443156612Spjd cp = g_new_consumer(gp); 444156612Spjd error = g_attach(cp, pp); 445156612Spjd if (error != 0) { 446156612Spjd g_topology_unlock(); 447156612Spjd gctl_error(req, "Cannot attach to %s.", pp->name); 448156612Spjd goto end; 449156612Spjd } 450156612Spjd error = g_access(cp, 0, 1, 1); 451156612Spjd if (error != 0) { 452156612Spjd g_topology_unlock(); 453156612Spjd gctl_error(req, "Cannot access %s.", pp->name); 454156612Spjd goto end; 455156612Spjd } 456156612Spjd g_topology_unlock(); 457156612Spjd name = gctl_get_asciiparam(req, "arg0"); 458156612Spjd if (name == NULL) { 459156612Spjd gctl_error(req, "No 'arg%u' argument.", 0); 460156612Spjd goto end; 461156612Spjd } 462156612Spjd sc = g_raid3_find_device(mp, name); 463156612Spjd if (sc == NULL) { 464156612Spjd gctl_error(req, "No such device: %s.", name); 465156612Spjd goto end; 466156612Spjd } 467245456Smav if (no != NULL) { 468245456Smav if (*no < 0 || *no >= sc->sc_ndisks) { 469245456Smav sx_xunlock(&sc->sc_lock); 470245456Smav gctl_error(req, "Invalid component number."); 471245456Smav goto end; 472245456Smav } 473245456Smav disk = &sc->sc_disks[*no]; 474245456Smav if (disk->d_state != G_RAID3_DISK_STATE_NODISK) { 475245456Smav sx_xunlock(&sc->sc_lock); 476245456Smav gctl_error(req, "Component %jd is already connected.", 477245456Smav *no); 478245456Smav goto end; 479245456Smav } 480245456Smav } else { 481245456Smav disk = NULL; 482245456Smav for (autono = 0; autono < sc->sc_ndisks && disk == NULL; autono++) 483245456Smav if (sc->sc_disks[autono].d_state == 484245456Smav G_RAID3_DISK_STATE_NODISK) 485245456Smav disk = &sc->sc_disks[autono]; 486245456Smav if (disk == NULL) { 487245456Smav sx_xunlock(&sc->sc_lock); 488245456Smav gctl_error(req, "No disconnected components."); 489245456Smav goto end; 490245456Smav } 491133808Spjd } 492133808Spjd if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) { 493156612Spjd sx_xunlock(&sc->sc_lock); 494133808Spjd gctl_error(req, 495133808Spjd "Cannot insert provider %s, because of its sector size.", 496133808Spjd pp->name); 497156612Spjd goto end; 498133808Spjd } 499134420Spjd compsize = sc->sc_mediasize / (sc->sc_ndisks - 1); 500134420Spjd if (compsize > pp->mediasize - pp->sectorsize) { 501156612Spjd sx_xunlock(&sc->sc_lock); 502134420Spjd gctl_error(req, "Provider %s too small.", pp->name); 503156612Spjd goto end; 504134420Spjd } 505134420Spjd if (compsize < pp->mediasize - pp->sectorsize) { 506134420Spjd gctl_error(req, 507134420Spjd "warning: %s: only %jd bytes from %jd bytes used.", 508134420Spjd pp->name, (intmax_t)compsize, 509134420Spjd (intmax_t)(pp->mediasize - pp->sectorsize)); 510134420Spjd } 511133808Spjd g_raid3_fill_metadata(disk, &md); 512156612Spjd sx_xunlock(&sc->sc_lock); 513133808Spjd md.md_syncid = 0; 514163886Spjd md.md_dflags = 0; 515133808Spjd if (*hardcode) 516163886Spjd strlcpy(md.md_provider, pp->name, sizeof(md.md_provider)); 517163886Spjd else 518163886Spjd bzero(md.md_provider, sizeof(md.md_provider)); 519156527Spjd md.md_provsize = pp->mediasize; 520133808Spjd sector = g_malloc(pp->sectorsize, M_WAITOK); 521133808Spjd raid3_metadata_encode(&md, sector); 522133808Spjd error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 523133808Spjd pp->sectorsize); 524133808Spjd g_free(sector); 525133808Spjd if (error != 0) 526133808Spjd gctl_error(req, "Cannot store metadata on %s.", pp->name); 527133808Spjdend: 528156612Spjd g_topology_lock(); 529146118Spjd if (cp->acw > 0) 530146118Spjd g_access(cp, 0, -1, -1); 531146118Spjd if (cp->provider != NULL) 532146118Spjd g_detach(cp); 533146118Spjd g_destroy_consumer(cp); 534146117Spjd g_destroy_geom(gp); 535156612Spjd g_topology_unlock(); 536133808Spjd} 537133808Spjd 538133808Spjdstatic void 539133808Spjdg_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp) 540133808Spjd{ 541133808Spjd struct g_raid3_softc *sc; 542133808Spjd struct g_raid3_disk *disk; 543133808Spjd const char *name; 544133808Spjd intmax_t *no; 545133808Spjd int *nargs; 546133808Spjd 547133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 548133808Spjd if (nargs == NULL) { 549133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 550133808Spjd return; 551133808Spjd } 552133808Spjd if (*nargs != 1) { 553133808Spjd gctl_error(req, "Invalid number of arguments."); 554133808Spjd return; 555133808Spjd } 556156612Spjd no = gctl_get_paraml(req, "number", sizeof(*no)); 557156612Spjd if (no == NULL) { 558156612Spjd gctl_error(req, "No '%s' argument.", "no"); 559156612Spjd return; 560156612Spjd } 561133808Spjd name = gctl_get_asciiparam(req, "arg0"); 562133808Spjd if (name == NULL) { 563133808Spjd gctl_error(req, "No 'arg%u' argument.", 0); 564133808Spjd return; 565133808Spjd } 566133808Spjd sc = g_raid3_find_device(mp, name); 567133808Spjd if (sc == NULL) { 568133808Spjd gctl_error(req, "No such device: %s.", name); 569133808Spjd return; 570133808Spjd } 571133808Spjd if (*no >= sc->sc_ndisks) { 572156612Spjd sx_xunlock(&sc->sc_lock); 573133808Spjd gctl_error(req, "Invalid component number."); 574133808Spjd return; 575133808Spjd } 576133808Spjd disk = &sc->sc_disks[*no]; 577133808Spjd switch (disk->d_state) { 578133808Spjd case G_RAID3_DISK_STATE_ACTIVE: 579133808Spjd /* 580133808Spjd * When replacing ACTIVE component, all the rest has to be also 581133808Spjd * ACTIVE. 582133808Spjd */ 583133808Spjd if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < 584133808Spjd sc->sc_ndisks) { 585162350Spjd gctl_error(req, "Cannot replace component number %jd.", 586133808Spjd *no); 587156612Spjd break; 588133808Spjd } 589133808Spjd /* FALLTHROUGH */ 590133808Spjd case G_RAID3_DISK_STATE_STALE: 591133808Spjd case G_RAID3_DISK_STATE_SYNCHRONIZING: 592133808Spjd if (g_raid3_clear_metadata(disk) != 0) { 593133808Spjd gctl_error(req, "Cannot clear metadata on %s.", 594133808Spjd g_raid3_get_diskname(disk)); 595139295Spjd } else { 596139295Spjd g_raid3_event_send(disk, 597139295Spjd G_RAID3_DISK_STATE_DISCONNECTED, 598156612Spjd G_RAID3_EVENT_DONTWAIT); 599133808Spjd } 600133808Spjd break; 601133808Spjd case G_RAID3_DISK_STATE_NODISK: 602133808Spjd break; 603133808Spjd default: 604162350Spjd gctl_error(req, "Cannot replace component number %jd.", *no); 605156612Spjd break; 606133808Spjd } 607156612Spjd sx_xunlock(&sc->sc_lock); 608133808Spjd} 609133808Spjd 610133808Spjdvoid 611133808Spjdg_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb) 612133808Spjd{ 613133808Spjd uint32_t *version; 614133808Spjd 615133808Spjd g_topology_assert(); 616133808Spjd 617133808Spjd version = gctl_get_paraml(req, "version", sizeof(*version)); 618133808Spjd if (version == NULL) { 619133808Spjd gctl_error(req, "No '%s' argument.", "version"); 620133808Spjd return; 621133808Spjd } 622133808Spjd if (*version != G_RAID3_VERSION) { 623133808Spjd gctl_error(req, "Userland and kernel parts are out of sync."); 624133808Spjd return; 625133808Spjd } 626133808Spjd 627156612Spjd g_topology_unlock(); 628133808Spjd if (strcmp(verb, "configure") == 0) 629133808Spjd g_raid3_ctl_configure(req, mp); 630133808Spjd else if (strcmp(verb, "insert") == 0) 631133808Spjd g_raid3_ctl_insert(req, mp); 632133808Spjd else if (strcmp(verb, "rebuild") == 0) 633133808Spjd g_raid3_ctl_rebuild(req, mp); 634133808Spjd else if (strcmp(verb, "remove") == 0) 635133808Spjd g_raid3_ctl_remove(req, mp); 636133808Spjd else if (strcmp(verb, "stop") == 0) 637133808Spjd g_raid3_ctl_stop(req, mp); 638133808Spjd else 639133808Spjd gctl_error(req, "Unknown verb."); 640156612Spjd g_topology_lock(); 641133808Spjd} 642