1 /*- 2 * Copyright (c) 2004 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/lock.h> 35 #include <sys/mutex.h> 36 #include <sys/bio.h> 37 #include <sys/sysctl.h> 38 #include <sys/malloc.h> 39 #include <sys/bitstring.h> 40 #include <vm/uma.h> 41 #include <machine/atomic.h> 42 #include <geom/geom.h> 43 #include <sys/proc.h> 44 #include <sys/kthread.h> 45 #include <geom/mirror/g_mirror.h> 46 47 48 static struct g_mirror_softc * 49 g_mirror_find_device(struct g_class *mp, const char *name) 50 { 51 struct g_mirror_softc *sc; 52 struct g_geom *gp; 53 54 g_topology_assert(); 55 LIST_FOREACH(gp, &mp->geom, geom) { 56 sc = gp->softc; 57 if (sc == NULL) 58 continue; 59 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) 60 continue; 61 if (strcmp(gp->name, name) == 0 || 62 strcmp(sc->sc_name, name) == 0) { 63 return (sc); 64 } 65 } 66 return (NULL); 67 } 68 69 static struct g_mirror_disk * 70 g_mirror_find_disk(struct g_mirror_softc *sc, const char *name) 71 { 72 struct g_mirror_disk *disk; 73 74 g_topology_assert(); 75 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 76 if (disk->d_consumer == NULL) 77 continue; 78 if (disk->d_consumer->provider == NULL) 79 continue; 80 if (strcmp(disk->d_consumer->provider->name, name) == 0) 81 return (disk); 82 } 83 return (NULL); 84 } 85 86 static void 87 g_mirror_ctl_configure(struct gctl_req *req, struct g_class *mp) 88 { 89 struct g_mirror_softc *sc; 90 struct g_mirror_disk *disk; 91 const char *name, *balancep; 92 intmax_t *slicep; 93 uint32_t slice; 94 uint8_t balance; 95 int *nargs, *autosync, *noautosync, do_sync = 0; 96 97 g_topology_assert(); 98 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 99 if (*nargs != 1) { 100 gctl_error(req, "Invalid number of arguments."); 101 return; 102 } 103 name = gctl_get_asciiparam(req, "arg0"); 104 sc = g_mirror_find_device(mp, name); 105 if (sc == NULL) { 106 gctl_error(req, "No such device: %s.", name); 107 return; 108 } 109 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 110 gctl_error(req, "Not all disks connected."); 111 return; 112 } 113 balancep = gctl_get_asciiparam(req, "balance"); 114 if (strcmp(balancep, "none") == 0) 115 balance = sc->sc_balance; 116 else { 117 if (balance_id(balancep) == -1) { 118 gctl_error(req, "Invalid balance algorithm."); 119 return; 120 } 121 balance = balance_id(balancep); 122 } 123 slicep = gctl_get_paraml(req, "slice", sizeof(*slicep)); 124 if (slicep == NULL) { 125 gctl_error(req, "No '%s' argument.", "slice"); 126 return; 127 } 128 if (*slicep == -1) 129 slice = sc->sc_slice; 130 else 131 slice = *slicep; 132 autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync)); 133 if (autosync == NULL) { 134 gctl_error(req, "No '%s' argument.", "autosync"); 135 return; 136 } 137 noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 138 if (noautosync == NULL) { 139 gctl_error(req, "No '%s' argument.", "noautosync"); 140 return; 141 } 142 if (sc->sc_balance == balance && sc->sc_slice == slice && !*autosync && 143 !*noautosync) { 144 gctl_error(req, "Nothing has changed."); 145 return; 146 } 147 if (*autosync && *noautosync) { 148 gctl_error(req, "'%s' and '%s' specified.", "autosync", 149 "noautosync"); 150 return; 151 } 152 sc->sc_balance = balance; 153 sc->sc_slice = slice; 154 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0) { 155 if (*autosync) { 156 sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_NOAUTOSYNC; 157 do_sync = 1; 158 } 159 } else { 160 if (*noautosync) 161 sc->sc_flags |= G_MIRROR_DEVICE_FLAG_NOAUTOSYNC; 162 } 163 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 164 if (do_sync) { 165 if (disk->d_state == G_MIRROR_DISK_STATE_SYNCHRONIZING) 166 disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC; 167 } 168 g_mirror_update_metadata(disk); 169 if (do_sync) { 170 if (disk->d_state == G_MIRROR_DISK_STATE_STALE) { 171 g_mirror_event_send(disk, 172 G_MIRROR_DISK_STATE_DISCONNECTED, 173 G_MIRROR_EVENT_DONTWAIT); 174 } 175 } 176 } 177 } 178 179 static void 180 g_mirror_ctl_rebuild(struct gctl_req *req, struct g_class *mp) 181 { 182 struct g_mirror_softc *sc; 183 struct g_mirror_disk *disk; 184 const char *name; 185 char param[16]; 186 int *nargs; 187 u_int i; 188 189 g_topology_assert(); 190 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 191 if (nargs == NULL) { 192 gctl_error(req, "No '%s' argument.", "nargs"); 193 return; 194 } 195 if (*nargs < 2) { 196 gctl_error(req, "Too few arguments."); 197 return; 198 } 199 name = gctl_get_asciiparam(req, "arg0"); 200 if (name == NULL) { 201 gctl_error(req, "No 'arg%u' argument.", 0); 202 return; 203 } 204 sc = g_mirror_find_device(mp, name); 205 if (sc == NULL) { 206 gctl_error(req, "No such device: %s.", name); 207 return; 208 } 209 210 for (i = 1; i < (u_int)*nargs; i++) { 211 snprintf(param, sizeof(param), "arg%u", i); 212 name = gctl_get_asciiparam(req, param); 213 if (name == NULL) { 214 gctl_error(req, "No 'arg%u' argument.", i); 215 return; 216 } 217 disk = g_mirror_find_disk(sc, name); 218 if (disk == NULL) { 219 gctl_error(req, "No such provider: %s.", name); 220 return; 221 } 222 if (g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) == 1 && 223 disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) { 224 /* 225 * This is the last active disk. There will be nothing 226 * to rebuild it from, so deny this request. 227 */ 228 gctl_error(req, 229 "Provider %s is the last active provider in %s.", 230 name, sc->sc_geom->name); 231 return; 232 } 233 /* 234 * Do rebuild by resetting syncid and disconnecting disk. 235 * It'll be retasted, connected to the mirror and 236 * synchronized. 237 */ 238 disk->d_sync.ds_syncid = 0; 239 if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_NOAUTOSYNC) != 0) 240 disk->d_flags |= G_MIRROR_DISK_FLAG_FORCE_SYNC; 241 g_mirror_update_metadata(disk); 242 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, 243 G_MIRROR_EVENT_WAIT); 244 } 245 } 246 247 static void 248 g_mirror_ctl_insert(struct gctl_req *req, struct g_class *mp) 249 { 250 struct g_mirror_softc *sc; 251 struct g_mirror_disk *disk; 252 struct g_mirror_metadata md; 253 struct g_provider *pp; 254 struct g_consumer *cp; 255 intmax_t *priority; 256 const char *name; 257 char param[16]; 258 u_char *sector; 259 u_int i, n; 260 int error, *nargs, *inactive; 261 struct { 262 struct g_provider *provider; 263 struct g_consumer *consumer; 264 } *disks; 265 266 g_topology_assert(); 267 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 268 if (nargs == NULL) { 269 gctl_error(req, "No '%s' argument.", "nargs"); 270 return; 271 } 272 if (*nargs < 2) { 273 gctl_error(req, "Too few arguments."); 274 return; 275 } 276 priority = gctl_get_paraml(req, "priority", sizeof(*priority)); 277 if (priority == NULL) { 278 gctl_error(req, "No '%s' argument.", "priority"); 279 return; 280 } 281 inactive = gctl_get_paraml(req, "inactive", sizeof(*inactive)); 282 if (inactive == NULL) { 283 gctl_error(req, "No '%s' argument.", "inactive"); 284 return; 285 } 286 name = gctl_get_asciiparam(req, "arg0"); 287 if (name == NULL) { 288 gctl_error(req, "No 'arg%u' argument.", 0); 289 return; 290 } 291 sc = g_mirror_find_device(mp, name); 292 if (sc == NULL) { 293 gctl_error(req, "No such device: %s.", name); 294 return; 295 } 296 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 297 gctl_error(req, "Not all disks connected."); 298 return; 299 } 300 301 disks = g_malloc(sizeof(*disks) * (*nargs), M_WAITOK | M_ZERO); 302 for (i = 1, n = 0; i < (u_int)*nargs; i++) { 303 snprintf(param, sizeof(param), "arg%u", i); 304 name = gctl_get_asciiparam(req, param); 305 if (name == NULL) { 306 gctl_error(req, "No 'arg%u' argument.", i); 307 continue; 308 } 309 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 310 name += strlen("/dev/"); 311 if (g_mirror_find_disk(sc, name) != NULL) { 312 gctl_error(req, "Provider %s already inserted.", name); 313 continue; 314 } 315 pp = g_provider_by_name(name); 316 if (pp == NULL) { 317 gctl_error(req, "Unknown provider %s.", name); 318 continue; 319 } 320 if (sc->sc_provider->mediasize > pp->mediasize) { 321 gctl_error(req, "Provider %s too small.", name); 322 continue; 323 } 324 if ((sc->sc_provider->sectorsize % pp->sectorsize) != 0) { 325 gctl_error(req, "Invalid sectorsize of provider %s.", 326 name); 327 continue; 328 } 329 cp = g_new_consumer(sc->sc_geom); 330 if (g_attach(cp, pp) != 0) { 331 g_destroy_consumer(cp); 332 gctl_error(req, "Cannot attach to provider %s.", name); 333 continue; 334 } 335 if (g_access(cp, 0, 1, 1) != 0) { 336 g_detach(cp); 337 g_destroy_consumer(cp); 338 gctl_error(req, "Cannot access provider %s.", name); 339 continue; 340 } 341 disks[n].provider = pp; 342 disks[n].consumer = cp; 343 n++; 344 } 345 if (n == 0) { 346 g_free(disks); 347 return; 348 } 349 sc->sc_ndisks += n; 350 again: 351 for (i = 0; i < n; i++) { 352 if (disks[i].consumer == NULL) 353 continue; 354 g_mirror_fill_metadata(sc, NULL, &md); 355 md.md_priority = *priority; 356 if (*inactive) 357 md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE; 358 pp = disks[i].provider; 359 sector = g_malloc(pp->sectorsize, M_WAITOK); 360 mirror_metadata_encode(&md, sector); 361 error = g_write_data(disks[i].consumer, 362 pp->mediasize - pp->sectorsize, sector, pp->sectorsize); 363 g_free(sector); 364 if (error != 0) { 365 gctl_error(req, "Cannot store metadata on %s.", 366 pp->name); 367 g_access(disks[i].consumer, 0, -1, -1); 368 g_detach(disks[i].consumer); 369 g_destroy_consumer(disks[i].consumer); 370 disks[i].consumer = NULL; 371 disks[i].provider = NULL; 372 sc->sc_ndisks--; 373 goto again; 374 } 375 } 376 if (i == 0) { 377 /* All writes failed. */ 378 g_free(disks); 379 return; 380 } 381 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 382 g_mirror_update_metadata(disk); 383 } 384 /* 385 * Release provider and wait for retaste. 386 */ 387 for (i = 0; i < n; i++) { 388 if (disks[i].consumer == NULL) 389 continue; 390 g_access(disks[i].consumer, 0, -1, -1); 391 g_detach(disks[i].consumer); 392 g_destroy_consumer(disks[i].consumer); 393 } 394 g_free(disks); 395 } 396 397 static void 398 g_mirror_ctl_remove(struct gctl_req *req, struct g_class *mp) 399 { 400 struct g_mirror_softc *sc; 401 struct g_mirror_disk *disk; 402 const char *name; 403 char param[16]; 404 int *nargs; 405 u_int i; 406 407 g_topology_assert(); 408 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 409 if (nargs == NULL) { 410 gctl_error(req, "No '%s' argument.", "nargs"); 411 return; 412 } 413 if (*nargs < 2) { 414 gctl_error(req, "Too few arguments."); 415 return; 416 } 417 name = gctl_get_asciiparam(req, "arg0"); 418 if (name == NULL) { 419 gctl_error(req, "No 'arg%u' argument.", 0); 420 return; 421 } 422 sc = g_mirror_find_device(mp, name); 423 if (sc == NULL) { 424 gctl_error(req, "No such device: %s.", name); 425 return; 426 } 427 if (g_mirror_ndisks(sc, -1) < sc->sc_ndisks) { 428 gctl_error(req, "Not all disks connected."); 429 return; 430 } 431 432 for (i = 1; i < (u_int)*nargs; i++) { 433 snprintf(param, sizeof(param), "arg%u", i); 434 name = gctl_get_asciiparam(req, param); 435 if (name == NULL) { 436 gctl_error(req, "No 'arg%u' argument.", i); 437 return; 438 } 439 disk = g_mirror_find_disk(sc, name); 440 if (disk == NULL) { 441 gctl_error(req, "No such provider: %s.", name); 442 return; 443 } 444 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DESTROY, 445 G_MIRROR_EVENT_WAIT); 446 } 447 } 448 449 static void 450 g_mirror_ctl_deactivate(struct gctl_req *req, struct g_class *mp) 451 { 452 struct g_mirror_softc *sc; 453 struct g_mirror_disk *disk; 454 const char *name; 455 char param[16]; 456 int *nargs; 457 u_int i; 458 459 g_topology_assert(); 460 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 461 if (nargs == NULL) { 462 gctl_error(req, "No '%s' argument.", "nargs"); 463 return; 464 } 465 if (*nargs < 2) { 466 gctl_error(req, "Too few arguments."); 467 return; 468 } 469 name = gctl_get_asciiparam(req, "arg0"); 470 if (name == NULL) { 471 gctl_error(req, "No 'arg%u' argument.", 0); 472 return; 473 } 474 sc = g_mirror_find_device(mp, name); 475 if (sc == NULL) { 476 gctl_error(req, "No such device: %s.", name); 477 return; 478 } 479 480 for (i = 1; i < (u_int)*nargs; i++) { 481 snprintf(param, sizeof(param), "arg%u", i); 482 name = gctl_get_asciiparam(req, param); 483 if (name == NULL) { 484 gctl_error(req, "No 'arg%u' argument.", i); 485 return; 486 } 487 disk = g_mirror_find_disk(sc, name); 488 if (disk == NULL) { 489 gctl_error(req, "No such provider: %s.", name); 490 return; 491 } 492 /* 493 * Do rebuild by resetting syncid and disconnecting disk. 494 * It'll be retasted, connected to the mirror and 495 * synchronized. 496 */ 497 disk->d_flags |= G_MIRROR_DISK_FLAG_INACTIVE; 498 disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC; 499 g_mirror_update_metadata(disk); 500 sc->sc_bump_syncid = G_MIRROR_BUMP_ON_FIRST_WRITE; 501 g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, 502 G_MIRROR_EVENT_WAIT); 503 } 504 } 505 506 static void 507 g_mirror_ctl_forget(struct gctl_req *req, struct g_class *mp) 508 { 509 struct g_mirror_softc *sc; 510 struct g_mirror_disk *disk; 511 const char *name; 512 char param[16]; 513 int *nargs; 514 u_int i; 515 516 g_topology_assert(); 517 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 518 if (nargs == NULL) { 519 gctl_error(req, "No '%s' argument.", "nargs"); 520 return; 521 } 522 if (*nargs < 1) { 523 gctl_error(req, "Missing device(s)."); 524 return; 525 } 526 527 for (i = 0; i < (u_int)*nargs; i++) { 528 snprintf(param, sizeof(param), "arg%u", i); 529 name = gctl_get_asciiparam(req, param); 530 if (name == NULL) { 531 gctl_error(req, "No 'arg%u' argument.", i); 532 return; 533 } 534 sc = g_mirror_find_device(mp, name); 535 if (sc == NULL) { 536 gctl_error(req, "No such device: %s.", name); 537 return; 538 } 539 if (g_mirror_ndisks(sc, -1) == sc->sc_ndisks) { 540 G_MIRROR_DEBUG(1, 541 "All disks connected in %s, skipping.", 542 sc->sc_name); 543 continue; 544 } 545 sc->sc_ndisks = g_mirror_ndisks(sc, -1); 546 LIST_FOREACH(disk, &sc->sc_disks, d_next) { 547 g_mirror_update_metadata(disk); 548 } 549 } 550 } 551 552 static void 553 g_mirror_ctl_stop(struct gctl_req *req, struct g_class *mp) 554 { 555 struct g_mirror_softc *sc; 556 int *force, *nargs, error; 557 const char *name; 558 char param[16]; 559 u_int i; 560 561 g_topology_assert(); 562 563 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 564 if (nargs == NULL) { 565 gctl_error(req, "No '%s' argument.", "nargs"); 566 return; 567 } 568 if (*nargs < 1) { 569 gctl_error(req, "Missing device(s)."); 570 return; 571 } 572 force = gctl_get_paraml(req, "force", sizeof(*force)); 573 if (force == NULL) { 574 gctl_error(req, "No '%s' argument.", "force"); 575 return; 576 } 577 578 for (i = 0; i < (u_int)*nargs; i++) { 579 snprintf(param, sizeof(param), "arg%u", i); 580 name = gctl_get_asciiparam(req, param); 581 if (name == NULL) { 582 gctl_error(req, "No 'arg%u' argument.", i); 583 return; 584 } 585 sc = g_mirror_find_device(mp, name); 586 if (sc == NULL) { 587 gctl_error(req, "No such device: %s.", name); 588 return; 589 } 590 error = g_mirror_destroy(sc, *force); 591 if (error != 0) { 592 gctl_error(req, "Cannot destroy device %s (error=%d).", 593 sc->sc_geom->name, error); 594 return; 595 } 596 } 597 } 598 599 void 600 g_mirror_config(struct gctl_req *req, struct g_class *mp, const char *verb) 601 { 602 uint32_t *version; 603 604 g_topology_assert(); 605 606 version = gctl_get_paraml(req, "version", sizeof(*version)); 607 if (version == NULL) { 608 gctl_error(req, "No '%s' argument.", "version"); 609 return; 610 } 611 if (*version != G_MIRROR_VERSION) { 612 gctl_error(req, "Userland and kernel parts are out of sync."); 613 return; 614 } 615 616 if (strcmp(verb, "configure") == 0) 617 g_mirror_ctl_configure(req, mp); 618 else if (strcmp(verb, "rebuild") == 0) 619 g_mirror_ctl_rebuild(req, mp); 620 else if (strcmp(verb, "insert") == 0) 621 g_mirror_ctl_insert(req, mp); 622 else if (strcmp(verb, "remove") == 0) 623 g_mirror_ctl_remove(req, mp); 624 else if (strcmp(verb, "deactivate") == 0) 625 g_mirror_ctl_deactivate(req, mp); 626 else if (strcmp(verb, "forget") == 0) 627 g_mirror_ctl_forget(req, mp); 628 else if (strcmp(verb, "stop") == 0) 629 g_mirror_ctl_stop(req, mp); 630 else 631 gctl_error(req, "Unknown verb."); 632 } 633