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