1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2004-2009 Pawel Jakub Dawidek <pjd@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bio.h> 35 #include <sys/kernel.h> 36 #include <sys/limits.h> 37 #include <sys/lock.h> 38 #include <sys/malloc.h> 39 #include <sys/sbuf.h> 40 #include <sys/sx.h> 41 42 #include <geom/geom.h> 43 #include <geom/geom_dbg.h> 44 #include <geom/geom_int.h> 45 #include <geom/mirror/g_mirror.h> 46 47 /* 48 * Configure, Rebuild, Remove, Deactivate, Forget, and Stop operations do not 49 * seem to depend on any particular g_mirror initialization state. 50 */ 51 static struct g_mirror_softc * 52 g_mirror_find_device(struct g_class *mp, const char *name) 53 { 54 struct g_mirror_softc *sc; 55 struct g_geom *gp; 56 57 g_topology_lock(); 58 LIST_FOREACH(gp, &mp->geom, geom) { 59 sc = gp->softc; 60 if (sc == NULL) 61 continue; 62 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) 63 continue; 64 if (strcmp(gp->name, name) == 0 || 65 strcmp(sc->sc_name, name) == 0) { 66 g_topology_unlock(); 67 sx_xlock(&sc->sc_lock); 68 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) { 69 sx_xunlock(&sc->sc_lock); 70 return (NULL); 71 } 72 return (sc); 73 } 74 } 75 g_topology_unlock(); 76 return (NULL); 77 } 78 79 /* Insert and Resize operations depend on a launched GEOM (sc_provider). */ 80 #define GMFL_VALID_FLAGS (M_WAITOK | M_NOWAIT) 81 static struct g_mirror_softc * 82 g_mirror_find_launched_device(struct g_class *mp, const char *name, int flags) 83 { 84 struct g_mirror_softc *sc; 85 int error; 86 87 KASSERT((flags & ~GMFL_VALID_FLAGS) == 0 && 88 flags != GMFL_VALID_FLAGS && flags != 0, 89 ("%s: Invalid flags %x\n", __func__, (unsigned)flags)); 90 #undef GMFL_VALID_FLAGS 91 92 while (true) { 93 sc = g_mirror_find_device(mp, name); 94 if (sc == NULL) 95 return (NULL); 96 if (sc->sc_provider != NULL) 97 return (sc); 98 if (flags & M_NOWAIT) { 99 sx_xunlock(&sc->sc_lock); 100 return (NULL); 101 } 102 103 /* 104 * This is a dumb hack. G_mirror does not expose any real 105 * wakeup API for observing state changes, and even if it did, 106 * its "RUNNING" state does not actually reflect all softc 107 * elements being initialized. 108 * 109 * Revamping g_mirror to have a 3rd, ACTUALLY_RUNNING state and 110 * updating all assertions and sc_state checks is a large work 111 * and would be easy to introduce regressions. 112 * 113 * Revamping g_mirror to have a wakeup for state changes would 114 * be difficult if one wanted to capture more than just 115 * sc_state and sc_provider. 116 * 117 * For now, just dummy sleep-poll until sc_provider shows up, 118 * the user cancels, or the g_mirror is destroyed. 119 */ 120 error = sx_sleep(&sc, &sc->sc_lock, PRIBIO | PCATCH | PDROP, 121 "GM:launched", 1); 122 if (error != 0 && error != EWOULDBLOCK) 123 return (NULL); 124 } 125 __unreachable(); 126 } 127 128 static struct g_mirror_disk * 129 g_mirror_find_disk(struct g_mirror_softc *sc, const char *name) 130 { 131 struct g_mirror_disk *disk; 132 133 sx_assert(&sc->sc_lock, SX_XLOCKED); 134 if (strncmp(name, _PATH_DEV, 5) == 0) 135 name += 5; 136 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 137 if (disk->d_consumer == NULL) 138 continue; 139 if (disk->d_consumer->provider == NULL) 140 continue; 141 if (strcmp(disk->d_consumer->provider->name, name) == 0) 142 return (disk); 143 } 144 return (NULL); 145 } 146 147 static void 148 g_mirror_ctl_configure(struct gctl_req *req, struct g_class *mp) 149 { 150 struct g_mirror_softc *sc; 151 struct g_mirror_disk *disk; 152 const char *name, *balancep, *prov; 153 intmax_t *slicep, *priority; 154 uint32_t slice; 155 uint8_t balance; 156 int *autosync, *noautosync, *failsync, *nofailsync, *hardcode, *dynamic; 157 int *nargs, do_sync = 0, dirty = 1, do_priority = 0; 158 159 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 160 if (nargs == NULL) { 161 gctl_error(req, "No '%s' argument.", "nargs"); 162 return; 163 } 164 if (*nargs != 1 && *nargs != 2) { 165 gctl_error(req, "Invalid number of arguments."); 166 return; 167 } 168 name = gctl_get_asciiparam(req, "arg0"); 169 if (name == NULL) { 170 gctl_error(req, "No 'arg%u' argument.", 0); 171 return; 172 } 173 balancep = gctl_get_asciiparam(req, "balance"); 174 if (balancep == NULL) { 175 gctl_error(req, "No '%s' argument.", "balance"); 176 return; 177 } 178 autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync)); 179 if (autosync == NULL) { 180 gctl_error(req, "No '%s' argument.", "autosync"); 181 return; 182 } 183 noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 184 if (noautosync == NULL) { 185 gctl_error(req, "No '%s' argument.", "noautosync"); 186 return; 187 } 188 failsync = gctl_get_paraml(req, "failsync", sizeof(*failsync)); 189 if (failsync == NULL) { 190 gctl_error(req, "No '%s' argument.", "failsync"); 191 return; 192 } 193 nofailsync = gctl_get_paraml(req, "nofailsync", sizeof(*nofailsync)); 194 if (nofailsync == NULL) { 195 gctl_error(req, "No '%s' argument.", "nofailsync"); 196 return; 197 } 198 hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 199 if (hardcode == NULL) { 200 gctl_error(req, "No '%s' argument.", "hardcode"); 201 return; 202 } 203 dynamic = gctl_get_paraml(req, "dynamic", sizeof(*dynamic)); 204 if (dynamic == NULL) { 205 gctl_error(req, "No '%s' argument.", "dynamic"); 206 return; 207 } 208 priority = gctl_get_paraml(req, "priority", sizeof(*priority)); 209 if (priority == NULL) { 210 gctl_error(req, "No '%s' argument.", "priority"); 211 return; 212 } 213 if (*priority < -1 || *priority > 255) { 214 gctl_error(req, "Priority range is 0 to 255, %jd given", 215 *priority); 216 return; 217 } 218 /* 219 * Since we have a priority, we also need a provider now. 220 * Note: be WARNS safe, by always assigning prov and only throw an 221 * error if *priority != -1. 222 */ 223 prov = gctl_get_asciiparam(req, "arg1"); 224 if (*priority > -1) { 225 if (prov == NULL) { 226 gctl_error(req, "Priority needs a disk name"); 227 return; 228 } 229 do_priority = 1; 230 } 231 if (*autosync && *noautosync) { 232 gctl_error(req, "'%s' and '%s' specified.", "autosync", 233 "noautosync"); 234 return; 235 } 236 if (*failsync && *nofailsync) { 237 gctl_error(req, "'%s' and '%s' specified.", "failsync", 238 "nofailsync"); 239 return; 240 } 241 if (*hardcode && *dynamic) { 242 gctl_error(req, "'%s' and '%s' specified.", "hardcode", 243 "dynamic"); 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 if (*balancep == '\0') 252 balance = sc->sc_balance; 253 else { 254 if (balance_id(balancep) == -1) { 255 gctl_error(req, "Invalid balance algorithm."); 256 sx_xunlock(&sc->sc_lock); 257 return; 258 } 259 balance = balance_id(balancep); 260 } 261 slicep = gctl_get_paraml(req, "slice", sizeof(*slicep)); 262 if (slicep == NULL) { 263 gctl_error(req, "No '%s' argument.", "slice"); 264 sx_xunlock(&sc->sc_lock); 265 return; 266 } 267 if (*slicep == -1) 268 slice = sc->sc_slice; 269 else 270 slice = *slicep; 271 /* Enforce usage() of -p not allowing any other options. */ 272 if (do_priority && (*autosync || *noautosync || *failsync || 273 *nofailsync || *hardcode || *dynamic || *slicep != -1 || 274 *balancep != '\0')) { 275 sx_xunlock(&sc->sc_lock); 276 gctl_error(req, "only -p accepted when setting priority"); 277 return; 278 } 279 if (sc->sc_balance == balance && sc->sc_slice == slice && !*autosync && 280 !*noautosync && !*failsync && !*nofailsync && !*hardcode && 281 !*dynamic && !do_priority) { 282 sx_xunlock(&sc->sc_lock); 283 gctl_error(req, "Nothing has changed."); 284 return; 285 } 286 if ((!do_priority && *nargs != 1) || (do_priority && *nargs != 2)) { 287 sx_xunlock(&sc->sc_lock); 288 gctl_error(req, "Invalid number of arguments."); 289 return; 290 } 291 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 292 sx_xunlock(&sc->sc_lock); 293 gctl_error(req, "Not all disks connected. Try 'forget' command " 294 "first."); 295 return; 296 } 297 sc->sc_balance = balance; 298 sc->sc_slice = slice; 299 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0) { 300 if (*autosync) { 301 sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_NOAUTOSYNC; 302 do_sync = 1; 303 } 304 } else { 305 if (*noautosync) 306 sc->sc_flags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC; 307 } 308 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOFAILSYNC) != 0) { 309 if (*failsync) 310 sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_NOFAILSYNC; 311 } else { 312 if (*nofailsync) { 313 sc->sc_flags |= G_MIRROR_DEVICE_FLAG_NOFAILSYNC; 314 dirty = 0; 315 } 316 } 317 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 318 /* 319 * Handle priority first, since we only need one disk, do one 320 * operation on it and then we're done. No need to check other 321 * flags, as usage doesn't allow it. 322 */ 323 if (do_priority) { 324 if (strcmp(disk->d_name, prov) == 0) { 325 if (disk->d_priority == *priority) 326 gctl_error(req, "Nothing has changed."); 327 else { 328 disk->d_priority = *priority; 329 g_mirror_update_metadata(disk); 330 } 331 break; 332 } 333 continue; 334 } 335 if (do_sync) { 336 if (disk->d_state == G_MIRROR_DISK_STATE_SYNCHRONIZING) 337 disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC; 338 } 339 if (*hardcode) 340 disk->d_flags |= G_MIRROR_DISK_FLAG_HARDCODED; 341 else if (*dynamic) 342 disk->d_flags &= ~G_MIRROR_DISK_FLAG_HARDCODED; 343 if (!dirty) 344 disk->d_flags &= ~G_MIRROR_DISK_FLAG_DIRTY; 345 g_mirror_update_metadata(disk); 346 if (do_sync) { 347 if (disk->d_state == G_MIRROR_DISK_STATE_STALE) { 348 g_mirror_event_send(disk, 349 G_MIRROR_DISK_STATE_DISCONNECTED, 350 G_MIRROR_EVENT_DONTWAIT); 351 } 352 } 353 } 354 sx_xunlock(&sc->sc_lock); 355 } 356 357 static void 358 g_mirror_create_orphan(struct g_consumer *cp) 359 { 360 361 KASSERT(1 == 0, ("%s called while creating %s.", __func__, 362 cp->provider->name)); 363 } 364 365 static void 366 g_mirror_ctl_create(struct gctl_req *req, struct g_class *mp) 367 { 368 struct g_mirror_metadata md; 369 struct g_geom *gp; 370 struct g_consumer *cp; 371 struct g_provider *pp; 372 struct g_mirror_softc *sc; 373 struct sbuf *sb; 374 const char *name; 375 char param[16]; 376 int *nargs; 377 intmax_t *val; 378 int *ival; 379 const char *sval; 380 int bal; 381 unsigned attached, no, sectorsize; 382 off_t mediasize; 383 384 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 385 if (nargs == NULL) { 386 gctl_error(req, "No '%s' argument.", "nargs"); 387 return; 388 } 389 if (*nargs <= 2) { 390 gctl_error(req, "Too few arguments."); 391 return; 392 } 393 394 strlcpy(md.md_magic, G_MIRROR_MAGIC, sizeof(md.md_magic)); 395 md.md_version = G_MIRROR_VERSION; 396 name = gctl_get_asciiparam(req, "arg0"); 397 if (name == NULL) { 398 gctl_error(req, "No 'arg%u' argument.", 0); 399 return; 400 } 401 strlcpy(md.md_name, name, sizeof(md.md_name)); 402 md.md_mid = arc4random(); 403 md.md_all = *nargs - 1; 404 md.md_genid = 0; 405 md.md_syncid = 1; 406 md.md_sync_offset = 0; 407 val = gctl_get_paraml(req, "slice", sizeof(*val)); 408 if (val == NULL) { 409 gctl_error(req, "No slice argument."); 410 return; 411 } 412 md.md_slice = *val; 413 sval = gctl_get_asciiparam(req, "balance"); 414 if (sval == NULL) { 415 gctl_error(req, "No balance argument."); 416 return; 417 } 418 bal = balance_id(sval); 419 if (bal < 0) { 420 gctl_error(req, "Invalid balance algorithm."); 421 return; 422 } 423 md.md_balance = bal; 424 md.md_mflags = 0; 425 md.md_dflags = 0; 426 ival = gctl_get_paraml(req, "noautosync", sizeof(*ival)); 427 if (ival != NULL && *ival) 428 md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC; 429 ival = gctl_get_paraml(req, "nofailsync", sizeof(*ival)); 430 if (ival != NULL && *ival) 431 md.md_mflags |= G_MIRROR_DEVICE_FLAG_NOFAILSYNC; 432 /* These fields not used in manual mode. */ 433 bzero(md.md_provider, sizeof(md.md_provider)); 434 md.md_provsize = 0; 435 436 g_topology_lock(); 437 mediasize = OFF_MAX; 438 sectorsize = 0; 439 gp = g_new_geomf(mp, "%s", md.md_name); 440 gp->orphan = g_mirror_create_orphan; 441 cp = g_new_consumer(gp); 442 for (no = 1; no < *nargs; no++) { 443 snprintf(param, sizeof(param), "arg%u", no); 444 pp = gctl_get_provider(req, param); 445 if (pp == NULL) { 446 err: 447 g_destroy_consumer(cp); 448 g_destroy_geom(gp); 449 g_topology_unlock(); 450 return; 451 } 452 g_attach(cp, pp); 453 if (g_access(cp, 1, 0, 0) != 0) { 454 G_MIRROR_DEBUG(1, "Can't open disk %s.", pp->name); 455 gctl_error(req, "Can't open disk %s.", pp->name); 456 err2: 457 g_detach(cp); 458 goto err; 459 } 460 if (pp->mediasize == 0 || pp->sectorsize == 0) { 461 G_MIRROR_DEBUG(1, "Disk %s has no media.", pp->name); 462 gctl_error(req, "Disk %s has no media.", pp->name); 463 g_access(cp, -1, 0, 0); 464 goto err2; 465 } 466 if (pp->mediasize < mediasize) 467 mediasize = pp->mediasize; 468 if (pp->sectorsize > sectorsize) 469 sectorsize = pp->sectorsize; 470 g_access(cp, -1, 0, 0); 471 g_detach(cp); 472 } 473 g_destroy_consumer(cp); 474 g_destroy_geom(gp); 475 md.md_mediasize = mediasize; 476 md.md_sectorsize = sectorsize; 477 md.md_mediasize -= (md.md_mediasize % md.md_sectorsize); 478 479 gp = g_mirror_create(mp, &md, G_MIRROR_TYPE_MANUAL); 480 if (gp == NULL) { 481 gctl_error(req, "Can't create %s.", md.md_name); 482 g_topology_unlock(); 483 return; 484 } 485 486 sc = gp->softc; 487 g_topology_unlock(); 488 sx_xlock(&sc->sc_lock); 489 sc->sc_flags |= G_MIRROR_DEVICE_FLAG_TASTING; 490 sb = sbuf_new_auto(); 491 sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name); 492 for (attached = 0, no = 1; no < *nargs; no++) { 493 snprintf(param, sizeof(param), "arg%u", no); 494 pp = gctl_get_provider(req, param); 495 if (pp == NULL) { 496 name = gctl_get_asciiparam(req, param); 497 MPASS(name != NULL); 498 sbuf_printf(sb, " %s", name); 499 continue; 500 } 501 md.md_did = arc4random(); 502 md.md_priority = no - 1; 503 if (g_mirror_add_disk(sc, pp, &md) != 0) { 504 G_MIRROR_DEBUG(1, "Disk %u (%s) not attached to %s.", 505 no, pp->name, gp->name); 506 sbuf_printf(sb, " %s", pp->name); 507 continue; 508 } 509 attached++; 510 } 511 sbuf_finish(sb); 512 sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_TASTING; 513 if (md.md_all != attached || 514 (sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) { 515 g_mirror_destroy(gp->softc, G_MIRROR_DESTROY_HARD); 516 gctl_error(req, "%s", sbuf_data(sb)); 517 } else 518 sx_xunlock(&sc->sc_lock); 519 sbuf_delete(sb); 520 } 521 522 static void 523 g_mirror_ctl_rebuild(struct gctl_req *req, struct g_class *mp) 524 { 525 struct g_mirror_metadata md; 526 struct g_mirror_softc *sc; 527 struct g_mirror_disk *disk; 528 struct g_provider *pp; 529 const char *name; 530 char param[16]; 531 int error, *nargs; 532 u_int i; 533 534 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 535 if (nargs == NULL) { 536 gctl_error(req, "No '%s' argument.", "nargs"); 537 return; 538 } 539 if (*nargs < 2) { 540 gctl_error(req, "Too few arguments."); 541 return; 542 } 543 name = gctl_get_asciiparam(req, "arg0"); 544 if (name == NULL) { 545 gctl_error(req, "No 'arg%u' argument.", 0); 546 return; 547 } 548 sc = g_mirror_find_device(mp, name); 549 if (sc == NULL) { 550 gctl_error(req, "No such device: %s.", name); 551 return; 552 } 553 for (i = 1; i < (u_int)*nargs; i++) { 554 snprintf(param, sizeof(param), "arg%u", i); 555 name = gctl_get_asciiparam(req, param); 556 if (name == NULL) { 557 gctl_error(req, "No 'arg%u' argument.", i); 558 continue; 559 } 560 disk = g_mirror_find_disk(sc, name); 561 if (disk == NULL) { 562 gctl_error(req, "No such provider: %s.", name); 563 continue; 564 } 565 if (g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) == 1 && 566 disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) { 567 /* 568 * This is the last active disk. There will be nothing 569 * to rebuild it from, so deny this request. 570 */ 571 gctl_error(req, 572 "Provider %s is the last active provider in %s.", 573 name, sc->sc_geom->name); 574 break; 575 } 576 /* 577 * Do rebuild by resetting syncid, disconnecting the disk and 578 * connecting it again. 579 */ 580 disk->d_sync.ds_syncid = 0; 581 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0) 582 disk->d_flags |= G_MIRROR_DISK_FLAG_FORCE_SYNC; 583 g_mirror_update_metadata(disk); 584 pp = disk->d_consumer->provider; 585 g_topology_lock(); 586 error = g_mirror_read_metadata(disk->d_consumer, &md); 587 g_topology_unlock(); 588 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, 589 G_MIRROR_EVENT_WAIT); 590 if (error != 0) { 591 gctl_error(req, "Cannot read metadata from %s.", 592 pp->name); 593 continue; 594 } 595 error = g_mirror_add_disk(sc, pp, &md); 596 if (error != 0) { 597 gctl_error(req, "Cannot reconnect component %s.", 598 pp->name); 599 continue; 600 } 601 } 602 sx_xunlock(&sc->sc_lock); 603 } 604 605 static void 606 g_mirror_ctl_insert(struct gctl_req *req, struct g_class *mp) 607 { 608 struct g_mirror_softc *sc; 609 struct g_mirror_disk *disk; 610 struct g_mirror_metadata md; 611 struct g_provider *pp; 612 struct g_consumer *cp; 613 intmax_t *priority; 614 const char *name; 615 char param[16]; 616 u_char *sector; 617 u_int i, n; 618 int error, *nargs, *hardcode, *inactive; 619 struct { 620 struct g_provider *provider; 621 struct g_consumer *consumer; 622 } *disks; 623 off_t mdsize; 624 625 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 626 if (nargs == NULL) { 627 gctl_error(req, "No '%s' argument.", "nargs"); 628 return; 629 } 630 if (*nargs < 2) { 631 gctl_error(req, "Too few arguments."); 632 return; 633 } 634 priority = gctl_get_paraml(req, "priority", sizeof(*priority)); 635 if (priority == NULL) { 636 gctl_error(req, "No '%s' argument.", "priority"); 637 return; 638 } 639 inactive = gctl_get_paraml(req, "inactive", sizeof(*inactive)); 640 if (inactive == NULL) { 641 gctl_error(req, "No '%s' argument.", "inactive"); 642 return; 643 } 644 hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 645 if (hardcode == NULL) { 646 gctl_error(req, "No '%s' argument.", "hardcode"); 647 return; 648 } 649 name = gctl_get_asciiparam(req, "arg0"); 650 if (name == NULL) { 651 gctl_error(req, "No 'arg%u' argument.", 0); 652 return; 653 } 654 sc = g_mirror_find_launched_device(mp, name, M_WAITOK); 655 if (sc == NULL) { 656 gctl_error(req, "No such device: %s.", name); 657 return; 658 } 659 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 660 gctl_error(req, "Not all disks connected."); 661 sx_xunlock(&sc->sc_lock); 662 return; 663 } 664 665 disks = g_malloc(sizeof(*disks) * (*nargs), M_WAITOK | M_ZERO); 666 g_topology_lock(); 667 for (i = 1, n = 0; i < (u_int)*nargs; i++) { 668 snprintf(param, sizeof(param), "arg%u", i); 669 pp = gctl_get_provider(req, param); 670 if (pp == NULL) 671 continue; 672 if (g_mirror_find_disk(sc, pp->name) != NULL) { 673 gctl_error(req, "Provider %s already inserted.", pp->name); 674 continue; 675 } 676 cp = g_new_consumer(sc->sc_geom); 677 if (g_attach(cp, pp) != 0) { 678 g_destroy_consumer(cp); 679 gctl_error(req, "Cannot attach to provider %s.", pp->name); 680 continue; 681 } 682 if (g_access(cp, 0, 1, 1) != 0) { 683 gctl_error(req, "Cannot access provider %s.", pp->name); 684 err: 685 g_detach(cp); 686 g_destroy_consumer(cp); 687 continue; 688 } 689 mdsize = (sc->sc_type == G_MIRROR_TYPE_AUTOMATIC) ? 690 pp->sectorsize : 0; 691 if (sc->sc_provider->mediasize > pp->mediasize - mdsize) { 692 gctl_error(req, "Provider %s too small.", pp->name); 693 err2: 694 g_access(cp, 0, -1, -1); 695 goto err; 696 } 697 if ((sc->sc_provider->sectorsize % pp->sectorsize) != 0) { 698 gctl_error(req, "Invalid sectorsize of provider %s.", 699 pp->name); 700 goto err2; 701 } 702 if (sc->sc_type != G_MIRROR_TYPE_AUTOMATIC) { 703 g_access(cp, 0, -1, -1); 704 g_detach(cp); 705 g_destroy_consumer(cp); 706 g_topology_unlock(); 707 sc->sc_ndisks++; 708 g_mirror_fill_metadata(sc, NULL, &md); 709 md.md_priority = *priority; 710 if (*inactive) 711 md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE; 712 if (g_mirror_add_disk(sc, pp, &md) != 0) { 713 sc->sc_ndisks--; 714 gctl_error(req, "Disk %s not inserted.", pp->name); 715 } 716 g_topology_lock(); 717 continue; 718 } 719 disks[n].provider = pp; 720 disks[n].consumer = cp; 721 n++; 722 } 723 if (n == 0) { 724 g_topology_unlock(); 725 sx_xunlock(&sc->sc_lock); 726 g_free(disks); 727 return; 728 } 729 sc->sc_ndisks += n; 730 again: 731 for (i = 0; i < n; i++) { 732 if (disks[i].consumer == NULL) 733 continue; 734 g_mirror_fill_metadata(sc, NULL, &md); 735 md.md_priority = *priority; 736 if (*inactive) 737 md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE; 738 pp = disks[i].provider; 739 if (*hardcode) { 740 strlcpy(md.md_provider, pp->name, 741 sizeof(md.md_provider)); 742 } else { 743 bzero(md.md_provider, sizeof(md.md_provider)); 744 } 745 md.md_provsize = pp->mediasize; 746 sector = g_malloc(pp->sectorsize, M_WAITOK); 747 mirror_metadata_encode(&md, sector); 748 error = g_write_data(disks[i].consumer, 749 pp->mediasize - pp->sectorsize, sector, pp->sectorsize); 750 g_free(sector); 751 if (error != 0) { 752 gctl_error(req, "Cannot store metadata on %s.", 753 pp->name); 754 g_access(disks[i].consumer, 0, -1, -1); 755 g_detach(disks[i].consumer); 756 g_destroy_consumer(disks[i].consumer); 757 disks[i].consumer = NULL; 758 disks[i].provider = NULL; 759 sc->sc_ndisks--; 760 goto again; 761 } 762 } 763 g_topology_unlock(); 764 if (i == 0) { 765 /* All writes failed. */ 766 sx_xunlock(&sc->sc_lock); 767 g_free(disks); 768 return; 769 } 770 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 771 g_mirror_update_metadata(disk); 772 } 773 /* 774 * Release provider and wait for retaste. 775 */ 776 g_topology_lock(); 777 for (i = 0; i < n; i++) { 778 if (disks[i].consumer == NULL) 779 continue; 780 g_access(disks[i].consumer, 0, -1, -1); 781 g_detach(disks[i].consumer); 782 g_destroy_consumer(disks[i].consumer); 783 } 784 g_topology_unlock(); 785 sx_xunlock(&sc->sc_lock); 786 g_free(disks); 787 } 788 789 static void 790 g_mirror_ctl_remove(struct gctl_req *req, struct g_class *mp) 791 { 792 struct g_mirror_softc *sc; 793 struct g_mirror_disk *disk; 794 const char *name; 795 char param[16]; 796 int *nargs; 797 u_int i, active; 798 799 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 800 if (nargs == NULL) { 801 gctl_error(req, "No '%s' argument.", "nargs"); 802 return; 803 } 804 if (*nargs < 2) { 805 gctl_error(req, "Too few arguments."); 806 return; 807 } 808 name = gctl_get_asciiparam(req, "arg0"); 809 if (name == NULL) { 810 gctl_error(req, "No 'arg%u' argument.", 0); 811 return; 812 } 813 sc = g_mirror_find_device(mp, name); 814 if (sc == NULL) { 815 gctl_error(req, "No such device: %s.", name); 816 return; 817 } 818 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 819 sx_xunlock(&sc->sc_lock); 820 gctl_error(req, "Not all disks connected. Try 'forget' command " 821 "first."); 822 return; 823 } 824 active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE); 825 for (i = 1; i < (u_int)*nargs; i++) { 826 snprintf(param, sizeof(param), "arg%u", i); 827 name = gctl_get_asciiparam(req, param); 828 if (name == NULL) { 829 gctl_error(req, "No 'arg%u' argument.", i); 830 continue; 831 } 832 disk = g_mirror_find_disk(sc, name); 833 if (disk == NULL) { 834 gctl_error(req, "No such provider: %s.", name); 835 continue; 836 } 837 if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) { 838 if (active > 1) 839 active--; 840 else { 841 gctl_error(req, "%s: Can't remove the last " 842 "ACTIVE component %s.", sc->sc_geom->name, 843 name); 844 continue; 845 } 846 } 847 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DESTROY, 848 G_MIRROR_EVENT_DONTWAIT); 849 } 850 sx_xunlock(&sc->sc_lock); 851 } 852 853 static void 854 g_mirror_ctl_resize(struct gctl_req *req, struct g_class *mp) 855 { 856 struct g_mirror_softc *sc; 857 struct g_mirror_disk *disk; 858 uint64_t mediasize; 859 const char *name, *s; 860 char *x; 861 int *nargs; 862 863 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 864 if (nargs == NULL) { 865 gctl_error(req, "No '%s' argument.", "nargs"); 866 return; 867 } 868 if (*nargs != 1) { 869 gctl_error(req, "Missing device."); 870 return; 871 } 872 name = gctl_get_asciiparam(req, "arg0"); 873 if (name == NULL) { 874 gctl_error(req, "No 'arg%u' argument.", 0); 875 return; 876 } 877 s = gctl_get_asciiparam(req, "size"); 878 if (s == NULL) { 879 gctl_error(req, "No '%s' argument.", "size"); 880 return; 881 } 882 mediasize = strtouq(s, &x, 0); 883 if (*x != '\0' || mediasize == 0) { 884 gctl_error(req, "Invalid '%s' argument.", "size"); 885 return; 886 } 887 sc = g_mirror_find_launched_device(mp, name, M_WAITOK); 888 if (sc == NULL) { 889 gctl_error(req, "No such device: %s.", name); 890 return; 891 } 892 /* Deny shrinking of an opened provider */ 893 if ((g_debugflags & G_F_FOOTSHOOTING) == 0 && sc->sc_provider_open > 0) { 894 if (sc->sc_mediasize > mediasize) { 895 gctl_error(req, "Device %s is busy.", 896 sc->sc_provider->name); 897 sx_xunlock(&sc->sc_lock); 898 return; 899 } 900 } 901 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 902 if (mediasize > disk->d_consumer->provider->mediasize - 903 disk->d_consumer->provider->sectorsize) { 904 gctl_error(req, "Provider %s is too small.", 905 disk->d_name); 906 sx_xunlock(&sc->sc_lock); 907 return; 908 } 909 } 910 /* Update the size. */ 911 sc->sc_mediasize = mediasize; 912 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 913 g_mirror_update_metadata(disk); 914 } 915 g_topology_lock(); 916 g_resize_provider(sc->sc_provider, mediasize); 917 g_topology_unlock(); 918 sx_xunlock(&sc->sc_lock); 919 } 920 921 static void 922 g_mirror_ctl_deactivate(struct gctl_req *req, struct g_class *mp) 923 { 924 struct g_mirror_softc *sc; 925 struct g_mirror_disk *disk; 926 const char *name; 927 char param[16]; 928 int *nargs; 929 u_int i, active; 930 931 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 932 if (nargs == NULL) { 933 gctl_error(req, "No '%s' argument.", "nargs"); 934 return; 935 } 936 if (*nargs < 2) { 937 gctl_error(req, "Too few arguments."); 938 return; 939 } 940 name = gctl_get_asciiparam(req, "arg0"); 941 if (name == NULL) { 942 gctl_error(req, "No 'arg%u' argument.", 0); 943 return; 944 } 945 sc = g_mirror_find_device(mp, name); 946 if (sc == NULL) { 947 gctl_error(req, "No such device: %s.", name); 948 return; 949 } 950 active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE); 951 for (i = 1; i < (u_int)*nargs; i++) { 952 snprintf(param, sizeof(param), "arg%u", i); 953 name = gctl_get_asciiparam(req, param); 954 if (name == NULL) { 955 gctl_error(req, "No 'arg%u' argument.", i); 956 continue; 957 } 958 disk = g_mirror_find_disk(sc, name); 959 if (disk == NULL) { 960 gctl_error(req, "No such provider: %s.", name); 961 continue; 962 } 963 if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) { 964 if (active > 1) 965 active--; 966 else { 967 gctl_error(req, "%s: Can't deactivate the " 968 "last ACTIVE component %s.", 969 sc->sc_geom->name, name); 970 continue; 971 } 972 } 973 disk->d_flags |= G_MIRROR_DISK_FLAG_INACTIVE; 974 disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC; 975 g_mirror_update_metadata(disk); 976 sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID; 977 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, 978 G_MIRROR_EVENT_DONTWAIT); 979 } 980 sx_xunlock(&sc->sc_lock); 981 } 982 983 static void 984 g_mirror_ctl_forget(struct gctl_req *req, struct g_class *mp) 985 { 986 struct g_mirror_softc *sc; 987 struct g_mirror_disk *disk; 988 const char *name; 989 char param[16]; 990 int *nargs; 991 u_int i; 992 993 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 994 if (nargs == NULL) { 995 gctl_error(req, "No '%s' argument.", "nargs"); 996 return; 997 } 998 if (*nargs < 1) { 999 gctl_error(req, "Missing device(s)."); 1000 return; 1001 } 1002 1003 for (i = 0; i < (u_int)*nargs; i++) { 1004 snprintf(param, sizeof(param), "arg%u", i); 1005 name = gctl_get_asciiparam(req, param); 1006 if (name == NULL) { 1007 gctl_error(req, "No 'arg%u' argument.", i); 1008 return; 1009 } 1010 sc = g_mirror_find_device(mp, name); 1011 if (sc == NULL) { 1012 gctl_error(req, "No such device: %s.", name); 1013 return; 1014 } 1015 if (g_mirror_ndisks(sc, -1) == sc->sc_ndisks) { 1016 sx_xunlock(&sc->sc_lock); 1017 G_MIRROR_DEBUG(1, 1018 "All disks connected in %s, skipping.", 1019 sc->sc_name); 1020 continue; 1021 } 1022 sc->sc_ndisks = g_mirror_ndisks(sc, -1); 1023 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 1024 g_mirror_update_metadata(disk); 1025 } 1026 sx_xunlock(&sc->sc_lock); 1027 } 1028 } 1029 1030 static void 1031 g_mirror_ctl_stop(struct gctl_req *req, struct g_class *mp, int wipe) 1032 { 1033 struct g_mirror_softc *sc; 1034 int *force, *nargs, error; 1035 const char *name; 1036 char param[16]; 1037 u_int i; 1038 int how; 1039 1040 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 1041 if (nargs == NULL) { 1042 gctl_error(req, "No '%s' argument.", "nargs"); 1043 return; 1044 } 1045 if (*nargs < 1) { 1046 gctl_error(req, "Missing device(s)."); 1047 return; 1048 } 1049 force = gctl_get_paraml(req, "force", sizeof(*force)); 1050 if (force == NULL) { 1051 gctl_error(req, "No '%s' argument.", "force"); 1052 return; 1053 } 1054 if (*force) 1055 how = G_MIRROR_DESTROY_HARD; 1056 else 1057 how = G_MIRROR_DESTROY_SOFT; 1058 1059 for (i = 0; i < (u_int)*nargs; i++) { 1060 snprintf(param, sizeof(param), "arg%u", i); 1061 name = gctl_get_asciiparam(req, param); 1062 if (name == NULL) { 1063 gctl_error(req, "No 'arg%u' argument.", i); 1064 return; 1065 } 1066 sc = g_mirror_find_device(mp, name); 1067 if (sc == NULL) { 1068 gctl_error(req, "No such device: %s.", name); 1069 return; 1070 } 1071 g_cancel_event(sc); 1072 if (wipe) 1073 sc->sc_flags |= G_MIRROR_DEVICE_FLAG_WIPE; 1074 error = g_mirror_destroy(sc, how); 1075 if (error != 0) { 1076 gctl_error(req, "Cannot destroy device %s (error=%d).", 1077 sc->sc_geom->name, error); 1078 if (wipe) 1079 sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_WIPE; 1080 sx_xunlock(&sc->sc_lock); 1081 return; 1082 } 1083 /* No need to unlock, because lock is already dead. */ 1084 } 1085 } 1086 1087 void 1088 g_mirror_config(struct gctl_req *req, struct g_class *mp, const char *verb) 1089 { 1090 uint32_t *version; 1091 1092 g_topology_assert(); 1093 1094 version = gctl_get_paraml(req, "version", sizeof(*version)); 1095 if (version == NULL) { 1096 gctl_error(req, "No '%s' argument.", "version"); 1097 return; 1098 } 1099 if (*version != G_MIRROR_VERSION) { 1100 gctl_error(req, "Userland and kernel parts are out of sync."); 1101 return; 1102 } 1103 1104 g_topology_unlock(); 1105 if (strcmp(verb, "configure") == 0) 1106 g_mirror_ctl_configure(req, mp); 1107 else if (strcmp(verb, "create") == 0) 1108 g_mirror_ctl_create(req, mp); 1109 else if (strcmp(verb, "rebuild") == 0) 1110 g_mirror_ctl_rebuild(req, mp); 1111 else if (strcmp(verb, "insert") == 0) 1112 g_mirror_ctl_insert(req, mp); 1113 else if (strcmp(verb, "remove") == 0) 1114 g_mirror_ctl_remove(req, mp); 1115 else if (strcmp(verb, "resize") == 0) 1116 g_mirror_ctl_resize(req, mp); 1117 else if (strcmp(verb, "deactivate") == 0) 1118 g_mirror_ctl_deactivate(req, mp); 1119 else if (strcmp(verb, "forget") == 0) 1120 g_mirror_ctl_forget(req, mp); 1121 else if (strcmp(verb, "stop") == 0) 1122 g_mirror_ctl_stop(req, mp, 0); 1123 else if (strcmp(verb, "destroy") == 0) 1124 g_mirror_ctl_stop(req, mp, 1); 1125 else 1126 gctl_error(req, "Unknown verb."); 1127 g_topology_lock(); 1128 } 1129