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