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 107832 2002-12-13 21:31:13Z phk $
|
35 * $FreeBSD: head/sys/geom/geom_bsd.c 107953 2002-12-16 22:33:27Z 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 server as the source in future copy&paste operations. 40 */ 41 42#include <sys/param.h> 43#ifndef _KERNEL 44#include <stdio.h> 45#include <string.h> 46#include <stdlib.h> 47#include <signal.h> 48#include <err.h> 49#else 50#include <sys/systm.h> 51#include <sys/kernel.h> 52#include <sys/conf.h> 53#include <sys/bio.h> 54#include <sys/malloc.h> 55#include <sys/lock.h> 56#include <sys/mutex.h> 57#endif 58#include <sys/stdint.h> 59#include <sys/errno.h> 60#include <sys/disklabel.h> 61#include <geom/geom.h> 62#include <geom/geom_slice.h> 63 64#define BSD_CLASS_NAME "BSD" 65 66#define ALPHA_LABEL_OFFSET 64 67 68/* 69 * Our private data about one instance. All the rest is handled by the 70 * slice code and stored in its softc, so this is just the stuff 71 * specific to BSD disklabels. 72 */ 73struct g_bsd_softc { 74 off_t labeloffset; 75 off_t mbroffset; 76 off_t rawoffset; 77 struct disklabel ondisk; 78 struct disklabel inram; 79}; 80 81/* 82 * The next 4 functions isolate us from how the compiler lays out and pads 83 * "struct disklabel". We treat what we read from disk as a bytestream and 84 * explicitly convert it into a struct disklabel. This makes us compiler- 85 * endianness- and wordsize- agnostic. 86 * For now we only have little-endian formats to deal with. 87 */ 88 89static void 90g_bsd_ledec_partition(u_char *ptr, struct partition *d) 91{ 92 d->p_size = g_dec_le4(ptr + 0); 93 d->p_offset = g_dec_le4(ptr + 4); 94 d->p_fsize = g_dec_le4(ptr + 8); 95 d->p_fstype = ptr[12]; 96 d->p_frag = ptr[13]; 97 d->p_cpg = g_dec_le2(ptr + 14); 98} 99 100static void 101g_bsd_ledec_disklabel(u_char *ptr, struct disklabel *d) 102{ 103 int i; 104 105 d->d_magic = g_dec_le4(ptr + 0); 106 d->d_type = g_dec_le2(ptr + 4); 107 d->d_subtype = g_dec_le2(ptr + 6); 108 bcopy(ptr + 8, d->d_typename, 16); 109 bcopy(ptr + 24, d->d_packname, 16); 110 d->d_secsize = g_dec_le4(ptr + 40); 111 d->d_nsectors = g_dec_le4(ptr + 44); 112 d->d_ntracks = g_dec_le4(ptr + 48); 113 d->d_ncylinders = g_dec_le4(ptr + 52); 114 d->d_secpercyl = g_dec_le4(ptr + 56); 115 d->d_secperunit = g_dec_le4(ptr + 60); 116 d->d_sparespertrack = g_dec_le2(ptr + 64); 117 d->d_sparespercyl = g_dec_le2(ptr + 66); 118 d->d_acylinders = g_dec_le4(ptr + 68); 119 d->d_rpm = g_dec_le2(ptr + 72); 120 d->d_interleave = g_dec_le2(ptr + 74); 121 d->d_trackskew = g_dec_le2(ptr + 76); 122 d->d_cylskew = g_dec_le2(ptr + 78); 123 d->d_headswitch = g_dec_le4(ptr + 80); 124 d->d_trkseek = g_dec_le4(ptr + 84); 125 d->d_flags = g_dec_le4(ptr + 88); 126 d->d_drivedata[0] = g_dec_le4(ptr + 92); 127 d->d_drivedata[1] = g_dec_le4(ptr + 96); 128 d->d_drivedata[2] = g_dec_le4(ptr + 100); 129 d->d_drivedata[3] = g_dec_le4(ptr + 104); 130 d->d_drivedata[4] = g_dec_le4(ptr + 108); 131 d->d_spare[0] = g_dec_le4(ptr + 112); 132 d->d_spare[1] = g_dec_le4(ptr + 116); 133 d->d_spare[2] = g_dec_le4(ptr + 120); 134 d->d_spare[3] = g_dec_le4(ptr + 124); 135 d->d_spare[4] = g_dec_le4(ptr + 128); 136 d->d_magic2 = g_dec_le4(ptr + 132); 137 d->d_checksum = g_dec_le2(ptr + 136); 138 d->d_npartitions = g_dec_le2(ptr + 138); 139 d->d_bbsize = g_dec_le4(ptr + 140); 140 d->d_sbsize = g_dec_le4(ptr + 144); 141 for (i = 0; i < MAXPARTITIONS; i++) 142 g_bsd_ledec_partition(ptr + 148 + 16 * i, &d->d_partitions[i]); 143} 144 145static void 146g_bsd_leenc_partition(u_char *ptr, struct partition *d) 147{ 148 g_enc_le4(ptr + 0, d->p_size); 149 g_enc_le4(ptr + 4, d->p_offset); 150 g_enc_le4(ptr + 8, d->p_fsize); 151 ptr[12] = d->p_fstype; 152 ptr[13] = d->p_frag; 153 g_enc_le2(ptr + 14, d->p_cpg); 154} 155 156static void 157g_bsd_leenc_disklabel(u_char *ptr, struct disklabel *d) 158{ 159 int i; 160 161 g_enc_le4(ptr + 0, d->d_magic); 162 g_enc_le2(ptr + 4, d->d_type); 163 g_enc_le2(ptr + 6, d->d_subtype); 164 bcopy(d->d_typename, ptr + 8, 16); 165 bcopy(d->d_packname, ptr + 24, 16); 166 g_enc_le4(ptr + 40, d->d_secsize); 167 g_enc_le4(ptr + 44, d->d_nsectors); 168 g_enc_le4(ptr + 48, d->d_ntracks); 169 g_enc_le4(ptr + 52, d->d_ncylinders); 170 g_enc_le4(ptr + 56, d->d_secpercyl); 171 g_enc_le4(ptr + 60, d->d_secperunit); 172 g_enc_le2(ptr + 64, d->d_sparespertrack); 173 g_enc_le2(ptr + 66, d->d_sparespercyl); 174 g_enc_le4(ptr + 68, d->d_acylinders); 175 g_enc_le2(ptr + 72, d->d_rpm); 176 g_enc_le2(ptr + 74, d->d_interleave); 177 g_enc_le2(ptr + 76, d->d_trackskew); 178 g_enc_le2(ptr + 78, d->d_cylskew); 179 g_enc_le4(ptr + 80, d->d_headswitch); 180 g_enc_le4(ptr + 84, d->d_trkseek); 181 g_enc_le4(ptr + 88, d->d_flags); 182 g_enc_le4(ptr + 92, d->d_drivedata[0]); 183 g_enc_le4(ptr + 96, d->d_drivedata[1]); 184 g_enc_le4(ptr + 100, d->d_drivedata[2]); 185 g_enc_le4(ptr + 104, d->d_drivedata[3]); 186 g_enc_le4(ptr + 108, d->d_drivedata[4]); 187 g_enc_le4(ptr + 112, d->d_spare[0]); 188 g_enc_le4(ptr + 116, d->d_spare[1]); 189 g_enc_le4(ptr + 120, d->d_spare[2]); 190 g_enc_le4(ptr + 124, d->d_spare[3]); 191 g_enc_le4(ptr + 128, d->d_spare[4]); 192 g_enc_le4(ptr + 132, d->d_magic2); 193 g_enc_le2(ptr + 136, d->d_checksum); 194 g_enc_le2(ptr + 138, d->d_npartitions); 195 g_enc_le4(ptr + 140, d->d_bbsize); 196 g_enc_le4(ptr + 144, d->d_sbsize); 197 for (i = 0; i < MAXPARTITIONS; i++) 198 g_bsd_leenc_partition(ptr + 148 + 16 * i, &d->d_partitions[i]); 199} 200 201static int 202g_bsd_ondisk_size(void) 203{ 204 return (148 + 16 * MAXPARTITIONS); 205} 206 207/* 208 * For reasons which were valid and just in their days, FreeBSD/i386 uses 209 * absolute disk-addresses in disklabels. The way it works is that the 210 * p_offset field of all partitions have the first sector number of the 211 * disk slice added to them. This was hidden kernel-magic, userland did 212 * not see these offsets. These two functions subtract and add them 213 * while converting from the "ondisk" to the "inram" labels and vice 214 * versa. 215 */ 216static void 217ondisk2inram(struct g_bsd_softc *sc) 218{ 219 struct partition *ppp; 220 struct disklabel *dl; 221 int i; 222 223 sc->inram = sc->ondisk; 224 dl = &sc->inram; 225 226 /* Basic sanity-check needed to avoid mistakes. */ 227 if (dl->d_magic != DISKMAGIC || dl->d_magic2 != DISKMAGIC) 228 return; 229 if (dl->d_npartitions > MAXPARTITIONS) 230 return; 231 232 sc->rawoffset = dl->d_partitions[RAW_PART].p_offset; 233 for (i = 0; i < dl->d_npartitions; i++) { 234 ppp = &dl->d_partitions[i]; 235 if (ppp->p_size != 0 && ppp->p_offset < sc->rawoffset) 236 sc->rawoffset = 0; 237 } 238 if (sc->rawoffset > 0) { 239 for (i = 0; i < dl->d_npartitions; i++) { 240 ppp = &dl->d_partitions[i]; 241 if (ppp->p_offset != 0) 242 ppp->p_offset -= sc->rawoffset; 243 } 244 } 245 dl->d_checksum = 0; 246 dl->d_checksum = dkcksum(&sc->inram); 247} 248 249static void 250inram2ondisk(struct g_bsd_softc *sc) 251{ 252 struct partition *ppp; 253 int i; 254 255 sc->ondisk = sc->inram; 256 if (sc->mbroffset != 0) 257 sc->rawoffset = sc->mbroffset / sc->inram.d_secsize; 258 if (sc->rawoffset != 0) { 259 for (i = 0; i < sc->inram.d_npartitions; i++) { 260 ppp = &sc->ondisk.d_partitions[i]; 261 if (ppp->p_size > 0) 262 ppp->p_offset += sc->rawoffset; 263 else 264 ppp->p_offset = 0; 265 } 266 } 267 sc->ondisk.d_checksum = 0; 268 sc->ondisk.d_checksum = dkcksum(&sc->ondisk); 269} 270 271/* 272 * Check that this looks like a valid disklabel, but be prepared 273 * to get any kind of junk. The checksum must be checked only 274 * after this function returns success to prevent a bogus d_npartitions 275 * value from tripping us up. 276 */ 277static int 278g_bsd_checklabel(struct disklabel *dl) 279{ 280 struct partition *ppp; 281 int i; 282 283 if (dl->d_magic != DISKMAGIC || dl->d_magic2 != DISKMAGIC) 284 return (EINVAL); 285 /* 286 * If the label specifies more partitions than we can handle 287 * we have to reject it: If people updated the label they would 288 * trash it, and that would break the checksum. 289 */ 290 if (dl->d_npartitions > MAXPARTITIONS) 291 return (EINVAL); 292 293 for (i = 0; i < dl->d_npartitions; i++) { 294 ppp = &dl->d_partitions[i]; 295 /* Cannot extend past unit. */ 296 if (ppp->p_size != 0 && 297 ppp->p_offset + ppp->p_size > dl->d_secperunit) { 298 return (EINVAL); 299 } 300 } 301 return (0); 302} 303 304/* 305 * Modify our slicer to match proposed disklabel, if possible. 306 * First carry out all the simple checks, then lock topology 307 * and check that no open providers are affected negatively 308 * then carry out all the changes. 309 * 310 * NB: Returns with topology held only if successful return. 311 */ 312static int 313g_bsd_modify(struct g_geom *gp, struct disklabel *dl) 314{ 315 int i, error; 316 struct partition *ppp; 317 struct g_slicer *gsp; 318 struct g_consumer *cp;
|
319 u_int secsize;
|
319 u_int secsize, u; |
320 off_t mediasize; 321 322 /* Basic check that this is indeed a disklabel. */ 323 error = g_bsd_checklabel(dl); 324 if (error) 325 return (error); 326 327 /* Make sure the checksum is OK. */ 328 if (dkcksum(dl) != 0) 329 return (EINVAL); 330 331 /* Get dimensions of our device. */ 332 cp = LIST_FIRST(&gp->consumer); 333 secsize = cp->provider->sectorsize; 334 mediasize = cp->provider->mediasize; 335 336#ifdef nolonger 337 /* 338 * The raw-partition must start at zero. We do not check that the 339 * size == mediasize because this is overly restrictive. We have 340 * already tested in g_bsd_checklabel() that it is not longer. 341 * XXX: RAW_PART is archaic anyway, and we should drop it. 342 */ 343 if (dl->d_partitions[RAW_PART].p_offset != 0) 344 return (EINVAL); 345#endif 346 347#ifdef notyet 348 /* 349 * Indications are that the d_secperunit is not correctly 350 * initialized in many cases, and since we don't need it 351 * for anything, we dont strictly need this test. 352 * Preemptive action to avoid confusing people in disklabel(8) 353 * may be in order. 354 */ 355 /* The label cannot claim a larger size than the media. */ 356 if ((off_t)dl->d_secperunit * dl->d_secsize > mediasize) 357 return (EINVAL); 358#endif 359 360 361 /* ... or a smaller sector size. */ 362 if (dl->d_secsize < secsize) 363 return (EINVAL); 364 365 /* ... or a non-multiple sector size. */ 366 if (dl->d_secsize % secsize != 0) 367 return (EINVAL); 368 369 g_topology_lock(); 370 371 /* Don't munge open partitions. */ 372 gsp = gp->softc; 373 for (i = 0; i < dl->d_npartitions; i++) { 374 ppp = &dl->d_partitions[i]; 375 376 error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, 377 (off_t)ppp->p_offset * dl->d_secsize, 378 (off_t)ppp->p_size * dl->d_secsize, 379 dl->d_secsize, 380 "%s%c", gp->name, 'a' + i); 381 if (error) { 382 g_topology_unlock(); 383 return (error); 384 } 385 } 386 387 /* Look good, go for it... */
|
388 for (i = 0; i < gsp->nslice; i++) {
389 ppp = &dl->d_partitions[i];
390 g_slice_config(gp, i, G_SLICE_CONFIG_SET,
|
388 for (u = 0; u < gsp->nslice; u++) { 389 ppp = &dl->d_partitions[u]; 390 g_slice_config(gp, u, G_SLICE_CONFIG_SET, |
391 (off_t)ppp->p_offset * dl->d_secsize, 392 (off_t)ppp->p_size * dl->d_secsize, 393 dl->d_secsize,
|
394 "%s%c", gp->name, 'a' + i);
|
394 "%s%c", gp->name, 'a' + u); |
395 } 396 return (0); 397} 398 399/* 400 * Calculate a disklabel checksum for a little-endian byte-stream. 401 * We need access to the decoded disklabel because the checksum only 402 * covers the partition data for the first d_npartitions. 403 */ 404static int 405g_bsd_lesum(struct disklabel *dl, u_char *p) 406{ 407 u_char *pe; 408 uint16_t sum; 409 410 pe = p + 148 + 16 * dl->d_npartitions; 411 sum = 0; 412 while (p < pe) { 413 sum ^= g_dec_le2(p); 414 p += 2; 415 } 416 return (sum); 417} 418 419/* 420 * This is an internal helper function, called multiple times from the taste 421 * function to try to locate a disklabel on the disk. More civilized formats 422 * will not need this, as there is only one possible place on disk to look 423 * for the magic spot. 424 */ 425 426static int 427g_bsd_try(struct g_geom *gp, struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset) 428{ 429 int error; 430 u_char *buf; 431 struct disklabel *dl; 432 off_t secoff; 433 434 /* 435 * We need to read entire aligned sectors, and we assume that the 436 * disklabel does not span sectors, so one sector is enough. 437 */ 438 error = 0; 439 secoff = offset % secsize; 440 buf = g_read_data(cp, offset - secoff, secsize, &error); 441 if (buf == NULL || error != 0) 442 return (ENOENT); 443 444 /* Decode into our native format. */ 445 dl = &ms->ondisk; 446 g_bsd_ledec_disklabel(buf + secoff, dl); 447 448 ondisk2inram(ms); 449 450 dl = &ms->inram; 451 /* Does it look like a label at all? */ 452 if (g_bsd_checklabel(dl)) 453 error = ENOENT; 454 /* ... and does the raw data have a good checksum? */ 455 if (error == 0 && g_bsd_lesum(dl, buf + secoff) != 0) 456 error = ENOENT; 457 458 /* Remember to free the buffer g_read_data() gave us. */ 459 g_free(buf); 460 461 /* If we had a label, record it properly. */ 462 if (error == 0) { 463 gsp->frontstuff = 16 * secsize; /* XXX */ 464 ms->labeloffset = offset; 465 g_topology_lock(); 466 g_slice_conf_hot(gp, 0, offset, g_bsd_ondisk_size()); 467 g_topology_unlock(); 468 } 469 return (error); 470} 471 472/* 473 * Implement certain ioctls to modify disklabels with. This function 474 * is called by the event handler thread with topology locked as result 475 * of the g_call_me() in g_bsd_start(). It is not necessary to keep 476 * topology locked all the time but make sure to return with topology 477 * locked as well. 478 */ 479 480static void 481g_bsd_ioctl(void *arg) 482{ 483 struct bio *bp; 484 struct g_geom *gp; 485 struct g_slicer *gsp; 486 struct g_bsd_softc *ms; 487 struct disklabel *dl; 488 struct g_ioctl *gio; 489 struct g_consumer *cp; 490 u_char *buf; 491 off_t secoff; 492 u_int secsize; 493 int error, i; 494 uint64_t sum; 495 496 /* We don't need topology for now. */ 497 g_topology_unlock(); 498 499 /* Get hold of the interesting bits from the bio. */ 500 bp = arg; 501 gp = bp->bio_to->geom; 502 gsp = gp->softc; 503 ms = gsp->softc; 504 gio = (struct g_ioctl *)bp->bio_data; 505 506 /* The disklabel to set is the ioctl argument. */ 507 dl = gio->data; 508 509 /* Validate and modify our slice instance to match. */ 510 error = g_bsd_modify(gp, dl); /* Picks up topology lock on success. */ 511 if (error) { 512 g_topology_lock(); 513 g_io_deliver(bp, error); 514 return; 515 } 516 /* Update our copy of the disklabel. */ 517 ms->inram = *dl; 518 inram2ondisk(ms); 519 520 if (gio->cmd == DIOCSDINFO) { 521 g_io_deliver(bp, 0); 522 return; 523 } 524 KASSERT(gio->cmd == DIOCWDINFO, ("Unknown ioctl in g_bsd_ioctl")); 525 cp = LIST_FIRST(&gp->consumer); 526 /* Get sector size, we need it to read data. */ 527 secsize = cp->provider->sectorsize; 528 secoff = ms->labeloffset % secsize; 529 buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error); 530 if (buf == NULL || error != 0) { 531 g_io_deliver(bp, error); 532 return; 533 } 534 dl = &ms->ondisk; 535 g_bsd_leenc_disklabel(buf + secoff, dl); 536 if (ms->labeloffset == ALPHA_LABEL_OFFSET) { 537 sum = 0; 538 for (i = 0; i < 63; i++) 539 sum += g_dec_le8(buf + i * 8); 540 g_enc_le8(buf + 504, sum); 541 } 542 error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize); 543 g_free(buf); 544 g_io_deliver(bp, error); 545} 546 547/* 548 * If the user tries to overwrite our disklabel through an open partition 549 * or via a magicwrite config call, we end up here and try to prevent 550 * footshooting as best we can. 551 */ 552static void 553g_bsd_hotwrite(void *arg) 554{ 555 struct bio *bp; 556 struct g_geom *gp; 557 struct g_slicer *gsp; 558 struct g_slice *gsl; 559 struct g_bsd_softc *ms; 560 struct g_bsd_softc fake; 561 u_char *p; 562 int error; 563 564 bp = arg; 565 gp = bp->bio_to->geom; 566 gsp = gp->softc; 567 ms = gsp->softc; 568 gsl = &gsp->slices[bp->bio_to->index];
|
569 p = bp->bio_data + ms->labeloffset
|
569 p = (u_char*)bp->bio_data + ms->labeloffset |
570 - (bp->bio_offset + gsl->offset); 571 g_bsd_ledec_disklabel(p, &fake.ondisk); 572 573 ondisk2inram(&fake); 574 if (g_bsd_checklabel(&fake.inram)) { 575 g_io_deliver(bp, EPERM); 576 return; 577 } 578 if (g_bsd_lesum(&fake.ondisk, p) != 0) { 579 g_io_deliver(bp, EPERM); 580 return; 581 } 582 g_topology_unlock(); 583 error = g_bsd_modify(gp, &fake.inram); /* May pick up topology. */ 584 if (error) { 585 g_io_deliver(bp, EPERM); 586 g_topology_lock(); 587 return; 588 } 589 /* Update our copy of the disklabel. */ 590 ms->inram = fake.inram; 591 inram2ondisk(ms); 592 g_bsd_leenc_disklabel(p, &ms->ondisk); 593 g_slice_finish_hot(bp); 594} 595 596/*- 597 * This start routine is only called for non-trivial requests, all the 598 * trivial ones are handled autonomously by the slice code. 599 * For requests we handle here, we must call the g_io_deliver() on the 600 * bio, and return non-zero to indicate to the slice code that we did so. 601 * This code executes in the "DOWN" I/O path, this means: 602 * * No sleeping. 603 * * Don't grab the topology lock. 604 * * Don't call biowait, g_getattr(), g_setattr() or g_read_data() 605 */ 606 607static int 608g_bsd_start(struct bio *bp) 609{ 610 struct g_geom *gp; 611 struct g_bsd_softc *ms; 612 struct g_slicer *gsp; 613 struct g_ioctl *gio; 614 int error; 615 616 gp = bp->bio_to->geom; 617 gsp = gp->softc; 618 ms = gsp->softc; 619 switch(bp->bio_cmd) { 620 case BIO_READ: 621 /* We allow reading of our hot spots */ 622 return (0); 623 case BIO_DELETE: 624 /* We do not allow deleting our hot spots */ 625 return (EPERM); 626 case BIO_WRITE: 627 g_call_me(g_bsd_hotwrite, bp); 628 return (EJUSTRETURN); 629 case BIO_GETATTR: 630 case BIO_SETATTR: 631 break; 632 default: 633 KASSERT(0 == 1, ("Unknown bio_cmd in g_bsd_start (%d)", 634 bp->bio_cmd)); 635 } 636 637 /* We only handle ioctl(2) requests of the right format. */ 638 if (strcmp(bp->bio_attribute, "GEOM::ioctl")) 639 return (0); 640 else if (bp->bio_length != sizeof(*gio)) 641 return (0); 642 643 /* Get hold of the ioctl parameters. */ 644 gio = (struct g_ioctl *)bp->bio_data; 645 646 switch (gio->cmd) { 647 case DIOCGDINFO: 648 /* Return a copy of the disklabel to userland. */ 649 bcopy(&ms->inram, gio->data, sizeof(ms->inram)); 650 g_io_deliver(bp, 0); 651 return (1); 652 case DIOCSDINFO: 653 case DIOCWDINFO: 654 /* 655 * These we cannot do without the topology lock and some 656 * some I/O requests. Ask the event-handler to schedule 657 * us in a less restricted environment. 658 */ 659 error = g_call_me(g_bsd_ioctl, bp); 660 if (error) 661 g_io_deliver(bp, error); 662 /* 663 * We must return non-zero to indicate that we will deal 664 * with this bio, even though we have not done so yet. 665 */ 666 return (1); 667 default: 668 return (0); 669 } 670} 671 672/* 673 * Dump configuration information in XML format. 674 * Notice that the function is called once for the geom and once for each 675 * consumer and provider. We let g_slice_dumpconf() do most of the work. 676 */ 677static void
|
678g_bsd_dumpconf(struct sbuf *sb, char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
|
678g_bsd_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp) |
679{ 680 struct g_bsd_softc *ms; 681 struct g_slicer *gsp; 682 683 gsp = gp->softc; 684 ms = gsp->softc; 685 g_slice_dumpconf(sb, indent, gp, cp, pp); 686 if (indent != NULL && pp == NULL && cp == NULL) { 687 sbuf_printf(sb, "%s<labeloffset>%jd</labeloffset>\n", 688 indent, (intmax_t)ms->labeloffset); 689 sbuf_printf(sb, "%s<rawoffset>%jd</rawoffset>\n", 690 indent, (intmax_t)ms->rawoffset); 691 sbuf_printf(sb, "%s<mbroffset>%jd</mbroffset>\n", 692 indent, (intmax_t)ms->mbroffset); 693 } 694} 695 696/* 697 * The taste function is called from the event-handler, with the topology 698 * lock already held and a provider to examine. The flags are unused. 699 * 700 * If flags == G_TF_NORMAL, the idea is to take a bite of the provider and 701 * if we find valid, consistent magic on it, build a geom on it. 702 * any magic bits which indicate that we should automatically put a BSD 703 * geom on it. 704 * 705 * There may be cases where the operator would like to put a BSD-geom on 706 * providers which do not meet all of the requirements. This can be done 707 * by instead passing the G_TF_INSIST flag, which will override these 708 * checks. 709 * 710 * The final flags value is G_TF_TRANSPARENT, which instructs the method 711 * to put a geom on top of the provider and configure it to be as transparent 712 * as possible. This is not really relevant to the BSD method and therefore 713 * not implemented here. 714 */ 715 716static struct g_geom * 717g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags) 718{ 719 struct g_geom *gp; 720 struct g_consumer *cp; 721 int error, i; 722 struct g_bsd_softc *ms; 723 struct disklabel *dl; 724 u_int secsize; 725 struct g_slicer *gsp; 726 727 g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name); 728 g_topology_assert(); 729 730 /* We don't implement transparent inserts. */ 731 if (flags == G_TF_TRANSPARENT) 732 return (NULL); 733 734 /* 735 * The BSD-method will not automatically configure itself recursively 736 * Note that it is legal to examine the class-name of our provider, 737 * nothing else should ever be examined inside the provider. 738 */ 739 if (flags == G_TF_NORMAL && 740 !strcmp(pp->geom->class->name, BSD_CLASS_NAME)) 741 return (NULL); 742 743 /* 744 * BSD labels are a subclass of the general "slicing" topology so 745 * a lot of the work can be done by the common "slice" code. 746 * Create a geom with space for MAXPARTITIONS providers, one consumer 747 * and a softc structure for us. Specify the provider to attach 748 * the consumer to and our "start" routine for special requests. 749 * The provider is opened with mode (1,0,0) so we can do reads 750 * from it. 751 */ 752 gp = g_slice_new(mp, MAXPARTITIONS, pp, &cp, &ms, 753 sizeof(*ms), g_bsd_start); 754 if (gp == NULL) 755 return (NULL); 756 757 /* 758 * Now that we have attached to and opened our provider, we do 759 * not need the topology lock until we change the topology again 760 * next time. 761 */ 762 g_topology_unlock(); 763 764 /* 765 * Fill in the optional details, in our case we have a dumpconf 766 * routine which the "slice" code should call at the right time 767 */ 768 gp->dumpconf = g_bsd_dumpconf; 769 770 /* Get the geom_slicer softc from the geom. */ 771 gsp = gp->softc; 772 773 /* 774 * The do...while loop here allows us to have multiple escapes 775 * using a simple "break". This improves code clarity without 776 * ending up in deep nesting and without using goto or come from. 777 */ 778 do { 779 /* 780 * If the provider is an MBR we will only auto attach 781 * to type 165 slices in the G_TF_NORMAL case. We will 782 * attach to any other type (BSD was handles above) 783 */ 784 error = g_getattr("MBR::type", cp, &i); 785 if (!error) { 786 if (i != 165 && flags == G_TF_NORMAL) 787 break; 788 error = g_getattr("MBR::offset", cp, &ms->mbroffset); 789 if (error) 790 break; 791 } 792 793 /* Same thing if we are inside a PC98 */ 794 error = g_getattr("PC98::type", cp, &i); 795 if (!error) { 796 if (i != 0xc494 && flags == G_TF_NORMAL) 797 break; 798 error = g_getattr("PC98::offset", cp, &ms->mbroffset); 799 if (error) 800 break; 801 } 802 803 /* Get sector size, we need it to read data. */ 804 secsize = cp->provider->sectorsize; 805 if (secsize < 512) 806 break; 807 808 /* First look for a label at the start of the second sector. */ 809 error = g_bsd_try(gp, gsp, cp, secsize, ms, secsize); 810 811 /* Next, look for alpha labels */ 812 if (error) 813 error = g_bsd_try(gp, gsp, cp, secsize, ms, 814 ALPHA_LABEL_OFFSET); 815 816 /* If we didn't find a label, punt. */ 817 if (error) 818 break; 819 820 /* 821 * Process the found disklabel, and modify our "slice" 822 * instance to match it, if possible. 823 */ 824 dl = &ms->inram; 825 error = g_bsd_modify(gp, dl); /* Picks up topology lock. */ 826 if (!error) 827 g_topology_unlock(); 828 break; 829 } while (0); 830 831 /* Success of failure, we can close our provider now. */ 832 g_topology_lock(); 833 error = g_access_rel(cp, -1, 0, 0); 834 835 /* If we have configured any providers, return the new geom. */ 836 if (gsp->nprovider > 0) 837 return (gp); 838 /* 839 * ...else push the "self-destruct" button, by spoiling our own 840 * consumer. This triggers a call to g_std_spoiled which will 841 * dismantle what was setup. 842 */ 843 g_std_spoiled(cp); 844 return (NULL); 845} 846 847/* Finally, register with GEOM infrastructure. */ 848static struct g_class g_bsd_class = { 849 BSD_CLASS_NAME, 850 g_bsd_taste, 851 NULL, 852 G_CLASS_INITIALIZER 853}; 854 855DECLARE_GEOM_CLASS(g_bsd_class, g_bsd);
|