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