1 /*- 2 * Copyright (c) 1994 Bruce D. Evans. 3 * All rights reserved. 4 * 5 * Copyright (c) 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * William Jolitz. 10 * 11 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 12 * All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the University of 25 * California, Berkeley and its contributors. 26 * 4. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 43 * from: wd.c,v 1.55 1994/10/22 01:57:12 phk Exp $ 44 * from: @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 45 * from: ufs_disksubr.c,v 1.8 1994/06/07 01:21:39 phk Exp $ 46 * $FreeBSD: src/sys/kern/subr_diskslice.c,v 1.82.2.6 2001/07/24 09:49:41 dd Exp $ 47 * $DragonFly: src/sys/kern/subr_diskslice.c,v 1.37 2007/05/19 09:46:18 dillon Exp $ 48 */ 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/buf.h> 53 #include <sys/conf.h> 54 #include <sys/disklabel.h> 55 #include <sys/diskslice.h> 56 #include <sys/disk.h> 57 #include <sys/diskmbr.h> 58 #include <sys/fcntl.h> 59 #include <sys/malloc.h> 60 #include <sys/stat.h> 61 #include <sys/syslog.h> 62 #include <sys/proc.h> 63 #include <sys/vnode.h> 64 #include <sys/device.h> 65 #include <sys/thread2.h> 66 67 #include <vfs/ufs/dinode.h> /* XXX used only for fs.h */ 68 #include <vfs/ufs/fs.h> /* XXX used only to get BBSIZE/SBSIZE */ 69 70 #define TRACE(str) do { if (ds_debug) kprintf str; } while (0) 71 72 typedef u_char bool_t; 73 74 static volatile bool_t ds_debug; 75 76 static struct disklabel *clone_label (struct disk_info *info, 77 struct diskslice *sp); 78 static void dsiodone (struct bio *bio); 79 static char *fixlabel (const char *sname, struct diskslice *sp, 80 struct disklabel *lp, int writeflag); 81 static int dsreadandsetlabel(cdev_t dev, u_int flags, 82 struct diskslices *ssp, struct diskslice *sp, 83 struct disk_info *info); 84 static void free_ds_label (struct diskslices *ssp, int slice); 85 static void partition_info (const char *sname, int part, struct partition *pp); 86 static void slice_info (const char *sname, struct diskslice *sp); 87 static void set_ds_label (struct diskslices *ssp, int slice, 88 struct disklabel *lp); 89 static void set_ds_wlabel (struct diskslices *ssp, int slice, int wlabel); 90 91 /* 92 * Create a disklabel based on a disk_info structure, initializing 93 * the appropriate fields and creating a raw partition that covers the 94 * whole disk. 95 * 96 * If a diskslice is passed, the label is truncated to the slice 97 */ 98 static struct disklabel * 99 clone_label(struct disk_info *info, struct diskslice *sp) 100 { 101 struct disklabel *lp1; 102 103 lp1 = kmalloc(sizeof *lp1, M_DEVBUF, M_WAITOK | M_ZERO); 104 lp1->d_nsectors = info->d_secpertrack; 105 lp1->d_ntracks = info->d_nheads; 106 lp1->d_secpercyl = info->d_secpercyl; 107 lp1->d_secsize = info->d_media_blksize; 108 109 if (sp) { 110 lp1->d_secperunit = (u_int)sp->ds_size; 111 lp1->d_partitions[RAW_PART].p_size = lp1->d_secperunit; 112 } else { 113 lp1->d_secperunit = (u_int)info->d_media_blocks; 114 lp1->d_partitions[RAW_PART].p_size = lp1->d_secperunit; 115 } 116 117 /* 118 * Used by the CD driver to create a compatibility slice which 119 * allows us to mount root from the CD. 120 */ 121 if (info->d_dsflags & DSO_COMPATPARTA) { 122 lp1->d_partitions[0].p_size = lp1->d_secperunit; 123 lp1->d_partitions[0].p_fstype = FS_OTHER; 124 } 125 126 if (lp1->d_typename[0] == '\0') 127 strncpy(lp1->d_typename, "amnesiac", sizeof(lp1->d_typename)); 128 if (lp1->d_packname[0] == '\0') 129 strncpy(lp1->d_packname, "fictitious", sizeof(lp1->d_packname)); 130 if (lp1->d_nsectors == 0) 131 lp1->d_nsectors = 32; 132 if (lp1->d_ntracks == 0) 133 lp1->d_ntracks = 64; 134 lp1->d_secpercyl = lp1->d_nsectors * lp1->d_ntracks; 135 lp1->d_ncylinders = lp1->d_secperunit / lp1->d_secpercyl; 136 if (lp1->d_rpm == 0) 137 lp1->d_rpm = 3600; 138 if (lp1->d_interleave == 0) 139 lp1->d_interleave = 1; 140 if (lp1->d_npartitions < RAW_PART + 1) 141 lp1->d_npartitions = MAXPARTITIONS; 142 if (lp1->d_bbsize == 0) 143 lp1->d_bbsize = BBSIZE; 144 if (lp1->d_sbsize == 0) 145 lp1->d_sbsize = SBSIZE; 146 lp1->d_partitions[RAW_PART].p_size = lp1->d_secperunit; 147 lp1->d_magic = DISKMAGIC; 148 lp1->d_magic2 = DISKMAGIC; 149 lp1->d_checksum = dkcksum(lp1); 150 return (lp1); 151 } 152 153 /* 154 * Determine the size of the transfer, and make sure it is 155 * within the boundaries of the partition. Adjust transfer 156 * if needed, and signal errors or early completion. 157 * 158 * XXX TODO: 159 * o Split buffers that are too big for the device. 160 * o Check for overflow. 161 * o Finish cleaning this up. 162 * 163 * This function returns 1 on success, 0 if transfer equates 164 * to EOF (end of disk) or -1 on failure. The appropriate 165 * 'errno' value is also set in bp->b_error and bp->b_flags 166 * is marked with B_ERROR. 167 */ 168 struct bio * 169 dscheck(cdev_t dev, struct bio *bio, struct diskslices *ssp) 170 { 171 struct buf *bp = bio->bio_buf; 172 struct bio *nbio; 173 struct disklabel *lp; 174 char *msg; 175 long nsec; 176 u_int64_t secno; 177 u_int64_t endsecno; 178 u_int64_t labelsect; 179 u_int64_t slicerel_secno; 180 struct diskslice *sp; 181 u_int32_t part; 182 u_int32_t slice; 183 int shift; 184 int mask; 185 186 slice = dkslice(dev); 187 part = dkpart(dev); 188 189 if (bio->bio_offset < 0) { 190 kprintf("dscheck(%s): negative bio_offset %lld\n", 191 devtoname(dev), bio->bio_offset); 192 goto bad; 193 } 194 if (slice >= ssp->dss_nslices) { 195 kprintf("dscheck(%s): slice too large %d/%d\n", 196 devtoname(dev), slice, ssp->dss_nslices); 197 goto bad; 198 } 199 sp = &ssp->dss_slices[slice]; 200 201 /* 202 * Calculate secno and nsec 203 */ 204 if (ssp->dss_secmult == 1) { 205 shift = DEV_BSHIFT; 206 goto doshift; 207 } else if (ssp->dss_secshift != -1) { 208 shift = DEV_BSHIFT + ssp->dss_secshift; 209 doshift: 210 mask = (1 << shift) - 1; 211 if ((int)bp->b_bcount & mask) 212 goto bad_bcount; 213 if ((int)bio->bio_offset & mask) 214 goto bad_blkno; 215 secno = bio->bio_offset >> shift; 216 nsec = bp->b_bcount >> shift; 217 } else { 218 if (bp->b_bcount % ssp->dss_secsize) 219 goto bad_bcount; 220 if (bio->bio_offset % ssp->dss_secsize) 221 goto bad_blkno; 222 secno = bio->bio_offset / ssp->dss_secsize; 223 nsec = bp->b_bcount / ssp->dss_secsize; 224 } 225 226 /* 227 * Calculate slice-relative sector number end slice-relative 228 * limit. 229 */ 230 if (slice == WHOLE_DISK_SLICE) { 231 /* 232 * Labels have not been allowed on whole-disks for a while. 233 * This really puts the nail in the coffin... no disk 234 * snooping will occur even if you tried to write a label 235 * without a slice structure. 236 * 237 * Accesses to the WHOLE_DISK_SLICE do not use a disklabel 238 * and partition numbers are special-cased. Currently numbers 239 * less then 128 are not allowed. Partition numbers >= 128 240 * are encoded in the high 8 bits of the 64 bit buffer offset 241 * and are fed directly through to the device with no 242 * further interpretation. In particular, no sector 243 * translation interpretation should occur because the 244 * sector size for the special raw access may not be the 245 * same as the nominal sector size for the device. 246 */ 247 lp = NULL; 248 if (part < 128) { 249 kprintf("dscheck(%s): illegal partition number (%d) " 250 "for WHOLE_DISK_SLICE access\n", 251 devtoname(dev), part); 252 goto bad; 253 } else if (part != WHOLE_SLICE_PART) { 254 nbio = push_bio(bio); 255 nbio->bio_offset = bio->bio_offset | 256 (u_int64_t)part << 56; 257 return(nbio); 258 } 259 260 /* 261 * sp->ds_size is for the whole disk in the WHOLE_DISK_SLICE. 262 */ 263 labelsect = 0; /* ignore any reserved sectors, do not sniff */ 264 endsecno = sp->ds_size; 265 slicerel_secno = secno; 266 } else if (part == WHOLE_SLICE_PART) { 267 /* 268 * We are accessing a slice. Snoop the label and check 269 * reserved blocks only if a label is present, otherwise 270 * do not. A label may be present if (1) there are active 271 * opens on the disk (not necessarily this slice) or 272 * (2) the disklabel program has written an in-core label 273 * and now wants to write it out, or (3) the management layer 274 * is trying to write out an in-core layer. In case (2) and 275 * (3) we MUST snoop the write or the on-disk version of the 276 * disklabel will not be properly translated. 277 * 278 * NOTE! opens on a whole-slice partition will not attempt 279 * to read a disklabel in. 280 */ 281 if ((lp = sp->ds_label) != NULL) { 282 labelsect = sp->ds_skip_bsdlabel; 283 } else { 284 labelsect = 0; 285 } 286 endsecno = sp->ds_size; 287 slicerel_secno = secno; 288 } else if ((lp = sp->ds_label) && part < lp->d_npartitions) { 289 /* 290 * Acesss through disklabel, partition present. 291 */ 292 struct partition *pp; 293 294 labelsect = sp->ds_skip_bsdlabel; 295 pp = &lp->d_partitions[dkpart(dev)]; 296 endsecno = pp->p_size; 297 slicerel_secno = pp->p_offset + secno; 298 } else if (lp) { 299 /* 300 * Partition out of bounds 301 */ 302 kprintf("dscheck(%s): partition out of bounds %d/%d\n", 303 devtoname(dev), 304 part, lp->d_npartitions); 305 goto bad; 306 } else { 307 /* 308 * Attempt to access partition when no disklabel present 309 */ 310 kprintf("dscheck(%s): attempt to access non-existant partition\n", 311 devtoname(dev)); 312 goto bad; 313 } 314 315 /* 316 * labelsect will reflect the extent of any reserved blocks from 317 * the beginning of the slice. We only check the slice reserved 318 * fields (sp->ds_skip_platform and sp->ds_skip_bsdlabel) if 319 * labelsect is non-zero, otherwise we ignore them. When labelsect 320 * is non-zero, sp->ds_skip_platform indicates the sector where the 321 * disklabel begins. 322 * 323 * First determine if an attempt is being made to write to a 324 * reserved area when such writes are not allowed. 325 */ 326 #if 0 327 if (slicerel_secno < 16 && nsec && 328 bp->b_cmd != BUF_CMD_READ) { 329 kprintf("Attempt to write to reserved sector %lld labelsect %lld label %p/%p skip_plat %d skip_bsd %d WLABEL %d\n", 330 slicerel_secno, 331 labelsect, 332 sp->ds_label, lp, 333 sp->ds_skip_platform, 334 sp->ds_skip_bsdlabel, 335 sp->ds_wlabel); 336 } 337 #endif 338 if (slicerel_secno < labelsect && nsec && 339 bp->b_cmd != BUF_CMD_READ && sp->ds_wlabel == 0) { 340 bp->b_error = EROFS; 341 goto error; 342 } 343 344 /* 345 * If we get here, bio_offset must be on a block boundary and 346 * the sector size must be a power of 2. 347 */ 348 if ((bio->bio_offset & (ssp->dss_secsize - 1)) || 349 (ssp->dss_secsize ^ (ssp->dss_secsize - 1)) != 350 ((ssp->dss_secsize << 1) - 1)) { 351 kprintf("%s: invalid BIO offset, not sector aligned or" 352 " invalid sector size (not power of 2) %08llx %d\n", 353 devtoname(dev), bio->bio_offset, ssp->dss_secsize); 354 goto bad; 355 } 356 357 /* 358 * EOF handling 359 */ 360 if (secno + nsec > endsecno) { 361 /* 362 * Return an error if beyond the end of the disk, or 363 * if B_BNOCLIP is set. Tell the system that we do not 364 * need to keep the buffer around. 365 */ 366 if (secno > endsecno || (bp->b_flags & B_BNOCLIP)) 367 goto bad; 368 369 /* 370 * If exactly at end of disk, return an EOF. Throw away 371 * the buffer contents, if any, by setting B_INVAL. 372 */ 373 if (secno == endsecno) { 374 bp->b_resid = bp->b_bcount; 375 bp->b_flags |= B_INVAL; 376 goto done; 377 } 378 379 /* 380 * Else truncate 381 */ 382 nsec = endsecno - secno; 383 bp->b_bcount = nsec * ssp->dss_secsize; 384 } 385 386 nbio = push_bio(bio); 387 nbio->bio_offset = (off_t)(sp->ds_offset + slicerel_secno) * 388 ssp->dss_secsize; 389 390 /* 391 * Snoop writes to the label area when labelsect is non-zero. 392 * The label sector starts at sector sp->ds_skip_platform within 393 * the slice and ends before sector sp->ds_skip_bsdlabel. The 394 * write must contain the label sector for us to be able to snoop it. 395 * 396 * We have to adjust the label's fields to the on-disk format on 397 * a write and then adjust them back on completion of the write, 398 * or on a read. 399 * 400 * SNOOPs are required for disklabel -r and the DIOC* ioctls also 401 * depend on it on the backend for label operations. XXX 402 * 403 * NOTE! ds_skip_platform is usually set to non-zero by the slice 404 * scanning code, indicating that the slice has reserved boot 405 * sector(s). It is also set for compatibility reasons via 406 * the DSO_COMPATMBR flag. But it is not a requirement and it 407 * can be 0, indicating that the disklabel (if present) is stored 408 * at the beginning of the slice. In most cases ds_skip_platform 409 * will be '1'. 410 * 411 * ds_skip_bsdlabel is inclusive of ds_skip_platform. If they are 412 * the same then there is no label present, even if non-zero. 413 */ 414 if (slicerel_secno < labelsect && /* also checks labelsect!=0 */ 415 sp->ds_skip_platform < labelsect && /* degenerate case */ 416 slicerel_secno <= sp->ds_skip_platform && 417 slicerel_secno + nsec > sp->ds_skip_platform) { 418 /* 419 * Set up our own callback on I/O completion to handle 420 * undoing the fixup we did for the write as well as 421 * doing the fixup for a read. 422 */ 423 nbio->bio_done = dsiodone; 424 nbio->bio_caller_info1.ptr = sp; 425 nbio->bio_caller_info2.offset = 426 (sp->ds_skip_platform - slicerel_secno) * ssp->dss_secsize; 427 if (bp->b_cmd != BUF_CMD_READ) { 428 msg = fixlabel( 429 NULL, sp, 430 (struct disklabel *) 431 (bp->b_data + (int)nbio->bio_caller_info2.offset), 432 TRUE); 433 if (msg != NULL) { 434 kprintf("dscheck(%s): %s\n", 435 devtoname(dev), msg); 436 bp->b_error = EROFS; 437 pop_bio(nbio); 438 goto error; 439 } 440 } 441 } 442 return (nbio); 443 444 bad_bcount: 445 kprintf( 446 "dscheck(%s): b_bcount %d is not on a sector boundary (ssize %d)\n", 447 devtoname(dev), bp->b_bcount, ssp->dss_secsize); 448 goto bad; 449 450 bad_blkno: 451 kprintf( 452 "dscheck(%s): bio_offset %lld is not on a sector boundary (ssize %d)\n", 453 devtoname(dev), bio->bio_offset, ssp->dss_secsize); 454 bad: 455 bp->b_error = EINVAL; 456 /* fall through */ 457 error: 458 /* 459 * Terminate the I/O with a ranging error. Since the buffer is 460 * either illegal or beyond the file EOF, mark it B_INVAL as well. 461 */ 462 bp->b_resid = bp->b_bcount; 463 bp->b_flags |= B_ERROR | B_INVAL; 464 done: 465 /* 466 * Caller must biodone() the originally passed bio if NULL is 467 * returned. 468 */ 469 return (NULL); 470 } 471 472 void 473 dsclose(cdev_t dev, int mode, struct diskslices *ssp) 474 { 475 u_int32_t part; 476 u_int32_t slice; 477 struct diskslice *sp; 478 479 slice = dkslice(dev); 480 part = dkpart(dev); 481 if (slice < ssp->dss_nslices) { 482 sp = &ssp->dss_slices[slice]; 483 if (part < sizeof(sp->ds_openmask) * 8) 484 sp->ds_openmask &= ~(1 << part); 485 } 486 } 487 488 void 489 dsgone(struct diskslices **sspp) 490 { 491 int slice; 492 struct diskslice *sp; 493 struct diskslices *ssp; 494 495 for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) { 496 sp = &ssp->dss_slices[slice]; 497 free_ds_label(ssp, slice); 498 } 499 kfree(ssp, M_DEVBUF); 500 *sspp = NULL; 501 } 502 503 /* 504 * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this 505 * is subject to the same restriction as dsopen(). 506 */ 507 int 508 dsioctl(cdev_t dev, u_long cmd, caddr_t data, int flags, 509 struct diskslices **sspp, struct disk_info *info) 510 { 511 int error; 512 struct disklabel *lp; 513 int old_wlabel; 514 u_char openmask; 515 int part; 516 int slice; 517 struct diskslice *sp; 518 struct diskslices *ssp; 519 struct partition *pp; 520 521 slice = dkslice(dev); 522 part = dkpart(dev); 523 ssp = *sspp; 524 if (slice >= ssp->dss_nslices) 525 return (EINVAL); 526 sp = &ssp->dss_slices[slice]; 527 lp = sp->ds_label; 528 switch (cmd) { 529 530 case DIOCGDVIRGIN: 531 /* 532 * You can only retrieve a virgin disklabel on the whole 533 * disk slice or whole-slice partition. 534 */ 535 if (slice != WHOLE_DISK_SLICE && 536 part != WHOLE_SLICE_PART) { 537 return(EINVAL); 538 } 539 540 lp = (struct disklabel *)data; 541 if (ssp->dss_slices[WHOLE_DISK_SLICE].ds_label) { 542 *lp = *ssp->dss_slices[WHOLE_DISK_SLICE].ds_label; 543 } else { 544 bzero(lp, sizeof(struct disklabel)); 545 } 546 547 lp->d_magic = DISKMAGIC; 548 lp->d_magic2 = DISKMAGIC; 549 pp = &lp->d_partitions[RAW_PART]; 550 pp->p_offset = 0; 551 pp->p_size = sp->ds_size; 552 553 lp->d_npartitions = MAXPARTITIONS; 554 if (lp->d_interleave == 0) 555 lp->d_interleave = 1; 556 if (lp->d_rpm == 0) 557 lp->d_rpm = 3600; 558 if (lp->d_nsectors == 0) 559 lp->d_nsectors = 32; 560 if (lp->d_ntracks == 0) 561 lp->d_ntracks = 64; 562 563 lp->d_bbsize = BBSIZE; 564 lp->d_sbsize = SBSIZE; 565 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 566 lp->d_ncylinders = sp->ds_size / lp->d_secpercyl; 567 lp->d_secperunit = sp->ds_size; 568 lp->d_checksum = 0; 569 lp->d_checksum = dkcksum(lp); 570 return (0); 571 572 case DIOCGDINFO: 573 /* 574 * You can only retrieve a disklabel on the whole 575 * slice partition. 576 * 577 * We do not support labels directly on whole-disks 578 * any more (that is, disks without slices), unless the 579 * device driver has asked for a compatible label (e.g. 580 * for a CD) to allow booting off of storage that is 581 * otherwise unlabeled. 582 */ 583 error = 0; 584 if (part != WHOLE_SLICE_PART) 585 return(EINVAL); 586 if (slice == WHOLE_DISK_SLICE && 587 (info->d_dsflags & DSO_COMPATLABEL) == 0) { 588 return (ENODEV); 589 } 590 if (sp->ds_label == NULL) { 591 error = dsreadandsetlabel(dev, info->d_dsflags, 592 ssp, sp, info); 593 } 594 if (error == 0) 595 *(struct disklabel *)data = *sp->ds_label; 596 return (error); 597 598 case DIOCGPART: 599 { 600 struct partinfo *dpart = (void *)data; 601 602 /* 603 * If accessing a whole-slice partition the disk 604 * management layer may not have tried to read the 605 * disklabel. We have to try to read the label 606 * in order to properly initialize the ds_skip_* 607 * fields. 608 * 609 * We ignore any error. 610 */ 611 if (sp->ds_label == NULL && part == WHOLE_SLICE_PART && 612 slice != WHOLE_DISK_SLICE) { 613 dsreadandsetlabel(dev, info->d_dsflags, 614 ssp, sp, info); 615 } 616 617 bzero(dpart, sizeof(*dpart)); 618 dpart->media_offset = (u_int64_t)sp->ds_offset * 619 info->d_media_blksize; 620 dpart->media_size = (u_int64_t)sp->ds_size * 621 info->d_media_blksize; 622 dpart->media_blocks = sp->ds_size; 623 dpart->media_blksize = info->d_media_blksize; 624 dpart->skip_platform = sp->ds_skip_platform; 625 dpart->skip_bsdlabel = sp->ds_skip_bsdlabel; 626 627 if (slice != WHOLE_DISK_SLICE && 628 part != WHOLE_SLICE_PART) { 629 struct partition *p; 630 631 if (lp == NULL || part >= lp->d_npartitions) 632 return(EINVAL); 633 634 p = &lp->d_partitions[part]; 635 dpart->fstype = p->p_fstype; 636 dpart->media_offset += (u_int64_t)p->p_offset * 637 info->d_media_blksize; 638 dpart->media_size = (u_int64_t)p->p_size * 639 info->d_media_blksize; 640 dpart->media_blocks = (u_int64_t)p->p_size; 641 642 /* 643 * partition starting sector (p_offset) 644 * requires slice's reserved areas to be 645 * adjusted. 646 */ 647 if (dpart->skip_platform > p->p_offset) 648 dpart->skip_platform -= p->p_offset; 649 else 650 dpart->skip_platform = 0; 651 if (dpart->skip_bsdlabel > p->p_offset) 652 dpart->skip_bsdlabel -= p->p_offset; 653 else 654 dpart->skip_bsdlabel = 0; 655 } 656 } 657 return (0); 658 659 case DIOCGSLICEINFO: 660 bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] - 661 (char *)ssp); 662 return (0); 663 664 case DIOCSDINFO: 665 /* 666 * You can write a disklabel on the whole disk slice or 667 * whole-slice partition. 668 */ 669 if (slice != WHOLE_DISK_SLICE && 670 part != WHOLE_SLICE_PART) { 671 return(EINVAL); 672 } 673 674 /* 675 * We no longer support writing disklabels directly to media 676 * without there being a slice. Keep this as a separate 677 * conditional. 678 */ 679 if (slice == WHOLE_DISK_SLICE) 680 return (ENODEV); 681 682 if (!(flags & FWRITE)) 683 return (EBADF); 684 lp = kmalloc(sizeof *lp, M_DEVBUF, M_WAITOK); 685 if (sp->ds_label == NULL) 686 bzero(lp, sizeof *lp); 687 else 688 bcopy(sp->ds_label, lp, sizeof *lp); 689 if (sp->ds_label == NULL) { 690 openmask = 0; 691 } else { 692 openmask = sp->ds_openmask; 693 if (slice == COMPATIBILITY_SLICE) { 694 openmask |= ssp->dss_slices[ 695 ssp->dss_first_bsd_slice].ds_openmask; 696 } else if (slice == ssp->dss_first_bsd_slice) { 697 openmask |= ssp->dss_slices[ 698 COMPATIBILITY_SLICE].ds_openmask; 699 } 700 } 701 error = setdisklabel(lp, (struct disklabel *)data, 702 (u_long)openmask); 703 /* XXX why doesn't setdisklabel() check this? */ 704 if (error == 0 && lp->d_partitions[RAW_PART].p_offset != 0) 705 error = EXDEV; 706 if (error == 0) { 707 if (lp->d_secperunit > sp->ds_size) 708 error = ENOSPC; 709 for (part = 0; part < lp->d_npartitions; part++) 710 if (lp->d_partitions[part].p_size > sp->ds_size) 711 error = ENOSPC; 712 } 713 if (error != 0) { 714 kfree(lp, M_DEVBUF); 715 return (error); 716 } 717 free_ds_label(ssp, slice); 718 set_ds_label(ssp, slice, lp); 719 return (0); 720 721 case DIOCSYNCSLICEINFO: 722 /* 723 * This ioctl can only be done on the whole disk 724 */ 725 if (slice != WHOLE_DISK_SLICE || part != WHOLE_SLICE_PART) 726 return (EINVAL); 727 728 if (*(int *)data == 0) { 729 for (slice = 0; slice < ssp->dss_nslices; slice++) { 730 openmask = ssp->dss_slices[slice].ds_openmask; 731 if (openmask && 732 (slice != WHOLE_DISK_SLICE || 733 openmask & ~(1 << RAW_PART))) { 734 return (EBUSY); 735 } 736 } 737 } 738 739 /* 740 * Temporarily forget the current slices struct and read 741 * the current one. 742 * 743 * NOTE: 744 * 745 * XXX should wait for current accesses on this disk to 746 * complete, then lock out future accesses and opens. 747 */ 748 *sspp = NULL; 749 lp = kmalloc(sizeof *lp, M_DEVBUF, M_WAITOK); 750 *lp = *ssp->dss_slices[WHOLE_DISK_SLICE].ds_label; 751 error = dsopen(dev, S_IFCHR, ssp->dss_oflags, sspp, info); 752 if (error != 0) { 753 kfree(lp, M_DEVBUF); 754 *sspp = ssp; 755 return (error); 756 } 757 758 /* 759 * Reopen everything. This is a no-op except in the "force" 760 * case and when the raw bdev and cdev are both open. Abort 761 * if anything fails. 762 */ 763 for (slice = 0; slice < ssp->dss_nslices; slice++) { 764 for (openmask = ssp->dss_slices[slice].ds_openmask, 765 part = 0; openmask; openmask >>= 1, part++) { 766 if (!(openmask & 1)) 767 continue; 768 error = dsopen(dkmodslice(dkmodpart(dev, part), 769 slice), 770 S_IFCHR, ssp->dss_oflags, sspp, 771 info); 772 if (error != 0) { 773 kfree(lp, M_DEVBUF); 774 *sspp = ssp; 775 return (EBUSY); 776 } 777 } 778 } 779 780 kfree(lp, M_DEVBUF); 781 dsgone(&ssp); 782 return (0); 783 784 case DIOCWDINFO: 785 error = dsioctl(dev, DIOCSDINFO, data, flags, &ssp, info); 786 if (error != 0) 787 return (error); 788 /* 789 * XXX this used to hack on dk_openpart to fake opening 790 * partition 0 in case that is used instead of dkpart(dev). 791 */ 792 old_wlabel = sp->ds_wlabel; 793 set_ds_wlabel(ssp, slice, TRUE); 794 error = writedisklabel(dev, sp->ds_label); 795 /* XXX should invalidate in-core label if write failed. */ 796 set_ds_wlabel(ssp, slice, old_wlabel); 797 return (error); 798 799 case DIOCWLABEL: 800 if (slice == WHOLE_DISK_SLICE) 801 return (ENODEV); 802 if (!(flags & FWRITE)) 803 return (EBADF); 804 set_ds_wlabel(ssp, slice, *(int *)data != 0); 805 return (0); 806 807 default: 808 return (ENOIOCTL); 809 } 810 } 811 812 /* 813 * Chain the bio_done. b_cmd remains valid through such chaining. 814 */ 815 static void 816 dsiodone(struct bio *bio) 817 { 818 struct buf *bp = bio->bio_buf; 819 char *msg; 820 821 if (bp->b_cmd != BUF_CMD_READ 822 || (!(bp->b_flags & B_ERROR) && bp->b_error == 0)) { 823 msg = fixlabel(NULL, bio->bio_caller_info1.ptr, 824 (struct disklabel *) 825 (bp->b_data + (int)bio->bio_caller_info2.offset), 826 FALSE); 827 if (msg != NULL) 828 kprintf("%s\n", msg); 829 } 830 biodone(bio->bio_prev); 831 } 832 833 int 834 dsisopen(struct diskslices *ssp) 835 { 836 int slice; 837 838 if (ssp == NULL) 839 return (0); 840 for (slice = 0; slice < ssp->dss_nslices; slice++) { 841 if (ssp->dss_slices[slice].ds_openmask) 842 return (1); 843 } 844 return (0); 845 } 846 847 /* 848 * Allocate a slices "struct" and initialize it to contain only an empty 849 * compatibility slice (pointing to itself), a whole disk slice (covering 850 * the disk as described by the label), and (nslices - BASE_SLICES) empty 851 * slices beginning at BASE_SLICE. 852 */ 853 struct diskslices * 854 dsmakeslicestruct(int nslices, struct disk_info *info) 855 { 856 struct diskslice *sp; 857 struct diskslices *ssp; 858 859 ssp = kmalloc(offsetof(struct diskslices, dss_slices) + 860 nslices * sizeof *sp, M_DEVBUF, M_WAITOK); 861 ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE; 862 ssp->dss_nslices = nslices; 863 ssp->dss_oflags = 0; 864 865 /* 866 * Figure out if we can use shifts or whether we have to 867 * use mod/multply to translate byte offsets into sector numbers. 868 */ 869 if ((info->d_media_blksize ^ (info->d_media_blksize - 1)) == 870 (info->d_media_blksize << 1) - 1) { 871 ssp->dss_secmult = info->d_media_blksize / DEV_BSIZE; 872 if (ssp->dss_secmult & (ssp->dss_secmult - 1)) 873 ssp->dss_secshift = -1; 874 else 875 ssp->dss_secshift = ffs(ssp->dss_secmult) - 1; 876 } else { 877 ssp->dss_secmult = 0; 878 ssp->dss_secshift = -1; 879 } 880 ssp->dss_secsize = info->d_media_blksize; 881 sp = &ssp->dss_slices[0]; 882 bzero(sp, nslices * sizeof *sp); 883 sp[WHOLE_DISK_SLICE].ds_size = info->d_media_blocks; 884 return (ssp); 885 } 886 887 char * 888 dsname(cdev_t dev, int unit, int slice, int part, char *partname) 889 { 890 static char name[32]; 891 const char *dname; 892 int used; 893 894 dname = dev_dname(dev); 895 if (strlen(dname) > 16) 896 dname = "nametoolong"; 897 ksnprintf(name, sizeof(name), "%s%d", dname, unit); 898 partname[0] = '\0'; 899 used = strlen(name); 900 901 if (slice != WHOLE_DISK_SLICE) { 902 if (slice != COMPATIBILITY_SLICE) { 903 used += ksnprintf(name + used, sizeof(name) - used, 904 "s%d", slice - BASE_SLICE + 1); 905 } 906 if (part != WHOLE_SLICE_PART) { 907 used += ksnprintf(name + used, sizeof(name) - used, 908 "%c", 'a' + part); 909 partname[0] = 'a' + part; 910 partname[1] = 0; 911 } 912 } else if (part > 128) { 913 /* 914 * Special access via the whole-disk-device (used to access 915 * CD audio tracks). 916 */ 917 used += ksnprintf(name + used, sizeof(name) - used, 918 "t%d", part - 128); 919 } 920 return (name); 921 } 922 923 /* 924 * This should only be called when the unit is inactive and the strategy 925 * routine should not allow it to become active unless we call it. Our 926 * strategy routine must be special to allow activity. 927 */ 928 int 929 dsopen(cdev_t dev, int mode, u_int flags, 930 struct diskslices **sspp, struct disk_info *info) 931 { 932 cdev_t dev1; 933 int error; 934 bool_t need_init; 935 struct diskslice *sp; 936 struct diskslices *ssp; 937 int slice; 938 int part; 939 940 dev->si_bsize_phys = info->d_media_blksize; 941 942 /* 943 * Do not attempt to read the slice table or disk label when 944 * accessing the whole-disk slice or a while-slice partition. 945 */ 946 if (dkslice(dev) == WHOLE_DISK_SLICE) 947 flags |= DSO_ONESLICE | DSO_NOLABELS; 948 if (dkpart(dev) == WHOLE_SLICE_PART) 949 flags |= DSO_NOLABELS; 950 951 /* 952 * Reinitialize the slice table unless there is an open device 953 * on the unit. 954 * 955 * It would be nice if we didn't have to do this but when a 956 * user is slicing and partitioning up a disk it is a lot safer 957 * to not take any chances. 958 */ 959 ssp = *sspp; 960 need_init = !dsisopen(ssp); 961 if (ssp != NULL && need_init) 962 dsgone(sspp); 963 if (need_init) { 964 /* 965 * Allocate a minimal slices "struct". This will become 966 * the final slices "struct" if we don't want real slices 967 * or if we can't find any real slices. 968 * 969 * Then scan the disk 970 */ 971 *sspp = dsmakeslicestruct(BASE_SLICE, info); 972 973 if ((flags & DSO_ONESLICE) == 0) { 974 TRACE(("mbrinit\n")); 975 error = mbrinit(dev, info, sspp); 976 if (error != 0) { 977 dsgone(sspp); 978 return (error); 979 } 980 } 981 ssp = *sspp; 982 ssp->dss_oflags = flags; 983 984 /* 985 * If there are no real slices, then make the compatiblity 986 * slice cover the whole disk. 987 * 988 * no sectors are reserved for the platform (ds_skip_platform 989 * will be 0) in this case. This means that if a disklabel 990 * is installed it will be directly installed in sector 0 991 * unless DSO_COMPATMBR is requested. 992 */ 993 if (ssp->dss_nslices == BASE_SLICE) { 994 sp = &ssp->dss_slices[COMPATIBILITY_SLICE]; 995 996 sp->ds_size = info->d_media_blocks; 997 if (info->d_dsflags & DSO_COMPATMBR) { 998 sp->ds_skip_platform = 1; 999 sp->ds_skip_bsdlabel = sp->ds_skip_platform; 1000 } 1001 } 1002 1003 /* 1004 * Point the compatibility slice at the BSD slice, if any. 1005 */ 1006 for (slice = BASE_SLICE; slice < ssp->dss_nslices; slice++) { 1007 sp = &ssp->dss_slices[slice]; 1008 if (sp->ds_type == DOSPTYP_386BSD /* XXX */) { 1009 struct diskslice *csp; 1010 1011 csp = &ssp->dss_slices[COMPATIBILITY_SLICE]; 1012 ssp->dss_first_bsd_slice = slice; 1013 csp->ds_offset = sp->ds_offset; 1014 csp->ds_size = sp->ds_size; 1015 csp->ds_type = sp->ds_type; 1016 csp->ds_skip_platform = sp->ds_skip_platform; 1017 csp->ds_skip_bsdlabel = sp->ds_skip_bsdlabel; 1018 break; 1019 } 1020 } 1021 1022 /* 1023 * By definition accesses via the whole-disk device do not 1024 * specify any reserved areas. The whole disk may be read 1025 * or written by the whole-disk device. 1026 * 1027 * ds_label for a whole-disk device is only used as a 1028 * template. 1029 */ 1030 sp = &ssp->dss_slices[WHOLE_DISK_SLICE]; 1031 sp->ds_label = clone_label(info, NULL); 1032 sp->ds_wlabel = TRUE; 1033 sp->ds_skip_platform = 0; 1034 sp->ds_skip_bsdlabel = 0; 1035 } 1036 1037 /* 1038 * Load the disklabel for the slice being accessed unless it is 1039 * a whole-disk-slice or a whole-slice-partition (as determined 1040 * by DSO_NOLABELS). 1041 * 1042 * We could scan all slices here and try to load up their 1043 * disklabels, but that would cause us to access slices that 1044 * the user may otherwise not intend us to access, or corrupted 1045 * slices, etc. 1046 * 1047 * XXX if there are no opens on the slice we may want to re-read 1048 * the disklabel anyway, even if we have one cached. 1049 */ 1050 slice = dkslice(dev); 1051 if (slice >= ssp->dss_nslices) 1052 return (ENXIO); 1053 sp = &ssp->dss_slices[slice]; 1054 part = dkpart(dev); 1055 1056 if ((flags & DSO_NOLABELS) == 0 && sp->ds_label == NULL) { 1057 dev1 = dkmodslice(dkmodpart(dev, WHOLE_SLICE_PART), slice); 1058 1059 /* 1060 * If opening a raw disk we do not try to 1061 * read the disklabel now. No interpretation of raw disks 1062 * (e.g. like 'da0') ever occurs. We will try to read the 1063 * disklabel for a raw slice if asked to via DIOC* ioctls. 1064 * 1065 * Access to the label area is disallowed by default. Note 1066 * however that accesses via WHOLE_DISK_SLICE, and accesses 1067 * via WHOLE_SLICE_PART for slices without valid disklabels, 1068 * will allow writes and ignore the flag. 1069 */ 1070 set_ds_wlabel(ssp, slice, FALSE); 1071 dsreadandsetlabel(dev1, flags, ssp, sp, info); 1072 } 1073 1074 /* 1075 * If opening a particular partition the disklabel must exist and 1076 * the partition must be present in the label. 1077 * 1078 * If the partition is the special whole-disk-slice no partition 1079 * table need exist. 1080 */ 1081 if (part != WHOLE_SLICE_PART && slice != WHOLE_DISK_SLICE) { 1082 if (sp->ds_label == NULL || part >= sp->ds_label->d_npartitions) 1083 return (EINVAL); 1084 if (part < sizeof(sp->ds_openmask) * 8) { 1085 sp->ds_openmask |= 1 << part; 1086 } 1087 } 1088 1089 /* 1090 * Do not allow special raw-extension partitions to be opened 1091 * if the device doesn't support them. Raw-extension partitions 1092 * are typically used to handle CD tracks. 1093 */ 1094 if (slice == WHOLE_DISK_SLICE && part >= 128 && 1095 part != WHOLE_SLICE_PART) { 1096 if ((info->d_dsflags & DSO_RAWEXTENSIONS) == 0) 1097 return (EINVAL); 1098 } 1099 return (0); 1100 } 1101 1102 /* 1103 * Attempt to read the disklabel. If successful, store it in sp->ds_label. 1104 * 1105 * If we cannot read the disklabel and DSO_COMPATLABEL is set, we construct 1106 * a fake label covering the whole disk. 1107 */ 1108 static 1109 int 1110 dsreadandsetlabel(cdev_t dev, u_int flags, 1111 struct diskslices *ssp, struct diskslice *sp, 1112 struct disk_info *info) 1113 { 1114 struct disklabel *lp1; 1115 const char *msg; 1116 const char *sname; 1117 char partname[2]; 1118 int slice = dkslice(dev); 1119 1120 sname = dsname(dev, dkunit(dev), slice, WHOLE_SLICE_PART, partname); 1121 lp1 = clone_label(info, sp); 1122 msg = readdisklabel(dev, lp1); 1123 1124 if (msg != NULL && (flags & DSO_COMPATLABEL)) { 1125 msg = NULL; 1126 kfree(lp1, M_DEVBUF); 1127 lp1 = clone_label(info, sp); 1128 } 1129 if (msg == NULL) 1130 msg = fixlabel(sname, sp, lp1, FALSE); 1131 if (msg == NULL && lp1->d_secsize != info->d_media_blksize) 1132 msg = "inconsistent sector size"; 1133 if (msg != NULL) { 1134 if (sp->ds_type == DOSPTYP_386BSD /* XXX */) 1135 log(LOG_WARNING, "%s: cannot find label (%s)\n", 1136 sname, msg); 1137 kfree(lp1, M_DEVBUF); 1138 } else { 1139 set_ds_label(ssp, slice, lp1); 1140 set_ds_wlabel(ssp, slice, FALSE); 1141 } 1142 return (msg ? EINVAL : 0); 1143 } 1144 1145 int64_t 1146 dssize(cdev_t dev, struct diskslices **sspp) 1147 { 1148 struct disklabel *lp; 1149 int part; 1150 int slice; 1151 struct diskslices *ssp; 1152 1153 slice = dkslice(dev); 1154 part = dkpart(dev); 1155 ssp = *sspp; 1156 if (ssp == NULL || slice >= ssp->dss_nslices 1157 || !(ssp->dss_slices[slice].ds_openmask & (1 << part))) { 1158 if (dev_dopen(dev, FREAD, S_IFCHR, proc0.p_ucred) != 0) 1159 return (-1); 1160 dev_dclose(dev, FREAD, S_IFCHR); 1161 ssp = *sspp; 1162 } 1163 lp = ssp->dss_slices[slice].ds_label; 1164 if (lp == NULL) 1165 return (-1); 1166 return ((int64_t)lp->d_partitions[part].p_size); 1167 } 1168 1169 static void 1170 free_ds_label(struct diskslices *ssp, int slice) 1171 { 1172 struct disklabel *lp; 1173 struct diskslice *sp; 1174 1175 sp = &ssp->dss_slices[slice]; 1176 lp = sp->ds_label; 1177 if (lp == NULL) 1178 return; 1179 kfree(lp, M_DEVBUF); 1180 set_ds_label(ssp, slice, (struct disklabel *)NULL); 1181 } 1182 1183 static char * 1184 fixlabel(const char *sname, struct diskslice *sp, struct disklabel *lp, int writeflag) 1185 { 1186 u_int64_t start; 1187 u_int64_t end; 1188 u_int64_t offset; 1189 int part; 1190 struct partition *pp; 1191 bool_t warned; 1192 1193 /* These errors "can't happen" so don't bother reporting details. */ 1194 if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC) 1195 return ("fixlabel: invalid magic"); 1196 if (dkcksum(lp) != 0) 1197 return ("fixlabel: invalid checksum"); 1198 1199 pp = &lp->d_partitions[RAW_PART]; 1200 1201 /* 1202 * What a mess. For ages old backwards compatibility the disklabel 1203 * on-disk stores absolute offsets instead of slice-relative offsets. 1204 * So fix it up when reading, writing, or snooping. 1205 * 1206 * The in-core label is always slice-relative. 1207 */ 1208 if (writeflag) { 1209 start = 0; 1210 offset = sp->ds_offset; 1211 } else { 1212 start = sp->ds_offset; 1213 offset = -sp->ds_offset; 1214 } 1215 if (pp->p_offset != start) { 1216 if (sname != NULL) { 1217 kprintf( 1218 "%s: rejecting BSD label: raw partition offset != slice offset\n", 1219 sname); 1220 slice_info(sname, sp); 1221 partition_info(sname, RAW_PART, pp); 1222 } 1223 return ("fixlabel: raw partition offset != slice offset"); 1224 } 1225 if (pp->p_size != sp->ds_size) { 1226 if (sname != NULL) { 1227 kprintf("%s: raw partition size != slice size\n", sname); 1228 slice_info(sname, sp); 1229 partition_info(sname, RAW_PART, pp); 1230 } 1231 if (pp->p_size > sp->ds_size) { 1232 if (sname == NULL) 1233 return ("fixlabel: raw partition size > slice size"); 1234 kprintf("%s: truncating raw partition\n", sname); 1235 pp->p_size = sp->ds_size; 1236 } 1237 } 1238 end = start + sp->ds_size; 1239 if (start > end) 1240 return ("fixlabel: slice wraps"); 1241 if (lp->d_secpercyl <= 0) 1242 return ("fixlabel: d_secpercyl <= 0"); 1243 pp -= RAW_PART; 1244 warned = FALSE; 1245 for (part = 0; part < lp->d_npartitions; part++, pp++) { 1246 if (pp->p_offset != 0 || pp->p_size != 0) { 1247 if (pp->p_offset < start 1248 || pp->p_offset + pp->p_size > end 1249 || pp->p_offset + pp->p_size < pp->p_offset) { 1250 if (sname != NULL) { 1251 kprintf( 1252 "%s: rejecting partition in BSD label: it isn't entirely within the slice\n", 1253 sname); 1254 if (!warned) { 1255 slice_info(sname, sp); 1256 warned = TRUE; 1257 } 1258 partition_info(sname, part, pp); 1259 } 1260 /* XXX else silently discard junk. */ 1261 bzero(pp, sizeof *pp); 1262 } else { 1263 pp->p_offset += offset; 1264 } 1265 } 1266 } 1267 lp->d_ncylinders = sp->ds_size / lp->d_secpercyl; 1268 lp->d_secperunit = sp->ds_size; 1269 lp->d_checksum = 0; 1270 lp->d_checksum = dkcksum(lp); 1271 return (NULL); 1272 } 1273 1274 static void 1275 partition_info(const char *sname, int part, struct partition *pp) 1276 { 1277 kprintf("%s%c: start %lu, end %lu, size %lu\n", sname, 'a' + part, 1278 (u_long)pp->p_offset, (u_long)(pp->p_offset + pp->p_size - 1), 1279 (u_long)pp->p_size); 1280 } 1281 1282 static void 1283 slice_info(const char *sname, struct diskslice *sp) 1284 { 1285 kprintf("%s: start %llu, end %llu, size %llu\n", sname, 1286 sp->ds_offset, sp->ds_offset + sp->ds_size - 1, sp->ds_size); 1287 } 1288 1289 static void 1290 set_ds_label(struct diskslices *ssp, int slice, struct disklabel *lp) 1291 { 1292 struct diskslice *sp1 = &ssp->dss_slices[slice]; 1293 struct diskslice *sp2; 1294 1295 if (slice == COMPATIBILITY_SLICE) 1296 sp2 = &ssp->dss_slices[ssp->dss_first_bsd_slice]; 1297 else if (slice == ssp->dss_first_bsd_slice) 1298 sp2 = &ssp->dss_slices[COMPATIBILITY_SLICE]; 1299 else 1300 sp2 = NULL; 1301 sp1->ds_label = lp; 1302 if (sp2) 1303 sp2->ds_label = lp; 1304 1305 /* 1306 * If the slice is not the whole-disk slice, setup the reserved 1307 * area(s). 1308 * 1309 * The reserved area for the original bsd disklabel, inclusive of 1310 * the label and space for boot2, is 15 sectors. If you've 1311 * noticed people traditionally skipping 16 sectors its because 1312 * the sector numbers start at the beginning of the slice rather 1313 * then the beginning of the disklabel and traditional dos slices 1314 * reserve a sector at the beginning for the boot code. 1315 * 1316 * NOTE! With the traditional bsdlabel, the first N bytes of boot2 1317 * overlap with the disklabel. The disklabel program checks that 1318 * they are 0. 1319 * 1320 * When clearing a label, the bsdlabel reserved area is reset. 1321 */ 1322 if (slice != WHOLE_DISK_SLICE) { 1323 if (lp) { 1324 sp1->ds_skip_bsdlabel = sp1->ds_skip_platform + 15; 1325 if (sp2) 1326 sp2->ds_skip_bsdlabel = sp1->ds_skip_bsdlabel; 1327 } else { 1328 sp1->ds_skip_bsdlabel = sp1->ds_skip_platform; 1329 if (sp2) 1330 sp2->ds_skip_bsdlabel = sp1->ds_skip_platform; 1331 } 1332 } 1333 } 1334 1335 static void 1336 set_ds_wlabel(struct diskslices *ssp, int slice, int wlabel) 1337 { 1338 ssp->dss_slices[slice].ds_wlabel = wlabel; 1339 if (slice == COMPATIBILITY_SLICE) 1340 ssp->dss_slices[ssp->dss_first_bsd_slice].ds_wlabel = wlabel; 1341 else if (slice == ssp->dss_first_bsd_slice) 1342 ssp->dss_slices[COMPATIBILITY_SLICE].ds_wlabel = wlabel; 1343 } 1344