1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2004, 2007 Lukas Ertl 5 * Copyright (c) 2007, 2009 Ulf Lilleengen 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31 #include <sys/param.h> 32 #include <sys/bio.h> 33 #include <sys/kernel.h> 34 #include <sys/kthread.h> 35 #include <sys/lock.h> 36 #include <sys/malloc.h> 37 #include <sys/module.h> 38 #include <sys/mutex.h> 39 #include <sys/sbuf.h> 40 #include <sys/sysctl.h> 41 #include <sys/systm.h> 42 43 #include <geom/geom.h> 44 #include <geom/geom_dbg.h> 45 #include <geom/vinum/geom_vinum_var.h> 46 #include <geom/vinum/geom_vinum.h> 47 #include <geom/vinum/geom_vinum_raid5.h> 48 49 SYSCTL_DECL(_kern_geom); 50 static SYSCTL_NODE(_kern_geom, OID_AUTO, vinum, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 51 "GEOM_VINUM stuff"); 52 u_int g_vinum_debug = 0; 53 SYSCTL_UINT(_kern_geom_vinum, OID_AUTO, debug, CTLFLAG_RWTUN, &g_vinum_debug, 0, 54 "Debug level"); 55 56 static int gv_create(struct g_geom *, struct gctl_req *); 57 static void gv_attach(struct gv_softc *, struct gctl_req *); 58 static void gv_detach(struct gv_softc *, struct gctl_req *); 59 static void gv_parityop(struct gv_softc *, struct gctl_req *); 60 61 static void 62 gv_orphan(struct g_consumer *cp) 63 { 64 struct g_geom *gp; 65 struct gv_softc *sc; 66 struct gv_drive *d; 67 68 g_topology_assert(); 69 70 KASSERT(cp != NULL, ("gv_orphan: null cp")); 71 gp = cp->geom; 72 KASSERT(gp != NULL, ("gv_orphan: null gp")); 73 sc = gp->softc; 74 KASSERT(sc != NULL, ("gv_orphan: null sc")); 75 d = cp->private; 76 KASSERT(d != NULL, ("gv_orphan: null d")); 77 78 g_trace(G_T_TOPOLOGY, "gv_orphan(%s)", gp->name); 79 80 gv_post_event(sc, GV_EVENT_DRIVE_LOST, d, NULL, 0, 0); 81 } 82 83 void 84 gv_start(struct bio *bp) 85 { 86 struct g_geom *gp; 87 struct gv_softc *sc; 88 89 gp = bp->bio_to->geom; 90 sc = gp->softc; 91 92 switch (bp->bio_cmd) { 93 case BIO_READ: 94 case BIO_WRITE: 95 case BIO_DELETE: 96 break; 97 case BIO_GETATTR: 98 default: 99 g_io_deliver(bp, EOPNOTSUPP); 100 return; 101 } 102 mtx_lock(&sc->bqueue_mtx); 103 bioq_disksort(sc->bqueue_down, bp); 104 wakeup(sc); 105 mtx_unlock(&sc->bqueue_mtx); 106 } 107 108 void 109 gv_done(struct bio *bp) 110 { 111 struct g_geom *gp; 112 struct gv_softc *sc; 113 114 KASSERT(bp != NULL, ("NULL bp")); 115 116 gp = bp->bio_from->geom; 117 sc = gp->softc; 118 119 mtx_lock(&sc->bqueue_mtx); 120 bioq_disksort(sc->bqueue_up, bp); 121 wakeup(sc); 122 mtx_unlock(&sc->bqueue_mtx); 123 } 124 125 int 126 gv_access(struct g_provider *pp, int dr, int dw, int de) 127 { 128 struct g_geom *gp; 129 struct gv_softc *sc; 130 struct gv_drive *d, *d2; 131 int error; 132 133 gp = pp->geom; 134 sc = gp->softc; 135 /* 136 * We want to modify the read count with the write count in case we have 137 * plexes in a RAID-5 organization. 138 */ 139 dr += dw; 140 141 LIST_FOREACH(d, &sc->drives, drive) { 142 if (d->consumer == NULL) 143 continue; 144 error = g_access(d->consumer, dr, dw, de); 145 if (error) { 146 LIST_FOREACH(d2, &sc->drives, drive) { 147 if (d == d2) 148 break; 149 g_access(d2->consumer, -dr, -dw, -de); 150 } 151 G_VINUM_DEBUG(0, "g_access '%s' failed: %d", d->name, 152 error); 153 return (error); 154 } 155 } 156 return (0); 157 } 158 159 static void 160 gv_init(struct g_class *mp) 161 { 162 struct g_geom *gp; 163 struct gv_softc *sc; 164 165 g_trace(G_T_TOPOLOGY, "gv_init(%p)", mp); 166 167 gp = g_new_geomf(mp, "VINUM"); 168 gp->spoiled = gv_orphan; 169 gp->orphan = gv_orphan; 170 gp->access = gv_access; 171 gp->start = gv_start; 172 gp->softc = g_malloc(sizeof(struct gv_softc), M_WAITOK | M_ZERO); 173 sc = gp->softc; 174 sc->geom = gp; 175 sc->bqueue_down = g_malloc(sizeof(struct bio_queue_head), 176 M_WAITOK | M_ZERO); 177 sc->bqueue_up = g_malloc(sizeof(struct bio_queue_head), 178 M_WAITOK | M_ZERO); 179 bioq_init(sc->bqueue_down); 180 bioq_init(sc->bqueue_up); 181 LIST_INIT(&sc->drives); 182 LIST_INIT(&sc->subdisks); 183 LIST_INIT(&sc->plexes); 184 LIST_INIT(&sc->volumes); 185 TAILQ_INIT(&sc->equeue); 186 mtx_init(&sc->config_mtx, "gv_config", NULL, MTX_DEF); 187 mtx_init(&sc->equeue_mtx, "gv_equeue", NULL, MTX_DEF); 188 mtx_init(&sc->bqueue_mtx, "gv_bqueue", NULL, MTX_DEF); 189 kproc_create(gv_worker, sc, &sc->worker, 0, 0, "gv_worker"); 190 } 191 192 static int 193 gv_unload(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) 194 { 195 struct gv_softc *sc; 196 197 g_trace(G_T_TOPOLOGY, "gv_unload(%p)", mp); 198 199 g_topology_assert(); 200 sc = gp->softc; 201 202 if (sc != NULL) { 203 gv_worker_exit(sc); 204 gp->softc = NULL; 205 g_wither_geom(gp, ENXIO); 206 } 207 208 return (0); 209 } 210 211 /* Handle userland request of attaching object. */ 212 static void 213 gv_attach(struct gv_softc *sc, struct gctl_req *req) 214 { 215 struct gv_volume *v; 216 struct gv_plex *p; 217 struct gv_sd *s; 218 off_t *offset; 219 int *rename, type_child, type_parent; 220 char *child, *parent; 221 222 child = gctl_get_param(req, "child", NULL); 223 if (child == NULL) { 224 gctl_error(req, "no child given"); 225 return; 226 } 227 parent = gctl_get_param(req, "parent", NULL); 228 if (parent == NULL) { 229 gctl_error(req, "no parent given"); 230 return; 231 } 232 offset = gctl_get_paraml(req, "offset", sizeof(*offset)); 233 if (offset == NULL) { 234 gctl_error(req, "no offset given"); 235 return; 236 } 237 rename = gctl_get_paraml(req, "rename", sizeof(*rename)); 238 if (rename == NULL) { 239 gctl_error(req, "no rename flag given"); 240 return; 241 } 242 243 type_child = gv_object_type(sc, child); 244 type_parent = gv_object_type(sc, parent); 245 246 switch (type_child) { 247 case GV_TYPE_PLEX: 248 if (type_parent != GV_TYPE_VOL) { 249 gctl_error(req, "no such volume to attach to"); 250 return; 251 } 252 v = gv_find_vol(sc, parent); 253 p = gv_find_plex(sc, child); 254 gv_post_event(sc, GV_EVENT_ATTACH_PLEX, p, v, *offset, *rename); 255 break; 256 case GV_TYPE_SD: 257 if (type_parent != GV_TYPE_PLEX) { 258 gctl_error(req, "no such plex to attach to"); 259 return; 260 } 261 p = gv_find_plex(sc, parent); 262 s = gv_find_sd(sc, child); 263 gv_post_event(sc, GV_EVENT_ATTACH_SD, s, p, *offset, *rename); 264 break; 265 default: 266 gctl_error(req, "invalid child type"); 267 break; 268 } 269 } 270 271 /* Handle userland request of detaching object. */ 272 static void 273 gv_detach(struct gv_softc *sc, struct gctl_req *req) 274 { 275 struct gv_plex *p; 276 struct gv_sd *s; 277 int *flags, type; 278 char *object; 279 280 object = gctl_get_param(req, "object", NULL); 281 if (object == NULL) { 282 gctl_error(req, "no argument given"); 283 return; 284 } 285 286 flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 287 type = gv_object_type(sc, object); 288 switch (type) { 289 case GV_TYPE_PLEX: 290 p = gv_find_plex(sc, object); 291 gv_post_event(sc, GV_EVENT_DETACH_PLEX, p, NULL, *flags, 0); 292 break; 293 case GV_TYPE_SD: 294 s = gv_find_sd(sc, object); 295 gv_post_event(sc, GV_EVENT_DETACH_SD, s, NULL, *flags, 0); 296 break; 297 default: 298 gctl_error(req, "invalid object type"); 299 break; 300 } 301 } 302 303 /* Handle userland requests for creating new objects. */ 304 static int 305 gv_create(struct g_geom *gp, struct gctl_req *req) 306 { 307 struct gv_softc *sc; 308 struct gv_drive *d, *d2; 309 struct gv_plex *p, *p2; 310 struct gv_sd *s, *s2; 311 struct gv_volume *v, *v2; 312 struct g_provider *pp; 313 int i, *drives, *flags, *plexes, *subdisks, *volumes; 314 char buf[20]; 315 316 g_topology_assert(); 317 318 sc = gp->softc; 319 320 /* Find out how many of each object have been passed in. */ 321 volumes = gctl_get_paraml(req, "volumes", sizeof(*volumes)); 322 plexes = gctl_get_paraml(req, "plexes", sizeof(*plexes)); 323 subdisks = gctl_get_paraml(req, "subdisks", sizeof(*subdisks)); 324 drives = gctl_get_paraml(req, "drives", sizeof(*drives)); 325 if (volumes == NULL || plexes == NULL || subdisks == NULL || 326 drives == NULL) { 327 gctl_error(req, "number of objects not given"); 328 return (-1); 329 } 330 flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 331 if (flags == NULL) { 332 gctl_error(req, "flags not given"); 333 return (-1); 334 } 335 336 /* First, handle drive definitions ... */ 337 for (i = 0; i < *drives; i++) { 338 snprintf(buf, sizeof(buf), "drive%d", i); 339 d2 = gctl_get_paraml(req, buf, sizeof(*d2)); 340 if (d2 == NULL) { 341 gctl_error(req, "no drive definition given"); 342 return (-1); 343 } 344 /* 345 * Make sure that the device specified in the drive config is 346 * an active GEOM provider. 347 */ 348 pp = g_provider_by_name(d2->device); 349 if (pp == NULL) { 350 gctl_error(req, "%s: device not found", d2->device); 351 goto error; 352 } 353 if (gv_find_drive(sc, d2->name) != NULL) { 354 /* Ignore error. */ 355 if (*flags & GV_FLAG_F) 356 continue; 357 gctl_error(req, "drive '%s' already exists", d2->name); 358 goto error; 359 } 360 if (gv_find_drive_device(sc, d2->device) != NULL) { 361 gctl_error(req, "device '%s' already configured in " 362 "gvinum", d2->device); 363 goto error; 364 } 365 366 d = g_malloc(sizeof(*d), M_WAITOK | M_ZERO); 367 bcopy(d2, d, sizeof(*d)); 368 369 gv_post_event(sc, GV_EVENT_CREATE_DRIVE, d, NULL, 0, 0); 370 } 371 372 /* ... then volume definitions ... */ 373 for (i = 0; i < *volumes; i++) { 374 snprintf(buf, sizeof(buf), "volume%d", i); 375 v2 = gctl_get_paraml(req, buf, sizeof(*v2)); 376 if (v2 == NULL) { 377 gctl_error(req, "no volume definition given"); 378 return (-1); 379 } 380 if (gv_find_vol(sc, v2->name) != NULL) { 381 /* Ignore error. */ 382 if (*flags & GV_FLAG_F) 383 continue; 384 gctl_error(req, "volume '%s' already exists", v2->name); 385 goto error; 386 } 387 388 v = g_malloc(sizeof(*v), M_WAITOK | M_ZERO); 389 bcopy(v2, v, sizeof(*v)); 390 391 gv_post_event(sc, GV_EVENT_CREATE_VOLUME, v, NULL, 0, 0); 392 } 393 394 /* ... then plex definitions ... */ 395 for (i = 0; i < *plexes; i++) { 396 snprintf(buf, sizeof(buf), "plex%d", i); 397 p2 = gctl_get_paraml(req, buf, sizeof(*p2)); 398 if (p2 == NULL) { 399 gctl_error(req, "no plex definition given"); 400 return (-1); 401 } 402 if (gv_find_plex(sc, p2->name) != NULL) { 403 /* Ignore error. */ 404 if (*flags & GV_FLAG_F) 405 continue; 406 gctl_error(req, "plex '%s' already exists", p2->name); 407 goto error; 408 } 409 410 p = g_malloc(sizeof(*p), M_WAITOK | M_ZERO); 411 bcopy(p2, p, sizeof(*p)); 412 413 gv_post_event(sc, GV_EVENT_CREATE_PLEX, p, NULL, 0, 0); 414 } 415 416 /* ... and, finally, subdisk definitions. */ 417 for (i = 0; i < *subdisks; i++) { 418 snprintf(buf, sizeof(buf), "sd%d", i); 419 s2 = gctl_get_paraml(req, buf, sizeof(*s2)); 420 if (s2 == NULL) { 421 gctl_error(req, "no subdisk definition given"); 422 return (-1); 423 } 424 if (gv_find_sd(sc, s2->name) != NULL) { 425 /* Ignore error. */ 426 if (*flags & GV_FLAG_F) 427 continue; 428 gctl_error(req, "sd '%s' already exists", s2->name); 429 goto error; 430 } 431 432 s = g_malloc(sizeof(*s), M_WAITOK | M_ZERO); 433 bcopy(s2, s, sizeof(*s)); 434 435 gv_post_event(sc, GV_EVENT_CREATE_SD, s, NULL, 0, 0); 436 } 437 438 error: 439 gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc, NULL, 0, 0); 440 gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); 441 442 return (0); 443 } 444 445 static void 446 gv_config(struct gctl_req *req, struct g_class *mp, char const *verb) 447 { 448 struct g_geom *gp; 449 struct gv_softc *sc; 450 struct sbuf *sb; 451 char *comment; 452 453 g_topology_assert(); 454 455 gp = LIST_FIRST(&mp->geom); 456 sc = gp->softc; 457 458 if (!strcmp(verb, "attach")) { 459 gv_attach(sc, req); 460 461 } else if (!strcmp(verb, "concat")) { 462 gv_concat(gp, req); 463 464 } else if (!strcmp(verb, "detach")) { 465 gv_detach(sc, req); 466 467 } else if (!strcmp(verb, "list")) { 468 gv_list(gp, req); 469 470 /* Save our configuration back to disk. */ 471 } else if (!strcmp(verb, "saveconfig")) { 472 gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); 473 474 /* Return configuration in string form. */ 475 } else if (!strcmp(verb, "getconfig")) { 476 comment = gctl_get_param(req, "comment", NULL); 477 if (comment == NULL) { 478 gctl_error(req, "no comment parameter given"); 479 return; 480 } 481 sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN); 482 gv_format_config(sc, sb, 0, comment); 483 sbuf_finish(sb); 484 gctl_set_param(req, "config", sbuf_data(sb), sbuf_len(sb) + 1); 485 sbuf_delete(sb); 486 487 } else if (!strcmp(verb, "create")) { 488 gv_create(gp, req); 489 490 } else if (!strcmp(verb, "mirror")) { 491 gv_mirror(gp, req); 492 493 } else if (!strcmp(verb, "move")) { 494 gv_move(gp, req); 495 496 } else if (!strcmp(verb, "raid5")) { 497 gv_raid5(gp, req); 498 499 } else if (!strcmp(verb, "rebuildparity") || 500 !strcmp(verb, "checkparity")) { 501 gv_parityop(sc, req); 502 503 } else if (!strcmp(verb, "remove")) { 504 gv_remove(gp, req); 505 506 } else if (!strcmp(verb, "rename")) { 507 gv_rename(gp, req); 508 509 } else if (!strcmp(verb, "resetconfig")) { 510 gv_post_event(sc, GV_EVENT_RESET_CONFIG, sc, NULL, 0, 0); 511 512 } else if (!strcmp(verb, "start")) { 513 gv_start_obj(gp, req); 514 515 } else if (!strcmp(verb, "stripe")) { 516 gv_stripe(gp, req); 517 518 } else if (!strcmp(verb, "setstate")) { 519 gv_setstate(gp, req); 520 } else 521 gctl_error(req, "Unknown verb parameter"); 522 } 523 524 static void 525 gv_parityop(struct gv_softc *sc, struct gctl_req *req) 526 { 527 struct gv_plex *p; 528 int *flags, *rebuild, type; 529 char *plex; 530 531 plex = gctl_get_param(req, "plex", NULL); 532 if (plex == NULL) { 533 gctl_error(req, "no plex given"); 534 return; 535 } 536 537 flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 538 if (flags == NULL) { 539 gctl_error(req, "no flags given"); 540 return; 541 } 542 543 rebuild = gctl_get_paraml(req, "rebuild", sizeof(*rebuild)); 544 if (rebuild == NULL) { 545 gctl_error(req, "no operation given"); 546 return; 547 } 548 549 type = gv_object_type(sc, plex); 550 if (type != GV_TYPE_PLEX) { 551 gctl_error(req, "'%s' is not a plex", plex); 552 return; 553 } 554 p = gv_find_plex(sc, plex); 555 556 if (p->state != GV_PLEX_UP) { 557 gctl_error(req, "plex %s is not completely accessible", 558 p->name); 559 return; 560 } 561 562 if (p->org != GV_PLEX_RAID5) { 563 gctl_error(req, "plex %s is not a RAID5 plex", p->name); 564 return; 565 } 566 567 /* Put it in the event queue. */ 568 /* XXX: The state of the plex might have changed when this event is 569 * picked up ... We should perhaps check this afterwards. */ 570 if (*rebuild) 571 gv_post_event(sc, GV_EVENT_PARITY_REBUILD, p, NULL, 0, 0); 572 else 573 gv_post_event(sc, GV_EVENT_PARITY_CHECK, p, NULL, 0, 0); 574 } 575 576 static struct g_geom * 577 gv_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 578 { 579 struct g_geom *gp; 580 struct g_consumer *cp; 581 struct gv_softc *sc; 582 struct gv_hdr vhdr; 583 int error; 584 585 g_topology_assert(); 586 g_trace(G_T_TOPOLOGY, "gv_taste(%s, %s)", mp->name, pp->name); 587 588 gp = LIST_FIRST(&mp->geom); 589 if (gp == NULL) { 590 G_VINUM_DEBUG(0, "error: tasting, but not initialized?"); 591 return (NULL); 592 } 593 sc = gp->softc; 594 595 cp = g_new_consumer(gp); 596 cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 597 if (g_attach(cp, pp) != 0) { 598 g_destroy_consumer(cp); 599 return (NULL); 600 } 601 if (g_access(cp, 1, 0, 0) != 0) { 602 g_detach(cp); 603 g_destroy_consumer(cp); 604 return (NULL); 605 } 606 g_topology_unlock(); 607 608 error = gv_read_header(cp, &vhdr); 609 610 g_topology_lock(); 611 g_access(cp, -1, 0, 0); 612 g_detach(cp); 613 g_destroy_consumer(cp); 614 615 /* Check if what we've been given is a valid vinum drive. */ 616 if (!error) 617 gv_post_event(sc, GV_EVENT_DRIVE_TASTED, pp, NULL, 0, 0); 618 619 return (NULL); 620 } 621 622 void 623 gv_worker(void *arg) 624 { 625 struct g_provider *pp; 626 struct gv_softc *sc; 627 struct gv_event *ev; 628 struct gv_volume *v; 629 struct gv_plex *p; 630 struct gv_sd *s; 631 struct gv_drive *d; 632 struct bio *bp; 633 int newstate, flags, err, rename; 634 char *newname; 635 off_t offset; 636 637 sc = arg; 638 KASSERT(sc != NULL, ("NULL sc")); 639 for (;;) { 640 /* Look at the events first... */ 641 ev = gv_get_event(sc); 642 if (ev != NULL) { 643 gv_remove_event(sc, ev); 644 645 switch (ev->type) { 646 case GV_EVENT_DRIVE_TASTED: 647 G_VINUM_DEBUG(2, "event 'drive tasted'"); 648 pp = ev->arg1; 649 gv_drive_tasted(sc, pp); 650 break; 651 652 case GV_EVENT_DRIVE_LOST: 653 G_VINUM_DEBUG(2, "event 'drive lost'"); 654 d = ev->arg1; 655 gv_drive_lost(sc, d); 656 break; 657 658 case GV_EVENT_CREATE_DRIVE: 659 G_VINUM_DEBUG(2, "event 'create drive'"); 660 d = ev->arg1; 661 gv_create_drive(sc, d); 662 break; 663 664 case GV_EVENT_CREATE_VOLUME: 665 G_VINUM_DEBUG(2, "event 'create volume'"); 666 v = ev->arg1; 667 gv_create_volume(sc, v); 668 break; 669 670 case GV_EVENT_CREATE_PLEX: 671 G_VINUM_DEBUG(2, "event 'create plex'"); 672 p = ev->arg1; 673 gv_create_plex(sc, p); 674 break; 675 676 case GV_EVENT_CREATE_SD: 677 G_VINUM_DEBUG(2, "event 'create sd'"); 678 s = ev->arg1; 679 gv_create_sd(sc, s); 680 break; 681 682 case GV_EVENT_RM_DRIVE: 683 G_VINUM_DEBUG(2, "event 'remove drive'"); 684 d = ev->arg1; 685 flags = ev->arg3; 686 gv_rm_drive(sc, d, flags); 687 /*gv_setup_objects(sc);*/ 688 break; 689 690 case GV_EVENT_RM_VOLUME: 691 G_VINUM_DEBUG(2, "event 'remove volume'"); 692 v = ev->arg1; 693 gv_rm_vol(sc, v); 694 /*gv_setup_objects(sc);*/ 695 break; 696 697 case GV_EVENT_RM_PLEX: 698 G_VINUM_DEBUG(2, "event 'remove plex'"); 699 p = ev->arg1; 700 gv_rm_plex(sc, p); 701 /*gv_setup_objects(sc);*/ 702 break; 703 704 case GV_EVENT_RM_SD: 705 G_VINUM_DEBUG(2, "event 'remove sd'"); 706 s = ev->arg1; 707 gv_rm_sd(sc, s); 708 /*gv_setup_objects(sc);*/ 709 break; 710 711 case GV_EVENT_SAVE_CONFIG: 712 G_VINUM_DEBUG(2, "event 'save config'"); 713 gv_save_config(sc); 714 break; 715 716 case GV_EVENT_SET_SD_STATE: 717 G_VINUM_DEBUG(2, "event 'setstate sd'"); 718 s = ev->arg1; 719 newstate = ev->arg3; 720 flags = ev->arg4; 721 err = gv_set_sd_state(s, newstate, flags); 722 if (err) 723 G_VINUM_DEBUG(0, "error setting subdisk" 724 " state: error code %d", err); 725 break; 726 727 case GV_EVENT_SET_DRIVE_STATE: 728 G_VINUM_DEBUG(2, "event 'setstate drive'"); 729 d = ev->arg1; 730 newstate = ev->arg3; 731 flags = ev->arg4; 732 err = gv_set_drive_state(d, newstate, flags); 733 if (err) 734 G_VINUM_DEBUG(0, "error setting drive " 735 "state: error code %d", err); 736 break; 737 738 case GV_EVENT_SET_VOL_STATE: 739 G_VINUM_DEBUG(2, "event 'setstate volume'"); 740 v = ev->arg1; 741 newstate = ev->arg3; 742 flags = ev->arg4; 743 err = gv_set_vol_state(v, newstate, flags); 744 if (err) 745 G_VINUM_DEBUG(0, "error setting volume " 746 "state: error code %d", err); 747 break; 748 749 case GV_EVENT_SET_PLEX_STATE: 750 G_VINUM_DEBUG(2, "event 'setstate plex'"); 751 p = ev->arg1; 752 newstate = ev->arg3; 753 flags = ev->arg4; 754 err = gv_set_plex_state(p, newstate, flags); 755 if (err) 756 G_VINUM_DEBUG(0, "error setting plex " 757 "state: error code %d", err); 758 break; 759 760 case GV_EVENT_SETUP_OBJECTS: 761 G_VINUM_DEBUG(2, "event 'setup objects'"); 762 gv_setup_objects(sc); 763 break; 764 765 case GV_EVENT_RESET_CONFIG: 766 G_VINUM_DEBUG(2, "event 'resetconfig'"); 767 err = gv_resetconfig(sc); 768 if (err) 769 G_VINUM_DEBUG(0, "error resetting " 770 "config: error code %d", err); 771 break; 772 773 case GV_EVENT_PARITY_REBUILD: 774 /* 775 * Start the rebuild. The gv_plex_done will 776 * handle issuing of the remaining rebuild bio's 777 * until it's finished. 778 */ 779 G_VINUM_DEBUG(2, "event 'rebuild'"); 780 p = ev->arg1; 781 if (p->state != GV_PLEX_UP) { 782 G_VINUM_DEBUG(0, "plex %s is not " 783 "completely accessible", p->name); 784 break; 785 } 786 if (p->flags & GV_PLEX_SYNCING || 787 p->flags & GV_PLEX_REBUILDING || 788 p->flags & GV_PLEX_GROWING) { 789 G_VINUM_DEBUG(0, "plex %s is busy with " 790 "syncing or parity build", p->name); 791 break; 792 } 793 p->synced = 0; 794 p->flags |= GV_PLEX_REBUILDING; 795 g_topology_assert_not(); 796 g_topology_lock(); 797 err = gv_access(p->vol_sc->provider, 1, 1, 0); 798 if (err) { 799 G_VINUM_DEBUG(0, "unable to access " 800 "provider"); 801 break; 802 } 803 g_topology_unlock(); 804 gv_parity_request(p, GV_BIO_CHECK | 805 GV_BIO_PARITY, 0); 806 break; 807 808 case GV_EVENT_PARITY_CHECK: 809 /* Start parity check. */ 810 G_VINUM_DEBUG(2, "event 'check'"); 811 p = ev->arg1; 812 if (p->state != GV_PLEX_UP) { 813 G_VINUM_DEBUG(0, "plex %s is not " 814 "completely accessible", p->name); 815 break; 816 } 817 if (p->flags & GV_PLEX_SYNCING || 818 p->flags & GV_PLEX_REBUILDING || 819 p->flags & GV_PLEX_GROWING) { 820 G_VINUM_DEBUG(0, "plex %s is busy with " 821 "syncing or parity build", p->name); 822 break; 823 } 824 p->synced = 0; 825 g_topology_assert_not(); 826 g_topology_lock(); 827 err = gv_access(p->vol_sc->provider, 1, 1, 0); 828 if (err) { 829 G_VINUM_DEBUG(0, "unable to access " 830 "provider"); 831 break; 832 } 833 g_topology_unlock(); 834 gv_parity_request(p, GV_BIO_CHECK, 0); 835 break; 836 837 case GV_EVENT_START_PLEX: 838 G_VINUM_DEBUG(2, "event 'start' plex"); 839 p = ev->arg1; 840 gv_start_plex(p); 841 break; 842 843 case GV_EVENT_START_VOLUME: 844 G_VINUM_DEBUG(2, "event 'start' volume"); 845 v = ev->arg1; 846 gv_start_vol(v); 847 break; 848 849 case GV_EVENT_ATTACH_PLEX: 850 G_VINUM_DEBUG(2, "event 'attach' plex"); 851 p = ev->arg1; 852 v = ev->arg2; 853 rename = ev->arg4; 854 err = gv_attach_plex(p, v, rename); 855 if (err) 856 G_VINUM_DEBUG(0, "error attaching %s to" 857 " %s: error code %d", p->name, 858 v->name, err); 859 break; 860 861 case GV_EVENT_ATTACH_SD: 862 G_VINUM_DEBUG(2, "event 'attach' sd"); 863 s = ev->arg1; 864 p = ev->arg2; 865 offset = ev->arg3; 866 rename = ev->arg4; 867 err = gv_attach_sd(s, p, offset, rename); 868 if (err) 869 G_VINUM_DEBUG(0, "error attaching %s to" 870 " %s: error code %d", s->name, 871 p->name, err); 872 break; 873 874 case GV_EVENT_DETACH_PLEX: 875 G_VINUM_DEBUG(2, "event 'detach' plex"); 876 p = ev->arg1; 877 flags = ev->arg3; 878 err = gv_detach_plex(p, flags); 879 if (err) 880 G_VINUM_DEBUG(0, "error detaching %s: " 881 "error code %d", p->name, err); 882 break; 883 884 case GV_EVENT_DETACH_SD: 885 G_VINUM_DEBUG(2, "event 'detach' sd"); 886 s = ev->arg1; 887 flags = ev->arg3; 888 err = gv_detach_sd(s, flags); 889 if (err) 890 G_VINUM_DEBUG(0, "error detaching %s: " 891 "error code %d", s->name, err); 892 break; 893 894 case GV_EVENT_RENAME_VOL: 895 G_VINUM_DEBUG(2, "event 'rename' volume"); 896 v = ev->arg1; 897 newname = ev->arg2; 898 flags = ev->arg3; 899 err = gv_rename_vol(sc, v, newname, flags); 900 if (err) 901 G_VINUM_DEBUG(0, "error renaming %s to " 902 "%s: error code %d", v->name, 903 newname, err); 904 g_free(newname); 905 /* Destroy and recreate the provider if we can. */ 906 if (gv_provider_is_open(v->provider)) { 907 G_VINUM_DEBUG(0, "unable to rename " 908 "provider to %s: provider in use", 909 v->name); 910 break; 911 } 912 g_topology_lock(); 913 g_wither_provider(v->provider, ENOENT); 914 g_topology_unlock(); 915 v->provider = NULL; 916 gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc, 917 NULL, 0, 0); 918 break; 919 920 case GV_EVENT_RENAME_PLEX: 921 G_VINUM_DEBUG(2, "event 'rename' plex"); 922 p = ev->arg1; 923 newname = ev->arg2; 924 flags = ev->arg3; 925 err = gv_rename_plex(sc, p, newname, flags); 926 if (err) 927 G_VINUM_DEBUG(0, "error renaming %s to " 928 "%s: error code %d", p->name, 929 newname, err); 930 g_free(newname); 931 break; 932 933 case GV_EVENT_RENAME_SD: 934 G_VINUM_DEBUG(2, "event 'rename' sd"); 935 s = ev->arg1; 936 newname = ev->arg2; 937 flags = ev->arg3; 938 err = gv_rename_sd(sc, s, newname, flags); 939 if (err) 940 G_VINUM_DEBUG(0, "error renaming %s to " 941 "%s: error code %d", s->name, 942 newname, err); 943 g_free(newname); 944 break; 945 946 case GV_EVENT_RENAME_DRIVE: 947 G_VINUM_DEBUG(2, "event 'rename' drive"); 948 d = ev->arg1; 949 newname = ev->arg2; 950 flags = ev->arg3; 951 err = gv_rename_drive(sc, d, newname, flags); 952 if (err) 953 G_VINUM_DEBUG(0, "error renaming %s to " 954 "%s: error code %d", d->name, 955 newname, err); 956 g_free(newname); 957 break; 958 959 case GV_EVENT_MOVE_SD: 960 G_VINUM_DEBUG(2, "event 'move' sd"); 961 s = ev->arg1; 962 d = ev->arg2; 963 flags = ev->arg3; 964 err = gv_move_sd(sc, s, d, flags); 965 if (err) 966 G_VINUM_DEBUG(0, "error moving %s to " 967 "%s: error code %d", s->name, 968 d->name, err); 969 break; 970 971 case GV_EVENT_THREAD_EXIT: 972 G_VINUM_DEBUG(2, "event 'thread exit'"); 973 g_free(ev); 974 mtx_lock(&sc->equeue_mtx); 975 mtx_lock(&sc->bqueue_mtx); 976 gv_cleanup(sc); 977 mtx_destroy(&sc->bqueue_mtx); 978 mtx_destroy(&sc->equeue_mtx); 979 g_free(sc->bqueue_down); 980 g_free(sc->bqueue_up); 981 g_free(sc); 982 kproc_exit(0); 983 /* NOTREACHED */ 984 985 default: 986 G_VINUM_DEBUG(1, "unknown event %d", ev->type); 987 } 988 989 g_free(ev); 990 continue; 991 } 992 993 /* ... then do I/O processing. */ 994 mtx_lock(&sc->bqueue_mtx); 995 /* First do new requests. */ 996 bp = bioq_takefirst(sc->bqueue_down); 997 if (bp != NULL) { 998 mtx_unlock(&sc->bqueue_mtx); 999 /* A bio that interfered with another bio. */ 1000 if (bp->bio_pflags & GV_BIO_ONHOLD) { 1001 s = bp->bio_caller1; 1002 p = s->plex_sc; 1003 /* Is it still locked out? */ 1004 if (gv_stripe_active(p, bp)) { 1005 /* Park the bio on the waiting queue. */ 1006 bioq_disksort(p->wqueue, bp); 1007 } else { 1008 bp->bio_pflags &= ~GV_BIO_ONHOLD; 1009 g_io_request(bp, s->drive_sc->consumer); 1010 } 1011 /* A special request requireing special handling. */ 1012 } else if (bp->bio_pflags & GV_BIO_INTERNAL) { 1013 p = bp->bio_caller1; 1014 gv_plex_start(p, bp); 1015 } else { 1016 gv_volume_start(sc, bp); 1017 } 1018 mtx_lock(&sc->bqueue_mtx); 1019 } 1020 /* Then do completed requests. */ 1021 bp = bioq_takefirst(sc->bqueue_up); 1022 if (bp == NULL) { 1023 msleep(sc, &sc->bqueue_mtx, PRIBIO, "-", hz/10); 1024 mtx_unlock(&sc->bqueue_mtx); 1025 continue; 1026 } 1027 mtx_unlock(&sc->bqueue_mtx); 1028 gv_bio_done(sc, bp); 1029 } 1030 } 1031 1032 #define VINUM_CLASS_NAME "VINUM" 1033 1034 static struct g_class g_vinum_class = { 1035 .name = VINUM_CLASS_NAME, 1036 .version = G_VERSION, 1037 .init = gv_init, 1038 .taste = gv_taste, 1039 .ctlreq = gv_config, 1040 .destroy_geom = gv_unload, 1041 }; 1042 1043 DECLARE_GEOM_CLASS(g_vinum_class, g_vinum); 1044 MODULE_VERSION(geom_vinum, 0); 1045