geom_bsd.c revision 115624
1/*- 2 * Copyright (c) 2002 Poul-Henning Kamp 3 * Copyright (c) 2002 Networks Associates Technology, Inc. 4 * All rights reserved. 5 * 6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7 * and NAI Labs, the Security Research Division of Network Associates, Inc. 8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9 * DARPA CHATS research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The names of the authors may not be used to endorse or promote 20 * products derived from this software without specific prior written 21 * permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $FreeBSD: head/sys/geom/geom_bsd.c 115624 2003-06-01 13:47:51Z phk $ 36 * 37 * This is the method for dealing with BSD disklabels. It has been 38 * extensively (by my standards at least) commented, in the vain hope that 39 * it will serve as the source in future copy&paste operations. 40 */ 41 42#include <sys/param.h> 43#include <sys/endian.h> 44#include <sys/systm.h> 45#include <sys/kernel.h> 46#include <sys/conf.h> 47#include <sys/bio.h> 48#include <sys/malloc.h> 49#include <sys/lock.h> 50#include <sys/mutex.h> 51#include <sys/md5.h> 52#include <sys/errno.h> 53#include <sys/disklabel.h> 54#include <geom/geom.h> 55#include <geom/geom_slice.h> 56 57#define BSD_CLASS_NAME "BSD" 58 59#define ALPHA_LABEL_OFFSET 64 60 61#define LABELSIZE (148 + 16 * MAXPARTITIONS) 62 63static void g_bsd_hotwrite(void *arg, int flag); 64/* 65 * Our private data about one instance. All the rest is handled by the 66 * slice code and stored in its softc, so this is just the stuff 67 * specific to BSD disklabels. 68 */ 69struct g_bsd_softc { 70 off_t labeloffset; 71 off_t mbroffset; 72 off_t rawoffset; 73 struct disklabel ondisk; 74 u_char label[LABELSIZE]; 75 u_char labelsum[16]; 76}; 77 78/* 79 * Modify our slicer to match proposed disklabel, if possible. 80 * This is where we make sure we don't do something stupid. 81 */ 82static int 83g_bsd_modify(struct g_geom *gp, u_char *label) 84{ 85 int i, error; 86 struct partition *ppp; 87 struct g_slicer *gsp; 88 struct g_consumer *cp; 89 struct g_bsd_softc *ms; 90 u_int secsize, u; 91 off_t rawoffset, o; 92 struct disklabel dl; 93 MD5_CTX md5sum; 94 95 g_topology_assert(); 96 gsp = gp->softc; 97 ms = gsp->softc; 98 99 error = bsd_disklabel_le_dec(label, &dl, MAXPARTITIONS); 100 if (error) { 101 return (error); 102 } 103 104 /* Get dimensions of our device. */ 105 cp = LIST_FIRST(&gp->consumer); 106 secsize = cp->provider->sectorsize; 107 108 /* ... or a smaller sector size. */ 109 if (dl.d_secsize < secsize) { 110 return (EINVAL); 111 } 112 113 /* ... or a non-multiple sector size. */ 114 if (dl.d_secsize % secsize != 0) { 115 return (EINVAL); 116 } 117 118 /* Historical braindamage... */ 119 rawoffset = (off_t)dl.d_partitions[RAW_PART].p_offset * dl.d_secsize; 120 121 for (i = 0; i < dl.d_npartitions; i++) { 122 ppp = &dl.d_partitions[i]; 123 if (ppp->p_size == 0) 124 continue; 125 o = (off_t)ppp->p_offset * dl.d_secsize; 126 127 if (o < rawoffset) 128 rawoffset = 0; 129 } 130 131 if (rawoffset != 0 && (off_t)rawoffset != ms->mbroffset) 132 printf("WARNING: Expected rawoffset %jd, found %jd\n", 133 (intmax_t)ms->mbroffset/dl.d_secsize, 134 (intmax_t)rawoffset/dl.d_secsize); 135 136 /* Don't munge open partitions. */ 137 for (i = 0; i < dl.d_npartitions; i++) { 138 ppp = &dl.d_partitions[i]; 139 140 o = (off_t)ppp->p_offset * dl.d_secsize; 141 if (o == 0) 142 o = rawoffset; 143 error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, 144 o - rawoffset, 145 (off_t)ppp->p_size * dl.d_secsize, 146 dl.d_secsize, 147 "%s%c", gp->name, 'a' + i); 148 if (error) 149 return (error); 150 } 151 152 /* Look good, go for it... */ 153 for (u = 0; u < gsp->nslice; u++) { 154 ppp = &dl.d_partitions[u]; 155 o = (off_t)ppp->p_offset * dl.d_secsize; 156 if (o == 0) 157 o = rawoffset; 158 g_slice_config(gp, u, G_SLICE_CONFIG_SET, 159 o - rawoffset, 160 (off_t)ppp->p_size * dl.d_secsize, 161 dl.d_secsize, 162 "%s%c", gp->name, 'a' + u); 163 } 164 165 /* Update our softc */ 166 ms->ondisk = dl; 167 if (label != ms->label) 168 bcopy(label, ms->label, LABELSIZE); 169 ms->rawoffset = rawoffset; 170 171 /* 172 * In order to avoid recursively attaching to the same 173 * on-disk label (it's usually visible through the 'c' 174 * partition) we calculate an MD5 and ask if other BSD's 175 * below us love that label. If they do, we don't. 176 */ 177 MD5Init(&md5sum); 178 MD5Update(&md5sum, ms->label, sizeof(ms->label)); 179 MD5Final(ms->labelsum, &md5sum); 180 181 return (0); 182} 183 184/* 185 * This is an internal helper function, called multiple times from the taste 186 * function to try to locate a disklabel on the disk. More civilized formats 187 * will not need this, as there is only one possible place on disk to look 188 * for the magic spot. 189 */ 190 191static int 192g_bsd_try(struct g_geom *gp, struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset) 193{ 194 int error; 195 u_char *buf; 196 struct disklabel *dl; 197 off_t secoff; 198 199 /* 200 * We need to read entire aligned sectors, and we assume that the 201 * disklabel does not span sectors, so one sector is enough. 202 */ 203 error = 0; 204 secoff = offset % secsize; 205 buf = g_read_data(cp, offset - secoff, secsize, &error); 206 if (buf == NULL || error != 0) 207 return (ENOENT); 208 209 /* Decode into our native format. */ 210 dl = &ms->ondisk; 211 error = bsd_disklabel_le_dec(buf + secoff, dl, MAXPARTITIONS); 212 if (!error) 213 bcopy(buf + secoff, ms->label, LABELSIZE); 214 215 /* Remember to free the buffer g_read_data() gave us. */ 216 g_free(buf); 217 218 ms->labeloffset = offset; 219 return (error); 220} 221 222/* 223 * This function writes the current label to disk, possibly updating 224 * the alpha SRM checksum. 225 */ 226 227static int 228g_bsd_writelabel(struct g_geom *gp, u_char *bootcode) 229{ 230 off_t secoff; 231 u_int secsize; 232 struct g_consumer *cp; 233 struct g_slicer *gsp; 234 struct g_bsd_softc *ms; 235 u_char *buf; 236 uint64_t sum; 237 int error, i; 238 239 gsp = gp->softc; 240 ms = gsp->softc; 241 cp = LIST_FIRST(&gp->consumer); 242 /* Get sector size, we need it to read data. */ 243 secsize = cp->provider->sectorsize; 244 secoff = ms->labeloffset % secsize; 245 if (bootcode == NULL) { 246 buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error); 247 if (buf == NULL || error != 0) 248 return (error); 249 bcopy(ms->label, buf + secoff, sizeof(ms->label)); 250 } else { 251 buf = bootcode; 252 bcopy(ms->label, buf + ms->labeloffset, sizeof(ms->label)); 253 } 254 if (ms->labeloffset == ALPHA_LABEL_OFFSET) { 255 sum = 0; 256 for (i = 0; i < 63; i++) 257 sum += le64dec(buf + i * 8); 258 le64enc(buf + 504, sum); 259 } 260 if (bootcode == NULL) { 261 error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize); 262 g_free(buf); 263 } else { 264 error = g_write_data(cp, 0, bootcode, BBSIZE); 265 } 266 return(error); 267} 268 269 270/* 271 * Implement certain ioctls to modify disklabels with. This function 272 * is called by the event handler thread with topology locked as result 273 * of the g_post_event() in g_bsd_start(). It is not necessary to keep 274 * topology locked all the time but make sure to return with topology 275 * locked as well. 276 */ 277 278static void 279g_bsd_ioctl(void *arg, int flag) 280{ 281 struct bio *bp; 282 struct g_geom *gp; 283 struct g_ioctl *gio; 284 u_char *label; 285 int error; 286 287 g_topology_assert(); 288 bp = arg; 289 if (flag == EV_CANCEL) { 290 g_io_deliver(bp, ENXIO); 291 return; 292 } 293 294 gp = bp->bio_to->geom; 295 gio = (struct g_ioctl *)bp->bio_data; 296 297 label = g_malloc(LABELSIZE, M_WAITOK); 298 299 /* The disklabel to set is the ioctl argument. */ 300 bsd_disklabel_le_enc(label, gio->data); 301 302 /* Validate and modify our slice instance to match. */ 303 error = g_bsd_modify(gp, label); /* Picks up topology lock on success. */ 304 g_free(label); 305 if (error || gio->cmd == DIOCSDINFO) { 306 g_io_deliver(bp, error); 307 return; 308 } 309 310 KASSERT(gio->cmd == DIOCWDINFO, ("Unknown ioctl in g_bsd_ioctl")); 311 g_io_deliver(bp, g_bsd_writelabel(gp, NULL)); 312} 313 314/* 315 * Rewrite the bootblock, which is BBSIZE bytes from the start of the disk. 316 * We punch down the disklabel where we expect it to be before writing. 317 */ 318static int 319g_bsd_diocbsdbb(dev_t dev, u_long cmd __unused, caddr_t data, int fflag __unused, struct thread *td __unused) 320{ 321 struct g_geom *gp; 322 struct g_slicer *gsp; 323 struct g_bsd_softc *ms; 324 struct g_consumer *cp; 325 u_char *buf; 326 void *p; 327 int error, i; 328 uint64_t sum; 329 330 /* Get hold of the interesting bits from the bio. */ 331 gp = (void *)dev; 332 gsp = gp->softc; 333 ms = gsp->softc; 334 335 /* The disklabel to set is the ioctl argument. */ 336 buf = g_malloc(BBSIZE, M_WAITOK); 337 p = *(void **)data; 338 error = copyin(p, buf, BBSIZE); 339 if (!error) { 340 DROP_GIANT(); 341 g_topology_lock(); 342 /* Validate and modify our slice instance to match. */ 343 error = g_bsd_modify(gp, buf + ms->labeloffset); 344 if (!error) { 345 cp = LIST_FIRST(&gp->consumer); 346 if (ms->labeloffset == ALPHA_LABEL_OFFSET) { 347 sum = 0; 348 for (i = 0; i < 63; i++) 349 sum += le64dec(buf + i * 8); 350 le64enc(buf + 504, sum); 351 } 352 error = g_write_data(cp, 0, buf, BBSIZE); 353 } 354 g_topology_unlock(); 355 PICKUP_GIANT(); 356 } 357 g_free(buf); 358 return (error); 359} 360 361/* 362 * If the user tries to overwrite our disklabel through an open partition 363 * or via a magicwrite config call, we end up here and try to prevent 364 * footshooting as best we can. 365 */ 366static void 367g_bsd_hotwrite(void *arg, int flag) 368{ 369 struct bio *bp; 370 struct g_geom *gp; 371 struct g_slicer *gsp; 372 struct g_slice *gsl; 373 struct g_bsd_softc *ms; 374 u_char *p; 375 int error; 376 377 g_topology_assert(); 378 /* 379 * We should never get canceled, because that would amount to a removal 380 * of the geom while there was outstanding I/O requests. 381 */ 382 KASSERT(flag != EV_CANCEL, ("g_bsd_hotwrite cancelled")); 383 bp = arg; 384 gp = bp->bio_to->geom; 385 gsp = gp->softc; 386 ms = gsp->softc; 387 gsl = &gsp->slices[bp->bio_to->index]; 388 p = (u_char*)bp->bio_data + ms->labeloffset 389 - (bp->bio_offset + gsl->offset); 390 error = g_bsd_modify(gp, p); 391 if (error) { 392 g_io_deliver(bp, EPERM); 393 return; 394 } 395 g_slice_finish_hot(bp); 396} 397 398/*- 399 * This start routine is only called for non-trivial requests, all the 400 * trivial ones are handled autonomously by the slice code. 401 * For requests we handle here, we must call the g_io_deliver() on the 402 * bio, and return non-zero to indicate to the slice code that we did so. 403 * This code executes in the "DOWN" I/O path, this means: 404 * * No sleeping. 405 * * Don't grab the topology lock. 406 * * Don't call biowait, g_getattr(), g_setattr() or g_read_data() 407 */ 408 409static int 410g_bsd_start(struct bio *bp) 411{ 412 struct g_geom *gp; 413 struct g_bsd_softc *ms; 414 struct g_slicer *gsp; 415 struct g_ioctl *gio; 416 int error; 417 418 gp = bp->bio_to->geom; 419 gsp = gp->softc; 420 ms = gsp->softc; 421 switch(bp->bio_cmd) { 422 case BIO_GETATTR: 423 if (g_handleattr(bp, "BSD::labelsum", ms->labelsum, 424 sizeof(ms->labelsum))) 425 return (1); 426 break; 427 default: 428 KASSERT(0 == 1, ("Unknown bio_cmd in g_bsd_start (%d)", 429 bp->bio_cmd)); 430 } 431 432 /* We only handle ioctl(2) requests of the right format. */ 433 if (strcmp(bp->bio_attribute, "GEOM::ioctl")) 434 return (0); 435 else if (bp->bio_length != sizeof(*gio)) 436 return (0); 437 438 /* Get hold of the ioctl parameters. */ 439 gio = (struct g_ioctl *)bp->bio_data; 440 441 switch (gio->cmd) { 442 case DIOCGDINFO: 443 /* Return a copy of the disklabel to userland. */ 444 bsd_disklabel_le_dec(ms->label, gio->data, MAXPARTITIONS); 445 g_io_deliver(bp, 0); 446 return (1); 447 case DIOCBSDBB: 448 gio->func = g_bsd_diocbsdbb; 449 gio->dev = (void *)gp; 450 g_io_deliver(bp, EDIRIOCTL); 451 return (1); 452 case DIOCSDINFO: 453 case DIOCWDINFO: 454 /* 455 * These we cannot do without the topology lock and some 456 * some I/O requests. Ask the event-handler to schedule 457 * us in a less restricted environment. 458 */ 459 error = g_post_event(g_bsd_ioctl, bp, M_NOWAIT, gp, NULL); 460 if (error) 461 g_io_deliver(bp, error); 462 /* 463 * We must return non-zero to indicate that we will deal 464 * with this bio, even though we have not done so yet. 465 */ 466 return (1); 467 default: 468 return (0); 469 } 470} 471 472/* 473 * Dump configuration information in XML format. 474 * Notice that the function is called once for the geom and once for each 475 * consumer and provider. We let g_slice_dumpconf() do most of the work. 476 */ 477static void 478g_bsd_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp) 479{ 480 struct g_bsd_softc *ms; 481 struct g_slicer *gsp; 482 483 gsp = gp->softc; 484 ms = gsp->softc; 485 g_slice_dumpconf(sb, indent, gp, cp, pp); 486 if (indent != NULL && pp == NULL && cp == NULL) { 487 sbuf_printf(sb, "%s<labeloffset>%jd</labeloffset>\n", 488 indent, (intmax_t)ms->labeloffset); 489 sbuf_printf(sb, "%s<rawoffset>%jd</rawoffset>\n", 490 indent, (intmax_t)ms->rawoffset); 491 sbuf_printf(sb, "%s<mbroffset>%jd</mbroffset>\n", 492 indent, (intmax_t)ms->mbroffset); 493 } else if (pp != NULL) { 494 if (indent == NULL) 495 sbuf_printf(sb, " ty %d", 496 ms->ondisk.d_partitions[pp->index].p_fstype); 497 else 498 sbuf_printf(sb, "%s<type>%d</type>\n", indent, 499 ms->ondisk.d_partitions[pp->index].p_fstype); 500 } 501} 502 503/* 504 * The taste function is called from the event-handler, with the topology 505 * lock already held and a provider to examine. The flags are unused. 506 * 507 * If flags == G_TF_NORMAL, the idea is to take a bite of the provider and 508 * if we find valid, consistent magic on it, build a geom on it. 509 * any magic bits which indicate that we should automatically put a BSD 510 * geom on it. 511 * 512 * There may be cases where the operator would like to put a BSD-geom on 513 * providers which do not meet all of the requirements. This can be done 514 * by instead passing the G_TF_INSIST flag, which will override these 515 * checks. 516 * 517 * The final flags value is G_TF_TRANSPARENT, which instructs the method 518 * to put a geom on top of the provider and configure it to be as transparent 519 * as possible. This is not really relevant to the BSD method and therefore 520 * not implemented here. 521 */ 522 523static struct g_geom * 524g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags) 525{ 526 struct g_geom *gp; 527 struct g_consumer *cp; 528 int error, i; 529 struct g_bsd_softc *ms; 530 u_int secsize; 531 struct g_slicer *gsp; 532 u_char hash[16]; 533 MD5_CTX md5sum; 534 535 g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name); 536 g_topology_assert(); 537 538 /* We don't implement transparent inserts. */ 539 if (flags == G_TF_TRANSPARENT) 540 return (NULL); 541 542 /* 543 * BSD labels are a subclass of the general "slicing" topology so 544 * a lot of the work can be done by the common "slice" code. 545 * Create a geom with space for MAXPARTITIONS providers, one consumer 546 * and a softc structure for us. Specify the provider to attach 547 * the consumer to and our "start" routine for special requests. 548 * The provider is opened with mode (1,0,0) so we can do reads 549 * from it. 550 */ 551 gp = g_slice_new(mp, MAXPARTITIONS, pp, &cp, &ms, 552 sizeof(*ms), g_bsd_start); 553 if (gp == NULL) 554 return (NULL); 555 556 /* 557 * Fill in the optional details, in our case we have a dumpconf 558 * routine which the "slice" code should call at the right time 559 */ 560 gp->dumpconf = g_bsd_dumpconf; 561 562 /* Get the geom_slicer softc from the geom. */ 563 gsp = gp->softc; 564 565 /* 566 * The do...while loop here allows us to have multiple escapes 567 * using a simple "break". This improves code clarity without 568 * ending up in deep nesting and without using goto or come from. 569 */ 570 do { 571 /* 572 * If the provider is an MBR we will only auto attach 573 * to type 165 slices in the G_TF_NORMAL case. We will 574 * attach to any other type. 575 */ 576 error = g_getattr("MBR::type", cp, &i); 577 if (!error) { 578 if (i != 165 && flags == G_TF_NORMAL) 579 break; 580 error = g_getattr("MBR::offset", cp, &ms->mbroffset); 581 if (error) 582 break; 583 } 584 585 /* Same thing if we are inside a PC98 */ 586 error = g_getattr("PC98::type", cp, &i); 587 if (!error) { 588 if (i != 0xc494 && flags == G_TF_NORMAL) 589 break; 590 error = g_getattr("PC98::offset", cp, &ms->mbroffset); 591 if (error) 592 break; 593 } 594 595 /* Get sector size, we need it to read data. */ 596 secsize = cp->provider->sectorsize; 597 if (secsize < 512) 598 break; 599 600 /* First look for a label at the start of the second sector. */ 601 error = g_bsd_try(gp, gsp, cp, secsize, ms, secsize); 602 603 /* Next, look for alpha labels */ 604 if (error) 605 error = g_bsd_try(gp, gsp, cp, secsize, ms, 606 ALPHA_LABEL_OFFSET); 607 608 /* If we didn't find a label, punt. */ 609 if (error) 610 break; 611 612 /* 613 * In order to avoid recursively attaching to the same 614 * on-disk label (it's usually visible through the 'c' 615 * partition) we calculate an MD5 and ask if other BSD's 616 * below us love that label. If they do, we don't. 617 */ 618 MD5Init(&md5sum); 619 MD5Update(&md5sum, ms->label, sizeof(ms->label)); 620 MD5Final(ms->labelsum, &md5sum); 621 622 error = g_getattr("BSD::labelsum", cp, &hash); 623 if (!error && !bcmp(ms->labelsum, hash, sizeof(hash))) 624 break; 625 626 /* 627 * Process the found disklabel, and modify our "slice" 628 * instance to match it, if possible. 629 */ 630 error = g_bsd_modify(gp, ms->label); 631 } while (0); 632 633 /* Success or failure, we can close our provider now. */ 634 error = g_access_rel(cp, -1, 0, 0); 635 636 /* If we have configured any providers, return the new geom. */ 637 if (gsp->nprovider > 0) { 638 g_slice_conf_hot(gp, 0, ms->labeloffset, LABELSIZE, 639 G_SLICE_HOT_ALLOW, G_SLICE_HOT_DENY, G_SLICE_HOT_CALL); 640 gsp->hot = g_bsd_hotwrite; 641 return (gp); 642 } 643 /* 644 * ...else push the "self-destruct" button, by spoiling our own 645 * consumer. This triggers a call to g_slice_spoiled which will 646 * dismantle what was setup. 647 */ 648 g_slice_spoiled(cp); 649 return (NULL); 650} 651 652struct h0h0 { 653 struct g_geom *gp; 654 struct g_bsd_softc *ms; 655 u_char *label; 656 int error; 657}; 658 659static void 660g_bsd_callconfig(void *arg, int flag) 661{ 662 struct h0h0 *hp; 663 664 hp = arg; 665 hp->error = g_bsd_modify(hp->gp, hp->label); 666 if (!hp->error) 667 hp->error = g_bsd_writelabel(hp->gp, NULL); 668} 669 670/* 671 * NB! curthread is user process which GCTL'ed. 672 */ 673static void 674g_bsd_config(struct gctl_req *req, struct g_class *mp, char const *verb) 675{ 676 u_char *label; 677 int error; 678 struct h0h0 h0h0; 679 struct g_geom *gp; 680 struct g_slicer *gsp; 681 struct g_consumer *cp; 682 struct g_bsd_softc *ms; 683 684 g_topology_assert(); 685 gp = gctl_get_geom(req, mp, "geom"); 686 if (gp == NULL) 687 return; 688 cp = LIST_FIRST(&gp->consumer); 689 gsp = gp->softc; 690 ms = gsp->softc; 691 if (!strcmp(verb, "read mbroffset")) { 692 gctl_set_param(req, "mbroffset", 693 &ms->mbroffset, sizeof(ms->mbroffset)); 694 return; 695 } else if (!strcmp(verb, "write label")) { 696 label = gctl_get_paraml(req, "label", LABELSIZE); 697 if (label == NULL) 698 return; 699 h0h0.gp = gp; 700 h0h0.ms = gsp->softc; 701 h0h0.label = label; 702 h0h0.error = -1; 703 /* XXX: Does this reference register with our selfdestruct code ? */ 704 error = g_access_rel(cp, 1, 1, 1); 705 if (error) { 706 gctl_error(req, "could not access consumer"); 707 return; 708 } 709 g_bsd_callconfig(&h0h0, 0); 710 error = h0h0.error; 711 g_access_rel(cp, -1, -1, -1); 712 } else if (!strcmp(verb, "write bootcode")) { 713 label = gctl_get_paraml(req, "bootcode", BBSIZE); 714 if (label == NULL) 715 return; 716 /* XXX: Does this reference register with our selfdestruct code ? */ 717 error = g_access_rel(cp, 1, 1, 1); 718 if (error) { 719 gctl_error(req, "could not access consumer"); 720 return; 721 } 722 error = g_bsd_writelabel(gp, label); 723 g_access_rel(cp, -1, -1, -1); 724 } else { 725 gctl_error(req, "Unknown verb parameter"); 726 } 727 728 return; 729} 730 731/* Finally, register with GEOM infrastructure. */ 732static struct g_class g_bsd_class = { 733 .name = BSD_CLASS_NAME, 734 .taste = g_bsd_taste, 735 .ctlreq = g_bsd_config, 736}; 737 738DECLARE_GEOM_CLASS(g_bsd_class, g_bsd); 739