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, "/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 name = gctl_get_asciiparam(req, param); 445 if (name == NULL) { 446 gctl_error(req, "No 'arg%u' argument.", no); 447 err: 448 g_destroy_consumer(cp); 449 g_destroy_geom(gp); 450 g_topology_unlock(); 451 return; 452 } 453 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 454 name += strlen("/dev/"); 455 pp = g_provider_by_name(name); 456 if (pp == NULL) { 457 G_MIRROR_DEBUG(1, "Disk %s is invalid.", name); 458 gctl_error(req, "Disk %s is invalid.", name); 459 goto err; 460 } 461 g_attach(cp, pp); 462 if (g_access(cp, 1, 0, 0) != 0) { 463 G_MIRROR_DEBUG(1, "Can't open disk %s.", name); 464 gctl_error(req, "Can't open disk %s.", name); 465 err2: 466 g_detach(cp); 467 goto err; 468 } 469 if (pp->mediasize == 0 || pp->sectorsize == 0) { 470 G_MIRROR_DEBUG(1, "Disk %s has no media.", name); 471 gctl_error(req, "Disk %s has no media.", name); 472 g_access(cp, -1, 0, 0); 473 goto err2; 474 } 475 if (pp->mediasize < mediasize) 476 mediasize = pp->mediasize; 477 if (pp->sectorsize > sectorsize) 478 sectorsize = pp->sectorsize; 479 g_access(cp, -1, 0, 0); 480 g_detach(cp); 481 } 482 g_destroy_consumer(cp); 483 g_destroy_geom(gp); 484 md.md_mediasize = mediasize; 485 md.md_sectorsize = sectorsize; 486 md.md_mediasize -= (md.md_mediasize % md.md_sectorsize); 487 488 gp = g_mirror_create(mp, &md, G_MIRROR_TYPE_MANUAL); 489 if (gp == NULL) { 490 gctl_error(req, "Can't create %s.", md.md_name); 491 g_topology_unlock(); 492 return; 493 } 494 495 sc = gp->softc; 496 g_topology_unlock(); 497 sx_xlock(&sc->sc_lock); 498 sc->sc_flags |= G_MIRROR_DEVICE_FLAG_TASTING; 499 sb = sbuf_new_auto(); 500 sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name); 501 for (attached = 0, no = 1; no < *nargs; no++) { 502 snprintf(param, sizeof(param), "arg%u", no); 503 name = gctl_get_asciiparam(req, param); 504 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 505 name += strlen("/dev/"); 506 pp = g_provider_by_name(name); 507 if (pp == NULL) { 508 G_MIRROR_DEBUG(1, "Provider %s disappear?!", name); 509 sbuf_printf(sb, " %s", name); 510 continue; 511 } 512 md.md_did = arc4random(); 513 md.md_priority = no - 1; 514 if (g_mirror_add_disk(sc, pp, &md) != 0) { 515 G_MIRROR_DEBUG(1, "Disk %u (%s) not attached to %s.", 516 no, pp->name, gp->name); 517 sbuf_printf(sb, " %s", pp->name); 518 continue; 519 } 520 attached++; 521 } 522 sbuf_finish(sb); 523 sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_TASTING; 524 if (md.md_all != attached || 525 (sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) { 526 g_mirror_destroy(gp->softc, G_MIRROR_DESTROY_HARD); 527 gctl_error(req, "%s", sbuf_data(sb)); 528 } else 529 sx_xunlock(&sc->sc_lock); 530 sbuf_delete(sb); 531 } 532 533 static void 534 g_mirror_ctl_rebuild(struct gctl_req *req, struct g_class *mp) 535 { 536 struct g_mirror_metadata md; 537 struct g_mirror_softc *sc; 538 struct g_mirror_disk *disk; 539 struct g_provider *pp; 540 const char *name; 541 char param[16]; 542 int error, *nargs; 543 u_int i; 544 545 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 546 if (nargs == NULL) { 547 gctl_error(req, "No '%s' argument.", "nargs"); 548 return; 549 } 550 if (*nargs < 2) { 551 gctl_error(req, "Too few arguments."); 552 return; 553 } 554 name = gctl_get_asciiparam(req, "arg0"); 555 if (name == NULL) { 556 gctl_error(req, "No 'arg%u' argument.", 0); 557 return; 558 } 559 sc = g_mirror_find_device(mp, name); 560 if (sc == NULL) { 561 gctl_error(req, "No such device: %s.", name); 562 return; 563 } 564 for (i = 1; i < (u_int)*nargs; i++) { 565 snprintf(param, sizeof(param), "arg%u", i); 566 name = gctl_get_asciiparam(req, param); 567 if (name == NULL) { 568 gctl_error(req, "No 'arg%u' argument.", i); 569 continue; 570 } 571 disk = g_mirror_find_disk(sc, name); 572 if (disk == NULL) { 573 gctl_error(req, "No such provider: %s.", name); 574 continue; 575 } 576 if (g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) == 1 && 577 disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) { 578 /* 579 * This is the last active disk. There will be nothing 580 * to rebuild it from, so deny this request. 581 */ 582 gctl_error(req, 583 "Provider %s is the last active provider in %s.", 584 name, sc->sc_geom->name); 585 break; 586 } 587 /* 588 * Do rebuild by resetting syncid, disconnecting the disk and 589 * connecting it again. 590 */ 591 disk->d_sync.ds_syncid = 0; 592 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0) 593 disk->d_flags |= G_MIRROR_DISK_FLAG_FORCE_SYNC; 594 g_mirror_update_metadata(disk); 595 pp = disk->d_consumer->provider; 596 g_topology_lock(); 597 error = g_mirror_read_metadata(disk->d_consumer, &md); 598 g_topology_unlock(); 599 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, 600 G_MIRROR_EVENT_WAIT); 601 if (error != 0) { 602 gctl_error(req, "Cannot read metadata from %s.", 603 pp->name); 604 continue; 605 } 606 error = g_mirror_add_disk(sc, pp, &md); 607 if (error != 0) { 608 gctl_error(req, "Cannot reconnect component %s.", 609 pp->name); 610 continue; 611 } 612 } 613 sx_xunlock(&sc->sc_lock); 614 } 615 616 static void 617 g_mirror_ctl_insert(struct gctl_req *req, struct g_class *mp) 618 { 619 struct g_mirror_softc *sc; 620 struct g_mirror_disk *disk; 621 struct g_mirror_metadata md; 622 struct g_provider *pp; 623 struct g_consumer *cp; 624 intmax_t *priority; 625 const char *name; 626 char param[16]; 627 u_char *sector; 628 u_int i, n; 629 int error, *nargs, *hardcode, *inactive; 630 struct { 631 struct g_provider *provider; 632 struct g_consumer *consumer; 633 } *disks; 634 off_t mdsize; 635 636 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 637 if (nargs == NULL) { 638 gctl_error(req, "No '%s' argument.", "nargs"); 639 return; 640 } 641 if (*nargs < 2) { 642 gctl_error(req, "Too few arguments."); 643 return; 644 } 645 priority = gctl_get_paraml(req, "priority", sizeof(*priority)); 646 if (priority == NULL) { 647 gctl_error(req, "No '%s' argument.", "priority"); 648 return; 649 } 650 inactive = gctl_get_paraml(req, "inactive", sizeof(*inactive)); 651 if (inactive == NULL) { 652 gctl_error(req, "No '%s' argument.", "inactive"); 653 return; 654 } 655 hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 656 if (hardcode == NULL) { 657 gctl_error(req, "No '%s' argument.", "hardcode"); 658 return; 659 } 660 name = gctl_get_asciiparam(req, "arg0"); 661 if (name == NULL) { 662 gctl_error(req, "No 'arg%u' argument.", 0); 663 return; 664 } 665 sc = g_mirror_find_launched_device(mp, name, M_WAITOK); 666 if (sc == NULL) { 667 gctl_error(req, "No such device: %s.", name); 668 return; 669 } 670 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 671 gctl_error(req, "Not all disks connected."); 672 sx_xunlock(&sc->sc_lock); 673 return; 674 } 675 676 disks = g_malloc(sizeof(*disks) * (*nargs), M_WAITOK | M_ZERO); 677 g_topology_lock(); 678 for (i = 1, n = 0; i < (u_int)*nargs; i++) { 679 snprintf(param, sizeof(param), "arg%u", i); 680 name = gctl_get_asciiparam(req, param); 681 if (name == NULL) { 682 gctl_error(req, "No 'arg%u' argument.", i); 683 continue; 684 } 685 if (g_mirror_find_disk(sc, name) != NULL) { 686 gctl_error(req, "Provider %s already inserted.", name); 687 continue; 688 } 689 if (strncmp(name, "/dev/", 5) == 0) 690 name += 5; 691 pp = g_provider_by_name(name); 692 if (pp == NULL) { 693 gctl_error(req, "Unknown provider %s.", name); 694 continue; 695 } 696 cp = g_new_consumer(sc->sc_geom); 697 if (g_attach(cp, pp) != 0) { 698 g_destroy_consumer(cp); 699 gctl_error(req, "Cannot attach to provider %s.", name); 700 continue; 701 } 702 if (g_access(cp, 0, 1, 1) != 0) { 703 gctl_error(req, "Cannot access provider %s.", name); 704 err: 705 g_detach(cp); 706 g_destroy_consumer(cp); 707 continue; 708 } 709 mdsize = (sc->sc_type == G_MIRROR_TYPE_AUTOMATIC) ? 710 pp->sectorsize : 0; 711 if (sc->sc_provider->mediasize > pp->mediasize - mdsize) { 712 gctl_error(req, "Provider %s too small.", name); 713 err2: 714 g_access(cp, 0, -1, -1); 715 goto err; 716 } 717 if ((sc->sc_provider->sectorsize % pp->sectorsize) != 0) { 718 gctl_error(req, "Invalid sectorsize of provider %s.", 719 name); 720 goto err2; 721 } 722 if (sc->sc_type != G_MIRROR_TYPE_AUTOMATIC) { 723 g_access(cp, 0, -1, -1); 724 g_detach(cp); 725 g_destroy_consumer(cp); 726 g_topology_unlock(); 727 sc->sc_ndisks++; 728 g_mirror_fill_metadata(sc, NULL, &md); 729 md.md_priority = *priority; 730 if (*inactive) 731 md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE; 732 if (g_mirror_add_disk(sc, pp, &md) != 0) { 733 sc->sc_ndisks--; 734 gctl_error(req, "Disk %s not inserted.", name); 735 } 736 g_topology_lock(); 737 continue; 738 } 739 disks[n].provider = pp; 740 disks[n].consumer = cp; 741 n++; 742 } 743 if (n == 0) { 744 g_topology_unlock(); 745 sx_xunlock(&sc->sc_lock); 746 g_free(disks); 747 return; 748 } 749 sc->sc_ndisks += n; 750 again: 751 for (i = 0; i < n; i++) { 752 if (disks[i].consumer == NULL) 753 continue; 754 g_mirror_fill_metadata(sc, NULL, &md); 755 md.md_priority = *priority; 756 if (*inactive) 757 md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE; 758 pp = disks[i].provider; 759 if (*hardcode) { 760 strlcpy(md.md_provider, pp->name, 761 sizeof(md.md_provider)); 762 } else { 763 bzero(md.md_provider, sizeof(md.md_provider)); 764 } 765 md.md_provsize = pp->mediasize; 766 sector = g_malloc(pp->sectorsize, M_WAITOK); 767 mirror_metadata_encode(&md, sector); 768 error = g_write_data(disks[i].consumer, 769 pp->mediasize - pp->sectorsize, sector, pp->sectorsize); 770 g_free(sector); 771 if (error != 0) { 772 gctl_error(req, "Cannot store metadata on %s.", 773 pp->name); 774 g_access(disks[i].consumer, 0, -1, -1); 775 g_detach(disks[i].consumer); 776 g_destroy_consumer(disks[i].consumer); 777 disks[i].consumer = NULL; 778 disks[i].provider = NULL; 779 sc->sc_ndisks--; 780 goto again; 781 } 782 } 783 g_topology_unlock(); 784 if (i == 0) { 785 /* All writes failed. */ 786 sx_xunlock(&sc->sc_lock); 787 g_free(disks); 788 return; 789 } 790 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 791 g_mirror_update_metadata(disk); 792 } 793 /* 794 * Release provider and wait for retaste. 795 */ 796 g_topology_lock(); 797 for (i = 0; i < n; i++) { 798 if (disks[i].consumer == NULL) 799 continue; 800 g_access(disks[i].consumer, 0, -1, -1); 801 g_detach(disks[i].consumer); 802 g_destroy_consumer(disks[i].consumer); 803 } 804 g_topology_unlock(); 805 sx_xunlock(&sc->sc_lock); 806 g_free(disks); 807 } 808 809 static void 810 g_mirror_ctl_remove(struct gctl_req *req, struct g_class *mp) 811 { 812 struct g_mirror_softc *sc; 813 struct g_mirror_disk *disk; 814 const char *name; 815 char param[16]; 816 int *nargs; 817 u_int i, active; 818 819 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 820 if (nargs == NULL) { 821 gctl_error(req, "No '%s' argument.", "nargs"); 822 return; 823 } 824 if (*nargs < 2) { 825 gctl_error(req, "Too few arguments."); 826 return; 827 } 828 name = gctl_get_asciiparam(req, "arg0"); 829 if (name == NULL) { 830 gctl_error(req, "No 'arg%u' argument.", 0); 831 return; 832 } 833 sc = g_mirror_find_device(mp, name); 834 if (sc == NULL) { 835 gctl_error(req, "No such device: %s.", name); 836 return; 837 } 838 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 839 sx_xunlock(&sc->sc_lock); 840 gctl_error(req, "Not all disks connected. Try 'forget' command " 841 "first."); 842 return; 843 } 844 active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE); 845 for (i = 1; i < (u_int)*nargs; i++) { 846 snprintf(param, sizeof(param), "arg%u", i); 847 name = gctl_get_asciiparam(req, param); 848 if (name == NULL) { 849 gctl_error(req, "No 'arg%u' argument.", i); 850 continue; 851 } 852 disk = g_mirror_find_disk(sc, name); 853 if (disk == NULL) { 854 gctl_error(req, "No such provider: %s.", name); 855 continue; 856 } 857 if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) { 858 if (active > 1) 859 active--; 860 else { 861 gctl_error(req, "%s: Can't remove the last " 862 "ACTIVE component %s.", sc->sc_geom->name, 863 name); 864 continue; 865 } 866 } 867 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DESTROY, 868 G_MIRROR_EVENT_DONTWAIT); 869 } 870 sx_xunlock(&sc->sc_lock); 871 } 872 873 static void 874 g_mirror_ctl_resize(struct gctl_req *req, struct g_class *mp) 875 { 876 struct g_mirror_softc *sc; 877 struct g_mirror_disk *disk; 878 uint64_t mediasize; 879 const char *name, *s; 880 char *x; 881 int *nargs; 882 883 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 884 if (nargs == NULL) { 885 gctl_error(req, "No '%s' argument.", "nargs"); 886 return; 887 } 888 if (*nargs != 1) { 889 gctl_error(req, "Missing device."); 890 return; 891 } 892 name = gctl_get_asciiparam(req, "arg0"); 893 if (name == NULL) { 894 gctl_error(req, "No 'arg%u' argument.", 0); 895 return; 896 } 897 s = gctl_get_asciiparam(req, "size"); 898 if (s == NULL) { 899 gctl_error(req, "No '%s' argument.", "size"); 900 return; 901 } 902 mediasize = strtouq(s, &x, 0); 903 if (*x != '\0' || mediasize == 0) { 904 gctl_error(req, "Invalid '%s' argument.", "size"); 905 return; 906 } 907 sc = g_mirror_find_launched_device(mp, name, M_WAITOK); 908 if (sc == NULL) { 909 gctl_error(req, "No such device: %s.", name); 910 return; 911 } 912 /* Deny shrinking of an opened provider */ 913 if ((g_debugflags & G_F_FOOTSHOOTING) == 0 && sc->sc_provider_open > 0) { 914 if (sc->sc_mediasize > mediasize) { 915 gctl_error(req, "Device %s is busy.", 916 sc->sc_provider->name); 917 sx_xunlock(&sc->sc_lock); 918 return; 919 } 920 } 921 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 922 if (mediasize > disk->d_consumer->provider->mediasize - 923 disk->d_consumer->provider->sectorsize) { 924 gctl_error(req, "Provider %s is too small.", 925 disk->d_name); 926 sx_xunlock(&sc->sc_lock); 927 return; 928 } 929 } 930 /* Update the size. */ 931 sc->sc_mediasize = mediasize; 932 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 933 g_mirror_update_metadata(disk); 934 } 935 g_topology_lock(); 936 g_resize_provider(sc->sc_provider, mediasize); 937 g_topology_unlock(); 938 sx_xunlock(&sc->sc_lock); 939 } 940 941 static void 942 g_mirror_ctl_deactivate(struct gctl_req *req, struct g_class *mp) 943 { 944 struct g_mirror_softc *sc; 945 struct g_mirror_disk *disk; 946 const char *name; 947 char param[16]; 948 int *nargs; 949 u_int i, active; 950 951 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 952 if (nargs == NULL) { 953 gctl_error(req, "No '%s' argument.", "nargs"); 954 return; 955 } 956 if (*nargs < 2) { 957 gctl_error(req, "Too few arguments."); 958 return; 959 } 960 name = gctl_get_asciiparam(req, "arg0"); 961 if (name == NULL) { 962 gctl_error(req, "No 'arg%u' argument.", 0); 963 return; 964 } 965 sc = g_mirror_find_device(mp, name); 966 if (sc == NULL) { 967 gctl_error(req, "No such device: %s.", name); 968 return; 969 } 970 active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE); 971 for (i = 1; i < (u_int)*nargs; i++) { 972 snprintf(param, sizeof(param), "arg%u", i); 973 name = gctl_get_asciiparam(req, param); 974 if (name == NULL) { 975 gctl_error(req, "No 'arg%u' argument.", i); 976 continue; 977 } 978 disk = g_mirror_find_disk(sc, name); 979 if (disk == NULL) { 980 gctl_error(req, "No such provider: %s.", name); 981 continue; 982 } 983 if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) { 984 if (active > 1) 985 active--; 986 else { 987 gctl_error(req, "%s: Can't deactivate the " 988 "last ACTIVE component %s.", 989 sc->sc_geom->name, name); 990 continue; 991 } 992 } 993 disk->d_flags |= G_MIRROR_DISK_FLAG_INACTIVE; 994 disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC; 995 g_mirror_update_metadata(disk); 996 sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID; 997 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, 998 G_MIRROR_EVENT_DONTWAIT); 999 } 1000 sx_xunlock(&sc->sc_lock); 1001 } 1002 1003 static void 1004 g_mirror_ctl_forget(struct gctl_req *req, struct g_class *mp) 1005 { 1006 struct g_mirror_softc *sc; 1007 struct g_mirror_disk *disk; 1008 const char *name; 1009 char param[16]; 1010 int *nargs; 1011 u_int i; 1012 1013 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 1014 if (nargs == NULL) { 1015 gctl_error(req, "No '%s' argument.", "nargs"); 1016 return; 1017 } 1018 if (*nargs < 1) { 1019 gctl_error(req, "Missing device(s)."); 1020 return; 1021 } 1022 1023 for (i = 0; i < (u_int)*nargs; i++) { 1024 snprintf(param, sizeof(param), "arg%u", i); 1025 name = gctl_get_asciiparam(req, param); 1026 if (name == NULL) { 1027 gctl_error(req, "No 'arg%u' argument.", i); 1028 return; 1029 } 1030 sc = g_mirror_find_device(mp, name); 1031 if (sc == NULL) { 1032 gctl_error(req, "No such device: %s.", name); 1033 return; 1034 } 1035 if (g_mirror_ndisks(sc, -1) == sc->sc_ndisks) { 1036 sx_xunlock(&sc->sc_lock); 1037 G_MIRROR_DEBUG(1, 1038 "All disks connected in %s, skipping.", 1039 sc->sc_name); 1040 continue; 1041 } 1042 sc->sc_ndisks = g_mirror_ndisks(sc, -1); 1043 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 1044 g_mirror_update_metadata(disk); 1045 } 1046 sx_xunlock(&sc->sc_lock); 1047 } 1048 } 1049 1050 static void 1051 g_mirror_ctl_stop(struct gctl_req *req, struct g_class *mp, int wipe) 1052 { 1053 struct g_mirror_softc *sc; 1054 int *force, *nargs, error; 1055 const char *name; 1056 char param[16]; 1057 u_int i; 1058 int how; 1059 1060 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 1061 if (nargs == NULL) { 1062 gctl_error(req, "No '%s' argument.", "nargs"); 1063 return; 1064 } 1065 if (*nargs < 1) { 1066 gctl_error(req, "Missing device(s)."); 1067 return; 1068 } 1069 force = gctl_get_paraml(req, "force", sizeof(*force)); 1070 if (force == NULL) { 1071 gctl_error(req, "No '%s' argument.", "force"); 1072 return; 1073 } 1074 if (*force) 1075 how = G_MIRROR_DESTROY_HARD; 1076 else 1077 how = G_MIRROR_DESTROY_SOFT; 1078 1079 for (i = 0; i < (u_int)*nargs; i++) { 1080 snprintf(param, sizeof(param), "arg%u", i); 1081 name = gctl_get_asciiparam(req, param); 1082 if (name == NULL) { 1083 gctl_error(req, "No 'arg%u' argument.", i); 1084 return; 1085 } 1086 sc = g_mirror_find_device(mp, name); 1087 if (sc == NULL) { 1088 gctl_error(req, "No such device: %s.", name); 1089 return; 1090 } 1091 g_cancel_event(sc); 1092 if (wipe) 1093 sc->sc_flags |= G_MIRROR_DEVICE_FLAG_WIPE; 1094 error = g_mirror_destroy(sc, how); 1095 if (error != 0) { 1096 gctl_error(req, "Cannot destroy device %s (error=%d).", 1097 sc->sc_geom->name, error); 1098 if (wipe) 1099 sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_WIPE; 1100 sx_xunlock(&sc->sc_lock); 1101 return; 1102 } 1103 /* No need to unlock, because lock is already dead. */ 1104 } 1105 } 1106 1107 void 1108 g_mirror_config(struct gctl_req *req, struct g_class *mp, const char *verb) 1109 { 1110 uint32_t *version; 1111 1112 g_topology_assert(); 1113 1114 version = gctl_get_paraml(req, "version", sizeof(*version)); 1115 if (version == NULL) { 1116 gctl_error(req, "No '%s' argument.", "version"); 1117 return; 1118 } 1119 if (*version != G_MIRROR_VERSION) { 1120 gctl_error(req, "Userland and kernel parts are out of sync."); 1121 return; 1122 } 1123 1124 g_topology_unlock(); 1125 if (strcmp(verb, "configure") == 0) 1126 g_mirror_ctl_configure(req, mp); 1127 else if (strcmp(verb, "create") == 0) 1128 g_mirror_ctl_create(req, mp); 1129 else if (strcmp(verb, "rebuild") == 0) 1130 g_mirror_ctl_rebuild(req, mp); 1131 else if (strcmp(verb, "insert") == 0) 1132 g_mirror_ctl_insert(req, mp); 1133 else if (strcmp(verb, "remove") == 0) 1134 g_mirror_ctl_remove(req, mp); 1135 else if (strcmp(verb, "resize") == 0) 1136 g_mirror_ctl_resize(req, mp); 1137 else if (strcmp(verb, "deactivate") == 0) 1138 g_mirror_ctl_deactivate(req, mp); 1139 else if (strcmp(verb, "forget") == 0) 1140 g_mirror_ctl_forget(req, mp); 1141 else if (strcmp(verb, "stop") == 0) 1142 g_mirror_ctl_stop(req, mp, 0); 1143 else if (strcmp(verb, "destroy") == 0) 1144 g_mirror_ctl_stop(req, mp, 1); 1145 else 1146 gctl_error(req, "Unknown verb."); 1147 g_topology_lock(); 1148 } 1149