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 #include <sys/devfs.h> 72 73 static int dsreadandsetlabel(cdev_t dev, u_int flags, 74 struct diskslices *ssp, struct diskslice *sp, 75 struct disk_info *info); 76 static void free_ds_label (struct diskslices *ssp, int slice); 77 static void set_ds_label (struct diskslices *ssp, int slice, disklabel_t lp, 78 disklabel_ops_t ops); 79 static void set_ds_wlabel (struct diskslices *ssp, int slice, int wlabel); 80 81 /* 82 * Determine the size of the transfer, and make sure it is 83 * within the boundaries of the partition. Adjust transfer 84 * if needed, and signal errors or early completion. 85 * 86 * XXX TODO: 87 * o Split buffers that are too big for the device. 88 * o Check for overflow. 89 * o Finish cleaning this up. 90 * 91 * This function returns 1 on success, 0 if transfer equates 92 * to EOF (end of disk) or -1 on failure. The appropriate 93 * 'errno' value is also set in bp->b_error and bp->b_flags 94 * is marked with B_ERROR. 95 */ 96 struct bio * 97 dscheck(cdev_t dev, struct bio *bio, struct diskslices *ssp) 98 { 99 struct buf *bp = bio->bio_buf; 100 struct bio *nbio; 101 disklabel_t lp; 102 disklabel_ops_t ops; 103 long nsec; 104 u_int64_t secno; 105 u_int64_t endsecno; 106 u_int64_t slicerel_secno; 107 struct diskslice *sp; 108 u_int32_t part; 109 u_int32_t slice; 110 int shift; 111 int mask; 112 113 slice = dkslice(dev); 114 part = dkpart(dev); 115 116 if (bio->bio_offset < 0) { 117 kprintf("dscheck(%s): negative bio_offset %lld\n", 118 devtoname(dev), (long long)bio->bio_offset); 119 goto bad; 120 } 121 if (slice >= ssp->dss_nslices) { 122 kprintf("dscheck(%s): slice too large %d/%d\n", 123 devtoname(dev), slice, ssp->dss_nslices); 124 goto bad; 125 } 126 sp = &ssp->dss_slices[slice]; 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 } else { 183 /* 184 * If writing to the raw disk request a 185 * reprobe on the last close. 186 */ 187 if (bp->b_cmd == BUF_CMD_WRITE) 188 sp->ds_flags |= DSF_REPROBE; 189 } 190 191 /* 192 * sp->ds_size is for the whole disk in the WHOLE_DISK_SLICE, 193 * there are no reserved areas. 194 */ 195 endsecno = sp->ds_size; 196 slicerel_secno = secno; 197 } else if (part == WHOLE_SLICE_PART) { 198 /* 199 * NOTE! opens on a whole-slice partition will not attempt 200 * to read a disklabel in, so there may not be an in-core 201 * disklabel even if there is one on the disk. 202 */ 203 endsecno = sp->ds_size; 204 slicerel_secno = secno; 205 } else if ((lp = sp->ds_label).opaque != NULL) { 206 /* 207 * A label is present, extract the partition. Snooping of 208 * the disklabel is not supported even if accessible. Of 209 * course, the reserved area is still write protected. 210 */ 211 ops = sp->ds_ops; 212 if (ops->op_getpartbounds(ssp, lp, part, 213 &slicerel_secno, &endsecno)) { 214 kprintf("dscheck(%s): partition %d out of bounds\n", 215 devtoname(dev), part); 216 goto bad; 217 } 218 slicerel_secno += secno; 219 } else { 220 /* 221 * Attempt to access partition when no disklabel present 222 */ 223 kprintf("dscheck(%s): attempt to access non-existent partition\n", 224 devtoname(dev)); 225 goto bad; 226 } 227 228 /* 229 * Disallow writes to reserved areas unless ds_wlabel allows it. 230 * If the reserved area is written to request a reprobe of the 231 * disklabel when the slice is closed. 232 */ 233 if (slicerel_secno < sp->ds_reserved && nsec && 234 bp->b_cmd == BUF_CMD_WRITE) { 235 if (sp->ds_wlabel == 0) { 236 bp->b_error = EROFS; 237 goto error; 238 } 239 sp->ds_flags |= DSF_REPROBE; 240 } 241 242 /* 243 * If we get here, bio_offset must be on a block boundary and 244 * the sector size must be a power of 2. 245 */ 246 if ((bio->bio_offset & (ssp->dss_secsize - 1)) || 247 (ssp->dss_secsize ^ (ssp->dss_secsize - 1)) != 248 ((ssp->dss_secsize << 1) - 1)) { 249 kprintf("%s: invalid BIO offset, not sector aligned or" 250 " invalid sector size (not power of 2) %08llx %d\n", 251 devtoname(dev), (long long)bio->bio_offset, 252 ssp->dss_secsize); 253 goto bad; 254 } 255 256 /* 257 * EOF handling 258 */ 259 if (secno + nsec > endsecno) { 260 /* 261 * Return an error if beyond the end of the disk, or 262 * if B_BNOCLIP is set. Tell the system that we do not 263 * need to keep the buffer around. 264 */ 265 if (secno > endsecno || (bp->b_flags & B_BNOCLIP)) 266 goto bad; 267 268 /* 269 * If exactly at end of disk, return an EOF. Throw away 270 * the buffer contents, if any, by setting B_INVAL. 271 */ 272 if (secno == endsecno) { 273 bp->b_resid = bp->b_bcount; 274 bp->b_flags |= B_INVAL; 275 goto done; 276 } 277 278 /* 279 * Else truncate 280 */ 281 nsec = endsecno - secno; 282 bp->b_bcount = nsec * ssp->dss_secsize; 283 } 284 285 nbio = push_bio(bio); 286 nbio->bio_offset = (off_t)(sp->ds_offset + slicerel_secno) * 287 ssp->dss_secsize; 288 return (nbio); 289 290 bad_bcount: 291 kprintf( 292 "dscheck(%s): b_bcount %d is not on a sector boundary (ssize %d)\n", 293 devtoname(dev), bp->b_bcount, ssp->dss_secsize); 294 goto bad; 295 296 bad_blkno: 297 kprintf( 298 "dscheck(%s): bio_offset %lld is not on a sector boundary (ssize %d)\n", 299 devtoname(dev), (long long)bio->bio_offset, ssp->dss_secsize); 300 bad: 301 bp->b_error = EINVAL; 302 /* fall through */ 303 error: 304 /* 305 * Terminate the I/O with a ranging error. Since the buffer is 306 * either illegal or beyond the file EOF, mark it B_INVAL as well. 307 */ 308 bp->b_resid = bp->b_bcount; 309 bp->b_flags |= B_ERROR | B_INVAL; 310 done: 311 /* 312 * Caller must biodone() the originally passed bio if NULL is 313 * returned. 314 */ 315 return (NULL); 316 } 317 318 /* 319 * dsclose() - close a cooked disk slice. 320 * 321 * WARNING! The passed diskslices and related diskslice structures may 322 * be invalidated or replaced by this function, callers must 323 * reload from the disk structure for continued access. 324 */ 325 void 326 dsclose(cdev_t dev, int mode, struct diskslices *ssp) 327 { 328 u_int32_t part; 329 u_int32_t slice; 330 struct diskslice *sp; 331 332 slice = dkslice(dev); 333 part = dkpart(dev); 334 if (slice < ssp->dss_nslices) { 335 sp = &ssp->dss_slices[slice]; 336 dsclrmask(sp, part); 337 if (sp->ds_flags & DSF_REPROBE) { 338 sp->ds_flags &= ~DSF_REPROBE; 339 if (slice == WHOLE_DISK_SLICE) { 340 disk_msg_send_sync(DISK_DISK_REPROBE, 341 dev->si_disk, NULL); 342 devfs_config(); 343 } else { 344 disk_msg_send_sync(DISK_SLICE_REPROBE, 345 dev->si_disk, sp); 346 devfs_config(); 347 } 348 /* ssp and sp may both be invalid after reprobe */ 349 } 350 } 351 } 352 353 void 354 dsgone(struct diskslices **sspp) 355 { 356 int slice; 357 struct diskslice *sp; 358 struct diskslices *ssp; 359 360 if ((ssp = *sspp) != NULL) { 361 for (slice = 0; slice < ssp->dss_nslices; slice++) { 362 sp = &ssp->dss_slices[slice]; 363 free_ds_label(ssp, slice); 364 } 365 kfree(ssp, M_DEVBUF); 366 *sspp = NULL; 367 } 368 } 369 370 /* 371 * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this 372 * is subject to the same restriction as dsopen(). 373 */ 374 int 375 dsioctl(cdev_t dev, u_long cmd, caddr_t data, int flags, 376 struct diskslices **sspp, struct disk_info *info) 377 { 378 int error; 379 disklabel_t lp; 380 disklabel_t lptmp; 381 disklabel_ops_t ops; 382 int old_wlabel; 383 u_int32_t openmask[DKMAXPARTITIONS/(sizeof(u_int32_t)*8)]; 384 int part; 385 int slice; 386 struct diskslice *sp; 387 struct diskslices *ssp; 388 389 slice = dkslice(dev); 390 part = dkpart(dev); 391 ssp = *sspp; 392 if (ssp == NULL) 393 return (EINVAL); 394 if (slice >= ssp->dss_nslices) 395 return (EINVAL); 396 sp = &ssp->dss_slices[slice]; 397 lp = sp->ds_label; 398 ops = sp->ds_ops; /* may be NULL if no label */ 399 400 switch (cmd) { 401 case DIOCGDVIRGIN32: 402 ops = &disklabel32_ops; 403 /* fall through */ 404 case DIOCGDVIRGIN64: 405 if (cmd != DIOCGDVIRGIN32) 406 ops = &disklabel64_ops; 407 /* 408 * You can only retrieve a virgin disklabel on the whole 409 * disk slice or whole-slice partition. 410 */ 411 if (slice != WHOLE_DISK_SLICE && 412 part != WHOLE_SLICE_PART) { 413 return(EINVAL); 414 } 415 416 lp.opaque = data; 417 ops->op_makevirginlabel(lp, ssp, sp, info); 418 return (0); 419 420 case DIOCGDINFO32: 421 case DIOCGDINFO64: 422 /* 423 * You can only retrieve a disklabel on the whole 424 * slice partition. 425 * 426 * We do not support labels directly on whole-disks 427 * any more (that is, disks without slices), unless the 428 * device driver has asked for a compatible label (e.g. 429 * for a CD) to allow booting off of storage that is 430 * otherwise unlabeled. 431 */ 432 error = 0; 433 if (part != WHOLE_SLICE_PART) 434 return(EINVAL); 435 if (slice == WHOLE_DISK_SLICE && 436 (info->d_dsflags & DSO_COMPATLABEL) == 0) { 437 return (ENODEV); 438 } 439 if (sp->ds_label.opaque == NULL) { 440 error = dsreadandsetlabel(dev, info->d_dsflags, 441 ssp, sp, info); 442 ops = sp->ds_ops; /* may be NULL */ 443 } 444 445 /* 446 * The type of label we found must match the type of 447 * label requested. 448 */ 449 if (error == 0 && IOCPARM_LEN(cmd) != ops->labelsize) 450 error = ENOATTR; 451 if (error == 0) 452 bcopy(sp->ds_label.opaque, data, ops->labelsize); 453 return (error); 454 455 case DIOCGPART: 456 { 457 struct partinfo *dpart = (void *)data; 458 459 /* 460 * The disk management layer may not have read the 461 * disklabel yet because simply opening a slice no 462 * longer 'probes' the disk that way. Be sure we 463 * have tried. 464 * 465 * We ignore any error. 466 */ 467 if (sp->ds_label.opaque == NULL && 468 part == WHOLE_SLICE_PART && 469 slice != WHOLE_DISK_SLICE) { 470 dsreadandsetlabel(dev, info->d_dsflags, 471 ssp, sp, info); 472 ops = sp->ds_ops; /* may be NULL */ 473 } 474 475 bzero(dpart, sizeof(*dpart)); 476 dpart->media_offset = (u_int64_t)sp->ds_offset * 477 info->d_media_blksize; 478 dpart->media_size = (u_int64_t)sp->ds_size * 479 info->d_media_blksize; 480 dpart->media_blocks = sp->ds_size; 481 dpart->media_blksize = info->d_media_blksize; 482 dpart->reserved_blocks= sp->ds_reserved; 483 dpart->fstype_uuid = sp->ds_type_uuid; 484 dpart->storage_uuid = sp->ds_stor_uuid; 485 486 if (slice != WHOLE_DISK_SLICE && 487 part != WHOLE_SLICE_PART) { 488 u_int64_t start; 489 u_int64_t blocks; 490 if (lp.opaque == NULL) 491 return(EINVAL); 492 if (ops->op_getpartbounds(ssp, lp, part, 493 &start, &blocks)) { 494 return(EINVAL); 495 } 496 ops->op_loadpartinfo(lp, part, dpart); 497 dpart->media_offset += start * 498 info->d_media_blksize; 499 dpart->media_size = blocks * 500 info->d_media_blksize; 501 dpart->media_blocks = blocks; 502 503 /* 504 * partition starting sector (p_offset) 505 * requires slice's reserved areas to be 506 * adjusted. 507 */ 508 if (dpart->reserved_blocks > start) 509 dpart->reserved_blocks -= start; 510 else 511 dpart->reserved_blocks = 0; 512 } 513 514 /* 515 * Load remaining fields from the info structure 516 */ 517 dpart->d_nheads = info->d_nheads; 518 dpart->d_ncylinders = info->d_ncylinders; 519 dpart->d_secpertrack = info->d_secpertrack; 520 dpart->d_secpercyl = info->d_secpercyl; 521 } 522 return (0); 523 524 case DIOCGSLICEINFO: 525 bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] - 526 (char *)ssp); 527 return (0); 528 529 case DIOCSDINFO32: 530 ops = &disklabel32_ops; 531 /* fall through */ 532 case DIOCSDINFO64: 533 if (cmd != DIOCSDINFO32) 534 ops = &disklabel64_ops; 535 /* 536 * You can write a disklabel on the whole disk slice or 537 * whole-slice partition. 538 */ 539 if (slice != WHOLE_DISK_SLICE && 540 part != WHOLE_SLICE_PART) { 541 return(EINVAL); 542 } 543 544 /* 545 * We no longer support writing disklabels directly to media 546 * without there being a slice. Keep this as a separate 547 * conditional. 548 */ 549 if (slice == WHOLE_DISK_SLICE) 550 return (ENODEV); 551 if (!(flags & FWRITE)) 552 return (EBADF); 553 554 /* 555 * If an existing label is present it must be the same 556 * type as the label being passed by the ioctl. 557 */ 558 if (sp->ds_label.opaque && sp->ds_ops != ops) 559 return (ENOATTR); 560 561 /* 562 * Create a temporary copy of the existing label 563 * (if present) so setdisklabel can compare it against 564 * the new label. 565 */ 566 lp.opaque = kmalloc(ops->labelsize, M_DEVBUF, M_WAITOK); 567 if (sp->ds_label.opaque == NULL) 568 bzero(lp.opaque, ops->labelsize); 569 else 570 bcopy(sp->ds_label.opaque, lp.opaque, ops->labelsize); 571 if (sp->ds_label.opaque == NULL) { 572 bzero(openmask, sizeof(openmask)); 573 } else { 574 bcopy(sp->ds_openmask, openmask, sizeof(openmask)); 575 } 576 lptmp.opaque = data; 577 error = ops->op_setdisklabel(lp, lptmp, ssp, sp, openmask); 578 disk_msg_send_sync(DISK_SLICE_REPROBE, dev->si_disk, sp); 579 devfs_config(); 580 if (error != 0) { 581 kfree(lp.opaque, M_DEVBUF); 582 return (error); 583 } 584 free_ds_label(ssp, slice); 585 set_ds_label(ssp, slice, lp, ops); 586 return (0); 587 588 case DIOCSYNCSLICEINFO: 589 /* 590 * This ioctl can only be done on the whole disk 591 */ 592 if (slice != WHOLE_DISK_SLICE || part != WHOLE_SLICE_PART) 593 return (EINVAL); 594 595 if (*(int *)data == 0) { 596 for (slice = 0; slice < ssp->dss_nslices; slice++) { 597 struct diskslice *ds = &ssp->dss_slices[slice]; 598 599 switch(dscountmask(ds)) { 600 case 0: 601 break; 602 case 1: 603 if (slice != WHOLE_DISK_SLICE) 604 return (EBUSY); 605 if (!dschkmask(ds, RAW_PART)) 606 return (EBUSY); 607 break; 608 default: 609 return (EBUSY); 610 } 611 } 612 } 613 614 disk_msg_send_sync(DISK_DISK_REPROBE, dev->si_disk, NULL); 615 devfs_config(); 616 return 0; 617 618 case DIOCWDINFO32: 619 case DIOCWDINFO64: 620 error = dsioctl(dev, ((cmd == DIOCWDINFO32) ? 621 DIOCSDINFO32 : DIOCSDINFO64), 622 data, flags, &ssp, info); 623 if (error == 0 && sp->ds_label.opaque == NULL) 624 error = EINVAL; 625 if (part != WHOLE_SLICE_PART) 626 error = EINVAL; 627 if (error != 0) 628 return (error); 629 630 /* 631 * Allow the reserved area to be written, reload ops 632 * because the DIOCSDINFO op above may have installed 633 * a new label type. 634 */ 635 ops = sp->ds_ops; 636 old_wlabel = sp->ds_wlabel; 637 set_ds_wlabel(ssp, slice, TRUE); 638 error = ops->op_writedisklabel(dev, ssp, sp, sp->ds_label); 639 disk_msg_send_sync(DISK_SLICE_REPROBE, dev->si_disk, sp); 640 devfs_config(); 641 set_ds_wlabel(ssp, slice, old_wlabel); 642 /* XXX should invalidate in-core label if write failed. */ 643 return (error); 644 645 case DIOCWLABEL: 646 if (slice == WHOLE_DISK_SLICE) 647 return (ENODEV); 648 if (!(flags & FWRITE)) 649 return (EBADF); 650 set_ds_wlabel(ssp, slice, *(int *)data != 0); 651 return (0); 652 653 default: 654 return (ENOIOCTL); 655 } 656 } 657 658 int 659 dsisopen(struct diskslices *ssp) 660 { 661 int slice; 662 663 if (ssp == NULL) 664 return (0); 665 for (slice = 0; slice < ssp->dss_nslices; slice++) { 666 if (dscountmask(&ssp->dss_slices[slice])) 667 return (1); 668 } 669 return (0); 670 } 671 672 /* 673 * Allocate a slices "struct" and initialize it to contain only an empty 674 * compatibility slice (pointing to itself), a whole disk slice (covering 675 * the disk as described by the label), and (nslices - BASE_SLICES) empty 676 * slices beginning at BASE_SLICE. 677 * 678 * Note that the compatibility slice is no longer really a compatibility 679 * slice. It is slice 0 if a GPT label is present, and the dangerously 680 * dedicated slice if no slice table otherwise exists. Else it is 0-sized. 681 */ 682 struct diskslices * 683 dsmakeslicestruct(int nslices, struct disk_info *info) 684 { 685 struct diskslice *sp; 686 struct diskslices *ssp; 687 688 ssp = kmalloc(offsetof(struct diskslices, dss_slices) + 689 nslices * sizeof *sp, M_DEVBUF, M_WAITOK); 690 ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE; 691 ssp->dss_nslices = nslices; 692 ssp->dss_oflags = 0; 693 694 /* 695 * Figure out if we can use shifts or whether we have to 696 * use mod/multply to translate byte offsets into sector numbers. 697 */ 698 if ((info->d_media_blksize ^ (info->d_media_blksize - 1)) == 699 (info->d_media_blksize << 1) - 1) { 700 ssp->dss_secmult = info->d_media_blksize / DEV_BSIZE; 701 if (ssp->dss_secmult & (ssp->dss_secmult - 1)) 702 ssp->dss_secshift = -1; 703 else 704 ssp->dss_secshift = ffs(ssp->dss_secmult) - 1; 705 } else { 706 ssp->dss_secmult = 0; 707 ssp->dss_secshift = -1; 708 } 709 ssp->dss_secsize = info->d_media_blksize; 710 sp = &ssp->dss_slices[0]; 711 bzero(sp, nslices * sizeof *sp); 712 sp[WHOLE_DISK_SLICE].ds_size = info->d_media_blocks; 713 return (ssp); 714 } 715 716 char * 717 dsname(cdev_t dev, int unit, int slice, int part, char *partname) 718 { 719 return dev->si_name; 720 } 721 722 /* 723 * This should only be called when the unit is inactive and the strategy 724 * routine should not allow it to become active unless we call it. Our 725 * strategy routine must be special to allow activity. 726 */ 727 int 728 dsopen(cdev_t dev, int mode, u_int flags, 729 struct diskslices **sspp, struct disk_info *info) 730 { 731 struct diskslice *sp; 732 struct diskslices *ssp; 733 int slice; 734 int part; 735 736 ssp = *sspp; 737 dev->si_bsize_phys = info->d_media_blksize; 738 slice = dkslice(dev); 739 part = dkpart(dev); 740 sp = &ssp->dss_slices[slice]; 741 dssetmask(sp, part); 742 743 return 0; 744 } 745 746 /* 747 * Attempt to read the disklabel. If successful, store it in sp->ds_label. 748 * 749 * If we cannot read the disklabel and DSO_COMPATLABEL is set, we construct 750 * a fake label covering the whole disk. 751 */ 752 static 753 int 754 dsreadandsetlabel(cdev_t dev, u_int flags, 755 struct diskslices *ssp, struct diskslice *sp, 756 struct disk_info *info) 757 { 758 disklabel_t lp; 759 disklabel_ops_t ops; 760 const char *msg; 761 const char *sname; 762 char partname[2]; 763 int slice = dkslice(dev); 764 765 /* 766 * Probe the disklabel 767 */ 768 lp.opaque = NULL; 769 sname = dsname(dev, dkunit(dev), slice, WHOLE_SLICE_PART, partname); 770 ops = &disklabel32_ops; 771 msg = ops->op_readdisklabel(dev, sp, &lp, info); 772 if (msg && strcmp(msg, "no disk label") == 0) { 773 ops = &disklabel64_ops; 774 msg = disklabel64_ops.op_readdisklabel(dev, sp, &lp, info); 775 } 776 777 /* 778 * If we failed and COMPATLABEL is set, create a dummy disklabel. 779 */ 780 if (msg != NULL && (flags & DSO_COMPATLABEL)) { 781 msg = NULL; 782 if (sp->ds_size >= 0x100000000ULL) 783 ops = &disklabel64_ops; 784 else 785 ops = &disklabel32_ops; 786 lp = ops->op_clone_label(info, sp); 787 } 788 if (msg != NULL) { 789 if (sp->ds_type == DOSPTYP_386BSD /* XXX */) 790 log(LOG_WARNING, "%s: cannot find label (%s)\n", 791 sname, msg); 792 if (lp.opaque) 793 kfree(lp.opaque, M_DEVBUF); 794 } else { 795 set_ds_label(ssp, slice, lp, ops); 796 set_ds_wlabel(ssp, slice, FALSE); 797 } 798 return (msg ? EINVAL : 0); 799 } 800 801 int64_t 802 dssize(cdev_t dev, struct diskslices **sspp) 803 { 804 disklabel_t lp; 805 disklabel_ops_t ops; 806 int part; 807 int slice; 808 struct diskslices *ssp; 809 u_int64_t start; 810 u_int64_t blocks; 811 812 slice = dkslice(dev); 813 part = dkpart(dev); 814 ssp = *sspp; 815 if (ssp == NULL || slice >= ssp->dss_nslices 816 || !dschkmask(&ssp->dss_slices[slice], part)) { 817 if (dev_dopen(dev, FREAD, S_IFCHR, proc0.p_ucred) != 0) 818 return (-1); 819 dev_dclose(dev, FREAD, S_IFCHR); 820 ssp = *sspp; 821 } 822 lp = ssp->dss_slices[slice].ds_label; 823 if (lp.opaque == NULL) 824 return (-1); 825 ops = ssp->dss_slices[slice].ds_ops; 826 if (ops->op_getpartbounds(ssp, lp, part, &start, &blocks)) 827 return (-1); 828 return ((int64_t)blocks); 829 } 830 831 static void 832 free_ds_label(struct diskslices *ssp, int slice) 833 { 834 struct diskslice *sp; 835 disklabel_t lp; 836 837 sp = &ssp->dss_slices[slice]; 838 lp = sp->ds_label; 839 if (lp.opaque != NULL) { 840 kfree(lp.opaque, M_DEVBUF); 841 lp.opaque = NULL; 842 set_ds_label(ssp, slice, lp, NULL); 843 } 844 } 845 846 static void 847 set_ds_label(struct diskslices *ssp, int slice, 848 disklabel_t lp, disklabel_ops_t ops) 849 { 850 struct diskslice *sp = &ssp->dss_slices[slice]; 851 852 sp->ds_label = lp; 853 sp->ds_ops = ops; 854 if (lp.opaque && slice != WHOLE_DISK_SLICE) 855 ops->op_adjust_label_reserved(ssp, slice, sp); 856 else 857 sp->ds_reserved = 0; 858 } 859 860 static void 861 set_ds_wlabel(struct diskslices *ssp, int slice, int wlabel) 862 { 863 ssp->dss_slices[slice].ds_wlabel = wlabel; 864 } 865 866