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