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 */ 48 49 #include <sys/param.h> 50 #include <sys/systm.h> 51 #include <sys/buf.h> 52 #include <sys/conf.h> 53 #include <sys/disklabel.h> 54 #include <sys/disklabel32.h> 55 #include <sys/disklabel64.h> 56 #include <sys/diskslice.h> 57 #include <sys/disk.h> 58 #include <sys/diskmbr.h> 59 #include <sys/fcntl.h> 60 #include <sys/malloc.h> 61 #include <sys/stat.h> 62 #include <sys/syslog.h> 63 #include <sys/proc.h> 64 #include <sys/vnode.h> 65 #include <sys/device.h> 66 #include <sys/thread2.h> 67 68 #include <vfs/ufs/dinode.h> /* XXX used only for fs.h */ 69 #include <vfs/ufs/fs.h> /* XXX used only to get BBSIZE/SBSIZE */ 70 #include <sys/devfs.h> 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 devfs_config(); 342 } else { 343 disk_msg_send_sync(DISK_SLICE_REPROBE, 344 dev->si_disk, sp); 345 devfs_config(); 346 } 347 /* ssp and sp may both be invalid after reprobe */ 348 } 349 } 350 } 351 352 void 353 dsgone(struct diskslices **sspp) 354 { 355 int slice; 356 struct diskslices *ssp; 357 358 if ((ssp = *sspp) != NULL) { 359 for (slice = 0; slice < ssp->dss_nslices; slice++) 360 free_ds_label(ssp, slice); 361 kfree(ssp, M_DEVBUF); 362 *sspp = NULL; 363 } 364 } 365 366 /* 367 * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this 368 * is subject to the same restriction as dsopen(). 369 */ 370 int 371 dsioctl(cdev_t dev, u_long cmd, caddr_t data, int flags, 372 struct diskslices **sspp, struct disk_info *info) 373 { 374 int error; 375 disklabel_t lp; 376 disklabel_t lptmp; 377 disklabel_ops_t ops; 378 int old_wlabel; 379 u_int32_t openmask[DKMAXPARTITIONS/(sizeof(u_int32_t)*8)]; 380 int part; 381 int slice; 382 struct diskslice *sp; 383 struct diskslices *ssp; 384 385 slice = dkslice(dev); 386 part = dkpart(dev); 387 ssp = *sspp; 388 if (ssp == NULL) 389 return (EINVAL); 390 if (slice >= ssp->dss_nslices) 391 return (EINVAL); 392 sp = &ssp->dss_slices[slice]; 393 lp = sp->ds_label; 394 ops = sp->ds_ops; /* may be NULL if no label */ 395 396 switch (cmd) { 397 case DIOCGDVIRGIN32: 398 ops = &disklabel32_ops; 399 /* fall through */ 400 case DIOCGDVIRGIN64: 401 if (cmd != DIOCGDVIRGIN32) 402 ops = &disklabel64_ops; 403 /* 404 * You can only retrieve a virgin disklabel on the whole 405 * disk slice or whole-slice partition. 406 */ 407 if (slice != WHOLE_DISK_SLICE && 408 part != WHOLE_SLICE_PART) { 409 return(EINVAL); 410 } 411 412 lp.opaque = data; 413 ops->op_makevirginlabel(lp, ssp, sp, info); 414 return (0); 415 416 case DIOCGDINFO32: 417 case DIOCGDINFO64: 418 /* 419 * You can only retrieve a disklabel on the whole 420 * slice partition. 421 * 422 * We do not support labels directly on whole-disks 423 * any more (that is, disks without slices), unless the 424 * device driver has asked for a compatible label (e.g. 425 * for a CD) to allow booting off of storage that is 426 * otherwise unlabeled. 427 */ 428 error = 0; 429 if (part != WHOLE_SLICE_PART) 430 return(EINVAL); 431 if (slice == WHOLE_DISK_SLICE && 432 (info->d_dsflags & DSO_COMPATLABEL) == 0) { 433 return (ENODEV); 434 } 435 if (sp->ds_label.opaque == NULL) { 436 error = dsreadandsetlabel(dev, info->d_dsflags, 437 ssp, sp, info); 438 ops = sp->ds_ops; /* may be NULL */ 439 } 440 441 /* 442 * The type of label we found must match the type of 443 * label requested. 444 */ 445 if (error == 0 && IOCPARM_LEN(cmd) != ops->labelsize) 446 error = ENOATTR; 447 if (error == 0) 448 bcopy(sp->ds_label.opaque, data, ops->labelsize); 449 return (error); 450 451 case DIOCGPART: 452 { 453 struct partinfo *dpart = (void *)data; 454 455 /* 456 * The disk management layer may not have read the 457 * disklabel yet because simply opening a slice no 458 * longer 'probes' the disk that way. Be sure we 459 * have tried. 460 * 461 * We ignore any error. 462 */ 463 if (sp->ds_label.opaque == NULL && 464 part == WHOLE_SLICE_PART && 465 slice != WHOLE_DISK_SLICE) { 466 dsreadandsetlabel(dev, info->d_dsflags, 467 ssp, sp, info); 468 ops = sp->ds_ops; /* may be NULL */ 469 } 470 471 bzero(dpart, sizeof(*dpart)); 472 dpart->media_offset = (u_int64_t)sp->ds_offset * 473 info->d_media_blksize; 474 dpart->media_size = (u_int64_t)sp->ds_size * 475 info->d_media_blksize; 476 dpart->media_blocks = sp->ds_size; 477 dpart->media_blksize = info->d_media_blksize; 478 dpart->reserved_blocks= sp->ds_reserved; 479 dpart->fstype_uuid = sp->ds_type_uuid; 480 dpart->storage_uuid = sp->ds_stor_uuid; 481 482 if (slice != WHOLE_DISK_SLICE && 483 part != WHOLE_SLICE_PART) { 484 u_int64_t start; 485 u_int64_t blocks; 486 if (lp.opaque == NULL) 487 return(EINVAL); 488 if (ops->op_getpartbounds(ssp, lp, part, 489 &start, &blocks)) { 490 return(EINVAL); 491 } 492 ops->op_loadpartinfo(lp, part, dpart); 493 dpart->media_offset += start * 494 info->d_media_blksize; 495 dpart->media_size = blocks * 496 info->d_media_blksize; 497 dpart->media_blocks = blocks; 498 499 /* 500 * partition starting sector (p_offset) 501 * requires slice's reserved areas to be 502 * adjusted. 503 */ 504 if (dpart->reserved_blocks > start) 505 dpart->reserved_blocks -= start; 506 else 507 dpart->reserved_blocks = 0; 508 } 509 510 /* 511 * Load remaining fields from the info structure 512 */ 513 dpart->d_nheads = info->d_nheads; 514 dpart->d_ncylinders = info->d_ncylinders; 515 dpart->d_secpertrack = info->d_secpertrack; 516 dpart->d_secpercyl = info->d_secpercyl; 517 } 518 return (0); 519 520 case DIOCGSLICEINFO: 521 bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] - 522 (char *)ssp); 523 return (0); 524 525 case DIOCSDINFO32: 526 ops = &disklabel32_ops; 527 /* fall through */ 528 case DIOCSDINFO64: 529 if (cmd != DIOCSDINFO32) 530 ops = &disklabel64_ops; 531 /* 532 * You can write a disklabel on the whole disk slice or 533 * whole-slice partition. 534 */ 535 if (slice != WHOLE_DISK_SLICE && 536 part != WHOLE_SLICE_PART) { 537 return(EINVAL); 538 } 539 540 /* 541 * We no longer support writing disklabels directly to media 542 * without there being a slice. Keep this as a separate 543 * conditional. 544 */ 545 if (slice == WHOLE_DISK_SLICE) 546 return (ENODEV); 547 if (!(flags & FWRITE)) 548 return (EBADF); 549 550 /* 551 * If an existing label is present it must be the same 552 * type as the label being passed by the ioctl. 553 */ 554 if (sp->ds_label.opaque && sp->ds_ops != ops) 555 return (ENOATTR); 556 557 /* 558 * Create a temporary copy of the existing label 559 * (if present) so setdisklabel can compare it against 560 * the new label. 561 */ 562 lp.opaque = kmalloc(ops->labelsize, M_DEVBUF, M_WAITOK); 563 if (sp->ds_label.opaque == NULL) 564 bzero(lp.opaque, ops->labelsize); 565 else 566 bcopy(sp->ds_label.opaque, lp.opaque, ops->labelsize); 567 if (sp->ds_label.opaque == NULL) { 568 bzero(openmask, sizeof(openmask)); 569 } else { 570 bcopy(sp->ds_openmask, openmask, sizeof(openmask)); 571 } 572 lptmp.opaque = data; 573 error = ops->op_setdisklabel(lp, lptmp, ssp, sp, openmask); 574 disk_msg_send_sync(DISK_SLICE_REPROBE, dev->si_disk, sp); 575 devfs_config(); 576 if (error != 0) { 577 kfree(lp.opaque, M_DEVBUF); 578 return (error); 579 } 580 free_ds_label(ssp, slice); 581 set_ds_label(ssp, slice, lp, ops); 582 return (0); 583 584 case DIOCSYNCSLICEINFO: 585 /* 586 * This ioctl can only be done on the whole disk 587 */ 588 if (slice != WHOLE_DISK_SLICE || part != WHOLE_SLICE_PART) 589 return (EINVAL); 590 591 if (*(int *)data == 0) { 592 for (slice = 0; slice < ssp->dss_nslices; slice++) { 593 struct diskslice *ds = &ssp->dss_slices[slice]; 594 595 switch(dscountmask(ds)) { 596 case 0: 597 break; 598 case 1: 599 if (slice != WHOLE_DISK_SLICE) 600 return (EBUSY); 601 if (!dschkmask(ds, RAW_PART)) 602 return (EBUSY); 603 break; 604 default: 605 return (EBUSY); 606 } 607 } 608 } 609 610 disk_msg_send_sync(DISK_DISK_REPROBE, dev->si_disk, NULL); 611 devfs_config(); 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 (part != WHOLE_SLICE_PART) 622 error = EINVAL; 623 if (error != 0) 624 return (error); 625 626 /* 627 * Allow the reserved area to be written, reload ops 628 * because the DIOCSDINFO op above may have installed 629 * a new label type. 630 */ 631 ops = sp->ds_ops; 632 old_wlabel = sp->ds_wlabel; 633 set_ds_wlabel(ssp, slice, TRUE); 634 error = ops->op_writedisklabel(dev, ssp, sp, sp->ds_label); 635 disk_msg_send_sync(DISK_SLICE_REPROBE, dev->si_disk, sp); 636 devfs_config(); 637 set_ds_wlabel(ssp, slice, old_wlabel); 638 /* XXX should invalidate in-core label if write failed. */ 639 return (error); 640 641 case DIOCWLABEL: 642 if (slice == WHOLE_DISK_SLICE) 643 return (ENODEV); 644 if (!(flags & FWRITE)) 645 return (EBADF); 646 set_ds_wlabel(ssp, slice, *(int *)data != 0); 647 return (0); 648 649 default: 650 return (ENOIOCTL); 651 } 652 } 653 654 int 655 dsisopen(struct diskslices *ssp) 656 { 657 int slice; 658 659 if (ssp == NULL) 660 return (0); 661 for (slice = 0; slice < ssp->dss_nslices; slice++) { 662 if (dscountmask(&ssp->dss_slices[slice])) 663 return (1); 664 } 665 return (0); 666 } 667 668 /* 669 * Allocate a slices "struct" and initialize it to contain only an empty 670 * compatibility slice (pointing to itself), a whole disk slice (covering 671 * the disk as described by the label), and (nslices - BASE_SLICES) empty 672 * slices beginning at BASE_SLICE. 673 * 674 * Note that the compatibility slice is no longer really a compatibility 675 * slice. It is slice 0 if a GPT label is present, and the dangerously 676 * dedicated slice if no slice table otherwise exists. Else it is 0-sized. 677 */ 678 struct diskslices * 679 dsmakeslicestruct(int nslices, struct disk_info *info) 680 { 681 struct diskslice *sp; 682 struct diskslices *ssp; 683 684 ssp = kmalloc(offsetof(struct diskslices, dss_slices) + 685 nslices * sizeof *sp, M_DEVBUF, M_WAITOK); 686 ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE; 687 ssp->dss_nslices = nslices; 688 ssp->dss_oflags = 0; 689 690 /* 691 * Figure out if we can use shifts or whether we have to 692 * use mod/multply to translate byte offsets into sector numbers. 693 */ 694 if ((info->d_media_blksize ^ (info->d_media_blksize - 1)) == 695 (info->d_media_blksize << 1) - 1) { 696 ssp->dss_secmult = info->d_media_blksize / DEV_BSIZE; 697 if (ssp->dss_secmult & (ssp->dss_secmult - 1)) 698 ssp->dss_secshift = -1; 699 else 700 ssp->dss_secshift = ffs(ssp->dss_secmult) - 1; 701 } else { 702 ssp->dss_secmult = 0; 703 ssp->dss_secshift = -1; 704 } 705 ssp->dss_secsize = info->d_media_blksize; 706 sp = &ssp->dss_slices[0]; 707 bzero(sp, nslices * sizeof *sp); 708 sp[WHOLE_DISK_SLICE].ds_size = info->d_media_blocks; 709 return (ssp); 710 } 711 712 char * 713 dsname(cdev_t dev, int unit, int slice, int part, char *partname) 714 { 715 return dev->si_name; 716 } 717 718 /* 719 * This should only be called when the unit is inactive and the strategy 720 * routine should not allow it to become active unless we call it. Our 721 * strategy routine must be special to allow activity. 722 */ 723 int 724 dsopen(cdev_t dev, int mode, u_int flags, 725 struct diskslices **sspp, struct disk_info *info) 726 { 727 struct diskslice *sp; 728 struct diskslices *ssp; 729 int slice; 730 int part; 731 732 ssp = *sspp; 733 dev->si_bsize_phys = info->d_media_blksize; 734 slice = dkslice(dev); 735 part = dkpart(dev); 736 sp = &ssp->dss_slices[slice]; 737 dssetmask(sp, part); 738 739 return 0; 740 } 741 742 /* 743 * Attempt to read the disklabel. If successful, store it in sp->ds_label. 744 * 745 * If we cannot read the disklabel and DSO_COMPATLABEL is set, we construct 746 * a fake label covering the whole disk. 747 */ 748 static 749 int 750 dsreadandsetlabel(cdev_t dev, u_int flags, 751 struct diskslices *ssp, struct diskslice *sp, 752 struct disk_info *info) 753 { 754 disklabel_t lp; 755 disklabel_ops_t ops; 756 const char *msg; 757 const char *sname; 758 char partname[2]; 759 int slice = dkslice(dev); 760 761 /* 762 * Probe the disklabel 763 */ 764 lp.opaque = NULL; 765 sname = dsname(dev, dkunit(dev), slice, WHOLE_SLICE_PART, partname); 766 ops = &disklabel32_ops; 767 msg = ops->op_readdisklabel(dev, sp, &lp, info); 768 if (msg && strcmp(msg, "no disk label") == 0) { 769 ops = &disklabel64_ops; 770 msg = disklabel64_ops.op_readdisklabel(dev, sp, &lp, info); 771 } 772 773 /* 774 * If we failed and COMPATLABEL is set, create a dummy disklabel. 775 */ 776 if (msg != NULL && (flags & DSO_COMPATLABEL)) { 777 msg = NULL; 778 if (sp->ds_size >= 0x100000000ULL) 779 ops = &disklabel64_ops; 780 else 781 ops = &disklabel32_ops; 782 lp = ops->op_clone_label(info, sp); 783 } 784 if (msg != NULL) { 785 if (sp->ds_type == DOSPTYP_386BSD /* XXX */) 786 log(LOG_WARNING, "%s: cannot find label (%s)\n", 787 sname, msg); 788 if (lp.opaque) 789 kfree(lp.opaque, M_DEVBUF); 790 } else { 791 set_ds_label(ssp, slice, lp, ops); 792 set_ds_wlabel(ssp, slice, FALSE); 793 } 794 return (msg ? EINVAL : 0); 795 } 796 797 int64_t 798 dssize(cdev_t dev, struct diskslices **sspp) 799 { 800 disklabel_t lp; 801 disklabel_ops_t ops; 802 int part; 803 int slice; 804 struct diskslices *ssp; 805 u_int64_t start; 806 u_int64_t blocks; 807 808 slice = dkslice(dev); 809 part = dkpart(dev); 810 ssp = *sspp; 811 if (ssp == NULL || slice >= ssp->dss_nslices 812 || !dschkmask(&ssp->dss_slices[slice], part)) { 813 if (dev_dopen(dev, FREAD, S_IFCHR, proc0.p_ucred) != 0) 814 return (-1); 815 dev_dclose(dev, FREAD, S_IFCHR); 816 ssp = *sspp; 817 } 818 lp = ssp->dss_slices[slice].ds_label; 819 if (lp.opaque == NULL) 820 return (-1); 821 ops = ssp->dss_slices[slice].ds_ops; 822 if (ops->op_getpartbounds(ssp, lp, part, &start, &blocks)) 823 return (-1); 824 return ((int64_t)blocks); 825 } 826 827 static void 828 free_ds_label(struct diskslices *ssp, int slice) 829 { 830 struct diskslice *sp; 831 disklabel_t lp; 832 833 sp = &ssp->dss_slices[slice]; 834 lp = sp->ds_label; 835 if (lp.opaque != NULL) { 836 kfree(lp.opaque, M_DEVBUF); 837 lp.opaque = NULL; 838 set_ds_label(ssp, slice, lp, NULL); 839 } 840 } 841 842 static void 843 set_ds_label(struct diskslices *ssp, int slice, 844 disklabel_t lp, disklabel_ops_t ops) 845 { 846 struct diskslice *sp = &ssp->dss_slices[slice]; 847 848 sp->ds_label = lp; 849 sp->ds_ops = ops; 850 if (lp.opaque && slice != WHOLE_DISK_SLICE) 851 ops->op_adjust_label_reserved(ssp, slice, sp); 852 else 853 sp->ds_reserved = 0; 854 } 855 856 static void 857 set_ds_wlabel(struct diskslices *ssp, int slice, int wlabel) 858 { 859 ssp->dss_slices[slice].ds_wlabel = wlabel; 860 } 861 862