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