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 <geom/geom.h> 40#include <geom/stripe/g_stripe.h> 41 42 43static MALLOC_DEFINE(M_STRIPE, "stripe data", "GEOM_STRIPE Data"); 44 45SYSCTL_DECL(_kern_geom); 46SYSCTL_NODE(_kern_geom, OID_AUTO, stripe, CTLFLAG_RW, 0, "GEOM_STRIPE stuff"); 47static u_int g_stripe_debug = 0; 48SYSCTL_UINT(_kern_geom_stripe, OID_AUTO, debug, CTLFLAG_RW, &g_stripe_debug, 0, 49 "Debug level"); 50 51static int g_stripe_destroy(struct g_stripe_softc *sc, boolean_t force); 52static int g_stripe_destroy_geom(struct gctl_req *req, struct g_class *mp, 53 struct g_geom *gp); 54 55static g_taste_t g_stripe_taste; 56static g_ctl_req_t g_stripe_config; 57static g_dumpconf_t g_stripe_dumpconf; 58 59struct g_class g_stripe_class = { 60 .name = G_STRIPE_CLASS_NAME, 61 .ctlreq = g_stripe_config, 62 .taste = g_stripe_taste, 63 .destroy_geom = g_stripe_destroy_geom 64}; 65 66 67/* 68 * Greatest Common Divisor. 69 */ 70static u_int 71gcd(u_int a, u_int b) 72{ 73 u_int c; 74 75 while (b != 0) { 76 c = a; 77 a = b; 78 b = (c % b); 79 } 80 return (a); 81} 82 83/* 84 * Least Common Multiple. 85 */ 86static u_int 87lcm(u_int a, u_int b) 88{ 89 90 return ((a * b) / gcd(a, b)); 91} 92 93/* 94 * Return the number of valid disks. 95 */ 96static u_int 97g_stripe_nvalid(struct g_stripe_softc *sc) 98{ 99 u_int i, no; 100 101 no = 0; 102 for (i = 0; i < sc->sc_ndisks; i++) { 103 if (sc->sc_disks[i] != NULL) 104 no++; 105 } 106 107 return (no); 108} 109 110static void 111g_stripe_remove_disk(struct g_consumer *cp) 112{ 113 struct g_stripe_softc *sc; 114 u_int no; 115 116 KASSERT(cp != NULL, ("Non-valid disk in %s.", __func__)); 117 sc = (struct g_stripe_softc *)cp->private; 118 KASSERT(sc != NULL, ("NULL sc in %s.", __func__)); 119 no = cp->index; 120 121 G_STRIPE_DEBUG(0, "Disk %s removed from %s.", cp->provider->name, 122 sc->sc_geom->name); 123 124 sc->sc_disks[no] = NULL; 125 if (sc->sc_provider != NULL) { 126 g_orphan_provider(sc->sc_provider, ENXIO); 127 sc->sc_provider = NULL; 128 G_STRIPE_DEBUG(0, "Device %s removed.", sc->sc_geom->name); 129 } 130 131 if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) 132 g_access(cp, -cp->acr, -cp->acw, -cp->ace); 133 g_detach(cp); 134 g_destroy_consumer(cp); 135} 136 137static void 138g_stripe_orphan(struct g_consumer *cp) 139{ 140 struct g_stripe_softc *sc; 141 struct g_geom *gp; 142 143 g_topology_assert(); 144 gp = cp->geom; 145 sc = gp->softc; 146 if (sc == NULL) 147 return; 148 149 g_stripe_remove_disk(cp); 150 /* If there are no valid disks anymore, remove device. */ 151 if (g_stripe_nvalid(sc) == 0) 152 g_stripe_destroy(sc, 1); 153} 154 155static int 156g_stripe_access(struct g_provider *pp, int dr, int dw, int de) 157{ 158 struct g_consumer *cp1, *cp2; 159 struct g_stripe_softc *sc; 160 struct g_geom *gp; 161 int error; 162 163 gp = pp->geom; 164 sc = gp->softc; 165 166 if (sc == NULL) { 167 /* 168 * It looks like geom is being withered. 169 * In that case we allow only negative requests. 170 */ 171 KASSERT(dr <= 0 && dw <= 0 && de <= 0, 172 ("Positive access request (device=%s).", pp->name)); 173 if ((pp->acr + dr) == 0 && (pp->acw + dw) == 0 && 174 (pp->ace + de) == 0) { 175 G_STRIPE_DEBUG(0, "Device %s definitely destroyed.", 176 gp->name); 177 } 178 return (0); 179 } 180 181 /* On first open, grab an extra "exclusive" bit */ 182 if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0) 183 de++; 184 /* ... and let go of it on last close */ 185 if ((pp->acr + dr) == 0 && (pp->acw + dw) == 0 && (pp->ace + de) == 0) 186 de--; 187 188 error = ENXIO; 189 LIST_FOREACH(cp1, &gp->consumer, consumer) { 190 error = g_access(cp1, dr, dw, de); 191 if (error == 0) 192 continue; 193 /* 194 * If we fail here, backout all previous changes. 195 */ 196 LIST_FOREACH(cp2, &gp->consumer, consumer) { 197 if (cp1 == cp2) 198 return (error); 199 g_access(cp2, -dr, -dw, -de); 200 } 201 /* NOTREACHED */ 202 } 203 204 return (error); 205} 206 207static void 208g_stripe_start(struct bio *bp) 209{ 210 struct g_provider *pp; 211 struct g_stripe_softc *sc; 212 off_t off, start, length, nstripe; 213 struct bio *cbp; 214 u_int sectorsize; 215 uint32_t stripesize; 216 uint16_t no; 217 char *addr; 218 219 pp = bp->bio_to; 220 sc = pp->geom->softc; 221 /* 222 * If sc == NULL, provider's error should be set and g_stripe_start() 223 * should not be called at all. 224 */ 225 KASSERT(sc != NULL, 226 ("Provider's error should be set (error=%d)(device=%s).", 227 bp->bio_to->error, bp->bio_to->name)); 228 229 G_STRIPE_LOGREQ(bp, "Request received."); 230 231 switch (bp->bio_cmd) { 232 case BIO_READ: 233 case BIO_WRITE: 234 case BIO_DELETE: 235 /* 236 * Only those requests are supported. 237 */ 238 break; 239 case BIO_GETATTR: 240 /* To which provider it should be delivered? */ 241 default: 242 g_io_deliver(bp, EOPNOTSUPP); 243 return; 244 } 245 246 addr = bp->bio_data; 247 sectorsize = sc->sc_provider->sectorsize; 248 stripesize = sc->sc_stripesize; 249 250 /* 251 * Calcucations are quite messy, but fast I hope. 252 */ 253 254 /* Stripe number. */ 255 /* nstripe = bp->bio_offset / stripesize; */ 256 nstripe = bp->bio_offset >> (off_t)sc->sc_stripebits; 257 /* Disk number. */ 258 no = nstripe % sc->sc_ndisks; 259 /* Start position in stripe. */ 260 /* start = bp->bio_offset % stripesize; */ 261 start = bp->bio_offset & (stripesize - 1); 262 /* Start position in disk. */ 263 /* off = (nstripe / sc->sc_ndisks) * stripesize + start; */ 264 off = ((nstripe / sc->sc_ndisks) << sc->sc_stripebits) + start; 265 /* Length of data to operate. */ 266 length = MIN(bp->bio_length, stripesize - start); 267 268 cbp = g_clone_bio(bp); 269 if (cbp == NULL) { 270 /* 271 * Deny all request. This is pointless 272 * to split rest of the request, bacause 273 * we're setting bio_error here, so all 274 * request will be denied, anyway. 275 */ 276 bp->bio_completed = bp->bio_length; 277 if (bp->bio_error == 0) 278 bp->bio_error = ENOMEM; 279 g_io_deliver(bp, bp->bio_error); 280 return; 281 } 282 /* 283 * Fill in the component buf structure. 284 */ 285 cbp->bio_done = g_std_done; 286 cbp->bio_offset = off; 287 cbp->bio_data = addr; 288 cbp->bio_length = length; 289 cbp->bio_to = sc->sc_disks[no]->provider; 290 G_STRIPE_LOGREQ(cbp, "Sending request."); 291 g_io_request(cbp, sc->sc_disks[no]); 292 293 /* off -= off % stripesize; */ 294 off -= off & (stripesize - 1); 295 addr += length; 296 length = bp->bio_length - length; 297 for (no++; length > 0; no++, length -= stripesize, addr += stripesize) { 298 if (no > sc->sc_ndisks - 1) { 299 no = 0; 300 off += stripesize; 301 } 302 cbp = g_clone_bio(bp); 303 if (cbp == NULL) { 304 /* 305 * Deny remaining part. This is pointless 306 * to split rest of the request, bacause 307 * we're setting bio_error here, so all 308 * request will be denied, anyway. 309 */ 310 bp->bio_completed += length; 311 if (bp->bio_error == 0) 312 bp->bio_error = ENOMEM; 313 if (bp->bio_completed == bp->bio_length) 314 g_io_deliver(bp, bp->bio_error); 315 return; 316 } 317 318 /* 319 * Fill in the component buf structure. 320 */ 321 cbp->bio_done = g_std_done; 322 cbp->bio_offset = off; 323 cbp->bio_data = addr; 324 /* 325 * MIN() is in case when 326 * (bp->bio_length % sc->sc_stripesize) != 0. 327 */ 328 cbp->bio_length = MIN(stripesize, length); 329 330 cbp->bio_to = sc->sc_disks[no]->provider; 331 G_STRIPE_LOGREQ(cbp, "Sending request."); 332 g_io_request(cbp, sc->sc_disks[no]); 333 } 334} 335 336static void 337g_stripe_check_and_run(struct g_stripe_softc *sc) 338{ 339 off_t mediasize, ms; 340 u_int no, sectorsize = 0; 341 342 if (g_stripe_nvalid(sc) != sc->sc_ndisks) 343 return; 344 345 sc->sc_provider = g_new_providerf(sc->sc_geom, "%s", sc->sc_geom->name); 346 /* 347 * Find the smallest disk. 348 */ 349 mediasize = sc->sc_disks[0]->provider->mediasize; 350 if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC) 351 mediasize -= sc->sc_disks[0]->provider->sectorsize; 352 mediasize -= mediasize % sc->sc_stripesize; 353 sectorsize = sc->sc_disks[0]->provider->sectorsize; 354 for (no = 1; no < sc->sc_ndisks; no++) { 355 ms = sc->sc_disks[no]->provider->mediasize; 356 if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC) 357 ms -= sc->sc_disks[no]->provider->sectorsize; 358 ms -= ms % sc->sc_stripesize; 359 if (ms < mediasize) 360 mediasize = ms; 361 sectorsize = lcm(sectorsize, 362 sc->sc_disks[no]->provider->sectorsize); 363 } 364 sc->sc_provider->sectorsize = sectorsize; 365 sc->sc_provider->mediasize = mediasize * sc->sc_ndisks; 366 g_error_provider(sc->sc_provider, 0); 367 368 G_STRIPE_DEBUG(0, "Device %s activated.", sc->sc_geom->name); 369} 370 371static int 372g_stripe_read_metadata(struct g_consumer *cp, struct g_stripe_metadata *md) 373{ 374 struct g_provider *pp; 375 u_char *buf; 376 int error; 377 378 g_topology_assert(); 379 380 error = g_access(cp, 1, 0, 0); 381 if (error != 0) 382 return (error); 383 pp = cp->provider; 384 g_topology_unlock(); 385 buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, 386 &error); 387 g_topology_lock(); 388 g_access(cp, -1, 0, 0); 389 if (buf == NULL) 390 return (error); 391 392 /* Decode metadata. */ 393 stripe_metadata_decode(buf, md); 394 g_free(buf); 395 396 return (0); 397} 398 399/* 400 * Add disk to given device. 401 */ 402static int 403g_stripe_add_disk(struct g_stripe_softc *sc, struct g_provider *pp, u_int no) 404{ 405 struct g_consumer *cp, *fcp; 406 struct g_geom *gp; 407 int error; 408 409 /* Metadata corrupted? */ 410 if (no >= sc->sc_ndisks) 411 return (EINVAL); 412 413 /* Check if disk is not already attached. */ 414 if (sc->sc_disks[no] != NULL) 415 return (EEXIST); 416 417 gp = sc->sc_geom; 418 fcp = LIST_FIRST(&gp->consumer); 419 420 cp = g_new_consumer(gp); 421 error = g_attach(cp, pp); 422 if (error != 0) { 423 g_destroy_consumer(cp); 424 return (error); 425 } 426 427 if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0)) { 428 error = g_access(cp, fcp->acr, fcp->acw, fcp->ace); 429 if (error != 0) { 430 g_detach(cp); 431 g_destroy_consumer(cp); 432 return (error); 433 } 434 } 435 if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC) { 436 struct g_stripe_metadata md; 437 438 /* Reread metadata. */ 439 error = g_stripe_read_metadata(cp, &md); 440 if (error != 0) 441 goto fail; 442 443 if (strcmp(md.md_magic, G_STRIPE_MAGIC) != 0 || 444 strcmp(md.md_name, sc->sc_name) != 0 || 445 md.md_id != sc->sc_id) { 446 G_STRIPE_DEBUG(0, "Metadata on %s changed.", pp->name); 447 goto fail; 448 } 449 } 450 451 cp->private = sc; 452 cp->index = no; 453 sc->sc_disks[no] = cp; 454 455 G_STRIPE_DEBUG(0, "Disk %s attached to %s.", pp->name, gp->name); 456 457 g_stripe_check_and_run(sc); 458 459 return (0); 460fail: 461 if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0)) 462 g_access(cp, -fcp->acr, -fcp->acw, -fcp->ace); 463 g_detach(cp); 464 g_destroy_consumer(cp); 465 return (error); 466} 467 468static struct g_geom * 469g_stripe_create(struct g_class *mp, const struct g_stripe_metadata *md, 470 u_int type) 471{ 472 struct g_stripe_softc *sc; 473 struct g_geom *gp; 474 u_int no; 475 476 G_STRIPE_DEBUG(1, "Creating device %s.stripe (id=%u).", md->md_name, 477 md->md_id); 478 479 /* Two disks is minimum. */ 480 if (md->md_all <= 1) { 481 G_STRIPE_DEBUG(0, "Too few disks defined for %s.stripe.", 482 md->md_name); 483 return (NULL); 484 } 485#if 0 486 /* Stripe size have to be grater than or equal to sector size. */ 487 if (md->md_stripesize < sectorsize) { 488 G_STRIPE_DEBUG(0, "Invalid stripe size for %s.stripe.", 489 md->md_name); 490 return (NULL); 491 } 492#endif 493 /* Stripe size have to be power of 2. */ 494 if (!powerof2(md->md_stripesize)) { 495 G_STRIPE_DEBUG(0, "Invalid stripe size for %s.stripe.", 496 md->md_name); 497 return (NULL); 498 } 499 500 /* Check for duplicate unit */ 501 LIST_FOREACH(gp, &mp->geom, geom) { 502 sc = gp->softc; 503 if (sc != NULL && strcmp(sc->sc_name, md->md_name) == 0) { 504 G_STRIPE_DEBUG(0, "Device %s already configured.", 505 gp->name); 506 return (NULL); 507 } 508 } 509 gp = g_new_geomf(mp, "%s.stripe", md->md_name); 510 gp->softc = NULL; /* for a moment */ 511 512 sc = malloc(sizeof(*sc), M_STRIPE, M_NOWAIT | M_ZERO); 513 if (sc == NULL) { 514 G_STRIPE_DEBUG(0, "Can't allocate memory for device %s.", 515 gp->name); 516 g_destroy_geom(gp); 517 return (NULL); 518 } 519 520 gp->start = g_stripe_start; 521 gp->spoiled = g_stripe_orphan; 522 gp->orphan = g_stripe_orphan; 523 gp->access = g_stripe_access; 524 gp->dumpconf = g_stripe_dumpconf; 525 526 strlcpy(sc->sc_name, md->md_name, sizeof(sc->sc_name)); 527 sc->sc_id = md->md_id; 528 sc->sc_stripesize = md->md_stripesize; 529 sc->sc_stripebits = BITCOUNT(sc->sc_stripesize - 1); 530 sc->sc_ndisks = md->md_all; 531 sc->sc_disks = malloc(sizeof(struct g_consumer *) * sc->sc_ndisks, 532 M_STRIPE, M_WAITOK | M_ZERO); 533 for (no = 0; no < sc->sc_ndisks; no++) 534 sc->sc_disks[no] = NULL; 535 sc->sc_type = type; 536 537 gp->softc = sc; 538 sc->sc_geom = gp; 539 sc->sc_provider = NULL; 540 541 G_STRIPE_DEBUG(0, "Device %s created (id=%u).", gp->name, sc->sc_id); 542 543 return (gp); 544} 545 546static int 547g_stripe_destroy(struct g_stripe_softc *sc, boolean_t force) 548{ 549 struct g_provider *pp; 550 struct g_geom *gp; 551 u_int no; 552 553 g_topology_assert(); 554 555 if (sc == NULL) 556 return (ENXIO); 557 558 pp = sc->sc_provider; 559 if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 560 if (force) { 561 G_STRIPE_DEBUG(0, "Device %s is still open, so it " 562 "can't be definitely removed.", pp->name); 563 } else { 564 G_STRIPE_DEBUG(1, 565 "Device %s is still open (r%dw%de%d).", pp->name, 566 pp->acr, pp->acw, pp->ace); 567 return (EBUSY); 568 } 569 } 570 571 for (no = 0; no < sc->sc_ndisks; no++) { 572 if (sc->sc_disks[no] != NULL) 573 g_stripe_remove_disk(sc->sc_disks[no]); 574 } 575 576 gp = sc->sc_geom; 577 gp->softc = NULL; 578 KASSERT(sc->sc_provider == NULL, ("Provider still exists? (device=%s)", 579 gp->name)); 580 free(sc->sc_disks, M_STRIPE); 581 free(sc, M_STRIPE); 582 583 pp = LIST_FIRST(&gp->provider); 584 if (pp == NULL || (pp->acr == 0 && pp->acw == 0 && pp->ace == 0)) 585 G_STRIPE_DEBUG(0, "Device %s destroyed.", gp->name); 586 587 g_wither_geom(gp, ENXIO); 588 589 return (0); 590} 591 592static int 593g_stripe_destroy_geom(struct gctl_req *req __unused, 594 struct g_class *mp __unused, struct g_geom *gp) 595{ 596 struct g_stripe_softc *sc; 597 598 sc = gp->softc; 599 return (g_stripe_destroy(sc, 0)); 600} 601 602static struct g_geom * 603g_stripe_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 604{ 605 struct g_stripe_metadata md; 606 struct g_stripe_softc *sc; 607 struct g_consumer *cp; 608 struct g_geom *gp; 609 int error; 610 611 g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); 612 g_topology_assert(); 613 614 G_STRIPE_DEBUG(3, "Tasting %s.", pp->name); 615 616 gp = g_new_geomf(mp, "stripe:taste"); 617 gp->start = g_stripe_start; 618 gp->access = g_stripe_access; 619 gp->orphan = g_stripe_orphan; 620 cp = g_new_consumer(gp); 621 g_attach(cp, pp); 622 623 error = g_stripe_read_metadata(cp, &md); 624 g_wither_geom(gp, ENXIO); 625 if (error != 0) 626 return (NULL); 627 gp = NULL; 628 629 if (strcmp(md.md_magic, G_STRIPE_MAGIC) != 0) 630 return (NULL); 631 if (md.md_version > G_STRIPE_VERSION) { 632 printf("geom_stripe.ko module is too old to handle %s.\n", 633 pp->name); 634 return (NULL); 635 } 636 637 /* 638 * Let's check if device already exists. 639 */ 640 sc = NULL; 641 LIST_FOREACH(gp, &mp->geom, geom) { 642 sc = gp->softc; 643 if (sc == NULL) 644 continue; 645 if (sc->sc_type != G_STRIPE_TYPE_AUTOMATIC) 646 continue; 647 if (strcmp(md.md_name, sc->sc_name) != 0) 648 continue; 649 if (md.md_id != sc->sc_id) 650 continue; 651 break; 652 } 653 if (gp != NULL) { 654 G_STRIPE_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name); 655 error = g_stripe_add_disk(sc, pp, md.md_no); 656 if (error != 0) { 657 G_STRIPE_DEBUG(0, 658 "Cannot add disk %s to %s (error=%d).", pp->name, 659 gp->name, error); 660 return (NULL); 661 } 662 } else { 663 gp = g_stripe_create(mp, &md, G_STRIPE_TYPE_AUTOMATIC); 664 if (gp == NULL) { 665 G_STRIPE_DEBUG(0, "Cannot create device %s.stripe.", 666 md.md_name); 667 return (NULL); 668 } 669 sc = gp->softc; 670 G_STRIPE_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name); 671 error = g_stripe_add_disk(sc, pp, md.md_no); 672 if (error != 0) { 673 G_STRIPE_DEBUG(0, 674 "Cannot add disk %s to %s (error=%d).", pp->name, 675 gp->name, error); 676 g_stripe_destroy(sc, 1); 677 return (NULL); 678 } 679 } 680 681 return (gp); 682} 683 684static void 685g_stripe_ctl_create(struct gctl_req *req, struct g_class *mp) 686{ 687 u_int attached, no; 688 struct g_stripe_metadata md; 689 struct g_provider *pp; 690 struct g_stripe_softc *sc; 691 struct g_geom *gp; 692 struct sbuf *sb; 693 intmax_t *stripesize; 694 const char *name; 695 char param[16]; 696 int *nargs; 697 698 g_topology_assert(); 699 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 700 if (nargs == NULL) { 701 gctl_error(req, "No '%s' argument.", "nargs"); 702 return; 703 } 704 if (*nargs <= 2) { 705 gctl_error(req, "Too few arguments."); 706 return; 707 } 708 709 strlcpy(md.md_magic, G_STRIPE_MAGIC, sizeof(md.md_magic)); 710 md.md_version = G_STRIPE_VERSION; 711 name = gctl_get_asciiparam(req, "arg0"); 712 if (name == NULL) { 713 gctl_error(req, "No 'arg%u' argument.", 0); 714 return; 715 } 716 strlcpy(md.md_name, name, sizeof(md.md_name)); 717 md.md_id = arc4random(); 718 md.md_no = 0; 719 md.md_all = *nargs - 1; 720 stripesize = gctl_get_paraml(req, "stripesize", sizeof(*stripesize)); 721 if (stripesize == NULL) { 722 gctl_error(req, "No '%s' argument.", "stripesize"); 723 return; 724 } 725 md.md_stripesize = *stripesize; 726 727 /* Check all providers are valid */ 728 for (no = 1; no < *nargs; no++) { 729 snprintf(param, sizeof(param), "arg%u", no); 730 name = gctl_get_asciiparam(req, param); 731 if (name == NULL) { 732 gctl_error(req, "No 'arg%u' argument.", no); 733 return; 734 } 735 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 736 name += strlen("/dev/"); 737 pp = g_provider_by_name(name); 738 if (pp == NULL) { 739 G_STRIPE_DEBUG(1, "Disk %s is invalid.", name); 740 gctl_error(req, "Disk %s is invalid.", name); 741 return; 742 } 743 } 744 745 gp = g_stripe_create(mp, &md, G_STRIPE_TYPE_MANUAL); 746 if (gp == NULL) { 747 gctl_error(req, "Can't configure %s.stripe.", md.md_name); 748 return; 749 } 750 751 sc = gp->softc; 752 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); 753 sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name); 754 for (attached = 0, no = 1; no < *nargs; no++) { 755 snprintf(param, sizeof(param), "arg%u", no); 756 name = gctl_get_asciiparam(req, param); 757 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 758 name += strlen("/dev/"); 759 pp = g_provider_by_name(name); 760 KASSERT(pp != NULL, ("Provider %s disappear?!", name)); 761 if (g_stripe_add_disk(sc, pp, no - 1) != 0) { 762 G_STRIPE_DEBUG(1, "Disk %u (%s) not attached to %s.", 763 no, pp->name, gp->name); 764 sbuf_printf(sb, " %s", pp->name); 765 continue; 766 } 767 attached++; 768 } 769 sbuf_finish(sb); 770 if (md.md_all != attached) { 771 g_stripe_destroy(gp->softc, 1); 772 gctl_error(req, "%s", sbuf_data(sb)); 773 } 774 sbuf_delete(sb); 775} 776 777static struct g_stripe_softc * 778g_stripe_find_device(struct g_class *mp, const char *name) 779{ 780 struct g_stripe_softc *sc; 781 struct g_geom *gp; 782 783 LIST_FOREACH(gp, &mp->geom, geom) { 784 sc = gp->softc; 785 if (sc == NULL) 786 continue; 787 if (strcmp(gp->name, name) == 0 || 788 strcmp(sc->sc_name, name) == 0) { 789 return (sc); 790 } 791 } 792 return (NULL); 793} 794 795static void 796g_stripe_ctl_destroy(struct gctl_req *req, struct g_class *mp) 797{ 798 struct g_stripe_softc *sc; 799 int *force, *nargs, error; 800 const char *name; 801 char param[16]; 802 u_int i; 803 804 g_topology_assert(); 805 806 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 807 if (nargs == NULL) { 808 gctl_error(req, "No '%s' argument.", "nargs"); 809 return; 810 } 811 if (*nargs <= 0) { 812 gctl_error(req, "Missing device(s)."); 813 return; 814 } 815 force = gctl_get_paraml(req, "force", sizeof(*force)); 816 if (force == NULL) { 817 gctl_error(req, "No '%s' argument.", "force"); 818 return; 819 } 820 821 for (i = 0; i < (u_int)*nargs; i++) { 822 snprintf(param, sizeof(param), "arg%u", i); 823 name = gctl_get_asciiparam(req, param); 824 if (name == NULL) { 825 gctl_error(req, "No 'arg%u' argument.", i); 826 return; 827 } 828 sc = g_stripe_find_device(mp, name); 829 if (sc == NULL) { 830 gctl_error(req, "No such device: %s.", name); 831 return; 832 } 833 error = g_stripe_destroy(sc, *force); 834 if (error != 0) { 835 gctl_error(req, "Cannot destroy device %s (error=%d).", 836 sc->sc_geom->name, error); 837 return; 838 } 839 } 840} 841 842static void 843g_stripe_config(struct gctl_req *req, struct g_class *mp, const char *verb) 844{ 845 uint32_t *version; 846 847 g_topology_assert(); 848 849 version = gctl_get_paraml(req, "version", sizeof(*version)); 850 if (version == NULL) { 851 gctl_error(req, "No '%s' argument.", "version"); 852 return; 853 } 854 if (*version != G_STRIPE_VERSION) { 855 gctl_error(req, "Userland and kernel parts are out of sync."); 856 return; 857 } 858 859 if (strcmp(verb, "create") == 0) { 860 g_stripe_ctl_create(req, mp); 861 return;
|