g_raid3_ctl.c revision 160330
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: head/sys/geom/raid3/g_raid3_ctl.c 160330 2006-07-13 20:37:59Z 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 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; 101134124Spjd int *nargs, do_sync = 0; 102134168Spjd int *autosync, *noautosync; 103134168Spjd int *round_robin, *noround_robin; 104134168Spjd int *verify, *noverify; 105133808Spjd u_int n; 106133808Spjd 107133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 108144142Spjd if (nargs == NULL) { 109144142Spjd gctl_error(req, "No '%s' argument.", "nargs"); 110144142Spjd return; 111144142Spjd } 112133808Spjd if (*nargs != 1) { 113133808Spjd gctl_error(req, "Invalid number of arguments."); 114133808Spjd return; 115133808Spjd } 116133808Spjd autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync)); 117133808Spjd if (autosync == NULL) { 118133808Spjd gctl_error(req, "No '%s' argument.", "autosync"); 119133808Spjd return; 120133808Spjd } 121133808Spjd noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 122133808Spjd if (noautosync == NULL) { 123133808Spjd gctl_error(req, "No '%s' argument.", "noautosync"); 124133808Spjd return; 125133808Spjd } 126133808Spjd if (*autosync && *noautosync) { 127133808Spjd gctl_error(req, "'%s' and '%s' specified.", "autosync", 128133808Spjd "noautosync"); 129133808Spjd return; 130133808Spjd } 131134124Spjd round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin)); 132134124Spjd if (round_robin == NULL) { 133134124Spjd gctl_error(req, "No '%s' argument.", "round_robin"); 134134124Spjd return; 135134124Spjd } 136134124Spjd noround_robin = gctl_get_paraml(req, "noround_robin", 137134124Spjd sizeof(*noround_robin)); 138134124Spjd if (noround_robin == NULL) { 139134124Spjd gctl_error(req, "No '%s' argument.", "noround_robin"); 140134124Spjd return; 141134124Spjd } 142134124Spjd if (*round_robin && *noround_robin) { 143134124Spjd gctl_error(req, "'%s' and '%s' specified.", "round_robin", 144134124Spjd "noround_robin"); 145134124Spjd return; 146134124Spjd } 147134168Spjd verify = gctl_get_paraml(req, "verify", sizeof(*verify)); 148134168Spjd if (verify == NULL) { 149134168Spjd gctl_error(req, "No '%s' argument.", "verify"); 150134168Spjd return; 151134168Spjd } 152134168Spjd noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify)); 153134168Spjd if (noverify == NULL) { 154134168Spjd gctl_error(req, "No '%s' argument.", "noverify"); 155134168Spjd return; 156134168Spjd } 157134168Spjd if (*verify && *noverify) { 158134168Spjd gctl_error(req, "'%s' and '%s' specified.", "verify", 159134168Spjd "noverify"); 160134168Spjd return; 161134168Spjd } 162134168Spjd if (!*autosync && !*noautosync && !*round_robin && !*noround_robin && 163134168Spjd !*verify && !*noverify) { 164134124Spjd gctl_error(req, "Nothing has changed."); 165134124Spjd return; 166134124Spjd } 167156612Spjd name = gctl_get_asciiparam(req, "arg0"); 168156612Spjd if (name == NULL) { 169156612Spjd gctl_error(req, "No 'arg%u' argument.", 0); 170156612Spjd return; 171156612Spjd } 172156612Spjd sc = g_raid3_find_device(mp, name); 173156612Spjd if (sc == NULL) { 174156612Spjd gctl_error(req, "No such device: %s.", name); 175156612Spjd return; 176156612Spjd } 177156612Spjd if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) { 178156612Spjd gctl_error(req, "Not all disks connected."); 179156612Spjd sx_xunlock(&sc->sc_lock); 180156612Spjd return; 181156612Spjd } 182133808Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) { 183133808Spjd if (*autosync) { 184133808Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 185133808Spjd do_sync = 1; 186133808Spjd } 187133808Spjd } else { 188133808Spjd if (*noautosync) 189133808Spjd sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 190133808Spjd } 191134168Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) { 192134168Spjd if (*noverify) 193134168Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY; 194134168Spjd } else { 195134168Spjd if (*verify) 196134168Spjd sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY; 197134168Spjd } 198134124Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 199134124Spjd if (*noround_robin) 200134124Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 201134124Spjd } else { 202134124Spjd if (*round_robin) 203134124Spjd sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 204134124Spjd } 205134168Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && 206134168Spjd (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 207134168Spjd /* 208134168Spjd * VERIFY and ROUND-ROBIN options are mutally exclusive. 209134168Spjd */ 210134168Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 211134168Spjd } 212133808Spjd for (n = 0; n < sc->sc_ndisks; n++) { 213133808Spjd disk = &sc->sc_disks[n]; 214133808Spjd if (do_sync) { 215133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) 216133808Spjd disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC; 217133808Spjd } 218133808Spjd g_raid3_update_metadata(disk); 219133808Spjd if (do_sync) { 220133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_STALE) { 221133808Spjd /* 222133808Spjd * XXX: This is probably possible that this 223133808Spjd * component will not be retasted. 224133808Spjd */ 225133808Spjd g_raid3_event_send(disk, 226133808Spjd G_RAID3_DISK_STATE_DISCONNECTED, 227133808Spjd G_RAID3_EVENT_DONTWAIT); 228133808Spjd } 229133808Spjd } 230133808Spjd } 231156612Spjd sx_xunlock(&sc->sc_lock); 232133808Spjd} 233133808Spjd 234133808Spjdstatic void 235133808Spjdg_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp) 236133808Spjd{ 237139671Spjd struct g_raid3_metadata md; 238133808Spjd struct g_raid3_softc *sc; 239133808Spjd struct g_raid3_disk *disk; 240139671Spjd struct g_provider *pp; 241133808Spjd const char *name; 242139671Spjd int error, *nargs; 243133808Spjd 244133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 245133808Spjd if (nargs == NULL) { 246133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 247133808Spjd return; 248133808Spjd } 249133808Spjd if (*nargs != 2) { 250133808Spjd gctl_error(req, "Invalid number of arguments."); 251133808Spjd return; 252133808Spjd } 253133808Spjd name = gctl_get_asciiparam(req, "arg0"); 254133808Spjd if (name == NULL) { 255133808Spjd gctl_error(req, "No 'arg%u' argument.", 0); 256133808Spjd return; 257133808Spjd } 258133808Spjd sc = g_raid3_find_device(mp, name); 259133808Spjd if (sc == NULL) { 260133808Spjd gctl_error(req, "No such device: %s.", name); 261133808Spjd return; 262133808Spjd } 263133808Spjd name = gctl_get_asciiparam(req, "arg1"); 264133808Spjd if (name == NULL) { 265133808Spjd gctl_error(req, "No 'arg%u' argument.", 1); 266156612Spjd sx_xunlock(&sc->sc_lock); 267133808Spjd return; 268133808Spjd } 269133808Spjd disk = g_raid3_find_disk(sc, name); 270133808Spjd if (disk == NULL) { 271133808Spjd gctl_error(req, "No such provider: %s.", name); 272156612Spjd sx_xunlock(&sc->sc_lock); 273133808Spjd return; 274133808Spjd } 275133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE && 276133808Spjd g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) { 277133808Spjd gctl_error(req, "There is one stale disk already.", name); 278156612Spjd sx_xunlock(&sc->sc_lock); 279133808Spjd return; 280133808Spjd } 281133808Spjd /* 282133808Spjd * Do rebuild by resetting syncid and disconnecting disk. 283133808Spjd * It'll be retasted, connected to the device and synchronized. 284133808Spjd */ 285133808Spjd disk->d_sync.ds_syncid = 0; 286133808Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) 287133808Spjd disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC; 288133808Spjd g_raid3_update_metadata(disk); 289139671Spjd pp = disk->d_consumer->provider; 290156612Spjd g_topology_lock(); 291139671Spjd error = g_raid3_read_metadata(disk->d_consumer, &md); 292156612Spjd g_topology_unlock(); 293133808Spjd g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 294133808Spjd G_RAID3_EVENT_WAIT); 295139671Spjd if (error != 0) { 296139671Spjd gctl_error(req, "Cannot read metadata from %s.", pp->name); 297156612Spjd sx_xunlock(&sc->sc_lock); 298139671Spjd return; 299139671Spjd } 300139671Spjd error = g_raid3_add_disk(sc, pp, &md); 301156612Spjd if (error != 0) 302139671Spjd gctl_error(req, "Cannot reconnect component %s.", pp->name); 303156612Spjd sx_xunlock(&sc->sc_lock); 304133808Spjd} 305133808Spjd 306133808Spjdstatic void 307133808Spjdg_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp) 308133808Spjd{ 309133808Spjd struct g_raid3_softc *sc; 310133808Spjd int *force, *nargs, error; 311133808Spjd const char *name; 312133808Spjd char param[16]; 313133808Spjd u_int i; 314157630Spjd int how; 315133808Spjd 316133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 317133808Spjd if (nargs == NULL) { 318133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 319133808Spjd return; 320133808Spjd } 321133808Spjd if (*nargs < 1) { 322133808Spjd gctl_error(req, "Missing device(s)."); 323133808Spjd return; 324133808Spjd } 325133808Spjd force = gctl_get_paraml(req, "force", sizeof(*force)); 326133808Spjd if (force == NULL) { 327133808Spjd gctl_error(req, "No '%s' argument.", "force"); 328133808Spjd return; 329133808Spjd } 330157630Spjd if (*force) 331157630Spjd how = G_RAID3_DESTROY_HARD; 332157630Spjd else 333157630Spjd how = G_RAID3_DESTROY_SOFT; 334133808Spjd 335133808Spjd for (i = 0; i < (u_int)*nargs; i++) { 336133808Spjd snprintf(param, sizeof(param), "arg%u", i); 337133808Spjd name = gctl_get_asciiparam(req, param); 338133808Spjd if (name == NULL) { 339133808Spjd gctl_error(req, "No 'arg%u' argument.", i); 340133808Spjd return; 341133808Spjd } 342133808Spjd sc = g_raid3_find_device(mp, name); 343133808Spjd if (sc == NULL) { 344133808Spjd gctl_error(req, "No such device: %s.", name); 345133808Spjd return; 346133808Spjd } 347157630Spjd g_cancel_event(sc); 348157630Spjd error = g_raid3_destroy(sc, how); 349133808Spjd if (error != 0) { 350133808Spjd gctl_error(req, "Cannot destroy device %s (error=%d).", 351133808Spjd sc->sc_geom->name, error); 352156612Spjd sx_xunlock(&sc->sc_lock); 353133808Spjd return; 354133808Spjd } 355156612Spjd /* No need to unlock, because lock is already dead. */ 356133808Spjd } 357133808Spjd} 358133808Spjd 359133808Spjdstatic void 360133808Spjdg_raid3_ctl_insert_orphan(struct g_consumer *cp) 361133808Spjd{ 362133808Spjd 363133808Spjd KASSERT(1 == 0, ("%s called while inserting %s.", __func__, 364133808Spjd cp->provider->name)); 365133808Spjd} 366133808Spjd 367133808Spjdstatic void 368133808Spjdg_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp) 369133808Spjd{ 370133808Spjd struct g_raid3_metadata md; 371133808Spjd struct g_raid3_softc *sc; 372133808Spjd struct g_raid3_disk *disk; 373133808Spjd struct g_geom *gp; 374133808Spjd struct g_provider *pp; 375133808Spjd struct g_consumer *cp; 376133808Spjd const char *name; 377133808Spjd u_char *sector; 378134420Spjd off_t compsize; 379133808Spjd intmax_t *no; 380133808Spjd int *hardcode, *nargs, error; 381133808Spjd 382133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 383133808Spjd if (nargs == NULL) { 384133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 385133808Spjd return; 386133808Spjd } 387133808Spjd if (*nargs != 2) { 388133808Spjd gctl_error(req, "Invalid number of arguments."); 389133808Spjd return; 390133808Spjd } 391156612Spjd hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 392156612Spjd if (hardcode == NULL) { 393156612Spjd gctl_error(req, "No '%s' argument.", "hardcode"); 394133808Spjd return; 395133808Spjd } 396156612Spjd name = gctl_get_asciiparam(req, "arg1"); 397156612Spjd if (name == NULL) { 398156612Spjd gctl_error(req, "No 'arg%u' argument.", 1); 399133808Spjd return; 400133808Spjd } 401133808Spjd no = gctl_get_paraml(req, "number", sizeof(*no)); 402133808Spjd if (no == NULL) { 403133808Spjd gctl_error(req, "No '%s' argument.", "no"); 404133808Spjd return; 405133808Spjd } 406160330Spjd if (strncmp(name, "/dev/", 5) == 0) 407160330Spjd name += 5; 408156612Spjd g_topology_lock(); 409156612Spjd pp = g_provider_by_name(name); 410156612Spjd if (pp == NULL) { 411156612Spjd g_topology_unlock(); 412156612Spjd gctl_error(req, "Invalid provider."); 413156612Spjd return; 414156612Spjd } 415156612Spjd gp = g_new_geomf(mp, "raid3:insert"); 416156612Spjd gp->orphan = g_raid3_ctl_insert_orphan; 417156612Spjd cp = g_new_consumer(gp); 418156612Spjd error = g_attach(cp, pp); 419156612Spjd if (error != 0) { 420156612Spjd g_topology_unlock(); 421156612Spjd gctl_error(req, "Cannot attach to %s.", pp->name); 422156612Spjd goto end; 423156612Spjd } 424156612Spjd error = g_access(cp, 0, 1, 1); 425156612Spjd if (error != 0) { 426156612Spjd g_topology_unlock(); 427156612Spjd gctl_error(req, "Cannot access %s.", pp->name); 428156612Spjd goto end; 429156612Spjd } 430156612Spjd g_topology_unlock(); 431156612Spjd name = gctl_get_asciiparam(req, "arg0"); 432156612Spjd if (name == NULL) { 433156612Spjd gctl_error(req, "No 'arg%u' argument.", 0); 434156612Spjd goto end; 435156612Spjd } 436156612Spjd sc = g_raid3_find_device(mp, name); 437156612Spjd if (sc == NULL) { 438156612Spjd gctl_error(req, "No such device: %s.", name); 439156612Spjd goto end; 440156612Spjd } 441133808Spjd if (*no >= sc->sc_ndisks) { 442156612Spjd sx_xunlock(&sc->sc_lock); 443133808Spjd gctl_error(req, "Invalid component number."); 444156612Spjd goto end; 445133808Spjd } 446133808Spjd disk = &sc->sc_disks[*no]; 447133808Spjd if (disk->d_state != G_RAID3_DISK_STATE_NODISK) { 448156612Spjd sx_xunlock(&sc->sc_lock); 449133808Spjd gctl_error(req, "Component %u is already connected.", *no); 450156612Spjd goto end; 451133808Spjd } 452133808Spjd if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) { 453156612Spjd sx_xunlock(&sc->sc_lock); 454133808Spjd gctl_error(req, 455133808Spjd "Cannot insert provider %s, because of its sector size.", 456133808Spjd pp->name); 457156612Spjd goto end; 458133808Spjd } 459134420Spjd compsize = sc->sc_mediasize / (sc->sc_ndisks - 1); 460134420Spjd if (compsize > pp->mediasize - pp->sectorsize) { 461156612Spjd sx_xunlock(&sc->sc_lock); 462134420Spjd gctl_error(req, "Provider %s too small.", pp->name); 463156612Spjd goto end; 464134420Spjd } 465134420Spjd if (compsize < pp->mediasize - pp->sectorsize) { 466134420Spjd gctl_error(req, 467134420Spjd "warning: %s: only %jd bytes from %jd bytes used.", 468134420Spjd pp->name, (intmax_t)compsize, 469134420Spjd (intmax_t)(pp->mediasize - pp->sectorsize)); 470134420Spjd } 471133808Spjd g_raid3_fill_metadata(disk, &md); 472156612Spjd sx_xunlock(&sc->sc_lock); 473133808Spjd md.md_syncid = 0; 474133808Spjd md.md_dflags = 0; 475133808Spjd if (*hardcode) 476133808Spjd strlcpy(md.md_provider, pp->name, sizeof(md.md_provider)); 477133808Spjd else 478133808Spjd bzero(md.md_provider, sizeof(md.md_provider)); 479156527Spjd md.md_provsize = pp->mediasize; 480133808Spjd sector = g_malloc(pp->sectorsize, M_WAITOK); 481133808Spjd raid3_metadata_encode(&md, sector); 482133808Spjd error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 483133808Spjd pp->sectorsize); 484133808Spjd g_free(sector); 485133808Spjd if (error != 0) 486133808Spjd gctl_error(req, "Cannot store metadata on %s.", pp->name); 487133808Spjdend: 488156612Spjd g_topology_lock(); 489146118Spjd if (cp->acw > 0) 490146118Spjd g_access(cp, 0, -1, -1); 491146118Spjd if (cp->provider != NULL) 492146118Spjd g_detach(cp); 493146118Spjd g_destroy_consumer(cp); 494146117Spjd g_destroy_geom(gp); 495156612Spjd g_topology_unlock(); 496133808Spjd} 497133808Spjd 498133808Spjdstatic void 499133808Spjdg_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp) 500133808Spjd{ 501133808Spjd struct g_raid3_softc *sc; 502133808Spjd struct g_raid3_disk *disk; 503133808Spjd const char *name; 504133808Spjd intmax_t *no; 505133808Spjd int *nargs; 506133808Spjd 507133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 508133808Spjd if (nargs == NULL) { 509133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 510133808Spjd return; 511133808Spjd } 512133808Spjd if (*nargs != 1) { 513133808Spjd gctl_error(req, "Invalid number of arguments."); 514133808Spjd return; 515133808Spjd } 516156612Spjd no = gctl_get_paraml(req, "number", sizeof(*no)); 517156612Spjd if (no == NULL) { 518156612Spjd gctl_error(req, "No '%s' argument.", "no"); 519156612Spjd return; 520156612Spjd } 521133808Spjd name = gctl_get_asciiparam(req, "arg0"); 522133808Spjd if (name == NULL) { 523133808Spjd gctl_error(req, "No 'arg%u' argument.", 0); 524133808Spjd return; 525133808Spjd } 526133808Spjd sc = g_raid3_find_device(mp, name); 527133808Spjd if (sc == NULL) { 528133808Spjd gctl_error(req, "No such device: %s.", name); 529133808Spjd return; 530133808Spjd } 531133808Spjd if (*no >= sc->sc_ndisks) { 532156612Spjd sx_xunlock(&sc->sc_lock); 533133808Spjd gctl_error(req, "Invalid component number."); 534133808Spjd return; 535133808Spjd } 536133808Spjd disk = &sc->sc_disks[*no]; 537133808Spjd switch (disk->d_state) { 538133808Spjd case G_RAID3_DISK_STATE_ACTIVE: 539133808Spjd /* 540133808Spjd * When replacing ACTIVE component, all the rest has to be also 541133808Spjd * ACTIVE. 542133808Spjd */ 543133808Spjd if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < 544133808Spjd sc->sc_ndisks) { 545133808Spjd gctl_error(req, "Cannot replace component number %u.", 546133808Spjd *no); 547156612Spjd break; 548133808Spjd } 549133808Spjd /* FALLTHROUGH */ 550133808Spjd case G_RAID3_DISK_STATE_STALE: 551133808Spjd case G_RAID3_DISK_STATE_SYNCHRONIZING: 552133808Spjd if (g_raid3_clear_metadata(disk) != 0) { 553133808Spjd gctl_error(req, "Cannot clear metadata on %s.", 554133808Spjd g_raid3_get_diskname(disk)); 555139295Spjd } else { 556139295Spjd g_raid3_event_send(disk, 557139295Spjd G_RAID3_DISK_STATE_DISCONNECTED, 558156612Spjd G_RAID3_EVENT_DONTWAIT); 559133808Spjd } 560133808Spjd break; 561133808Spjd case G_RAID3_DISK_STATE_NODISK: 562133808Spjd break; 563133808Spjd default: 564133808Spjd gctl_error(req, "Cannot replace component number %u.", *no); 565156612Spjd break; 566133808Spjd } 567156612Spjd sx_xunlock(&sc->sc_lock); 568133808Spjd} 569133808Spjd 570133808Spjdvoid 571133808Spjdg_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb) 572133808Spjd{ 573133808Spjd uint32_t *version; 574133808Spjd 575133808Spjd g_topology_assert(); 576133808Spjd 577133808Spjd version = gctl_get_paraml(req, "version", sizeof(*version)); 578133808Spjd if (version == NULL) { 579133808Spjd gctl_error(req, "No '%s' argument.", "version"); 580133808Spjd return; 581133808Spjd } 582133808Spjd if (*version != G_RAID3_VERSION) { 583133808Spjd gctl_error(req, "Userland and kernel parts are out of sync."); 584133808Spjd return; 585133808Spjd } 586133808Spjd 587156612Spjd g_topology_unlock(); 588133808Spjd if (strcmp(verb, "configure") == 0) 589133808Spjd g_raid3_ctl_configure(req, mp); 590133808Spjd else if (strcmp(verb, "insert") == 0) 591133808Spjd g_raid3_ctl_insert(req, mp); 592133808Spjd else if (strcmp(verb, "rebuild") == 0) 593133808Spjd g_raid3_ctl_rebuild(req, mp); 594133808Spjd else if (strcmp(verb, "remove") == 0) 595133808Spjd g_raid3_ctl_remove(req, mp); 596133808Spjd else if (strcmp(verb, "stop") == 0) 597133808Spjd g_raid3_ctl_stop(req, mp); 598133808Spjd else 599133808Spjd gctl_error(req, "Unknown verb."); 600156612Spjd g_topology_lock(); 601133808Spjd} 602