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