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