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 * Calculate secno and nsec 128 */ 129 if (ssp->dss_secmult == 1) { 130 shift = DEV_BSHIFT; 131 goto doshift; 132 } else if (ssp->dss_secshift != -1) { 133 shift = DEV_BSHIFT + ssp->dss_secshift; 134 doshift: 135 mask = (1 << shift) - 1; 136 if ((int)bp->b_bcount & mask) 137 goto bad_bcount; 138 if ((int)bio->bio_offset & mask) 139 goto bad_blkno; 140 secno = bio->bio_offset >> shift; 141 nsec = bp->b_bcount >> shift; 142 } else { 143 if (bp->b_bcount % ssp->dss_secsize) 144 goto bad_bcount; 145 if (bio->bio_offset % ssp->dss_secsize) 146 goto bad_blkno; 147 secno = bio->bio_offset / ssp->dss_secsize; 148 nsec = bp->b_bcount / ssp->dss_secsize; 149 } 150 151 /* 152 * Calculate slice-relative sector number end slice-relative 153 * limit. 154 */ 155 if (slice == WHOLE_DISK_SLICE) { 156 /* 157 * Labels have not been allowed on whole-disks for a while. 158 * This really puts the nail in the coffin. 159 * 160 * Accesses to the WHOLE_DISK_SLICE do not use a disklabel 161 * and partition numbers are special-cased. Currently numbers 162 * less then 128 are not allowed. Partition numbers >= 128 163 * are encoded in the high 8 bits of the 64 bit buffer offset 164 * and are fed directly through to the device with no 165 * further interpretation. In particular, no sector 166 * translation interpretation should occur because the 167 * sector size for the special raw access may not be the 168 * same as the nominal sector size for the device. 169 */ 170 lp.opaque = NULL; 171 if (part < 128) { 172 kprintf("dscheck(%s): illegal partition number (%d) " 173 "for WHOLE_DISK_SLICE access\n", 174 devtoname(dev), part); 175 goto bad; 176 } else if (part != WHOLE_SLICE_PART) { 177 nbio = push_bio(bio); 178 nbio->bio_offset = bio->bio_offset | 179 (u_int64_t)part << 56; 180 return(nbio); 181 } else { 182 /* 183 * If writing to the raw disk request a 184 * reprobe on the last close. 185 */ 186 if (bp->b_cmd == BUF_CMD_WRITE) 187 sp->ds_flags |= DSF_REPROBE; 188 } 189 190 /* 191 * sp->ds_size is for the whole disk in the WHOLE_DISK_SLICE, 192 * there are no reserved areas. 193 */ 194 endsecno = sp->ds_size; 195 slicerel_secno = secno; 196 } else if (part == WHOLE_SLICE_PART) { 197 /* 198 * NOTE! opens on a whole-slice partition will not attempt 199 * to read a disklabel in, so there may not be an in-core 200 * disklabel even if there is one on the disk. 201 */ 202 endsecno = sp->ds_size; 203 slicerel_secno = secno; 204 } else if ((lp = sp->ds_label).opaque != NULL) { 205 /* 206 * A label is present, extract the partition. Snooping of 207 * the disklabel is not supported even if accessible. Of 208 * course, the reserved area is still write protected. 209 */ 210 ops = sp->ds_ops; 211 if (ops->op_getpartbounds(ssp, lp, part, 212 &slicerel_secno, &endsecno)) { 213 kprintf("dscheck(%s): partition %d out of bounds\n", 214 devtoname(dev), part); 215 goto bad; 216 } 217 slicerel_secno += secno; 218 } else { 219 /* 220 * Attempt to access partition when no disklabel present 221 */ 222 kprintf("dscheck(%s): attempt to access non-existent partition\n", 223 devtoname(dev)); 224 goto bad; 225 } 226 227 /* 228 * Disallow writes to reserved areas unless ds_wlabel allows it. 229 * If the reserved area is written to request a reprobe of the 230 * disklabel when the slice is closed. 231 */ 232 if (slicerel_secno < sp->ds_reserved && nsec && 233 bp->b_cmd == BUF_CMD_WRITE) { 234 if (sp->ds_wlabel == 0) { 235 bp->b_error = EROFS; 236 goto error; 237 } 238 sp->ds_flags |= DSF_REPROBE; 239 } 240 241 /* 242 * If we get here, bio_offset must be on a block boundary and 243 * the sector size must be a power of 2. 244 */ 245 if ((bio->bio_offset & (ssp->dss_secsize - 1)) || 246 (ssp->dss_secsize ^ (ssp->dss_secsize - 1)) != 247 ((ssp->dss_secsize << 1) - 1)) { 248 kprintf("%s: invalid BIO offset, not sector aligned or" 249 " invalid sector size (not power of 2) %08llx %d\n", 250 devtoname(dev), (long long)bio->bio_offset, 251 ssp->dss_secsize); 252 goto bad; 253 } 254 255 /* 256 * EOF handling 257 */ 258 if (secno + nsec > endsecno) { 259 /* 260 * Return an error if beyond the end of the disk, or 261 * if B_BNOCLIP is set. Tell the system that we do not 262 * need to keep the buffer around. 263 */ 264 if (secno > endsecno || (bp->b_flags & B_BNOCLIP)) 265 goto bad; 266 267 /* 268 * If exactly at end of disk, return an EOF. Throw away 269 * the buffer contents, if any, by setting B_INVAL. 270 */ 271 if (secno == endsecno) { 272 bp->b_resid = bp->b_bcount; 273 bp->b_flags |= B_INVAL; 274 goto done; 275 } 276 277 /* 278 * Else truncate 279 */ 280 nsec = endsecno - secno; 281 bp->b_bcount = nsec * ssp->dss_secsize; 282 } 283 284 nbio = push_bio(bio); 285 nbio->bio_offset = (off_t)(sp->ds_offset + slicerel_secno) * 286 ssp->dss_secsize; 287 return (nbio); 288 289 bad_bcount: 290 kprintf( 291 "dscheck(%s): b_bcount %d is not on a sector boundary (ssize %d)\n", 292 devtoname(dev), bp->b_bcount, ssp->dss_secsize); 293 goto bad; 294 295 bad_blkno: 296 kprintf( 297 "dscheck(%s): bio_offset %lld is not on a sector boundary (ssize %d)\n", 298 devtoname(dev), (long long)bio->bio_offset, ssp->dss_secsize); 299 bad: 300 bp->b_error = EINVAL; 301 /* fall through */ 302 error: 303 /* 304 * Terminate the I/O with a ranging error. Since the buffer is 305 * either illegal or beyond the file EOF, mark it B_INVAL as well. 306 */ 307 bp->b_resid = bp->b_bcount; 308 bp->b_flags |= B_ERROR | B_INVAL; 309 done: 310 /* 311 * Caller must biodone() the originally passed bio if NULL is 312 * returned. 313 */ 314 return (NULL); 315 } 316 317 /* 318 * dsclose() - close a cooked disk slice. 319 * 320 * WARNING! The passed diskslices and related diskslice structures may 321 * be invalidated or replaced by this function, callers must 322 * reload from the disk structure for continued access. 323 */ 324 void 325 dsclose(cdev_t dev, int mode, struct diskslices *ssp) 326 { 327 u_int32_t part; 328 u_int32_t slice; 329 struct diskslice *sp; 330 331 slice = dkslice(dev); 332 part = dkpart(dev); 333 if (slice < ssp->dss_nslices) { 334 sp = &ssp->dss_slices[slice]; 335 dsclrmask(sp, part); 336 if (sp->ds_flags & DSF_REPROBE) { 337 sp->ds_flags &= ~DSF_REPROBE; 338 if (slice == WHOLE_DISK_SLICE) { 339 disk_msg_send_sync(DISK_DISK_REPROBE, 340 dev->si_disk, NULL); 341 } else { 342 disk_msg_send_sync(DISK_SLICE_REPROBE, 343 dev->si_disk, sp); 344 } 345 /* ssp and sp may both be invalid after reprobe */ 346 } 347 } 348 } 349 350 void 351 dsgone(struct diskslices **sspp) 352 { 353 int slice; 354 struct diskslice *sp; 355 struct diskslices *ssp; 356 357 kprintf("dsgone is called... fear!\n"); 358 359 for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) { 360 sp = &ssp->dss_slices[slice]; 361 free_ds_label(ssp, slice); 362 } 363 kfree(ssp, M_DEVBUF); 364 *sspp = NULL; 365 } 366 367 /* 368 * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this 369 * is subject to the same restriction as dsopen(). 370 */ 371 int 372 dsioctl(cdev_t dev, u_long cmd, caddr_t data, int flags, 373 struct diskslices **sspp, struct disk_info *info) 374 { 375 int error; 376 disklabel_t lp; 377 disklabel_t lptmp; 378 disklabel_ops_t ops; 379 int old_wlabel; 380 u_int32_t openmask[DKMAXPARTITIONS/(sizeof(u_int32_t)*8)]; 381 int part; 382 int slice; 383 struct diskslice *sp; 384 struct diskslices *ssp; 385 386 slice = dkslice(dev); 387 part = dkpart(dev); 388 ssp = *sspp; 389 if (slice >= ssp->dss_nslices) 390 return (EINVAL); 391 sp = &ssp->dss_slices[slice]; 392 lp = sp->ds_label; 393 ops = sp->ds_ops; /* may be NULL if no label */ 394 395 switch (cmd) { 396 case DIOCGDVIRGIN32: 397 ops = &disklabel32_ops; 398 /* fall through */ 399 case DIOCGDVIRGIN64: 400 if (cmd != DIOCGDVIRGIN32) 401 ops = &disklabel64_ops; 402 /* 403 * You can only retrieve a virgin disklabel on the whole 404 * disk slice or whole-slice partition. 405 */ 406 if (slice != WHOLE_DISK_SLICE && 407 part != WHOLE_SLICE_PART) { 408 return(EINVAL); 409 } 410 411 lp.opaque = data; 412 ops->op_makevirginlabel(lp, ssp, sp, info); 413 return (0); 414 415 case DIOCGDINFO32: 416 case DIOCGDINFO64: 417 /* 418 * You can only retrieve a disklabel on the whole 419 * slice partition. 420 * 421 * We do not support labels directly on whole-disks 422 * any more (that is, disks without slices), unless the 423 * device driver has asked for a compatible label (e.g. 424 * for a CD) to allow booting off of storage that is 425 * otherwise unlabeled. 426 */ 427 error = 0; 428 if (part != WHOLE_SLICE_PART) 429 return(EINVAL); 430 if (slice == WHOLE_DISK_SLICE && 431 (info->d_dsflags & DSO_COMPATLABEL) == 0) { 432 return (ENODEV); 433 } 434 if (sp->ds_label.opaque == NULL) { 435 error = dsreadandsetlabel(dev, info->d_dsflags, 436 ssp, sp, info); 437 ops = sp->ds_ops; /* may be NULL */ 438 } 439 440 /* 441 * The type of label we found must match the type of 442 * label requested. 443 */ 444 if (error == 0 && IOCPARM_LEN(cmd) != ops->labelsize) 445 error = ENOATTR; 446 if (error == 0) 447 bcopy(sp->ds_label.opaque, data, ops->labelsize); 448 return (error); 449 450 case DIOCGPART: 451 { 452 struct partinfo *dpart = (void *)data; 453 454 /* 455 * The disk management layer may not have read the 456 * disklabel yet because simply opening a slice no 457 * longer 'probes' the disk that way. Be sure we 458 * have tried. 459 * 460 * We ignore any error. 461 */ 462 if (sp->ds_label.opaque == NULL && 463 part == WHOLE_SLICE_PART && 464 slice != WHOLE_DISK_SLICE) { 465 dsreadandsetlabel(dev, info->d_dsflags, 466 ssp, sp, info); 467 ops = sp->ds_ops; /* may be NULL */ 468 } 469 470 bzero(dpart, sizeof(*dpart)); 471 dpart->media_offset = (u_int64_t)sp->ds_offset * 472 info->d_media_blksize; 473 dpart->media_size = (u_int64_t)sp->ds_size * 474 info->d_media_blksize; 475 dpart->media_blocks = sp->ds_size; 476 dpart->media_blksize = info->d_media_blksize; 477 dpart->reserved_blocks= sp->ds_reserved; 478 dpart->fstype_uuid = sp->ds_type_uuid; 479 dpart->storage_uuid = sp->ds_stor_uuid; 480 481 if (slice != WHOLE_DISK_SLICE && 482 part != WHOLE_SLICE_PART) { 483 u_int64_t start; 484 u_int64_t blocks; 485 if (lp.opaque == NULL) 486 return(EINVAL); 487 if (ops->op_getpartbounds(ssp, lp, part, 488 &start, &blocks)) { 489 return(EINVAL); 490 } 491 ops->op_loadpartinfo(lp, part, dpart); 492 dpart->media_offset += start * 493 info->d_media_blksize; 494 dpart->media_size = blocks * 495 info->d_media_blksize; 496 dpart->media_blocks = blocks; 497 498 /* 499 * partition starting sector (p_offset) 500 * requires slice's reserved areas to be 501 * adjusted. 502 */ 503 if (dpart->reserved_blocks > start) 504 dpart->reserved_blocks -= start; 505 else 506 dpart->reserved_blocks = 0; 507 } 508 509 /* 510 * Load remaining fields from the info structure 511 */ 512 dpart->d_nheads = info->d_nheads; 513 dpart->d_ncylinders = info->d_ncylinders; 514 dpart->d_secpertrack = info->d_secpertrack; 515 dpart->d_secpercyl = info->d_secpercyl; 516 } 517 return (0); 518 519 case DIOCGSLICEINFO: 520 bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] - 521 (char *)ssp); 522 return (0); 523 524 case DIOCSDINFO32: 525 ops = &disklabel32_ops; 526 /* fall through */ 527 case DIOCSDINFO64: 528 if (cmd != DIOCSDINFO32) 529 ops = &disklabel64_ops; 530 /* 531 * You can write a disklabel on the whole disk slice or 532 * whole-slice partition. 533 */ 534 if (slice != WHOLE_DISK_SLICE && 535 part != WHOLE_SLICE_PART) { 536 return(EINVAL); 537 } 538 539 /* 540 * We no longer support writing disklabels directly to media 541 * without there being a slice. Keep this as a separate 542 * conditional. 543 */ 544 if (slice == WHOLE_DISK_SLICE) 545 return (ENODEV); 546 if (!(flags & FWRITE)) 547 return (EBADF); 548 549 /* 550 * If an existing label is present it must be the same 551 * type as the label being passed by the ioctl. 552 */ 553 if (sp->ds_label.opaque && sp->ds_ops != ops) 554 return (ENOATTR); 555 556 /* 557 * Create a temporary copy of the existing label 558 * (if present) so setdisklabel can compare it against 559 * the new label. 560 */ 561 lp.opaque = kmalloc(ops->labelsize, M_DEVBUF, M_WAITOK); 562 if (sp->ds_label.opaque == NULL) 563 bzero(lp.opaque, ops->labelsize); 564 else 565 bcopy(sp->ds_label.opaque, lp.opaque, ops->labelsize); 566 if (sp->ds_label.opaque == NULL) { 567 bzero(openmask, sizeof(openmask)); 568 } else { 569 bcopy(sp->ds_openmask, openmask, sizeof(openmask)); 570 } 571 lptmp.opaque = data; 572 error = ops->op_setdisklabel(lp, lptmp, ssp, sp, openmask); 573 disk_msg_send_sync(DISK_SLICE_REPROBE, dev->si_disk, sp); 574 if (error != 0) { 575 kfree(lp.opaque, M_DEVBUF); 576 return (error); 577 } 578 free_ds_label(ssp, slice); 579 set_ds_label(ssp, slice, lp, ops); 580 return (0); 581 582 case DIOCSYNCSLICEINFO: 583 /* 584 * This ioctl can only be done on the whole disk 585 */ 586 if (slice != WHOLE_DISK_SLICE || part != WHOLE_SLICE_PART) 587 return (EINVAL); 588 589 if (*(int *)data == 0) { 590 for (slice = 0; slice < ssp->dss_nslices; slice++) { 591 struct diskslice *ds = &ssp->dss_slices[slice]; 592 593 switch(dscountmask(ds)) { 594 case 0: 595 break; 596 case 1: 597 if (slice != WHOLE_DISK_SLICE) 598 return (EBUSY); 599 if (!dschkmask(ds, RAW_PART)) 600 return (EBUSY); 601 break; 602 default: 603 return (EBUSY); 604 } 605 } 606 } 607 608 disk_msg_send_sync(DISK_DISK_REPROBE, dev->si_disk, NULL); 609 return 0; 610 611 case DIOCWDINFO32: 612 case DIOCWDINFO64: 613 error = dsioctl(dev, ((cmd == DIOCWDINFO32) ? 614 DIOCSDINFO32 : DIOCSDINFO64), 615 data, flags, &ssp, info); 616 if (error == 0 && sp->ds_label.opaque == NULL) 617 error = EINVAL; 618 if (part != WHOLE_SLICE_PART) 619 error = EINVAL; 620 if (error != 0) 621 return (error); 622 623 /* 624 * Allow the reserved area to be written, reload ops 625 * because the DIOCSDINFO op above may have installed 626 * a new label type. 627 */ 628 ops = sp->ds_ops; 629 old_wlabel = sp->ds_wlabel; 630 set_ds_wlabel(ssp, slice, TRUE); 631 error = ops->op_writedisklabel(dev, ssp, sp, sp->ds_label); 632 disk_msg_send_sync(DISK_SLICE_REPROBE, dev->si_disk, sp); 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 return dev->si_name; 712 } 713 714 /* 715 * This should only be called when the unit is inactive and the strategy 716 * routine should not allow it to become active unless we call it. Our 717 * strategy routine must be special to allow activity. 718 */ 719 int 720 dsopen(cdev_t dev, int mode, u_int flags, 721 struct diskslices **sspp, struct disk_info *info) 722 { 723 struct diskslice *sp; 724 struct diskslices *ssp; 725 int slice; 726 int part; 727 728 ssp = *sspp; 729 dev->si_bsize_phys = info->d_media_blksize; 730 slice = dkslice(dev); 731 part = dkpart(dev); 732 sp = &ssp->dss_slices[slice]; 733 dssetmask(sp, part); 734 735 return 0; 736 } 737 738 /* 739 * Attempt to read the disklabel. If successful, store it in sp->ds_label. 740 * 741 * If we cannot read the disklabel and DSO_COMPATLABEL is set, we construct 742 * a fake label covering the whole disk. 743 */ 744 static 745 int 746 dsreadandsetlabel(cdev_t dev, u_int flags, 747 struct diskslices *ssp, struct diskslice *sp, 748 struct disk_info *info) 749 { 750 disklabel_t lp; 751 disklabel_ops_t ops; 752 const char *msg; 753 const char *sname; 754 char partname[2]; 755 int slice = dkslice(dev); 756 757 /* 758 * Probe the disklabel 759 */ 760 lp.opaque = NULL; 761 sname = dsname(dev, dkunit(dev), slice, WHOLE_SLICE_PART, partname); 762 ops = &disklabel32_ops; 763 msg = ops->op_readdisklabel(dev, sp, &lp, info); 764 if (msg && strcmp(msg, "no disk label") == 0) { 765 ops = &disklabel64_ops; 766 msg = disklabel64_ops.op_readdisklabel(dev, sp, &lp, info); 767 } 768 769 /* 770 * If we failed and COMPATLABEL is set, create a dummy disklabel. 771 */ 772 if (msg != NULL && (flags & DSO_COMPATLABEL)) { 773 msg = NULL; 774 if (sp->ds_size >= 0x100000000ULL) 775 ops = &disklabel64_ops; 776 else 777 ops = &disklabel32_ops; 778 lp = ops->op_clone_label(info, sp); 779 } 780 if (msg != NULL) { 781 if (sp->ds_type == DOSPTYP_386BSD /* XXX */) 782 log(LOG_WARNING, "%s: cannot find label (%s)\n", 783 sname, msg); 784 if (lp.opaque) 785 kfree(lp.opaque, M_DEVBUF); 786 } else { 787 set_ds_label(ssp, slice, lp, ops); 788 set_ds_wlabel(ssp, slice, FALSE); 789 } 790 return (msg ? EINVAL : 0); 791 } 792 793 int64_t 794 dssize(cdev_t dev, struct diskslices **sspp) 795 { 796 disklabel_t lp; 797 disklabel_ops_t ops; 798 int part; 799 int slice; 800 struct diskslices *ssp; 801 u_int64_t start; 802 u_int64_t blocks; 803 804 slice = dkslice(dev); 805 part = dkpart(dev); 806 ssp = *sspp; 807 if (ssp == NULL || slice >= ssp->dss_nslices 808 || !dschkmask(&ssp->dss_slices[slice], part)) { 809 if (dev_dopen(dev, FREAD, S_IFCHR, proc0.p_ucred) != 0) 810 return (-1); 811 dev_dclose(dev, FREAD, S_IFCHR); 812 ssp = *sspp; 813 } 814 lp = ssp->dss_slices[slice].ds_label; 815 if (lp.opaque == NULL) 816 return (-1); 817 ops = ssp->dss_slices[slice].ds_ops; 818 if (ops->op_getpartbounds(ssp, lp, part, &start, &blocks)) 819 return (-1); 820 return ((int64_t)blocks); 821 } 822 823 static void 824 free_ds_label(struct diskslices *ssp, int slice) 825 { 826 struct diskslice *sp; 827 disklabel_t lp; 828 829 sp = &ssp->dss_slices[slice]; 830 lp = sp->ds_label; 831 if (lp.opaque != NULL) { 832 kfree(lp.opaque, M_DEVBUF); 833 lp.opaque = NULL; 834 set_ds_label(ssp, slice, lp, NULL); 835 } 836 } 837 838 static void 839 set_ds_label(struct diskslices *ssp, int slice, 840 disklabel_t lp, disklabel_ops_t ops) 841 { 842 struct diskslice *sp = &ssp->dss_slices[slice]; 843 844 sp->ds_label = lp; 845 sp->ds_ops = ops; 846 if (lp.opaque && slice != WHOLE_DISK_SLICE) 847 ops->op_adjust_label_reserved(ssp, slice, sp); 848 else 849 sp->ds_reserved = 0; 850 } 851 852 static void 853 set_ds_wlabel(struct diskslices *ssp, int slice, int wlabel) 854 { 855 ssp->dss_slices[slice].ds_wlabel = wlabel; 856 } 857 858