1 /*- 2 * Copyright (c) 2004-2009 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/limits.h> 35 #include <sys/lock.h> 36 #include <sys/mutex.h> 37 #include <sys/bio.h> 38 #include <sys/sysctl.h> 39 #include <sys/malloc.h> 40 #include <sys/bitstring.h> 41 #include <vm/uma.h> 42 #include <machine/atomic.h> 43 #include <geom/geom.h> 44 #include <geom/geom_int.h> 45 #include <sys/proc.h> 46 #include <sys/kthread.h> 47 #include <geom/mirror/g_mirror.h> 48 49 50 static struct g_mirror_softc * 51 g_mirror_find_device(struct g_class *mp, const char *name) 52 { 53 struct g_mirror_softc *sc; 54 struct g_geom *gp; 55 56 g_topology_lock(); 57 LIST_FOREACH(gp, &mp->geom, geom) { 58 sc = gp->softc; 59 if (sc == NULL) 60 continue; 61 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) 62 continue; 63 if (strcmp(gp->name, name) == 0 || 64 strcmp(sc->sc_name, name) == 0) { 65 g_topology_unlock(); 66 sx_xlock(&sc->sc_lock); 67 return (sc); 68 } 69 } 70 g_topology_unlock(); 71 return (NULL); 72 } 73 74 static struct g_mirror_disk * 75 g_mirror_find_disk(struct g_mirror_softc *sc, const char *name) 76 { 77 struct g_mirror_disk *disk; 78 79 sx_assert(&sc->sc_lock, SX_XLOCKED); 80 if (strncmp(name, "/dev/", 5) == 0) 81 name += 5; 82 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 83 if (disk->d_consumer == NULL) 84 continue; 85 if (disk->d_consumer->provider == NULL) 86 continue; 87 if (strcmp(disk->d_consumer->provider->name, name) == 0) 88 return (disk); 89 } 90 return (NULL); 91 } 92 93 static void 94 g_mirror_ctl_configure(struct gctl_req *req, struct g_class *mp) 95 { 96 struct g_mirror_softc *sc; 97 struct g_mirror_disk *disk; 98 const char *name, *balancep, *prov; 99 intmax_t *slicep, *priority; 100 uint32_t slice; 101 uint8_t balance; 102 int *autosync, *noautosync, *failsync, *nofailsync, *hardcode, *dynamic; 103 int *nargs, do_sync = 0, dirty = 1, do_priority = 0; 104 105 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 106 if (nargs == NULL) { 107 gctl_error(req, "No '%s' argument.", "nargs"); 108 return; 109 } 110 if (*nargs != 1 && *nargs != 2) { 111 gctl_error(req, "Invalid number of arguments."); 112 return; 113 } 114 name = gctl_get_asciiparam(req, "arg0"); 115 if (name == NULL) { 116 gctl_error(req, "No 'arg%u' argument.", 0); 117 return; 118 } 119 balancep = gctl_get_asciiparam(req, "balance"); 120 if (balancep == NULL) { 121 gctl_error(req, "No '%s' argument.", "balance"); 122 return; 123 } 124 autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync)); 125 if (autosync == NULL) { 126 gctl_error(req, "No '%s' argument.", "autosync"); 127 return; 128 } 129 noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 130 if (noautosync == NULL) { 131 gctl_error(req, "No '%s' argument.", "noautosync"); 132 return; 133 } 134 failsync = gctl_get_paraml(req, "failsync", sizeof(*failsync)); 135 if (failsync == NULL) { 136 gctl_error(req, "No '%s' argument.", "failsync"); 137 return; 138 } 139 nofailsync = gctl_get_paraml(req, "nofailsync", sizeof(*nofailsync)); 140 if (nofailsync == NULL) { 141 gctl_error(req, "No '%s' argument.", "nofailsync"); 142 return; 143 } 144 hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 145 if (hardcode == NULL) { 146 gctl_error(req, "No '%s' argument.", "hardcode"); 147 return; 148 } 149 dynamic = gctl_get_paraml(req, "dynamic", sizeof(*dynamic)); 150 if (dynamic == NULL) { 151 gctl_error(req, "No '%s' argument.", "dynamic"); 152 return; 153 } 154 priority = gctl_get_paraml(req, "priority", sizeof(*priority)); 155 if (priority == NULL) { 156 gctl_error(req, "No '%s' argument.", "priority"); 157 return; 158 } 159 if (*priority < -1 || *priority > 255) { 160 gctl_error(req, "Priority range is 0 to 255, %jd given", 161 *priority); 162 return; 163 } 164 /* 165 * Since we have a priority, we also need a provider now. 166 * Note: be WARNS safe, by always assigning prov and only throw an 167 * error if *priority != -1. 168 */ 169 prov = gctl_get_asciiparam(req, "arg1"); 170 if (*priority > -1) { 171 if (prov == NULL) { 172 gctl_error(req, "Priority needs a disk name"); 173 return; 174 } 175 do_priority = 1; 176 } 177 if (*autosync && *noautosync) { 178 gctl_error(req, "'%s' and '%s' specified.", "autosync", 179 "noautosync"); 180 return; 181 } 182 if (*failsync && *nofailsync) { 183 gctl_error(req, "'%s' and '%s' specified.", "failsync", 184 "nofailsync"); 185 return; 186 } 187 if (*hardcode && *dynamic) { 188 gctl_error(req, "'%s' and '%s' specified.", "hardcode", 189 "dynamic"); 190 return; 191 } 192 sc = g_mirror_find_device(mp, name); 193 if (sc == NULL) { 194 gctl_error(req, "No such device: %s.", name); 195 return; 196 } 197 if (*balancep == '\0') 198 balance = sc->sc_balance; 199 else { 200 if (balance_id(balancep) == -1) { 201 gctl_error(req, "Invalid balance algorithm."); 202 sx_xunlock(&sc->sc_lock); 203 return; 204 } 205 balance = balance_id(balancep); 206 } 207 slicep = gctl_get_paraml(req, "slice", sizeof(*slicep)); 208 if (slicep == NULL) { 209 gctl_error(req, "No '%s' argument.", "slice"); 210 sx_xunlock(&sc->sc_lock); 211 return; 212 } 213 if (*slicep == -1) 214 slice = sc->sc_slice; 215 else 216 slice = *slicep; 217 /* Enforce usage() of -p not allowing any other options. */ 218 if (do_priority && (*autosync || *noautosync || *failsync || 219 *nofailsync || *hardcode || *dynamic || *slicep != -1 || 220 *balancep != '\0')) { 221 sx_xunlock(&sc->sc_lock); 222 gctl_error(req, "only -p accepted when setting priority"); 223 return; 224 } 225 if (sc->sc_balance == balance && sc->sc_slice == slice && !*autosync && 226 !*noautosync && !*failsync && !*nofailsync && !*hardcode && 227 !*dynamic && !do_priority) { 228 sx_xunlock(&sc->sc_lock); 229 gctl_error(req, "Nothing has changed."); 230 return; 231 } 232 if ((!do_priority && *nargs != 1) || (do_priority && *nargs != 2)) { 233 sx_xunlock(&sc->sc_lock); 234 gctl_error(req, "Invalid number of arguments."); 235 return; 236 } 237 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 238 sx_xunlock(&sc->sc_lock); 239 gctl_error(req, "Not all disks connected. Try 'forget' command " 240 "first."); 241 return; 242 } 243 sc->sc_balance = balance; 244 sc->sc_slice = slice; 245 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0) { 246 if (*autosync) { 247 sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_NOAUTOSYNC; 248 do_sync = 1; 249 } 250 } else { 251 if (*noautosync) 252 sc->sc_flags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC; 253 } 254 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOFAILSYNC) != 0) { 255 if (*failsync) 256 sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_NOFAILSYNC; 257 } else { 258 if (*nofailsync) { 259 sc->sc_flags |= G_MIRROR_DEVICE_FLAG_NOFAILSYNC; 260 dirty = 0; 261 } 262 } 263 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 264 /* 265 * Handle priority first, since we only need one disk, do one 266 * operation on it and then we're done. No need to check other 267 * flags, as usage doesn't allow it. 268 */ 269 if (do_priority) { 270 if (strcmp(disk->d_name, prov) == 0) { 271 if (disk->d_priority == *priority) 272 gctl_error(req, "Nothing has changed."); 273 else { 274 disk->d_priority = *priority; 275 g_mirror_update_metadata(disk); 276 } 277 break; 278 } 279 continue; 280 } 281 if (do_sync) { 282 if (disk->d_state == G_MIRROR_DISK_STATE_SYNCHRONIZING) 283 disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC; 284 } 285 if (*hardcode) 286 disk->d_flags |= G_MIRROR_DISK_FLAG_HARDCODED; 287 else if (*dynamic) 288 disk->d_flags &= ~G_MIRROR_DISK_FLAG_HARDCODED; 289 if (!dirty) 290 disk->d_flags &= ~G_MIRROR_DISK_FLAG_DIRTY; 291 g_mirror_update_metadata(disk); 292 if (do_sync) { 293 if (disk->d_state == G_MIRROR_DISK_STATE_STALE) { 294 g_mirror_event_send(disk, 295 G_MIRROR_DISK_STATE_DISCONNECTED, 296 G_MIRROR_EVENT_DONTWAIT); 297 } 298 } 299 } 300 sx_xunlock(&sc->sc_lock); 301 } 302 303 static void 304 g_mirror_ctl_rebuild(struct gctl_req *req, struct g_class *mp) 305 { 306 struct g_mirror_metadata md; 307 struct g_mirror_softc *sc; 308 struct g_mirror_disk *disk; 309 struct g_provider *pp; 310 const char *name; 311 char param[16]; 312 int error, *nargs; 313 u_int i; 314 315 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 316 if (nargs == NULL) { 317 gctl_error(req, "No '%s' argument.", "nargs"); 318 return; 319 } 320 if (*nargs < 2) { 321 gctl_error(req, "Too few arguments."); 322 return; 323 } 324 name = gctl_get_asciiparam(req, "arg0"); 325 if (name == NULL) { 326 gctl_error(req, "No 'arg%u' argument.", 0); 327 return; 328 } 329 sc = g_mirror_find_device(mp, name); 330 if (sc == NULL) { 331 gctl_error(req, "No such device: %s.", name); 332 return; 333 } 334 for (i = 1; i < (u_int)*nargs; i++) { 335 snprintf(param, sizeof(param), "arg%u", i); 336 name = gctl_get_asciiparam(req, param); 337 if (name == NULL) { 338 gctl_error(req, "No 'arg%u' argument.", i); 339 continue; 340 } 341 disk = g_mirror_find_disk(sc, name); 342 if (disk == NULL) { 343 gctl_error(req, "No such provider: %s.", name); 344 continue; 345 } 346 if (g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) == 1 && 347 disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) { 348 /* 349 * This is the last active disk. There will be nothing 350 * to rebuild it from, so deny this request. 351 */ 352 gctl_error(req, 353 "Provider %s is the last active provider in %s.", 354 name, sc->sc_geom->name); 355 break; 356 } 357 /* 358 * Do rebuild by resetting syncid, disconnecting the disk and 359 * connecting it again. 360 */ 361 disk->d_sync.ds_syncid = 0; 362 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0) 363 disk->d_flags |= G_MIRROR_DISK_FLAG_FORCE_SYNC; 364 g_mirror_update_metadata(disk); 365 pp = disk->d_consumer->provider; 366 g_topology_lock(); 367 error = g_mirror_read_metadata(disk->d_consumer, &md); 368 g_topology_unlock(); 369 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, 370 G_MIRROR_EVENT_WAIT); 371 if (error != 0) { 372 gctl_error(req, "Cannot read metadata from %s.", 373 pp->name); 374 continue; 375 } 376 error = g_mirror_add_disk(sc, pp, &md); 377 if (error != 0) { 378 gctl_error(req, "Cannot reconnect component %s.", 379 pp->name); 380 continue; 381 } 382 } 383 sx_xunlock(&sc->sc_lock); 384 } 385 386 static void 387 g_mirror_ctl_insert(struct gctl_req *req, struct g_class *mp) 388 { 389 struct g_mirror_softc *sc; 390 struct g_mirror_disk *disk; 391 struct g_mirror_metadata md; 392 struct g_provider *pp; 393 struct g_consumer *cp; 394 intmax_t *priority; 395 const char *name; 396 char param[16]; 397 u_char *sector; 398 u_int i, n; 399 int error, *nargs, *hardcode, *inactive; 400 struct { 401 struct g_provider *provider; 402 struct g_consumer *consumer; 403 } *disks; 404 405 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 406 if (nargs == NULL) { 407 gctl_error(req, "No '%s' argument.", "nargs"); 408 return; 409 } 410 if (*nargs < 2) { 411 gctl_error(req, "Too few arguments."); 412 return; 413 } 414 priority = gctl_get_paraml(req, "priority", sizeof(*priority)); 415 if (priority == NULL) { 416 gctl_error(req, "No '%s' argument.", "priority"); 417 return; 418 } 419 inactive = gctl_get_paraml(req, "inactive", sizeof(*inactive)); 420 if (inactive == NULL) { 421 gctl_error(req, "No '%s' argument.", "inactive"); 422 return; 423 } 424 hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 425 if (hardcode == NULL) { 426 gctl_error(req, "No '%s' argument.", "hardcode"); 427 return; 428 } 429 name = gctl_get_asciiparam(req, "arg0"); 430 if (name == NULL) { 431 gctl_error(req, "No 'arg%u' argument.", 0); 432 return; 433 } 434 sc = g_mirror_find_device(mp, name); 435 if (sc == NULL) { 436 gctl_error(req, "No such device: %s.", name); 437 return; 438 } 439 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 440 gctl_error(req, "Not all disks connected."); 441 sx_xunlock(&sc->sc_lock); 442 return; 443 } 444 445 disks = g_malloc(sizeof(*disks) * (*nargs), M_WAITOK | M_ZERO); 446 g_topology_lock(); 447 for (i = 1, n = 0; i < (u_int)*nargs; i++) { 448 snprintf(param, sizeof(param), "arg%u", i); 449 name = gctl_get_asciiparam(req, param); 450 if (name == NULL) { 451 gctl_error(req, "No 'arg%u' argument.", i); 452 continue; 453 } 454 if (g_mirror_find_disk(sc, name) != NULL) { 455 gctl_error(req, "Provider %s already inserted.", name); 456 continue; 457 } 458 if (strncmp(name, "/dev/", 5) == 0) 459 name += 5; 460 pp = g_provider_by_name(name); 461 if (pp == NULL) { 462 gctl_error(req, "Unknown provider %s.", name); 463 continue; 464 } 465 if (sc->sc_provider->mediasize > 466 pp->mediasize - pp->sectorsize) { 467 gctl_error(req, "Provider %s too small.", name); 468 continue; 469 } 470 if ((sc->sc_provider->sectorsize % pp->sectorsize) != 0) { 471 gctl_error(req, "Invalid sectorsize of provider %s.", 472 name); 473 continue; 474 } 475 cp = g_new_consumer(sc->sc_geom); 476 if (g_attach(cp, pp) != 0) { 477 g_destroy_consumer(cp); 478 gctl_error(req, "Cannot attach to provider %s.", name); 479 continue; 480 } 481 if (g_access(cp, 0, 1, 1) != 0) { 482 g_detach(cp); 483 g_destroy_consumer(cp); 484 gctl_error(req, "Cannot access provider %s.", name); 485 continue; 486 } 487 disks[n].provider = pp; 488 disks[n].consumer = cp; 489 n++; 490 } 491 if (n == 0) { 492 g_topology_unlock(); 493 sx_xunlock(&sc->sc_lock); 494 g_free(disks); 495 return; 496 } 497 sc->sc_ndisks += n; 498 again: 499 for (i = 0; i < n; i++) { 500 if (disks[i].consumer == NULL) 501 continue; 502 g_mirror_fill_metadata(sc, NULL, &md); 503 md.md_priority = *priority; 504 if (*inactive) 505 md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE; 506 pp = disks[i].provider; 507 if (*hardcode) { 508 strlcpy(md.md_provider, pp->name, 509 sizeof(md.md_provider)); 510 } else { 511 bzero(md.md_provider, sizeof(md.md_provider)); 512 } 513 md.md_provsize = pp->mediasize; 514 sector = g_malloc(pp->sectorsize, M_WAITOK); 515 mirror_metadata_encode(&md, sector); 516 error = g_write_data(disks[i].consumer, 517 pp->mediasize - pp->sectorsize, sector, pp->sectorsize); 518 g_free(sector); 519 if (error != 0) { 520 gctl_error(req, "Cannot store metadata on %s.", 521 pp->name); 522 g_access(disks[i].consumer, 0, -1, -1); 523 g_detach(disks[i].consumer); 524 g_destroy_consumer(disks[i].consumer); 525 disks[i].consumer = NULL; 526 disks[i].provider = NULL; 527 sc->sc_ndisks--; 528 goto again; 529 } 530 } 531 g_topology_unlock(); 532 if (i == 0) { 533 /* All writes failed. */ 534 sx_xunlock(&sc->sc_lock); 535 g_free(disks); 536 return; 537 } 538 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 539 g_mirror_update_metadata(disk); 540 } 541 /* 542 * Release provider and wait for retaste. 543 */ 544 g_topology_lock(); 545 for (i = 0; i < n; i++) { 546 if (disks[i].consumer == NULL) 547 continue; 548 g_access(disks[i].consumer, 0, -1, -1); 549 g_detach(disks[i].consumer); 550 g_destroy_consumer(disks[i].consumer); 551 } 552 g_topology_unlock(); 553 sx_xunlock(&sc->sc_lock); 554 g_free(disks); 555 } 556 557 static void 558 g_mirror_ctl_remove(struct gctl_req *req, struct g_class *mp) 559 { 560 struct g_mirror_softc *sc; 561 struct g_mirror_disk *disk; 562 const char *name; 563 char param[16]; 564 int *nargs; 565 u_int i, active; 566 567 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 568 if (nargs == NULL) { 569 gctl_error(req, "No '%s' argument.", "nargs"); 570 return; 571 } 572 if (*nargs < 2) { 573 gctl_error(req, "Too few arguments."); 574 return; 575 } 576 name = gctl_get_asciiparam(req, "arg0"); 577 if (name == NULL) { 578 gctl_error(req, "No 'arg%u' argument.", 0); 579 return; 580 } 581 sc = g_mirror_find_device(mp, name); 582 if (sc == NULL) { 583 gctl_error(req, "No such device: %s.", name); 584 return; 585 } 586 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 587 sx_xunlock(&sc->sc_lock); 588 gctl_error(req, "Not all disks connected. Try 'forget' command " 589 "first."); 590 return; 591 } 592 active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE); 593 for (i = 1; i < (u_int)*nargs; i++) { 594 snprintf(param, sizeof(param), "arg%u", i); 595 name = gctl_get_asciiparam(req, param); 596 if (name == NULL) { 597 gctl_error(req, "No 'arg%u' argument.", i); 598 continue; 599 } 600 disk = g_mirror_find_disk(sc, name); 601 if (disk == NULL) { 602 gctl_error(req, "No such provider: %s.", name); 603 continue; 604 } 605 if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) { 606 if (active > 1) 607 active--; 608 else { 609 gctl_error(req, "%s: Can't remove the last " 610 "ACTIVE component %s.", sc->sc_geom->name, 611 name); 612 continue; 613 } 614 } 615 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DESTROY, 616 G_MIRROR_EVENT_DONTWAIT); 617 } 618 sx_xunlock(&sc->sc_lock); 619 } 620 621 static void 622 g_mirror_ctl_resize(struct gctl_req *req, struct g_class *mp) 623 { 624 struct g_mirror_softc *sc; 625 struct g_mirror_disk *disk; 626 uint64_t mediasize; 627 const char *name, *s; 628 char *x; 629 int *nargs; 630 631 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 632 if (nargs == NULL) { 633 gctl_error(req, "No '%s' argument.", "nargs"); 634 return; 635 } 636 if (*nargs != 1) { 637 gctl_error(req, "Missing device."); 638 return; 639 } 640 name = gctl_get_asciiparam(req, "arg0"); 641 if (name == NULL) { 642 gctl_error(req, "No 'arg%u' argument.", 0); 643 return; 644 } 645 s = gctl_get_asciiparam(req, "size"); 646 if (s == NULL) { 647 gctl_error(req, "No '%s' argument.", "size"); 648 return; 649 } 650 mediasize = strtouq(s, &x, 0); 651 if (*x != '\0' || mediasize == 0) { 652 gctl_error(req, "Invalid '%s' argument.", "size"); 653 return; 654 } 655 sc = g_mirror_find_device(mp, name); 656 if (sc == NULL) { 657 gctl_error(req, "No such device: %s.", name); 658 return; 659 } 660 /* Deny shrinking of an opened provider */ 661 if ((g_debugflags & 16) == 0 && (sc->sc_provider->acr > 0 || 662 sc->sc_provider->acw > 0 || sc->sc_provider->ace > 0)) { 663 if (sc->sc_mediasize > mediasize) { 664 gctl_error(req, "Device %s is busy.", 665 sc->sc_provider->name); 666 sx_xunlock(&sc->sc_lock); 667 return; 668 } 669 } 670 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 671 if (mediasize > disk->d_consumer->provider->mediasize - 672 disk->d_consumer->provider->sectorsize) { 673 gctl_error(req, "Provider %s is too small.", 674 disk->d_name); 675 sx_xunlock(&sc->sc_lock); 676 return; 677 } 678 } 679 /* Update the size. */ 680 sc->sc_mediasize = mediasize; 681 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 682 g_mirror_update_metadata(disk); 683 } 684 g_topology_lock(); 685 g_resize_provider(sc->sc_provider, mediasize); 686 g_topology_unlock(); 687 sx_xunlock(&sc->sc_lock); 688 } 689 690 static void 691 g_mirror_ctl_deactivate(struct gctl_req *req, struct g_class *mp) 692 { 693 struct g_mirror_softc *sc; 694 struct g_mirror_disk *disk; 695 const char *name; 696 char param[16]; 697 int *nargs; 698 u_int i, active; 699 700 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 701 if (nargs == NULL) { 702 gctl_error(req, "No '%s' argument.", "nargs"); 703 return; 704 } 705 if (*nargs < 2) { 706 gctl_error(req, "Too few arguments."); 707 return; 708 } 709 name = gctl_get_asciiparam(req, "arg0"); 710 if (name == NULL) { 711 gctl_error(req, "No 'arg%u' argument.", 0); 712 return; 713 } 714 sc = g_mirror_find_device(mp, name); 715 if (sc == NULL) { 716 gctl_error(req, "No such device: %s.", name); 717 return; 718 } 719 active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE); 720 for (i = 1; i < (u_int)*nargs; i++) { 721 snprintf(param, sizeof(param), "arg%u", i); 722 name = gctl_get_asciiparam(req, param); 723 if (name == NULL) { 724 gctl_error(req, "No 'arg%u' argument.", i); 725 continue; 726 } 727 disk = g_mirror_find_disk(sc, name); 728 if (disk == NULL) { 729 gctl_error(req, "No such provider: %s.", name); 730 continue; 731 } 732 if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) { 733 if (active > 1) 734 active--; 735 else { 736 gctl_error(req, "%s: Can't deactivate the " 737 "last ACTIVE component %s.", 738 sc->sc_geom->name, name); 739 continue; 740 } 741 } 742 disk->d_flags |= G_MIRROR_DISK_FLAG_INACTIVE; 743 disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC; 744 g_mirror_update_metadata(disk); 745 sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID; 746 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, 747 G_MIRROR_EVENT_DONTWAIT); 748 } 749 sx_xunlock(&sc->sc_lock); 750 } 751 752 static void 753 g_mirror_ctl_forget(struct gctl_req *req, struct g_class *mp) 754 { 755 struct g_mirror_softc *sc; 756 struct g_mirror_disk *disk; 757 const char *name; 758 char param[16]; 759 int *nargs; 760 u_int i; 761 762 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 763 if (nargs == NULL) { 764 gctl_error(req, "No '%s' argument.", "nargs"); 765 return; 766 } 767 if (*nargs < 1) { 768 gctl_error(req, "Missing device(s)."); 769 return; 770 } 771 772 for (i = 0; i < (u_int)*nargs; i++) { 773 snprintf(param, sizeof(param), "arg%u", i); 774 name = gctl_get_asciiparam(req, param); 775 if (name == NULL) { 776 gctl_error(req, "No 'arg%u' argument.", i); 777 return; 778 } 779 sc = g_mirror_find_device(mp, name); 780 if (sc == NULL) { 781 gctl_error(req, "No such device: %s.", name); 782 return; 783 } 784 if (g_mirror_ndisks(sc, -1) == sc->sc_ndisks) { 785 sx_xunlock(&sc->sc_lock); 786 G_MIRROR_DEBUG(1, 787 "All disks connected in %s, skipping.", 788 sc->sc_name); 789 continue; 790 } 791 sc->sc_ndisks = g_mirror_ndisks(sc, -1); 792 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 793 g_mirror_update_metadata(disk); 794 } 795 sx_xunlock(&sc->sc_lock); 796 } 797 } 798 799 static void 800 g_mirror_ctl_stop(struct gctl_req *req, struct g_class *mp, int wipe) 801 { 802 struct g_mirror_softc *sc; 803 int *force, *nargs, error; 804 const char *name; 805 char param[16]; 806 u_int i; 807 int how; 808 809 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 810 if (nargs == NULL) { 811 gctl_error(req, "No '%s' argument.", "nargs"); 812 return; 813 } 814 if (*nargs < 1) { 815 gctl_error(req, "Missing device(s)."); 816 return; 817 } 818 force = gctl_get_paraml(req, "force", sizeof(*force)); 819 if (force == NULL) { 820 gctl_error(req, "No '%s' argument.", "force"); 821 return; 822 } 823 if (*force) 824 how = G_MIRROR_DESTROY_HARD; 825 else 826 how = G_MIRROR_DESTROY_SOFT; 827 828 for (i = 0; i < (u_int)*nargs; i++) { 829 snprintf(param, sizeof(param), "arg%u", i); 830 name = gctl_get_asciiparam(req, param); 831 if (name == NULL) { 832 gctl_error(req, "No 'arg%u' argument.", i); 833 return; 834 } 835 sc = g_mirror_find_device(mp, name); 836 if (sc == NULL) { 837 gctl_error(req, "No such device: %s.", name); 838 return; 839 } 840 g_cancel_event(sc); 841 if (wipe) 842 sc->sc_flags |= G_MIRROR_DEVICE_FLAG_WIPE; 843 error = g_mirror_destroy(sc, how); 844 if (error != 0) { 845 gctl_error(req, "Cannot destroy device %s (error=%d).", 846 sc->sc_geom->name, error); 847 if (wipe) 848 sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_WIPE; 849 sx_xunlock(&sc->sc_lock); 850 return; 851 } 852 /* No need to unlock, because lock is already dead. */ 853 } 854 } 855 856 void 857 g_mirror_config(struct gctl_req *req, struct g_class *mp, const char *verb) 858 { 859 uint32_t *version; 860 861 g_topology_assert(); 862 863 version = gctl_get_paraml(req, "version", sizeof(*version)); 864 if (version == NULL) { 865 gctl_error(req, "No '%s' argument.", "version"); 866 return; 867 } 868 if (*version != G_MIRROR_VERSION) { 869 gctl_error(req, "Userland and kernel parts are out of sync."); 870 return; 871 } 872 873 g_topology_unlock(); 874 if (strcmp(verb, "configure") == 0) 875 g_mirror_ctl_configure(req, mp); 876 else if (strcmp(verb, "rebuild") == 0) 877 g_mirror_ctl_rebuild(req, mp); 878 else if (strcmp(verb, "insert") == 0) 879 g_mirror_ctl_insert(req, mp); 880 else if (strcmp(verb, "remove") == 0) 881 g_mirror_ctl_remove(req, mp); 882 else if (strcmp(verb, "resize") == 0) 883 g_mirror_ctl_resize(req, mp); 884 else if (strcmp(verb, "deactivate") == 0) 885 g_mirror_ctl_deactivate(req, mp); 886 else if (strcmp(verb, "forget") == 0) 887 g_mirror_ctl_forget(req, mp); 888 else if (strcmp(verb, "stop") == 0) 889 g_mirror_ctl_stop(req, mp, 0); 890 else if (strcmp(verb, "destroy") == 0) 891 g_mirror_ctl_stop(req, mp, 1); 892 else 893 gctl_error(req, "Unknown verb."); 894 g_topology_lock(); 895 } 896