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.51 2008/08/29 20:08:36 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/disklabel32.h> 56 #include <sys/disklabel64.h> 57 #include <sys/diskslice.h> 58 #include <sys/disk.h> 59 #include <sys/diskmbr.h> 60 #include <sys/fcntl.h> 61 #include <sys/malloc.h> 62 #include <sys/stat.h> 63 #include <sys/syslog.h> 64 #include <sys/proc.h> 65 #include <sys/vnode.h> 66 #include <sys/device.h> 67 #include <sys/thread2.h> 68 69 #include <vfs/ufs/dinode.h> /* XXX used only for fs.h */ 70 #include <vfs/ufs/fs.h> /* XXX used only to get BBSIZE/SBSIZE */ 71 72 static int dsreadandsetlabel(cdev_t dev, u_int flags, 73 struct diskslices *ssp, struct diskslice *sp, 74 struct disk_info *info); 75 static void free_ds_label (struct diskslices *ssp, int slice); 76 static void set_ds_label (struct diskslices *ssp, int slice, disklabel_t lp, 77 disklabel_ops_t ops); 78 static void set_ds_wlabel (struct diskslices *ssp, int slice, int wlabel); 79 80 /* 81 * Determine the size of the transfer, and make sure it is 82 * within the boundaries of the partition. Adjust transfer 83 * if needed, and signal errors or early completion. 84 * 85 * XXX TODO: 86 * o Split buffers that are too big for the device. 87 * o Check for overflow. 88 * o Finish cleaning this up. 89 * 90 * This function returns 1 on success, 0 if transfer equates 91 * to EOF (end of disk) or -1 on failure. The appropriate 92 * 'errno' value is also set in bp->b_error and bp->b_flags 93 * is marked with B_ERROR. 94 */ 95 struct bio * 96 dscheck(cdev_t dev, struct bio *bio, struct diskslices *ssp) 97 { 98 struct buf *bp = bio->bio_buf; 99 struct bio *nbio; 100 disklabel_t lp; 101 disklabel_ops_t ops; 102 long nsec; 103 u_int64_t secno; 104 u_int64_t endsecno; 105 u_int64_t slicerel_secno; 106 struct diskslice *sp; 107 u_int32_t part; 108 u_int32_t slice; 109 int shift; 110 int mask; 111 112 slice = dkslice(dev); 113 part = dkpart(dev); 114 115 if (bio->bio_offset < 0) { 116 kprintf("dscheck(%s): negative bio_offset %lld\n", 117 devtoname(dev), bio->bio_offset); 118 goto bad; 119 } 120 if (slice >= ssp->dss_nslices) { 121 kprintf("dscheck(%s): slice too large %d/%d\n", 122 devtoname(dev), slice, ssp->dss_nslices); 123 goto bad; 124 } 125 sp = &ssp->dss_slices[slice]; 126 127 /* 128 * Calculate secno and nsec 129 */ 130 if (ssp->dss_secmult == 1) { 131 shift = DEV_BSHIFT; 132 goto doshift; 133 } else if (ssp->dss_secshift != -1) { 134 shift = DEV_BSHIFT + ssp->dss_secshift; 135 doshift: 136 mask = (1 << shift) - 1; 137 if ((int)bp->b_bcount & mask) 138 goto bad_bcount; 139 if ((int)bio->bio_offset & mask) 140 goto bad_blkno; 141 secno = bio->bio_offset >> shift; 142 nsec = bp->b_bcount >> shift; 143 } else { 144 if (bp->b_bcount % ssp->dss_secsize) 145 goto bad_bcount; 146 if (bio->bio_offset % ssp->dss_secsize) 147 goto bad_blkno; 148 secno = bio->bio_offset / ssp->dss_secsize; 149 nsec = bp->b_bcount / ssp->dss_secsize; 150 } 151 152 /* 153 * Calculate slice-relative sector number end slice-relative 154 * limit. 155 */ 156 if (slice == WHOLE_DISK_SLICE) { 157 /* 158 * Labels have not been allowed on whole-disks for a while. 159 * This really puts the nail in the coffin. 160 * 161 * Accesses to the WHOLE_DISK_SLICE do not use a disklabel 162 * and partition numbers are special-cased. Currently numbers 163 * less then 128 are not allowed. Partition numbers >= 128 164 * are encoded in the high 8 bits of the 64 bit buffer offset 165 * and are fed directly through to the device with no 166 * further interpretation. In particular, no sector 167 * translation interpretation should occur because the 168 * sector size for the special raw access may not be the 169 * same as the nominal sector size for the device. 170 */ 171 lp.opaque = NULL; 172 if (part < 128) { 173 kprintf("dscheck(%s): illegal partition number (%d) " 174 "for WHOLE_DISK_SLICE access\n", 175 devtoname(dev), part); 176 goto bad; 177 } else if (part != WHOLE_SLICE_PART) { 178 nbio = push_bio(bio); 179 nbio->bio_offset = bio->bio_offset | 180 (u_int64_t)part << 56; 181 return(nbio); 182 } 183 184 /* 185 * sp->ds_size is for the whole disk in the WHOLE_DISK_SLICE, 186 * there are no reserved areas. 187 */ 188 endsecno = sp->ds_size; 189 slicerel_secno = secno; 190 } else if (part == WHOLE_SLICE_PART) { 191 /* 192 * NOTE! opens on a whole-slice partition will not attempt 193 * to read a disklabel in, so there may not be an in-core 194 * disklabel even if there is one on the disk. 195 */ 196 endsecno = sp->ds_size; 197 slicerel_secno = secno; 198 } else if ((lp = sp->ds_label).opaque != NULL) { 199 /* 200 * A label is present, extract the partition. Snooping of 201 * the disklabel is not supported even if accessible. Of 202 * course, the reserved area is still write protected. 203 */ 204 ops = sp->ds_ops; 205 if (ops->op_getpartbounds(ssp, lp, part, 206 &slicerel_secno, &endsecno)) { 207 kprintf("dscheck(%s): partition %d out of bounds\n", 208 devtoname(dev), part); 209 goto bad; 210 } 211 slicerel_secno += secno; 212 } else { 213 /* 214 * Attempt to access partition when no disklabel present 215 */ 216 kprintf("dscheck(%s): attempt to access non-existent partition\n", 217 devtoname(dev)); 218 goto bad; 219 } 220 221 /* 222 * Disallow writes to reserved areas unless ds_wlabel allows it. 223 */ 224 if (slicerel_secno < sp->ds_reserved && nsec && 225 bp->b_cmd == BUF_CMD_WRITE && sp->ds_wlabel == 0) { 226 bp->b_error = EROFS; 227 goto error; 228 } 229 230 /* 231 * If we get here, bio_offset must be on a block boundary and 232 * the sector size must be a power of 2. 233 */ 234 if ((bio->bio_offset & (ssp->dss_secsize - 1)) || 235 (ssp->dss_secsize ^ (ssp->dss_secsize - 1)) != 236 ((ssp->dss_secsize << 1) - 1)) { 237 kprintf("%s: invalid BIO offset, not sector aligned or" 238 " invalid sector size (not power of 2) %08llx %d\n", 239 devtoname(dev), bio->bio_offset, ssp->dss_secsize); 240 goto bad; 241 } 242 243 /* 244 * EOF handling 245 */ 246 if (secno + nsec > endsecno) { 247 /* 248 * Return an error if beyond the end of the disk, or 249 * if B_BNOCLIP is set. Tell the system that we do not 250 * need to keep the buffer around. 251 */ 252 if (secno > endsecno || (bp->b_flags & B_BNOCLIP)) 253 goto bad; 254 255 /* 256 * If exactly at end of disk, return an EOF. Throw away 257 * the buffer contents, if any, by setting B_INVAL. 258 */ 259 if (secno == endsecno) { 260 bp->b_resid = bp->b_bcount; 261 bp->b_flags |= B_INVAL; 262 goto done; 263 } 264 265 /* 266 * Else truncate 267 */ 268 nsec = endsecno - secno; 269 bp->b_bcount = nsec * ssp->dss_secsize; 270 } 271 272 nbio = push_bio(bio); 273 nbio->bio_offset = (off_t)(sp->ds_offset + slicerel_secno) * 274 ssp->dss_secsize; 275 return (nbio); 276 277 bad_bcount: 278 kprintf( 279 "dscheck(%s): b_bcount %d is not on a sector boundary (ssize %d)\n", 280 devtoname(dev), bp->b_bcount, ssp->dss_secsize); 281 goto bad; 282 283 bad_blkno: 284 kprintf( 285 "dscheck(%s): bio_offset %lld is not on a sector boundary (ssize %d)\n", 286 devtoname(dev), bio->bio_offset, ssp->dss_secsize); 287 bad: 288 bp->b_error = EINVAL; 289 /* fall through */ 290 error: 291 /* 292 * Terminate the I/O with a ranging error. Since the buffer is 293 * either illegal or beyond the file EOF, mark it B_INVAL as well. 294 */ 295 bp->b_resid = bp->b_bcount; 296 bp->b_flags |= B_ERROR | B_INVAL; 297 done: 298 /* 299 * Caller must biodone() the originally passed bio if NULL is 300 * returned. 301 */ 302 return (NULL); 303 } 304 305 void 306 dsclose(cdev_t dev, int mode, struct diskslices *ssp) 307 { 308 u_int32_t part; 309 u_int32_t slice; 310 struct diskslice *sp; 311 312 slice = dkslice(dev); 313 part = dkpart(dev); 314 if (slice < ssp->dss_nslices) { 315 sp = &ssp->dss_slices[slice]; 316 dsclrmask(sp, part); 317 } 318 } 319 320 void 321 dsgone(struct diskslices **sspp) 322 { 323 int slice; 324 struct diskslice *sp; 325 struct diskslices *ssp; 326 327 for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) { 328 sp = &ssp->dss_slices[slice]; 329 free_ds_label(ssp, slice); 330 } 331 kfree(ssp, M_DEVBUF); 332 *sspp = NULL; 333 } 334 335 /* 336 * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this 337 * is subject to the same restriction as dsopen(). 338 */ 339 int 340 dsioctl(cdev_t dev, u_long cmd, caddr_t data, int flags, 341 struct diskslices **sspp, struct disk_info *info) 342 { 343 int error; 344 disklabel_t lp; 345 disklabel_t lptmp; 346 disklabel_ops_t ops; 347 int old_wlabel; 348 u_int32_t openmask[DKMAXPARTITIONS/(sizeof(u_int32_t)*8)]; 349 int part; 350 int slice; 351 struct diskslice *sp; 352 struct diskslices *ssp; 353 354 slice = dkslice(dev); 355 part = dkpart(dev); 356 ssp = *sspp; 357 if (slice >= ssp->dss_nslices) 358 return (EINVAL); 359 sp = &ssp->dss_slices[slice]; 360 lp = sp->ds_label; 361 ops = sp->ds_ops; /* may be NULL if no label */ 362 363 switch (cmd) { 364 case DIOCGDVIRGIN32: 365 ops = &disklabel32_ops; 366 /* fall through */ 367 case DIOCGDVIRGIN64: 368 if (cmd != DIOCGDVIRGIN32) 369 ops = &disklabel64_ops; 370 /* 371 * You can only retrieve a virgin disklabel on the whole 372 * disk slice or whole-slice partition. 373 */ 374 if (slice != WHOLE_DISK_SLICE && 375 part != WHOLE_SLICE_PART) { 376 return(EINVAL); 377 } 378 379 lp.opaque = data; 380 ops->op_makevirginlabel(lp, ssp, sp, info); 381 return (0); 382 383 case DIOCGDINFO32: 384 case DIOCGDINFO64: 385 /* 386 * You can only retrieve a disklabel on the whole 387 * slice partition. 388 * 389 * We do not support labels directly on whole-disks 390 * any more (that is, disks without slices), unless the 391 * device driver has asked for a compatible label (e.g. 392 * for a CD) to allow booting off of storage that is 393 * otherwise unlabeled. 394 */ 395 error = 0; 396 if (part != WHOLE_SLICE_PART) 397 return(EINVAL); 398 if (slice == WHOLE_DISK_SLICE && 399 (info->d_dsflags & DSO_COMPATLABEL) == 0) { 400 return (ENODEV); 401 } 402 if (sp->ds_label.opaque == NULL) { 403 error = dsreadandsetlabel(dev, info->d_dsflags, 404 ssp, sp, info); 405 ops = sp->ds_ops; /* may be NULL */ 406 } 407 408 /* 409 * The type of label we found must match the type of 410 * label requested. 411 */ 412 if (error == 0 && IOCPARM_LEN(cmd) != ops->labelsize) 413 error = ENOATTR; 414 if (error == 0) 415 bcopy(sp->ds_label.opaque, data, ops->labelsize); 416 return (error); 417 418 case DIOCGPART: 419 { 420 struct partinfo *dpart = (void *)data; 421 422 /* 423 * The disk management layer may not have read the 424 * disklabel yet because simply opening a slice no 425 * longer 'probes' the disk that way. Be sure we 426 * have tried. 427 * 428 * We ignore any error. 429 */ 430 if (sp->ds_label.opaque == NULL && 431 part == WHOLE_SLICE_PART && 432 slice != WHOLE_DISK_SLICE) { 433 dsreadandsetlabel(dev, info->d_dsflags, 434 ssp, sp, info); 435 ops = sp->ds_ops; /* may be NULL */ 436 } 437 438 bzero(dpart, sizeof(*dpart)); 439 dpart->media_offset = (u_int64_t)sp->ds_offset * 440 info->d_media_blksize; 441 dpart->media_size = (u_int64_t)sp->ds_size * 442 info->d_media_blksize; 443 dpart->media_blocks = sp->ds_size; 444 dpart->media_blksize = info->d_media_blksize; 445 dpart->reserved_blocks= sp->ds_reserved; 446 dpart->fstype_uuid = sp->ds_type_uuid; 447 dpart->storage_uuid = sp->ds_stor_uuid; 448 449 if (slice != WHOLE_DISK_SLICE && 450 part != WHOLE_SLICE_PART) { 451 u_int64_t start; 452 u_int64_t blocks; 453 if (lp.opaque == NULL) 454 return(EINVAL); 455 if (ops->op_getpartbounds(ssp, lp, part, 456 &start, &blocks)) { 457 return(EINVAL); 458 } 459 ops->op_loadpartinfo(lp, part, dpart); 460 dpart->media_offset += start * 461 info->d_media_blksize; 462 dpart->media_size = blocks * 463 info->d_media_blksize; 464 dpart->media_blocks = blocks; 465 466 /* 467 * partition starting sector (p_offset) 468 * requires slice's reserved areas to be 469 * adjusted. 470 */ 471 if (dpart->reserved_blocks > start) 472 dpart->reserved_blocks -= start; 473 else 474 dpart->reserved_blocks = 0; 475 } 476 477 /* 478 * Load remaining fields from the info structure 479 */ 480 dpart->d_nheads = info->d_nheads; 481 dpart->d_ncylinders = info->d_ncylinders; 482 dpart->d_secpertrack = info->d_secpertrack; 483 dpart->d_secpercyl = info->d_secpercyl; 484 } 485 return (0); 486 487 case DIOCGSLICEINFO: 488 bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] - 489 (char *)ssp); 490 return (0); 491 492 case DIOCSDINFO32: 493 ops = &disklabel32_ops; 494 /* fall through */ 495 case DIOCSDINFO64: 496 if (cmd != DIOCSDINFO32) 497 ops = &disklabel64_ops; 498 /* 499 * You can write a disklabel on the whole disk slice or 500 * whole-slice partition. 501 */ 502 if (slice != WHOLE_DISK_SLICE && 503 part != WHOLE_SLICE_PART) { 504 return(EINVAL); 505 } 506 507 /* 508 * We no longer support writing disklabels directly to media 509 * without there being a slice. Keep this as a separate 510 * conditional. 511 */ 512 if (slice == WHOLE_DISK_SLICE) 513 return (ENODEV); 514 if (!(flags & FWRITE)) 515 return (EBADF); 516 517 /* 518 * If an existing label is present it must be the same 519 * type as the label being passed by the ioctl. 520 */ 521 if (sp->ds_label.opaque && sp->ds_ops != ops) 522 return (ENOATTR); 523 524 /* 525 * Create a temporary copy of the existing label 526 * (if present) so setdisklabel can compare it against 527 * the new label. 528 */ 529 lp.opaque = kmalloc(ops->labelsize, M_DEVBUF, M_WAITOK); 530 if (sp->ds_label.opaque == NULL) 531 bzero(lp.opaque, ops->labelsize); 532 else 533 bcopy(sp->ds_label.opaque, lp.opaque, ops->labelsize); 534 if (sp->ds_label.opaque == NULL) { 535 bzero(openmask, sizeof(openmask)); 536 } else { 537 bcopy(sp->ds_openmask, openmask, sizeof(openmask)); 538 } 539 lptmp.opaque = data; 540 error = ops->op_setdisklabel(lp, lptmp, ssp, sp, openmask); 541 if (error != 0) { 542 kfree(lp.opaque, M_DEVBUF); 543 return (error); 544 } 545 free_ds_label(ssp, slice); 546 set_ds_label(ssp, slice, lp, ops); 547 return (0); 548 549 case DIOCSYNCSLICEINFO: 550 /* 551 * This ioctl can only be done on the whole disk 552 */ 553 if (slice != WHOLE_DISK_SLICE || part != WHOLE_SLICE_PART) 554 return (EINVAL); 555 556 if (*(int *)data == 0) { 557 for (slice = 0; slice < ssp->dss_nslices; slice++) { 558 struct diskslice *ds = &ssp->dss_slices[slice]; 559 560 switch(dscountmask(ds)) { 561 case 0: 562 break; 563 case 1: 564 if (slice != WHOLE_DISK_SLICE) 565 return (EBUSY); 566 if (!dschkmask(ds, RAW_PART)) 567 return (EBUSY); 568 break; 569 default: 570 return (EBUSY); 571 } 572 } 573 } 574 575 /* 576 * Temporarily forget the current slices struct and read 577 * the current one. 578 * 579 * NOTE: 580 * 581 * XXX should wait for current accesses on this disk to 582 * complete, then lock out future accesses and opens. 583 */ 584 *sspp = NULL; 585 error = dsopen(dev, S_IFCHR, ssp->dss_oflags, sspp, info); 586 if (error != 0) { 587 *sspp = ssp; 588 return (error); 589 } 590 591 /* 592 * Reopen everything. This is a no-op except in the "force" 593 * case and when the raw bdev and cdev are both open. Abort 594 * if anything fails. 595 */ 596 for (slice = 0; slice < ssp->dss_nslices; slice++) { 597 for (part = 0; part < DKMAXPARTITIONS; ++part) { 598 if (!dschkmask(&ssp->dss_slices[slice], part)) 599 continue; 600 error = dsopen(dkmodslice(dkmodpart(dev, part), 601 slice), 602 S_IFCHR, ssp->dss_oflags, sspp, 603 info); 604 if (error != 0) { 605 *sspp = ssp; 606 return (EBUSY); 607 } 608 } 609 } 610 611 dsgone(&ssp); 612 return (0); 613 614 case DIOCWDINFO32: 615 case DIOCWDINFO64: 616 error = dsioctl(dev, ((cmd == DIOCWDINFO32) ? 617 DIOCSDINFO32 : DIOCSDINFO64), 618 data, flags, &ssp, info); 619 if (error == 0 && sp->ds_label.opaque == NULL) 620 error = EINVAL; 621 if (error != 0) 622 return (error); 623 624 /* 625 * Allow the reserved area to be written, reload ops 626 * because the DIOCSDINFO op above may have installed 627 * a new label type. 628 */ 629 ops = sp->ds_ops; 630 old_wlabel = sp->ds_wlabel; 631 set_ds_wlabel(ssp, slice, TRUE); 632 error = ops->op_writedisklabel(dev, ssp, sp, sp->ds_label); 633 set_ds_wlabel(ssp, slice, old_wlabel); 634 /* XXX should invalidate in-core label if write failed. */ 635 return (error); 636 637 case DIOCWLABEL: 638 if (slice == WHOLE_DISK_SLICE) 639 return (ENODEV); 640 if (!(flags & FWRITE)) 641 return (EBADF); 642 set_ds_wlabel(ssp, slice, *(int *)data != 0); 643 return (0); 644 645 default: 646 return (ENOIOCTL); 647 } 648 } 649 650 int 651 dsisopen(struct diskslices *ssp) 652 { 653 int slice; 654 655 if (ssp == NULL) 656 return (0); 657 for (slice = 0; slice < ssp->dss_nslices; slice++) { 658 if (dscountmask(&ssp->dss_slices[slice])) 659 return (1); 660 } 661 return (0); 662 } 663 664 /* 665 * Allocate a slices "struct" and initialize it to contain only an empty 666 * compatibility slice (pointing to itself), a whole disk slice (covering 667 * the disk as described by the label), and (nslices - BASE_SLICES) empty 668 * slices beginning at BASE_SLICE. 669 * 670 * Note that the compatibility slice is no longer really a compatibility 671 * slice. It is slice 0 if a GPT label is present, and the dangerously 672 * dedicated slice if no slice table otherwise exists. Else it is 0-sized. 673 */ 674 struct diskslices * 675 dsmakeslicestruct(int nslices, struct disk_info *info) 676 { 677 struct diskslice *sp; 678 struct diskslices *ssp; 679 680 ssp = kmalloc(offsetof(struct diskslices, dss_slices) + 681 nslices * sizeof *sp, M_DEVBUF, M_WAITOK); 682 ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE; 683 ssp->dss_nslices = nslices; 684 ssp->dss_oflags = 0; 685 686 /* 687 * Figure out if we can use shifts or whether we have to 688 * use mod/multply to translate byte offsets into sector numbers. 689 */ 690 if ((info->d_media_blksize ^ (info->d_media_blksize - 1)) == 691 (info->d_media_blksize << 1) - 1) { 692 ssp->dss_secmult = info->d_media_blksize / DEV_BSIZE; 693 if (ssp->dss_secmult & (ssp->dss_secmult - 1)) 694 ssp->dss_secshift = -1; 695 else 696 ssp->dss_secshift = ffs(ssp->dss_secmult) - 1; 697 } else { 698 ssp->dss_secmult = 0; 699 ssp->dss_secshift = -1; 700 } 701 ssp->dss_secsize = info->d_media_blksize; 702 sp = &ssp->dss_slices[0]; 703 bzero(sp, nslices * sizeof *sp); 704 sp[WHOLE_DISK_SLICE].ds_size = info->d_media_blocks; 705 return (ssp); 706 } 707 708 char * 709 dsname(cdev_t dev, int unit, int slice, int part, char *partname) 710 { 711 static char name[32]; 712 const char *dname; 713 int used; 714 715 dname = dev_dname(dev); 716 if (strlen(dname) > 16) 717 dname = "nametoolong"; 718 ksnprintf(name, sizeof(name), "%s%d", dname, unit); 719 partname[0] = '\0'; 720 used = strlen(name); 721 722 if (slice != WHOLE_DISK_SLICE) { 723 /* 724 * slice or slice + partition. BASE_SLICE is s1, but 725 * the compatibility slice (0) needs to be s0. 726 */ 727 used += ksnprintf(name + used, sizeof(name) - used, 728 "s%d", (slice ? slice - BASE_SLICE + 1 : 0)); 729 if (part != WHOLE_SLICE_PART) { 730 used += ksnprintf(name + used, sizeof(name) - used, 731 "%c", 'a' + part); 732 partname[0] = 'a' + part; 733 partname[1] = 0; 734 } 735 } else if (part == WHOLE_SLICE_PART) { 736 /* 737 * whole-disk-device, raw access to disk 738 */ 739 /* no string extension */ 740 } else if (part > 128) { 741 /* 742 * whole-disk-device, extended raw access partitions. 743 * (typically used to access CD audio tracks) 744 */ 745 used += ksnprintf(name + used, sizeof(name) - used, 746 "t%d", part - 128); 747 } else { 748 /* 749 * whole-disk-device, illegal partition number 750 */ 751 used += ksnprintf(name + used, sizeof(name) - used, 752 "?%d", part); 753 } 754 return (name); 755 } 756 757 /* 758 * This should only be called when the unit is inactive and the strategy 759 * routine should not allow it to become active unless we call it. Our 760 * strategy routine must be special to allow activity. 761 */ 762 int 763 dsopen(cdev_t dev, int mode, u_int flags, 764 struct diskslices **sspp, struct disk_info *info) 765 { 766 cdev_t dev1; 767 int error; 768 int need_init; 769 struct diskslice *sp; 770 struct diskslices *ssp; 771 int slice; 772 int part; 773 774 dev->si_bsize_phys = info->d_media_blksize; 775 776 /* 777 * Do not attempt to read the slice table or disk label when 778 * accessing the whole-disk slice or a while-slice partition. 779 */ 780 if (dkslice(dev) == WHOLE_DISK_SLICE) 781 flags |= DSO_ONESLICE | DSO_NOLABELS; 782 if (dkpart(dev) == WHOLE_SLICE_PART) 783 flags |= DSO_NOLABELS; 784 785 /* 786 * Reinitialize the slice table unless there is an open device 787 * on the unit. 788 * 789 * It would be nice if we didn't have to do this but when a 790 * user is slicing and partitioning up a disk it is a lot safer 791 * to not take any chances. 792 */ 793 ssp = *sspp; 794 need_init = !dsisopen(ssp); 795 if (ssp != NULL && need_init) 796 dsgone(sspp); 797 if (need_init) { 798 /* 799 * Allocate a minimal slices "struct". This will become 800 * the final slices "struct" if we don't want real slices 801 * or if we can't find any real slices. 802 * 803 * Then scan the disk 804 */ 805 *sspp = dsmakeslicestruct(BASE_SLICE, info); 806 807 if ((flags & DSO_ONESLICE) == 0) { 808 error = mbrinit(dev, info, sspp); 809 if (error != 0) { 810 dsgone(sspp); 811 return (error); 812 } 813 } 814 ssp = *sspp; 815 ssp->dss_oflags = flags; 816 817 /* 818 * If there are no real slices, then make the compatiblity 819 * slice cover the whole disk. 820 */ 821 if (ssp->dss_nslices == BASE_SLICE) { 822 sp = &ssp->dss_slices[COMPATIBILITY_SLICE]; 823 824 sp->ds_size = info->d_media_blocks; 825 sp->ds_reserved = 0; 826 } 827 828 /* 829 * Set dss_first_bsd_slice to point at the first BSD 830 * slice, if any. 831 */ 832 for (slice = BASE_SLICE; slice < ssp->dss_nslices; slice++) { 833 sp = &ssp->dss_slices[slice]; 834 if (sp->ds_type == DOSPTYP_386BSD /* XXX */) { 835 #if 0 836 struct diskslice *csp; 837 #endif 838 839 ssp->dss_first_bsd_slice = slice; 840 #if 0 841 /* 842 * no longer supported, s0 is a real slice 843 * for GPT 844 */ 845 csp = &ssp->dss_slices[COMPATIBILITY_SLICE]; 846 csp->ds_offset = sp->ds_offset; 847 csp->ds_size = sp->ds_size; 848 csp->ds_type = sp->ds_type; 849 csp->ds_reserved = sp->ds_reserved; 850 #endif 851 break; 852 } 853 } 854 855 /* 856 * By definition accesses via the whole-disk device do not 857 * specify any reserved areas. The whole disk may be read 858 * or written by the whole-disk device. 859 * 860 * The whole-disk slice does not ever have a label. 861 */ 862 sp = &ssp->dss_slices[WHOLE_DISK_SLICE]; 863 sp->ds_wlabel = TRUE; 864 sp->ds_reserved = 0; 865 } 866 867 /* 868 * Load the disklabel for the slice being accessed unless it is 869 * a whole-disk-slice or a whole-slice-partition (as determined 870 * by DSO_NOLABELS). 871 * 872 * We could scan all slices here and try to load up their 873 * disklabels, but that would cause us to access slices that 874 * the user may otherwise not intend us to access, or corrupted 875 * slices, etc. 876 * 877 * XXX if there are no opens on the slice we may want to re-read 878 * the disklabel anyway, even if we have one cached. 879 */ 880 slice = dkslice(dev); 881 if (slice >= ssp->dss_nslices) 882 return (ENXIO); 883 sp = &ssp->dss_slices[slice]; 884 part = dkpart(dev); 885 886 if ((flags & DSO_NOLABELS) == 0 && sp->ds_label.opaque == NULL) { 887 dev1 = dkmodslice(dkmodpart(dev, WHOLE_SLICE_PART), slice); 888 889 /* 890 * If opening a raw disk we do not try to 891 * read the disklabel now. No interpretation of raw disks 892 * (e.g. like 'da0') ever occurs. We will try to read the 893 * disklabel for a raw slice if asked to via DIOC* ioctls. 894 * 895 * Access to the label area is disallowed by default. Note 896 * however that accesses via WHOLE_DISK_SLICE, and accesses 897 * via WHOLE_SLICE_PART for slices without valid disklabels, 898 * will allow writes and ignore the flag. 899 */ 900 set_ds_wlabel(ssp, slice, FALSE); 901 dsreadandsetlabel(dev1, flags, ssp, sp, info); 902 } 903 904 /* 905 * If opening a particular partition the disklabel must exist and 906 * the partition must be present in the label. 907 * 908 * If the partition is the special whole-disk-slice no partition 909 * table need exist. 910 */ 911 if (part != WHOLE_SLICE_PART && slice != WHOLE_DISK_SLICE) { 912 if (sp->ds_label.opaque == NULL || 913 part >= sp->ds_ops->op_getnumparts(sp->ds_label)) { 914 return (EINVAL); 915 } 916 } 917 918 /* 919 * Do not allow special raw-extension partitions to be opened 920 * if the device doesn't support them. Raw-extension partitions 921 * are typically used to handle CD tracks. 922 */ 923 if (slice == WHOLE_DISK_SLICE && part >= 128 && 924 part != WHOLE_SLICE_PART) { 925 if ((info->d_dsflags & DSO_RAWEXTENSIONS) == 0) 926 return (EINVAL); 927 } 928 929 /* 930 * Ok, we are open 931 */ 932 dssetmask(sp, part); 933 return (0); 934 } 935 936 /* 937 * Attempt to read the disklabel. If successful, store it in sp->ds_label. 938 * 939 * If we cannot read the disklabel and DSO_COMPATLABEL is set, we construct 940 * a fake label covering the whole disk. 941 */ 942 static 943 int 944 dsreadandsetlabel(cdev_t dev, u_int flags, 945 struct diskslices *ssp, struct diskslice *sp, 946 struct disk_info *info) 947 { 948 disklabel_t lp; 949 disklabel_ops_t ops; 950 const char *msg; 951 const char *sname; 952 char partname[2]; 953 int slice = dkslice(dev); 954 955 /* 956 * Probe the disklabel 957 */ 958 lp.opaque = NULL; 959 sname = dsname(dev, dkunit(dev), slice, WHOLE_SLICE_PART, partname); 960 ops = &disklabel32_ops; 961 msg = ops->op_readdisklabel(dev, sp, &lp, info); 962 if (msg && strcmp(msg, "no disk label") == 0) { 963 ops = &disklabel64_ops; 964 msg = disklabel64_ops.op_readdisklabel(dev, sp, &lp, info); 965 } 966 967 /* 968 * If we failed and COMPATLABEL is set, create a dummy disklabel. 969 */ 970 if (msg != NULL && (flags & DSO_COMPATLABEL)) { 971 msg = NULL; 972 if (sp->ds_size >= 0x100000000ULL) 973 ops = &disklabel64_ops; 974 else 975 ops = &disklabel32_ops; 976 lp = ops->op_clone_label(info, sp); 977 } 978 if (msg != NULL) { 979 if (sp->ds_type == DOSPTYP_386BSD /* XXX */) 980 log(LOG_WARNING, "%s: cannot find label (%s)\n", 981 sname, msg); 982 if (lp.opaque) 983 kfree(lp.opaque, M_DEVBUF); 984 } else { 985 set_ds_label(ssp, slice, lp, ops); 986 set_ds_wlabel(ssp, slice, FALSE); 987 } 988 return (msg ? EINVAL : 0); 989 } 990 991 int64_t 992 dssize(cdev_t dev, struct diskslices **sspp) 993 { 994 disklabel_t lp; 995 disklabel_ops_t ops; 996 int part; 997 int slice; 998 struct diskslices *ssp; 999 u_int64_t start; 1000 u_int64_t blocks; 1001 1002 slice = dkslice(dev); 1003 part = dkpart(dev); 1004 ssp = *sspp; 1005 if (ssp == NULL || slice >= ssp->dss_nslices 1006 || !dschkmask(&ssp->dss_slices[slice], part)) { 1007 if (dev_dopen(dev, FREAD, S_IFCHR, proc0.p_ucred) != 0) 1008 return (-1); 1009 dev_dclose(dev, FREAD, S_IFCHR); 1010 ssp = *sspp; 1011 } 1012 lp = ssp->dss_slices[slice].ds_label; 1013 if (lp.opaque == NULL) 1014 return (-1); 1015 ops = ssp->dss_slices[slice].ds_ops; 1016 if (ops->op_getpartbounds(ssp, lp, part, &start, &blocks)) 1017 return (-1); 1018 return ((int64_t)blocks); 1019 } 1020 1021 static void 1022 free_ds_label(struct diskslices *ssp, int slice) 1023 { 1024 struct diskslice *sp; 1025 disklabel_t lp; 1026 1027 sp = &ssp->dss_slices[slice]; 1028 lp = sp->ds_label; 1029 if (lp.opaque != NULL) { 1030 kfree(lp.opaque, M_DEVBUF); 1031 lp.opaque = NULL; 1032 set_ds_label(ssp, slice, lp, NULL); 1033 } 1034 } 1035 1036 static void 1037 set_ds_label(struct diskslices *ssp, int slice, 1038 disklabel_t lp, disklabel_ops_t ops) 1039 { 1040 struct diskslice *sp = &ssp->dss_slices[slice]; 1041 1042 sp->ds_label = lp; 1043 sp->ds_ops = ops; 1044 if (lp.opaque && slice != WHOLE_DISK_SLICE) 1045 ops->op_adjust_label_reserved(ssp, slice, sp); 1046 else 1047 sp->ds_reserved = 0; 1048 } 1049 1050 static void 1051 set_ds_wlabel(struct diskslices *ssp, int slice, int wlabel) 1052 { 1053 ssp->dss_slices[slice].ds_wlabel = wlabel; 1054 } 1055 1056