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