1 /*- 2 * Copyright (c) 2004 Lukas Ertl 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 AUTHOR 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 AUTHOR 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/bio.h> 32 #include <sys/kernel.h> 33 #include <sys/kthread.h> 34 #include <sys/libkern.h> 35 #include <sys/malloc.h> 36 #include <sys/queue.h> 37 38 #include <geom/geom.h> 39 #include <geom/vinum/geom_vinum_var.h> 40 #include <geom/vinum/geom_vinum.h> 41 #include <geom/vinum/geom_vinum_share.h> 42 43 static int gv_init_plex(struct gv_plex *); 44 void gv_init_td(void *); 45 static int gv_rebuild_plex(struct gv_plex *); 46 void gv_rebuild_td(void *); 47 static int gv_start_plex(struct gv_plex *); 48 static int gv_start_vol(struct gv_volume *); 49 static int gv_sync(struct gv_volume *); 50 void gv_sync_td(void *); 51 52 struct gv_sync_args { 53 struct gv_volume *v; 54 struct gv_plex *from; 55 struct gv_plex *to; 56 off_t syncsize; 57 }; 58 59 void 60 gv_parityop(struct g_geom *gp, struct gctl_req *req) 61 { 62 struct gv_softc *sc; 63 struct gv_plex *p; 64 struct bio *bp; 65 struct g_consumer *cp; 66 int error, *flags, type, *rebuild, rv; 67 char *plex; 68 69 rv = -1; 70 71 plex = gctl_get_param(req, "plex", NULL); 72 if (plex == NULL) { 73 gctl_error(req, "no plex given"); 74 goto out; 75 } 76 77 flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 78 if (flags == NULL) { 79 gctl_error(req, "no flags given"); 80 goto out; 81 } 82 83 rebuild = gctl_get_paraml(req, "rebuild", sizeof(*rebuild)); 84 if (rebuild == NULL) { 85 gctl_error(req, "no rebuild op given"); 86 goto out; 87 } 88 89 sc = gp->softc; 90 type = gv_object_type(sc, plex); 91 switch (type) { 92 case GV_TYPE_PLEX: 93 break; 94 case GV_TYPE_VOL: 95 case GV_TYPE_SD: 96 case GV_TYPE_DRIVE: 97 default: 98 gctl_error(req, "'%s' is not a plex", plex); 99 goto out; 100 } 101 102 p = gv_find_plex(sc, plex); 103 if (p->state != GV_PLEX_UP) { 104 gctl_error(req, "plex %s is not completely accessible", 105 p->name); 106 goto out; 107 } 108 if (p->org != GV_PLEX_RAID5) { 109 gctl_error(req, "plex %s is not a RAID5 plex", p->name); 110 goto out; 111 } 112 113 cp = p->consumer; 114 error = g_access(cp, 1, 1, 0); 115 if (error) { 116 gctl_error(req, "cannot access consumer"); 117 goto out; 118 } 119 g_topology_unlock(); 120 121 /* Reset the check pointer when using -f. */ 122 if (*flags & GV_FLAG_F) 123 p->synced = 0; 124 125 bp = g_new_bio(); 126 if (bp == NULL) { 127 gctl_error(req, "cannot create BIO - out of memory"); 128 g_topology_lock(); 129 error = g_access(cp, -1, -1, 0); 130 goto out; 131 } 132 bp->bio_cmd = BIO_WRITE; 133 bp->bio_done = NULL; 134 bp->bio_data = g_malloc(p->stripesize, M_WAITOK | M_ZERO); 135 bp->bio_cflags |= GV_BIO_CHECK; 136 if (*rebuild) 137 bp->bio_cflags |= GV_BIO_PARITY; 138 bp->bio_offset = p->synced; 139 bp->bio_length = p->stripesize; 140 141 /* Schedule it down ... */ 142 g_io_request(bp, cp); 143 144 /* ... and wait for the result. */ 145 error = biowait(bp, "gwrite"); 146 g_free(bp->bio_data); 147 g_destroy_bio(bp); 148 149 if (error) { 150 /* Incorrect parity. */ 151 if (error == EAGAIN) 152 rv = 1; 153 154 /* Some other error happened. */ 155 else 156 gctl_error(req, "Parity check failed at offset 0x%jx, " 157 "errno %d", (intmax_t)p->synced, error); 158 159 /* Correct parity. */ 160 } else 161 rv = 0; 162 163 gctl_set_param(req, "offset", &p->synced, sizeof(p->synced)); 164 165 /* Advance the checkpointer if there was no error. */ 166 if (rv == 0) 167 p->synced += p->stripesize; 168 169 /* End of plex; reset the check pointer and signal it to the caller. */ 170 if (p->synced >= p->size) { 171 p->synced = 0; 172 rv = -2; 173 } 174 175 g_topology_lock(); 176 error = g_access(cp, -1, -1, 0); 177 178 out: 179 gctl_set_param(req, "rv", &rv, sizeof(rv)); 180 } 181 182 void 183 gv_start_obj(struct g_geom *gp, struct gctl_req *req) 184 { 185 struct gv_softc *sc; 186 struct gv_volume *v; 187 struct gv_plex *p; 188 int *argc, *initsize; 189 char *argv, buf[20]; 190 int err, i, type; 191 192 argc = gctl_get_paraml(req, "argc", sizeof(*argc)); 193 initsize = gctl_get_paraml(req, "initsize", sizeof(*initsize)); 194 195 if (argc == NULL || *argc == 0) { 196 gctl_error(req, "no arguments given"); 197 return; 198 } 199 200 sc = gp->softc; 201 202 for (i = 0; i < *argc; i++) { 203 snprintf(buf, sizeof(buf), "argv%d", i); 204 argv = gctl_get_param(req, buf, NULL); 205 if (argv == NULL) 206 continue; 207 type = gv_object_type(sc, argv); 208 switch (type) { 209 case GV_TYPE_VOL: 210 v = gv_find_vol(sc, argv); 211 err = gv_start_vol(v); 212 if (err) { 213 if (err == EINPROGRESS) { 214 gctl_error(req, "cannot start volume " 215 "'%s': already in progress", argv); 216 } else { 217 gctl_error(req, "cannot start volume " 218 "'%s'; errno: %d", argv, err); 219 } 220 return; 221 } 222 break; 223 224 case GV_TYPE_PLEX: 225 p = gv_find_plex(sc, argv); 226 err = gv_start_plex(p); 227 if (err) { 228 if (err == EINPROGRESS) { 229 gctl_error(req, "cannot start plex " 230 "'%s': already in progress", argv); 231 } else { 232 gctl_error(req, "cannot start plex " 233 "'%s'; errno: %d", argv, err); 234 } 235 return; 236 } 237 break; 238 239 case GV_TYPE_SD: 240 case GV_TYPE_DRIVE: 241 /* XXX not yet */ 242 gctl_error(req, "cannot start '%s' - not yet supported", 243 argv); 244 return; 245 default: 246 gctl_error(req, "unknown object '%s'", argv); 247 return; 248 } 249 } 250 } 251 252 static int 253 gv_start_plex(struct gv_plex *p) 254 { 255 struct gv_volume *v; 256 int error; 257 258 KASSERT(p != NULL, ("gv_start_plex: NULL p")); 259 260 if (p->state == GV_PLEX_UP) 261 return (0); 262 263 error = 0; 264 v = p->vol_sc; 265 if ((v != NULL) && (v->plexcount > 1)) 266 error = gv_sync(v); 267 else if (p->org == GV_PLEX_RAID5) { 268 if (p->state == GV_PLEX_DEGRADED) 269 error = gv_rebuild_plex(p); 270 else 271 error = gv_init_plex(p); 272 } 273 274 return (error); 275 } 276 277 static int 278 gv_start_vol(struct gv_volume *v) 279 { 280 struct gv_plex *p; 281 struct gv_sd *s; 282 int error; 283 284 KASSERT(v != NULL, ("gv_start_vol: NULL v")); 285 286 error = 0; 287 288 if (v->plexcount == 0) 289 return (ENXIO); 290 291 else if (v->plexcount == 1) { 292 p = LIST_FIRST(&v->plexes); 293 KASSERT(p != NULL, ("gv_start_vol: NULL p on %s", v->name)); 294 if (p->org == GV_PLEX_RAID5) { 295 switch (p->state) { 296 case GV_PLEX_DOWN: 297 error = gv_init_plex(p); 298 break; 299 case GV_PLEX_DEGRADED: 300 error = gv_rebuild_plex(p); 301 break; 302 default: 303 return (0); 304 } 305 } else { 306 LIST_FOREACH(s, &p->subdisks, in_plex) { 307 gv_set_sd_state(s, GV_SD_UP, 308 GV_SETSTATE_CONFIG); 309 } 310 } 311 } else 312 error = gv_sync(v); 313 314 return (error); 315 } 316 317 static int 318 gv_sync(struct gv_volume *v) 319 { 320 struct gv_softc *sc; 321 struct gv_plex *p, *up; 322 struct gv_sync_args *sync; 323 324 KASSERT(v != NULL, ("gv_sync: NULL v")); 325 sc = v->vinumconf; 326 KASSERT(sc != NULL, ("gv_sync: NULL sc on %s", v->name)); 327 328 /* Find the plex that's up. */ 329 up = NULL; 330 LIST_FOREACH(up, &v->plexes, in_volume) { 331 if (up->state == GV_PLEX_UP) 332 break; 333 } 334 335 /* Didn't find a good plex. */ 336 if (up == NULL) 337 return (ENXIO); 338 339 LIST_FOREACH(p, &v->plexes, in_volume) { 340 if ((p == up) || (p->state == GV_PLEX_UP)) 341 continue; 342 if (p->flags & GV_PLEX_SYNCING) { 343 return (EINPROGRESS); 344 } 345 p->flags |= GV_PLEX_SYNCING; 346 sync = g_malloc(sizeof(*sync), M_WAITOK | M_ZERO); 347 sync->v = v; 348 sync->from = up; 349 sync->to = p; 350 sync->syncsize = GV_DFLT_SYNCSIZE; 351 kproc_create(gv_sync_td, sync, NULL, 0, 0, "gv_sync '%s'", 352 p->name); 353 } 354 355 return (0); 356 } 357 358 static int 359 gv_rebuild_plex(struct gv_plex *p) 360 { 361 struct gv_sync_args *sync; 362 363 if (gv_is_open(p->geom)) 364 return (EBUSY); 365 366 if (p->flags & GV_PLEX_SYNCING) 367 return (EINPROGRESS); 368 p->flags |= GV_PLEX_SYNCING; 369 370 sync = g_malloc(sizeof(*sync), M_WAITOK | M_ZERO); 371 sync->to = p; 372 sync->syncsize = GV_DFLT_SYNCSIZE; 373 374 kproc_create(gv_rebuild_td, sync, NULL, 0, 0, "gv_rebuild %s", 375 p->name); 376 377 return (0); 378 } 379 380 static int 381 gv_init_plex(struct gv_plex *p) 382 { 383 struct gv_sd *s; 384 385 KASSERT(p != NULL, ("gv_init_plex: NULL p")); 386 387 LIST_FOREACH(s, &p->subdisks, in_plex) { 388 if (s->state == GV_SD_INITIALIZING) 389 return (EINPROGRESS); 390 gv_set_sd_state(s, GV_SD_INITIALIZING, GV_SETSTATE_FORCE); 391 s->init_size = GV_DFLT_SYNCSIZE; 392 kproc_create(gv_init_td, s, NULL, 0, 0, "gv_init %s", 393 s->name); 394 } 395 396 return (0); 397 } 398 399 /* This thread is responsible for rebuilding a degraded RAID5 plex. */ 400 void 401 gv_rebuild_td(void *arg) 402 { 403 struct bio *bp; 404 struct gv_plex *p; 405 struct g_consumer *cp; 406 struct gv_sync_args *sync; 407 u_char *buf; 408 off_t i; 409 int error; 410 411 buf = NULL; 412 bp = NULL; 413 414 sync = arg; 415 p = sync->to; 416 p->synced = 0; 417 cp = p->consumer; 418 419 g_topology_lock(); 420 error = g_access(cp, 1, 1, 0); 421 if (error) { 422 g_topology_unlock(); 423 printf("GEOM_VINUM: rebuild of %s failed to access consumer: " 424 "%d\n", p->name, error); 425 kproc_exit(error); 426 } 427 g_topology_unlock(); 428 429 buf = g_malloc(sync->syncsize, M_WAITOK); 430 431 printf("GEOM_VINUM: rebuild of %s started\n", p->name); 432 i = 0; 433 for (i = 0; i < p->size; i += (p->stripesize * (p->sdcount - 1))) { 434 /* 435 if (i + sync->syncsize > p->size) 436 sync->syncsize = p->size - i; 437 */ 438 bp = g_new_bio(); 439 if (bp == NULL) { 440 printf("GEOM_VINUM: rebuild of %s failed creating bio: " 441 "out of memory\n", p->name); 442 break; 443 } 444 bp->bio_cmd = BIO_WRITE; 445 bp->bio_done = NULL; 446 bp->bio_data = buf; 447 bp->bio_cflags |= GV_BIO_REBUILD; 448 bp->bio_offset = i; 449 bp->bio_length = p->stripesize; 450 451 /* Schedule it down ... */ 452 g_io_request(bp, cp); 453 454 /* ... and wait for the result. */ 455 error = biowait(bp, "gwrite"); 456 if (error) { 457 printf("GEOM_VINUM: rebuild of %s failed at offset %jd " 458 "errno: %d\n", p->name, i, error); 459 break; 460 } 461 g_destroy_bio(bp); 462 bp = NULL; 463 } 464 465 if (bp != NULL) 466 g_destroy_bio(bp); 467 if (buf != NULL) 468 g_free(buf); 469 470 g_topology_lock(); 471 g_access(cp, -1, -1, 0); 472 gv_save_config_all(p->vinumconf); 473 g_topology_unlock(); 474 475 p->flags &= ~GV_PLEX_SYNCING; 476 p->synced = 0; 477 478 /* Successful initialization. */ 479 if (!error) 480 printf("GEOM_VINUM: rebuild of %s finished\n", p->name); 481 482 g_free(sync); 483 kproc_exit(error); 484 } 485 486 void 487 gv_sync_td(void *arg) 488 { 489 struct bio *bp; 490 struct gv_plex *p; 491 struct g_consumer *from, *to; 492 struct gv_sync_args *sync; 493 u_char *buf; 494 off_t i; 495 int error; 496 497 sync = arg; 498 499 from = sync->from->consumer; 500 to = sync->to->consumer; 501 502 p = sync->to; 503 p->synced = 0; 504 505 error = 0; 506 507 g_topology_lock(); 508 error = g_access(from, 1, 0, 0); 509 if (error) { 510 g_topology_unlock(); 511 printf("GEOM_VINUM: sync from '%s' failed to access " 512 "consumer: %d\n", sync->from->name, error); 513 g_free(sync); 514 kproc_exit(error); 515 } 516 error = g_access(to, 0, 1, 0); 517 if (error) { 518 g_access(from, -1, 0, 0); 519 g_topology_unlock(); 520 printf("GEOM_VINUM: sync to '%s' failed to access " 521 "consumer: %d\n", p->name, error); 522 g_free(sync); 523 kproc_exit(error); 524 } 525 g_topology_unlock(); 526 527 printf("GEOM_VINUM: plex sync %s -> %s started\n", sync->from->name, 528 sync->to->name); 529 for (i = 0; i < p->size; i+= sync->syncsize) { 530 /* Read some bits from the good plex. */ 531 buf = g_read_data(from, i, sync->syncsize, &error); 532 if (buf == NULL) { 533 printf("GEOM_VINUM: sync read from '%s' failed at " 534 "offset %jd; errno: %d\n", sync->from->name, i, 535 error); 536 break; 537 } 538 539 /* 540 * Create a bio and schedule it down on the 'bad' plex. We 541 * cannot simply use g_write_data() because we have to let the 542 * lower parts know that we are an initialization process and 543 * not a 'normal' request. 544 */ 545 bp = g_new_bio(); 546 if (bp == NULL) { 547 printf("GEOM_VINUM: sync write to '%s' failed at " 548 "offset %jd; out of memory\n", p->name, i); 549 g_free(buf); 550 break; 551 } 552 bp->bio_cmd = BIO_WRITE; 553 bp->bio_offset = i; 554 bp->bio_length = sync->syncsize; 555 bp->bio_data = buf; 556 bp->bio_done = NULL; 557 558 /* 559 * This hack declare this bio as part of an initialization 560 * process, so that the lower levels allow it to get through. 561 */ 562 bp->bio_cflags |= GV_BIO_SYNCREQ; 563 564 /* Schedule it down ... */ 565 g_io_request(bp, to); 566 567 /* ... and wait for the result. */ 568 error = biowait(bp, "gwrite"); 569 g_destroy_bio(bp); 570 g_free(buf); 571 if (error) { 572 printf("GEOM_VINUM: sync write to '%s' failed at " 573 "offset %jd; errno: %d\n", p->name, i, error); 574 break; 575 } 576 577 /* Note that we have synced a little bit more. */ 578 p->synced += sync->syncsize; 579 } 580 581 g_topology_lock(); 582 g_access(from, -1, 0, 0); 583 g_access(to, 0, -1, 0); 584 gv_save_config_all(p->vinumconf); 585 g_topology_unlock(); 586 587 /* Successful initialization. */ 588 if (!error) 589 printf("GEOM_VINUM: plex sync %s -> %s finished\n", 590 sync->from->name, sync->to->name); 591 592 p->flags &= ~GV_PLEX_SYNCING; 593 p->synced = 0; 594 595 g_free(sync); 596 kproc_exit(error); 597 } 598 599 void 600 gv_init_td(void *arg) 601 { 602 struct gv_sd *s; 603 struct gv_drive *d; 604 struct g_geom *gp; 605 struct g_consumer *cp; 606 int error; 607 off_t i, init_size, start, offset, length; 608 u_char *buf; 609 610 s = arg; 611 KASSERT(s != NULL, ("gv_init_td: NULL s")); 612 d = s->drive_sc; 613 KASSERT(d != NULL, ("gv_init_td: NULL d")); 614 gp = d->geom; 615 KASSERT(gp != NULL, ("gv_init_td: NULL gp")); 616 617 cp = LIST_FIRST(&gp->consumer); 618 KASSERT(cp != NULL, ("gv_init_td: NULL cp")); 619 620 s->init_error = 0; 621 init_size = s->init_size; 622 start = s->drive_offset + s->initialized; 623 offset = s->drive_offset; 624 length = s->size; 625 626 buf = g_malloc(s->init_size, M_WAITOK | M_ZERO); 627 628 g_topology_lock(); 629 error = g_access(cp, 0, 1, 0); 630 if (error) { 631 s->init_error = error; 632 g_topology_unlock(); 633 printf("GEOM_VINUM: subdisk '%s' init: failed to access " 634 "consumer; error: %d\n", s->name, error); 635 kproc_exit(error); 636 } 637 g_topology_unlock(); 638 639 for (i = start; i < offset + length; i += init_size) { 640 error = g_write_data(cp, i, buf, init_size); 641 if (error) { 642 printf("GEOM_VINUM: subdisk '%s' init: write failed" 643 " at offset %jd (drive offset %jd); error %d\n", 644 s->name, (intmax_t)s->initialized, (intmax_t)i, 645 error); 646 break; 647 } 648 s->initialized += init_size; 649 } 650 651 g_free(buf); 652 653 g_topology_lock(); 654 g_access(cp, 0, -1, 0); 655 g_topology_unlock(); 656 if (error) { 657 s->init_error = error; 658 g_topology_lock(); 659 gv_set_sd_state(s, GV_SD_STALE, 660 GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG); 661 g_topology_unlock(); 662 } else { 663 g_topology_lock(); 664 gv_set_sd_state(s, GV_SD_UP, GV_SETSTATE_CONFIG); 665 g_topology_unlock(); 666 s->initialized = 0; 667 printf("GEOM_VINUM: subdisk '%s' init: finished successfully\n", 668 s->name); 669 } 670 kproc_exit(error); 671 } 672