1 /*- 2 * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/module.h> 34 #include <sys/lock.h> 35 #include <sys/mutex.h> 36 #include <sys/bio.h> 37 #include <sys/sysctl.h> 38 #include <sys/malloc.h> 39 #include <sys/bitstring.h> 40 #include <vm/uma.h> 41 #include <machine/atomic.h> 42 #include <geom/geom.h> 43 #include <sys/proc.h> 44 #include <sys/kthread.h> 45 #include <geom/mirror/g_mirror.h> 46 47 48 static struct g_mirror_softc * 49 g_mirror_find_device(struct g_class *mp, const char *name) 50 { 51 struct g_mirror_softc *sc; 52 struct g_geom *gp; 53 54 g_topology_lock(); 55 LIST_FOREACH(gp, &mp->geom, geom) { 56 sc = gp->softc; 57 if (sc == NULL) 58 continue; 59 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) 60 continue; 61 if (strcmp(gp->name, name) == 0 || 62 strcmp(sc->sc_name, name) == 0) { 63 g_topology_unlock(); 64 sx_xlock(&sc->sc_lock); 65 return (sc); 66 } 67 } 68 g_topology_unlock(); 69 return (NULL); 70 } 71 72 static struct g_mirror_disk * 73 g_mirror_find_disk(struct g_mirror_softc *sc, const char *name) 74 { 75 struct g_mirror_disk *disk; 76 77 sx_assert(&sc->sc_lock, SX_XLOCKED); 78 if (strncmp(name, "/dev/", 5) == 0) 79 name += 5; 80 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 81 if (disk->d_consumer == NULL) 82 continue; 83 if (disk->d_consumer->provider == NULL) 84 continue; 85 if (strcmp(disk->d_consumer->provider->name, name) == 0) 86 return (disk); 87 } 88 return (NULL); 89 } 90 91 static void 92 g_mirror_ctl_configure(struct gctl_req *req, struct g_class *mp) 93 { 94 struct g_mirror_softc *sc; 95 struct g_mirror_disk *disk; 96 const char *name, *balancep; 97 intmax_t *slicep; 98 uint32_t slice; 99 uint8_t balance; 100 int *nargs, *autosync, *noautosync, *hardcode, *dynamic, do_sync = 0; 101 102 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 103 if (nargs == NULL) { 104 gctl_error(req, "No '%s' argument.", "nargs"); 105 return; 106 } 107 if (*nargs != 1) { 108 gctl_error(req, "Invalid number of arguments."); 109 return; 110 } 111 name = gctl_get_asciiparam(req, "arg0"); 112 if (name == NULL) { 113 gctl_error(req, "No 'arg%u' argument.", 0); 114 return; 115 } 116 balancep = gctl_get_asciiparam(req, "balance"); 117 if (balancep == NULL) { 118 gctl_error(req, "No '%s' argument.", "balance"); 119 return; 120 } 121 autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync)); 122 if (autosync == NULL) { 123 gctl_error(req, "No '%s' argument.", "autosync"); 124 return; 125 } 126 noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 127 if (noautosync == NULL) { 128 gctl_error(req, "No '%s' argument.", "noautosync"); 129 return; 130 } 131 hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 132 if (hardcode == NULL) { 133 gctl_error(req, "No '%s' argument.", "hardcode"); 134 return; 135 } 136 dynamic = gctl_get_paraml(req, "dynamic", sizeof(*dynamic)); 137 if (dynamic == NULL) { 138 gctl_error(req, "No '%s' argument.", "dynamic"); 139 return; 140 } 141 if (*autosync && *noautosync) { 142 gctl_error(req, "'%s' and '%s' specified.", "autosync", 143 "noautosync"); 144 return; 145 } 146 if (*hardcode && *dynamic) { 147 gctl_error(req, "'%s' and '%s' specified.", "hardcode", 148 "dynamic"); 149 return; 150 } 151 sc = g_mirror_find_device(mp, name); 152 if (sc == NULL) { 153 gctl_error(req, "No such device: %s.", name); 154 return; 155 } 156 if (strcmp(balancep, "none") == 0) 157 balance = sc->sc_balance; 158 else { 159 if (balance_id(balancep) == -1) { 160 gctl_error(req, "Invalid balance algorithm."); 161 sx_xunlock(&sc->sc_lock); 162 return; 163 } 164 balance = balance_id(balancep); 165 } 166 slicep = gctl_get_paraml(req, "slice", sizeof(*slicep)); 167 if (slicep == NULL) { 168 gctl_error(req, "No '%s' argument.", "slice"); 169 sx_xunlock(&sc->sc_lock); 170 return; 171 } 172 if (*slicep == -1) 173 slice = sc->sc_slice; 174 else 175 slice = *slicep; 176 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 177 sx_xunlock(&sc->sc_lock); 178 gctl_error(req, "Not all disks connected. Try 'forget' command " 179 "first."); 180 return; 181 } 182 if (sc->sc_balance == balance && sc->sc_slice == slice && !*autosync && 183 !*noautosync && !*hardcode && !*dynamic) { 184 sx_xunlock(&sc->sc_lock); 185 gctl_error(req, "Nothing has changed."); 186 return; 187 } 188 sc->sc_balance = balance; 189 sc->sc_slice = slice; 190 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0) { 191 if (*autosync) { 192 sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_NOAUTOSYNC; 193 do_sync = 1; 194 } 195 } else { 196 if (*noautosync) 197 sc->sc_flags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC; 198 } 199 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 200 if (do_sync) { 201 if (disk->d_state == G_MIRROR_DISK_STATE_SYNCHRONIZING) 202 disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC; 203 } 204 if (*hardcode) 205 disk->d_flags |= G_MIRROR_DISK_FLAG_HARDCODED; 206 else if (*dynamic) 207 disk->d_flags &= ~G_MIRROR_DISK_FLAG_HARDCODED; 208 g_mirror_update_metadata(disk); 209 if (do_sync) { 210 if (disk->d_state == G_MIRROR_DISK_STATE_STALE) { 211 g_mirror_event_send(disk, 212 G_MIRROR_DISK_STATE_DISCONNECTED, 213 G_MIRROR_EVENT_DONTWAIT); 214 } 215 } 216 } 217 sx_xunlock(&sc->sc_lock); 218 } 219 220 static void 221 g_mirror_ctl_rebuild(struct gctl_req *req, struct g_class *mp) 222 { 223 struct g_mirror_metadata md; 224 struct g_mirror_softc *sc; 225 struct g_mirror_disk *disk; 226 struct g_provider *pp; 227 const char *name; 228 char param[16]; 229 int error, *nargs; 230 u_int i; 231 232 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 233 if (nargs == NULL) { 234 gctl_error(req, "No '%s' argument.", "nargs"); 235 return; 236 } 237 if (*nargs < 2) { 238 gctl_error(req, "Too few arguments."); 239 return; 240 } 241 name = gctl_get_asciiparam(req, "arg0"); 242 if (name == NULL) { 243 gctl_error(req, "No 'arg%u' argument.", 0); 244 return; 245 } 246 sc = g_mirror_find_device(mp, name); 247 if (sc == NULL) { 248 gctl_error(req, "No such device: %s.", name); 249 return; 250 } 251 for (i = 1; i < (u_int)*nargs; i++) { 252 snprintf(param, sizeof(param), "arg%u", i); 253 name = gctl_get_asciiparam(req, param); 254 if (name == NULL) { 255 gctl_error(req, "No 'arg%u' argument.", i); 256 continue; 257 } 258 disk = g_mirror_find_disk(sc, name); 259 if (disk == NULL) { 260 gctl_error(req, "No such provider: %s.", name); 261 continue; 262 } 263 if (g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) == 1 && 264 disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) { 265 /* 266 * This is the last active disk. There will be nothing 267 * to rebuild it from, so deny this request. 268 */ 269 gctl_error(req, 270 "Provider %s is the last active provider in %s.", 271 name, sc->sc_geom->name); 272 break; 273 } 274 /* 275 * Do rebuild by resetting syncid, disconnecting the disk and 276 * connecting it again. 277 */ 278 disk->d_sync.ds_syncid = 0; 279 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0) 280 disk->d_flags |= G_MIRROR_DISK_FLAG_FORCE_SYNC; 281 g_mirror_update_metadata(disk); 282 pp = disk->d_consumer->provider; 283 g_topology_lock(); 284 error = g_mirror_read_metadata(disk->d_consumer, &md); 285 g_topology_unlock(); 286 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, 287 G_MIRROR_EVENT_WAIT); 288 if (error != 0) { 289 gctl_error(req, "Cannot read metadata from %s.", 290 pp->name); 291 continue; 292 } 293 error = g_mirror_add_disk(sc, pp, &md); 294 if (error != 0) { 295 gctl_error(req, "Cannot reconnect component %s.", 296 pp->name); 297 continue; 298 } 299 } 300 sx_xunlock(&sc->sc_lock); 301 } 302 303 static void 304 g_mirror_ctl_insert(struct gctl_req *req, struct g_class *mp) 305 { 306 struct g_mirror_softc *sc; 307 struct g_mirror_disk *disk; 308 struct g_mirror_metadata md; 309 struct g_provider *pp; 310 struct g_consumer *cp; 311 intmax_t *priority; 312 const char *name; 313 char param[16]; 314 u_char *sector; 315 u_int i, n; 316 int error, *nargs, *hardcode, *inactive; 317 struct { 318 struct g_provider *provider; 319 struct g_consumer *consumer; 320 } *disks; 321 322 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 323 if (nargs == NULL) { 324 gctl_error(req, "No '%s' argument.", "nargs"); 325 return; 326 } 327 if (*nargs < 2) { 328 gctl_error(req, "Too few arguments."); 329 return; 330 } 331 priority = gctl_get_paraml(req, "priority", sizeof(*priority)); 332 if (priority == NULL) { 333 gctl_error(req, "No '%s' argument.", "priority"); 334 return; 335 } 336 inactive = gctl_get_paraml(req, "inactive", sizeof(*inactive)); 337 if (inactive == NULL) { 338 gctl_error(req, "No '%s' argument.", "inactive"); 339 return; 340 } 341 hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 342 if (hardcode == NULL) { 343 gctl_error(req, "No '%s' argument.", "hardcode"); 344 return; 345 } 346 name = gctl_get_asciiparam(req, "arg0"); 347 if (name == NULL) { 348 gctl_error(req, "No 'arg%u' argument.", 0); 349 return; 350 } 351 sc = g_mirror_find_device(mp, name); 352 if (sc == NULL) { 353 gctl_error(req, "No such device: %s.", name); 354 return; 355 } 356 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 357 gctl_error(req, "Not all disks connected."); 358 sx_xunlock(&sc->sc_lock); 359 return; 360 } 361 362 disks = g_malloc(sizeof(*disks) * (*nargs), M_WAITOK | M_ZERO); 363 g_topology_lock(); 364 for (i = 1, n = 0; i < (u_int)*nargs; i++) { 365 snprintf(param, sizeof(param), "arg%u", i); 366 name = gctl_get_asciiparam(req, param); 367 if (name == NULL) { 368 gctl_error(req, "No 'arg%u' argument.", i); 369 continue; 370 } 371 if (g_mirror_find_disk(sc, name) != NULL) { 372 gctl_error(req, "Provider %s already inserted.", name); 373 continue; 374 } 375 if (strncmp(name, "/dev/", 5) == 0) 376 name += 5; 377 pp = g_provider_by_name(name); 378 if (pp == NULL) { 379 gctl_error(req, "Unknown provider %s.", name); 380 continue; 381 } 382 if (sc->sc_provider->mediasize > 383 pp->mediasize - pp->sectorsize) { 384 gctl_error(req, "Provider %s too small.", name); 385 continue; 386 } 387 if ((sc->sc_provider->sectorsize % pp->sectorsize) != 0) { 388 gctl_error(req, "Invalid sectorsize of provider %s.", 389 name); 390 continue; 391 } 392 cp = g_new_consumer(sc->sc_geom); 393 if (g_attach(cp, pp) != 0) { 394 g_destroy_consumer(cp); 395 gctl_error(req, "Cannot attach to provider %s.", name); 396 continue; 397 } 398 if (g_access(cp, 0, 1, 1) != 0) { 399 g_detach(cp); 400 g_destroy_consumer(cp); 401 gctl_error(req, "Cannot access provider %s.", name); 402 continue; 403 } 404 disks[n].provider = pp; 405 disks[n].consumer = cp; 406 n++; 407 } 408 if (n == 0) { 409 g_topology_unlock(); 410 sx_xunlock(&sc->sc_lock); 411 g_free(disks); 412 return; 413 } 414 sc->sc_ndisks += n; 415 again: 416 for (i = 0; i < n; i++) { 417 if (disks[i].consumer == NULL) 418 continue; 419 g_mirror_fill_metadata(sc, NULL, &md); 420 md.md_priority = *priority; 421 if (*inactive) 422 md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE; 423 pp = disks[i].provider; 424 if (*hardcode) { 425 strlcpy(md.md_provider, pp->name, 426 sizeof(md.md_provider)); 427 } else { 428 bzero(md.md_provider, sizeof(md.md_provider)); 429 } 430 md.md_provsize = pp->mediasize; 431 sector = g_malloc(pp->sectorsize, M_WAITOK); 432 mirror_metadata_encode(&md, sector); 433 error = g_write_data(disks[i].consumer, 434 pp->mediasize - pp->sectorsize, sector, pp->sectorsize); 435 g_free(sector); 436 if (error != 0) { 437 gctl_error(req, "Cannot store metadata on %s.", 438 pp->name); 439 g_access(disks[i].consumer, 0, -1, -1); 440 g_detach(disks[i].consumer); 441 g_destroy_consumer(disks[i].consumer); 442 disks[i].consumer = NULL; 443 disks[i].provider = NULL; 444 sc->sc_ndisks--; 445 goto again; 446 } 447 } 448 g_topology_unlock(); 449 if (i == 0) { 450 /* All writes failed. */ 451 sx_xunlock(&sc->sc_lock); 452 g_free(disks); 453 return; 454 } 455 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 456 g_mirror_update_metadata(disk); 457 } 458 /* 459 * Release provider and wait for retaste. 460 */ 461 g_topology_lock(); 462 for (i = 0; i < n; i++) { 463 if (disks[i].consumer == NULL) 464 continue; 465 g_access(disks[i].consumer, 0, -1, -1); 466 g_detach(disks[i].consumer); 467 g_destroy_consumer(disks[i].consumer); 468 } 469 g_topology_unlock(); 470 sx_xunlock(&sc->sc_lock); 471 g_free(disks); 472 } 473 474 static void 475 g_mirror_ctl_remove(struct gctl_req *req, struct g_class *mp) 476 { 477 struct g_mirror_softc *sc; 478 struct g_mirror_disk *disk; 479 const char *name; 480 char param[16]; 481 int *nargs; 482 u_int i; 483 484 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 485 if (nargs == NULL) { 486 gctl_error(req, "No '%s' argument.", "nargs"); 487 return; 488 } 489 if (*nargs < 2) { 490 gctl_error(req, "Too few arguments."); 491 return; 492 } 493 name = gctl_get_asciiparam(req, "arg0"); 494 if (name == NULL) { 495 gctl_error(req, "No 'arg%u' argument.", 0); 496 return; 497 } 498 sc = g_mirror_find_device(mp, name); 499 if (sc == NULL) { 500 gctl_error(req, "No such device: %s.", name); 501 return; 502 } 503 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 504 sx_xunlock(&sc->sc_lock); 505 gctl_error(req, "Not all disks connected. Try 'forget' command " 506 "first."); 507 return; 508 } 509 for (i = 1; i < (u_int)*nargs; i++) { 510 snprintf(param, sizeof(param), "arg%u", i); 511 name = gctl_get_asciiparam(req, param); 512 if (name == NULL) { 513 gctl_error(req, "No 'arg%u' argument.", i); 514 continue; 515 } 516 disk = g_mirror_find_disk(sc, name); 517 if (disk == NULL) { 518 gctl_error(req, "No such provider: %s.", name); 519 continue; 520 } 521 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DESTROY, 522 G_MIRROR_EVENT_DONTWAIT); 523 } 524 sx_xunlock(&sc->sc_lock); 525 } 526 527 static void 528 g_mirror_ctl_deactivate(struct gctl_req *req, struct g_class *mp) 529 { 530 struct g_mirror_softc *sc; 531 struct g_mirror_disk *disk; 532 const char *name; 533 char param[16]; 534 int *nargs; 535 u_int i; 536 537 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 538 if (nargs == NULL) { 539 gctl_error(req, "No '%s' argument.", "nargs"); 540 return; 541 } 542 if (*nargs < 2) { 543 gctl_error(req, "Too few arguments."); 544 return; 545 } 546 name = gctl_get_asciiparam(req, "arg0"); 547 if (name == NULL) { 548 gctl_error(req, "No 'arg%u' argument.", 0); 549 return; 550 } 551 sc = g_mirror_find_device(mp, name); 552 if (sc == NULL) { 553 gctl_error(req, "No such device: %s.", name); 554 return; 555 } 556 for (i = 1; i < (u_int)*nargs; i++) { 557 snprintf(param, sizeof(param), "arg%u", i); 558 name = gctl_get_asciiparam(req, param); 559 if (name == NULL) { 560 gctl_error(req, "No 'arg%u' argument.", i); 561 continue; 562 } 563 disk = g_mirror_find_disk(sc, name); 564 if (disk == NULL) { 565 gctl_error(req, "No such provider: %s.", name); 566 continue; 567 } 568 disk->d_flags |= G_MIRROR_DISK_FLAG_INACTIVE; 569 disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC; 570 g_mirror_update_metadata(disk); 571 sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID; 572 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, 573 G_MIRROR_EVENT_DONTWAIT); 574 } 575 sx_xunlock(&sc->sc_lock); 576 } 577 578 static void 579 g_mirror_ctl_forget(struct gctl_req *req, struct g_class *mp) 580 { 581 struct g_mirror_softc *sc; 582 struct g_mirror_disk *disk; 583 const char *name; 584 char param[16]; 585 int *nargs; 586 u_int i; 587 588 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 589 if (nargs == NULL) { 590 gctl_error(req, "No '%s' argument.", "nargs"); 591 return; 592 } 593 if (*nargs < 1) { 594 gctl_error(req, "Missing device(s)."); 595 return; 596 } 597 598 for (i = 0; i < (u_int)*nargs; i++) { 599 snprintf(param, sizeof(param), "arg%u", i); 600 name = gctl_get_asciiparam(req, param); 601 if (name == NULL) { 602 gctl_error(req, "No 'arg%u' argument.", i); 603 return; 604 } 605 sc = g_mirror_find_device(mp, name); 606 if (sc == NULL) { 607 gctl_error(req, "No such device: %s.", name); 608 return; 609 } 610 if (g_mirror_ndisks(sc, -1) == sc->sc_ndisks) { 611 sx_xunlock(&sc->sc_lock); 612 G_MIRROR_DEBUG(1, 613 "All disks connected in %s, skipping.", 614 sc->sc_name); 615 continue; 616 } 617 sc->sc_ndisks = g_mirror_ndisks(sc, -1); 618 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 619 g_mirror_update_metadata(disk); 620 } 621 sx_xunlock(&sc->sc_lock); 622 } 623 } 624 625 static void 626 g_mirror_ctl_stop(struct gctl_req *req, struct g_class *mp) 627 { 628 struct g_mirror_softc *sc; 629 int *force, *nargs, error; 630 const char *name; 631 char param[16]; 632 u_int i; 633 int how; 634 635 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 636 if (nargs == NULL) { 637 gctl_error(req, "No '%s' argument.", "nargs"); 638 return; 639 } 640 if (*nargs < 1) { 641 gctl_error(req, "Missing device(s)."); 642 return; 643 } 644 force = gctl_get_paraml(req, "force", sizeof(*force)); 645 if (force == NULL) { 646 gctl_error(req, "No '%s' argument.", "force"); 647 return; 648 } 649 if (*force) 650 how = G_MIRROR_DESTROY_HARD; 651 else 652 how = G_MIRROR_DESTROY_SOFT; 653 654 for (i = 0; i < (u_int)*nargs; i++) { 655 snprintf(param, sizeof(param), "arg%u", i); 656 name = gctl_get_asciiparam(req, param); 657 if (name == NULL) { 658 gctl_error(req, "No 'arg%u' argument.", i); 659 return; 660 } 661 sc = g_mirror_find_device(mp, name); 662 if (sc == NULL) { 663 gctl_error(req, "No such device: %s.", name); 664 return; 665 } 666 g_cancel_event(sc); 667 error = g_mirror_destroy(sc, how); 668 if (error != 0) { 669 gctl_error(req, "Cannot destroy device %s (error=%d).", 670 sc->sc_geom->name, error); 671 sx_xunlock(&sc->sc_lock); 672 return; 673 } 674 /* No need to unlock, because lock is already dead. */ 675 } 676 } 677 678 void 679 g_mirror_config(struct gctl_req *req, struct g_class *mp, const char *verb) 680 { 681 uint32_t *version; 682 683 g_topology_assert(); 684 685 version = gctl_get_paraml(req, "version", sizeof(*version)); 686 if (version == NULL) { 687 gctl_error(req, "No '%s' argument.", "version"); 688 return; 689 } 690 if (*version != G_MIRROR_VERSION) { 691 gctl_error(req, "Userland and kernel parts are out of sync."); 692 return; 693 } 694 695 g_topology_unlock(); 696 if (strcmp(verb, "configure") == 0) 697 g_mirror_ctl_configure(req, mp); 698 else if (strcmp(verb, "rebuild") == 0) 699 g_mirror_ctl_rebuild(req, mp); 700 else if (strcmp(verb, "insert") == 0) 701 g_mirror_ctl_insert(req, mp); 702 else if (strcmp(verb, "remove") == 0) 703 g_mirror_ctl_remove(req, mp); 704 else if (strcmp(verb, "deactivate") == 0) 705 g_mirror_ctl_deactivate(req, mp); 706 else if (strcmp(verb, "forget") == 0) 707 g_mirror_ctl_forget(req, mp); 708 else if (strcmp(verb, "stop") == 0) 709 g_mirror_ctl_stop(req, mp); 710 else 711 gctl_error(req, "Unknown verb."); 712 g_topology_lock(); 713 } 714