Disklabel separation work - Generally shift all disklabel-specific
[dragonfly/vkernel-mp.git] / sys / kern / subr_diskslice.c
blob42c61d91a7fc68bc26891e2dd2a4f081c121f112
1 /*-
2 * Copyright (c) 1994 Bruce D. Evans.
3 * All rights reserved.
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * William Jolitz.
11 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
12 * All rights reserved.
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.
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.
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.45 2007/06/17 23:50:16 dillon Exp $
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/diskslice.h>
56 #include <sys/disk.h>
57 #include <sys/diskmbr.h>
58 #include <sys/fcntl.h>
59 #include <sys/malloc.h>
60 #include <sys/stat.h>
61 #include <sys/syslog.h>
62 #include <sys/proc.h>
63 #include <sys/vnode.h>
64 #include <sys/device.h>
65 #include <sys/thread2.h>
67 #include <vfs/ufs/dinode.h> /* XXX used only for fs.h */
68 #include <vfs/ufs/fs.h> /* XXX used only to get BBSIZE/SBSIZE */
70 static void dsiodone (struct bio *bio);
71 static int dsreadandsetlabel(cdev_t dev, u_int flags,
72 struct diskslices *ssp, struct diskslice *sp,
73 struct disk_info *info);
74 static void free_ds_label (struct diskslices *ssp, int slice);
75 static void set_ds_label (struct diskslices *ssp, int slice,
76 struct disklabel *lp);
77 static void set_ds_wlabel (struct diskslices *ssp, int slice, int wlabel);
80 * Determine the size of the transfer, and make sure it is
81 * within the boundaries of the partition. Adjust transfer
82 * if needed, and signal errors or early completion.
84 * XXX TODO:
85 * o Split buffers that are too big for the device.
86 * o Check for overflow.
87 * o Finish cleaning this up.
89 * This function returns 1 on success, 0 if transfer equates
90 * to EOF (end of disk) or -1 on failure. The appropriate
91 * 'errno' value is also set in bp->b_error and bp->b_flags
92 * is marked with B_ERROR.
94 struct bio *
95 dscheck(cdev_t dev, struct bio *bio, struct diskslices *ssp)
97 struct buf *bp = bio->bio_buf;
98 struct bio *nbio;
99 struct disklabel *lp;
100 char *msg;
101 long nsec;
102 u_int64_t secno;
103 u_int64_t endsecno;
104 u_int64_t slicerel_secno;
105 struct diskslice *sp;
106 u_int32_t part;
107 u_int32_t slice;
108 int shift;
109 int mask;
110 int snoop;
112 slice = dkslice(dev);
113 part = dkpart(dev);
115 if (bio->bio_offset < 0) {
116 kprintf("dscheck(%s): negative bio_offset %lld\n",
117 devtoname(dev), bio->bio_offset);
118 goto bad;
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;
125 sp = &ssp->dss_slices[slice];
128 * Calculate secno and nsec
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;
153 * Calculate slice-relative sector number end slice-relative
154 * limit.
156 if (slice == WHOLE_DISK_SLICE) {
158 * Labels have not been allowed on whole-disks for a while.
159 * This really puts the nail in the coffin... no disk
160 * snooping will occur even if you tried to write a label
161 * without a slice structure.
163 * Accesses to the WHOLE_DISK_SLICE do not use a disklabel
164 * and partition numbers are special-cased. Currently numbers
165 * less then 128 are not allowed. Partition numbers >= 128
166 * are encoded in the high 8 bits of the 64 bit buffer offset
167 * and are fed directly through to the device with no
168 * further interpretation. In particular, no sector
169 * translation interpretation should occur because the
170 * sector size for the special raw access may not be the
171 * same as the nominal sector size for the device.
173 lp = NULL;
174 if (part < 128) {
175 kprintf("dscheck(%s): illegal partition number (%d) "
176 "for WHOLE_DISK_SLICE access\n",
177 devtoname(dev), part);
178 goto bad;
179 } else if (part != WHOLE_SLICE_PART) {
180 nbio = push_bio(bio);
181 nbio->bio_offset = bio->bio_offset |
182 (u_int64_t)part << 56;
183 return(nbio);
187 * sp->ds_size is for the whole disk in the WHOLE_DISK_SLICE,
188 * there are no reserved areas.
190 endsecno = sp->ds_size;
191 slicerel_secno = secno;
192 snoop = 0;
193 } else if (part == WHOLE_SLICE_PART) {
195 * We are accessing a slice. Enable snooping of the bsd
196 * label. Note that snooping only occurs if ds_reserved
197 * is also non-zero. ds_reserved will be non-zero if
198 * an in-core label is present or snooping has been
199 * explicitly requested via an ioctl().
201 * NOTE! opens on a whole-slice partition will not attempt
202 * to read a disklabel in, so there may not be an in-core
203 * disklabel even if there is one on the disk.
205 endsecno = sp->ds_size;
206 slicerel_secno = secno;
207 snoop = 1;
208 } else if ((lp = sp->ds_label) != NULL) {
210 * A label is present, extract the partition. Snooping of
211 * the disklabel is not supported even if accessible. Of
212 * course, the reserved area is still write protected.
214 if (getpartbounds(lp, part, &slicerel_secno, &endsecno)) {
215 kprintf("dscheck(%s): partition %d out of bounds\n",
216 devtoname(dev), part);
217 goto bad;
219 slicerel_secno += secno;
220 snoop = 0;
221 } else {
223 * Attempt to access partition when no disklabel present
225 kprintf("dscheck(%s): attempt to access non-existant partition\n",
226 devtoname(dev));
227 goto bad;
231 * Disallow writes to reserved areas unless ds_wlabel allows it.
233 if (slicerel_secno < sp->ds_reserved && nsec &&
234 bp->b_cmd != BUF_CMD_READ && sp->ds_wlabel == 0) {
235 bp->b_error = EROFS;
236 goto error;
240 * If we get here, bio_offset must be on a block boundary and
241 * the sector size must be a power of 2.
243 if ((bio->bio_offset & (ssp->dss_secsize - 1)) ||
244 (ssp->dss_secsize ^ (ssp->dss_secsize - 1)) !=
245 ((ssp->dss_secsize << 1) - 1)) {
246 kprintf("%s: invalid BIO offset, not sector aligned or"
247 " invalid sector size (not power of 2) %08llx %d\n",
248 devtoname(dev), bio->bio_offset, ssp->dss_secsize);
249 goto bad;
253 * EOF handling
255 if (secno + nsec > endsecno) {
257 * Return an error if beyond the end of the disk, or
258 * if B_BNOCLIP is set. Tell the system that we do not
259 * need to keep the buffer around.
261 if (secno > endsecno || (bp->b_flags & B_BNOCLIP))
262 goto bad;
265 * If exactly at end of disk, return an EOF. Throw away
266 * the buffer contents, if any, by setting B_INVAL.
268 if (secno == endsecno) {
269 bp->b_resid = bp->b_bcount;
270 bp->b_flags |= B_INVAL;
271 goto done;
275 * Else truncate
277 nsec = endsecno - secno;
278 bp->b_bcount = nsec * ssp->dss_secsize;
281 nbio = push_bio(bio);
282 nbio->bio_offset = (off_t)(sp->ds_offset + slicerel_secno) *
283 ssp->dss_secsize;
286 * Snoop reads and writes to the label area - only done if
287 * snoop is non-zero, ds_reserved is non-zero, and the
288 * read covers the label sector.
290 if (snoop && slicerel_secno < sp->ds_reserved &&
291 slicerel_secno <= LABELSECTOR &&
292 nsec && slicerel_secno + nsec > LABELSECTOR) {
294 * Set up our own callback on I/O completion to handle
295 * undoing the fixup we did for the write as well as
296 * doing the fixup for a read.
298 * Set info2.offset to the offset within the buffer containing
299 * the start of the label.
301 nbio->bio_done = dsiodone;
302 nbio->bio_caller_info1.ptr = sp;
303 nbio->bio_caller_info2.offset =
304 (LABELSECTOR - slicerel_secno) * ssp->dss_secsize;
305 if (bp->b_cmd != BUF_CMD_READ) {
306 msg = fixlabel(
307 NULL, sp,
308 (struct disklabel *)
309 (bp->b_data + (int)nbio->bio_caller_info2.offset),
310 TRUE);
311 if (msg != NULL) {
312 kprintf("dscheck(%s): %s\n",
313 devtoname(dev), msg);
314 bp->b_error = EROFS;
315 pop_bio(nbio);
316 goto error;
320 return (nbio);
322 bad_bcount:
323 kprintf(
324 "dscheck(%s): b_bcount %d is not on a sector boundary (ssize %d)\n",
325 devtoname(dev), bp->b_bcount, ssp->dss_secsize);
326 goto bad;
328 bad_blkno:
329 kprintf(
330 "dscheck(%s): bio_offset %lld is not on a sector boundary (ssize %d)\n",
331 devtoname(dev), bio->bio_offset, ssp->dss_secsize);
332 bad:
333 bp->b_error = EINVAL;
334 /* fall through */
335 error:
337 * Terminate the I/O with a ranging error. Since the buffer is
338 * either illegal or beyond the file EOF, mark it B_INVAL as well.
340 bp->b_resid = bp->b_bcount;
341 bp->b_flags |= B_ERROR | B_INVAL;
342 done:
344 * Caller must biodone() the originally passed bio if NULL is
345 * returned.
347 return (NULL);
350 void
351 dsclose(cdev_t dev, int mode, struct diskslices *ssp)
353 u_int32_t part;
354 u_int32_t slice;
355 struct diskslice *sp;
357 slice = dkslice(dev);
358 part = dkpart(dev);
359 if (slice < ssp->dss_nslices) {
360 sp = &ssp->dss_slices[slice];
361 dsclrmask(sp, part);
365 void
366 dsgone(struct diskslices **sspp)
368 int slice;
369 struct diskslice *sp;
370 struct diskslices *ssp;
372 for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) {
373 sp = &ssp->dss_slices[slice];
374 free_ds_label(ssp, slice);
376 kfree(ssp, M_DEVBUF);
377 *sspp = NULL;
381 * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this
382 * is subject to the same restriction as dsopen().
385 dsioctl(cdev_t dev, u_long cmd, caddr_t data, int flags,
386 struct diskslices **sspp, struct disk_info *info)
388 int error;
389 struct disklabel *lp;
390 int old_wlabel;
391 u_int32_t openmask[DKMAXPARTITIONS/(sizeof(u_int32_t)*8)];
392 u_int64_t old_reserved;
393 int part;
394 int slice;
395 struct diskslice *sp;
396 struct diskslices *ssp;
398 slice = dkslice(dev);
399 part = dkpart(dev);
400 ssp = *sspp;
401 if (slice >= ssp->dss_nslices)
402 return (EINVAL);
403 sp = &ssp->dss_slices[slice];
404 lp = sp->ds_label;
406 switch (cmd) {
407 case DIOCGDVIRGIN:
409 * You can only retrieve a virgin disklabel on the whole
410 * disk slice or whole-slice partition.
412 if (slice != WHOLE_DISK_SLICE &&
413 part != WHOLE_SLICE_PART) {
414 return(EINVAL);
417 lp = (struct disklabel *)data;
418 makevirginlabel(lp, ssp, sp, info);
419 return (0);
421 case DIOCGDINFO:
423 * You can only retrieve a disklabel on the whole
424 * slice partition.
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.
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);
439 if (sp->ds_label == NULL) {
440 error = dsreadandsetlabel(dev, info->d_dsflags,
441 ssp, sp, info);
443 if (error == 0)
444 *(struct disklabel *)data = *sp->ds_label;
445 return (error);
447 case DIOCGPART:
449 struct partinfo *dpart = (void *)data;
452 * The disk management layer may not have read the
453 * disklabel yet because simply opening a slice no
454 * longer 'probes' the disk that way. Be sure we
455 * have tried.
457 * We ignore any error.
459 if (sp->ds_label == NULL && part == WHOLE_SLICE_PART &&
460 slice != WHOLE_DISK_SLICE) {
461 dsreadandsetlabel(dev, info->d_dsflags,
462 ssp, sp, info);
465 bzero(dpart, sizeof(*dpart));
466 dpart->media_offset = (u_int64_t)sp->ds_offset *
467 info->d_media_blksize;
468 dpart->media_size = (u_int64_t)sp->ds_size *
469 info->d_media_blksize;
470 dpart->media_blocks = sp->ds_size;
471 dpart->media_blksize = info->d_media_blksize;
472 dpart->reserved_blocks= sp->ds_reserved;
474 if (slice != WHOLE_DISK_SLICE &&
475 part != WHOLE_SLICE_PART) {
476 u_int64_t start;
477 u_int64_t blocks;
478 if (lp == NULL)
479 return(EINVAL);
480 if (getpartbounds(lp, part, &start, &blocks))
481 return(EINVAL);
482 dpart->fstype = getpartfstype(lp, part);
483 dpart->media_offset += start *
484 info->d_media_blksize;
485 dpart->media_size = blocks *
486 info->d_media_blksize;
487 dpart->media_blocks = blocks;
490 * partition starting sector (p_offset)
491 * requires slice's reserved areas to be
492 * adjusted.
494 if (dpart->reserved_blocks > start)
495 dpart->reserved_blocks -= start;
496 else
497 dpart->reserved_blocks = 0;
501 * Load remaining fields from the info structure
503 dpart->d_nheads = info->d_nheads;
504 dpart->d_ncylinders = info->d_ncylinders;
505 dpart->d_secpertrack = info->d_secpertrack;
506 dpart->d_secpercyl = info->d_secpercyl;
508 return (0);
510 case DIOCGSLICEINFO:
511 bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] -
512 (char *)ssp);
513 return (0);
515 case DIOCSDINFO:
517 * You can write a disklabel on the whole disk slice or
518 * whole-slice partition.
520 if (slice != WHOLE_DISK_SLICE &&
521 part != WHOLE_SLICE_PART) {
522 return(EINVAL);
526 * We no longer support writing disklabels directly to media
527 * without there being a slice. Keep this as a separate
528 * conditional.
530 if (slice == WHOLE_DISK_SLICE)
531 return (ENODEV);
533 if (!(flags & FWRITE))
534 return (EBADF);
535 lp = kmalloc(sizeof *lp, M_DEVBUF, M_WAITOK);
536 if (sp->ds_label == NULL)
537 bzero(lp, sizeof *lp);
538 else
539 bcopy(sp->ds_label, lp, sizeof *lp);
540 if (sp->ds_label == NULL) {
541 bzero(openmask, sizeof(openmask));
542 } else {
543 bcopy(sp->ds_openmask, openmask, sizeof(openmask));
545 error = setdisklabel(lp, (struct disklabel *)data,
546 sp, openmask);
547 if (error != 0) {
548 kfree(lp, M_DEVBUF);
549 return (error);
551 free_ds_label(ssp, slice);
552 set_ds_label(ssp, slice, lp);
553 return (0);
555 case DIOCSYNCSLICEINFO:
557 * This ioctl can only be done on the whole disk
559 if (slice != WHOLE_DISK_SLICE || part != WHOLE_SLICE_PART)
560 return (EINVAL);
562 if (*(int *)data == 0) {
563 for (slice = 0; slice < ssp->dss_nslices; slice++) {
564 struct diskslice *ds = &ssp->dss_slices[slice];
566 switch(dscountmask(ds)) {
567 case 0:
568 break;
569 case 1:
570 if (slice != WHOLE_DISK_SLICE)
571 return (EBUSY);
572 if (!dschkmask(ds, RAW_PART))
573 return (EBUSY);
574 break;
575 default:
576 return (EBUSY);
582 * Temporarily forget the current slices struct and read
583 * the current one.
585 * NOTE:
587 * XXX should wait for current accesses on this disk to
588 * complete, then lock out future accesses and opens.
590 *sspp = NULL;
591 lp = kmalloc(sizeof *lp, M_DEVBUF, M_WAITOK);
592 *lp = *ssp->dss_slices[WHOLE_DISK_SLICE].ds_label;
593 error = dsopen(dev, S_IFCHR, ssp->dss_oflags, sspp, info);
594 if (error != 0) {
595 kfree(lp, M_DEVBUF);
596 *sspp = ssp;
597 return (error);
601 * Reopen everything. This is a no-op except in the "force"
602 * case and when the raw bdev and cdev are both open. Abort
603 * if anything fails.
605 for (slice = 0; slice < ssp->dss_nslices; slice++) {
606 for (part = 0; part < DKMAXPARTITIONS; ++part) {
607 if (!dschkmask(&ssp->dss_slices[slice], part))
608 continue;
609 error = dsopen(dkmodslice(dkmodpart(dev, part),
610 slice),
611 S_IFCHR, ssp->dss_oflags, sspp,
612 info);
613 if (error != 0) {
614 kfree(lp, M_DEVBUF);
615 *sspp = ssp;
616 return (EBUSY);
621 kfree(lp, M_DEVBUF);
622 dsgone(&ssp);
623 return (0);
625 case DIOCWDINFO:
626 error = dsioctl(dev, DIOCSDINFO, data, flags, &ssp, info);
627 if (error != 0)
628 return (error);
631 * Set the reserved area
633 old_wlabel = sp->ds_wlabel;
634 set_ds_wlabel(ssp, slice, TRUE);
635 old_reserved = sp->ds_reserved;
636 sp->ds_reserved = SBSIZE / ssp->dss_secsize;
637 error = writedisklabel(dev, sp->ds_label);
638 set_ds_wlabel(ssp, slice, old_wlabel);
639 sp->ds_reserved = old_reserved;
640 /* XXX should invalidate in-core label if write failed. */
641 return (error);
643 case DIOCSETSNOOP:
645 * Set label snooping even if there is no label present.
647 if (slice == WHOLE_DISK_SLICE || part != WHOLE_SLICE_PART)
648 return (EINVAL);
649 if (lp == NULL) {
650 if (*(int *)data) {
651 sp->ds_reserved = SBSIZE / ssp->dss_secsize;
652 } else {
653 sp->ds_reserved = 0;
656 return (0);
658 case DIOCWLABEL:
659 if (slice == WHOLE_DISK_SLICE)
660 return (ENODEV);
661 if (!(flags & FWRITE))
662 return (EBADF);
663 set_ds_wlabel(ssp, slice, *(int *)data != 0);
664 return (0);
666 default:
667 return (ENOIOCTL);
672 * Chain the bio_done. b_cmd remains valid through such chaining.
674 static void
675 dsiodone(struct bio *bio)
677 struct buf *bp = bio->bio_buf;
678 char *msg;
680 if (bp->b_cmd != BUF_CMD_READ
681 || (!(bp->b_flags & B_ERROR) && bp->b_error == 0)) {
682 msg = fixlabel(NULL, bio->bio_caller_info1.ptr,
683 (struct disklabel *)
684 (bp->b_data + (int)bio->bio_caller_info2.offset),
685 FALSE);
686 if (msg != NULL)
687 kprintf("%s\n", msg);
689 biodone(bio->bio_prev);
693 dsisopen(struct diskslices *ssp)
695 int slice;
697 if (ssp == NULL)
698 return (0);
699 for (slice = 0; slice < ssp->dss_nslices; slice++) {
700 if (dscountmask(&ssp->dss_slices[slice]))
701 return (1);
703 return (0);
707 * Allocate a slices "struct" and initialize it to contain only an empty
708 * compatibility slice (pointing to itself), a whole disk slice (covering
709 * the disk as described by the label), and (nslices - BASE_SLICES) empty
710 * slices beginning at BASE_SLICE.
712 * Note that the compatibility slice is no longer really a compatibility
713 * slice. It is slice 0 if a GPT label is present, and the dangerously
714 * dedicated slice if no slice table otherwise exists. Else it is 0-sized.
716 struct diskslices *
717 dsmakeslicestruct(int nslices, struct disk_info *info)
719 struct diskslice *sp;
720 struct diskslices *ssp;
722 ssp = kmalloc(offsetof(struct diskslices, dss_slices) +
723 nslices * sizeof *sp, M_DEVBUF, M_WAITOK);
724 ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE;
725 ssp->dss_nslices = nslices;
726 ssp->dss_oflags = 0;
729 * Figure out if we can use shifts or whether we have to
730 * use mod/multply to translate byte offsets into sector numbers.
732 if ((info->d_media_blksize ^ (info->d_media_blksize - 1)) ==
733 (info->d_media_blksize << 1) - 1) {
734 ssp->dss_secmult = info->d_media_blksize / DEV_BSIZE;
735 if (ssp->dss_secmult & (ssp->dss_secmult - 1))
736 ssp->dss_secshift = -1;
737 else
738 ssp->dss_secshift = ffs(ssp->dss_secmult) - 1;
739 } else {
740 ssp->dss_secmult = 0;
741 ssp->dss_secshift = -1;
743 ssp->dss_secsize = info->d_media_blksize;
744 sp = &ssp->dss_slices[0];
745 bzero(sp, nslices * sizeof *sp);
746 sp[WHOLE_DISK_SLICE].ds_size = info->d_media_blocks;
747 return (ssp);
750 char *
751 dsname(cdev_t dev, int unit, int slice, int part, char *partname)
753 static char name[32];
754 const char *dname;
755 int used;
757 dname = dev_dname(dev);
758 if (strlen(dname) > 16)
759 dname = "nametoolong";
760 ksnprintf(name, sizeof(name), "%s%d", dname, unit);
761 partname[0] = '\0';
762 used = strlen(name);
764 if (slice != WHOLE_DISK_SLICE) {
766 * slice or slice + partition. BASE_SLICE is s1, but
767 * the compatibility slice (0) needs to be s0.
769 used += ksnprintf(name + used, sizeof(name) - used,
770 "s%d", (slice ? slice - BASE_SLICE + 1 : 0));
771 if (part != WHOLE_SLICE_PART) {
772 used += ksnprintf(name + used, sizeof(name) - used,
773 "%c", 'a' + part);
774 partname[0] = 'a' + part;
775 partname[1] = 0;
777 } else if (part == WHOLE_SLICE_PART) {
779 * whole-disk-device, raw access to disk
781 /* no string extension */
782 } else if (part > 128) {
784 * whole-disk-device, extended raw access partitions.
785 * (typically used to access CD audio tracks)
787 used += ksnprintf(name + used, sizeof(name) - used,
788 "t%d", part - 128);
789 } else {
791 * whole-disk-device, illegal partition number
793 used += ksnprintf(name + used, sizeof(name) - used,
794 "?%d", part);
796 return (name);
800 * This should only be called when the unit is inactive and the strategy
801 * routine should not allow it to become active unless we call it. Our
802 * strategy routine must be special to allow activity.
805 dsopen(cdev_t dev, int mode, u_int flags,
806 struct diskslices **sspp, struct disk_info *info)
808 cdev_t dev1;
809 int error;
810 int need_init;
811 struct diskslice *sp;
812 struct diskslices *ssp;
813 int slice;
814 int part;
816 dev->si_bsize_phys = info->d_media_blksize;
819 * Do not attempt to read the slice table or disk label when
820 * accessing the whole-disk slice or a while-slice partition.
822 if (dkslice(dev) == WHOLE_DISK_SLICE)
823 flags |= DSO_ONESLICE | DSO_NOLABELS;
824 if (dkpart(dev) == WHOLE_SLICE_PART)
825 flags |= DSO_NOLABELS;
828 * Reinitialize the slice table unless there is an open device
829 * on the unit.
831 * It would be nice if we didn't have to do this but when a
832 * user is slicing and partitioning up a disk it is a lot safer
833 * to not take any chances.
835 ssp = *sspp;
836 need_init = !dsisopen(ssp);
837 if (ssp != NULL && need_init)
838 dsgone(sspp);
839 if (need_init) {
841 * Allocate a minimal slices "struct". This will become
842 * the final slices "struct" if we don't want real slices
843 * or if we can't find any real slices.
845 * Then scan the disk
847 *sspp = dsmakeslicestruct(BASE_SLICE, info);
849 if ((flags & DSO_ONESLICE) == 0) {
850 error = mbrinit(dev, info, sspp);
851 if (error != 0) {
852 dsgone(sspp);
853 return (error);
856 ssp = *sspp;
857 ssp->dss_oflags = flags;
860 * If there are no real slices, then make the compatiblity
861 * slice cover the whole disk.
863 if (ssp->dss_nslices == BASE_SLICE) {
864 sp = &ssp->dss_slices[COMPATIBILITY_SLICE];
866 sp->ds_size = info->d_media_blocks;
867 sp->ds_reserved = 0;
871 * Set dss_first_bsd_slice to point at the first BSD
872 * slice, if any.
874 for (slice = BASE_SLICE; slice < ssp->dss_nslices; slice++) {
875 sp = &ssp->dss_slices[slice];
876 if (sp->ds_type == DOSPTYP_386BSD /* XXX */) {
877 #if 0
878 struct diskslice *csp;
879 #endif
881 ssp->dss_first_bsd_slice = slice;
882 #if 0
884 * no longer supported, s0 is a real slice
885 * for GPT
887 csp = &ssp->dss_slices[COMPATIBILITY_SLICE];
888 csp->ds_offset = sp->ds_offset;
889 csp->ds_size = sp->ds_size;
890 csp->ds_type = sp->ds_type;
891 csp->ds_reserved = sp->ds_reserved;
892 #endif
893 break;
898 * By definition accesses via the whole-disk device do not
899 * specify any reserved areas. The whole disk may be read
900 * or written by the whole-disk device.
902 * ds_label for a whole-disk device is only used as a
903 * template.
905 sp = &ssp->dss_slices[WHOLE_DISK_SLICE];
906 sp->ds_label = clone_label(info, NULL);
907 sp->ds_wlabel = TRUE;
908 sp->ds_reserved = 0;
912 * Load the disklabel for the slice being accessed unless it is
913 * a whole-disk-slice or a whole-slice-partition (as determined
914 * by DSO_NOLABELS).
916 * We could scan all slices here and try to load up their
917 * disklabels, but that would cause us to access slices that
918 * the user may otherwise not intend us to access, or corrupted
919 * slices, etc.
921 * XXX if there are no opens on the slice we may want to re-read
922 * the disklabel anyway, even if we have one cached.
924 slice = dkslice(dev);
925 if (slice >= ssp->dss_nslices)
926 return (ENXIO);
927 sp = &ssp->dss_slices[slice];
928 part = dkpart(dev);
930 if ((flags & DSO_NOLABELS) == 0 && sp->ds_label == NULL) {
931 dev1 = dkmodslice(dkmodpart(dev, WHOLE_SLICE_PART), slice);
934 * If opening a raw disk we do not try to
935 * read the disklabel now. No interpretation of raw disks
936 * (e.g. like 'da0') ever occurs. We will try to read the
937 * disklabel for a raw slice if asked to via DIOC* ioctls.
939 * Access to the label area is disallowed by default. Note
940 * however that accesses via WHOLE_DISK_SLICE, and accesses
941 * via WHOLE_SLICE_PART for slices without valid disklabels,
942 * will allow writes and ignore the flag.
944 set_ds_wlabel(ssp, slice, FALSE);
945 dsreadandsetlabel(dev1, flags, ssp, sp, info);
949 * If opening a particular partition the disklabel must exist and
950 * the partition must be present in the label.
952 * If the partition is the special whole-disk-slice no partition
953 * table need exist.
955 if (part != WHOLE_SLICE_PART && slice != WHOLE_DISK_SLICE) {
956 if (sp->ds_label == NULL || part >= getnumparts(sp->ds_label))
957 return (EINVAL);
959 dssetmask(sp, part);
962 * Do not allow special raw-extension partitions to be opened
963 * if the device doesn't support them. Raw-extension partitions
964 * are typically used to handle CD tracks.
966 if (slice == WHOLE_DISK_SLICE && part >= 128 &&
967 part != WHOLE_SLICE_PART) {
968 if ((info->d_dsflags & DSO_RAWEXTENSIONS) == 0)
969 return (EINVAL);
971 return (0);
975 * Attempt to read the disklabel. If successful, store it in sp->ds_label.
977 * If we cannot read the disklabel and DSO_COMPATLABEL is set, we construct
978 * a fake label covering the whole disk.
980 static
982 dsreadandsetlabel(cdev_t dev, u_int flags,
983 struct diskslices *ssp, struct diskslice *sp,
984 struct disk_info *info)
986 struct disklabel *lp1;
987 const char *msg;
988 const char *sname;
989 char partname[2];
990 int slice = dkslice(dev);
991 u_int64_t old_reserved;
993 sname = dsname(dev, dkunit(dev), slice, WHOLE_SLICE_PART, partname);
994 lp1 = clone_label(info, sp);
995 old_reserved = sp->ds_reserved;
996 sp->ds_reserved = 0;
997 msg = readdisklabel(dev, lp1);
998 sp->ds_reserved = old_reserved;
1000 if (msg != NULL && (flags & DSO_COMPATLABEL)) {
1001 msg = NULL;
1002 kfree(lp1, M_DEVBUF);
1003 lp1 = clone_label(info, sp);
1005 if (msg == NULL)
1006 msg = fixlabel(sname, sp, lp1, FALSE);
1007 if (msg != NULL) {
1008 if (sp->ds_type == DOSPTYP_386BSD /* XXX */)
1009 log(LOG_WARNING, "%s: cannot find label (%s)\n",
1010 sname, msg);
1011 kfree(lp1, M_DEVBUF);
1012 } else {
1013 set_ds_label(ssp, slice, lp1);
1014 set_ds_wlabel(ssp, slice, FALSE);
1016 return (msg ? EINVAL : 0);
1019 int64_t
1020 dssize(cdev_t dev, struct diskslices **sspp)
1022 struct disklabel *lp;
1023 int part;
1024 int slice;
1025 struct diskslices *ssp;
1026 u_int64_t start;
1027 u_int64_t blocks;
1029 slice = dkslice(dev);
1030 part = dkpart(dev);
1031 ssp = *sspp;
1032 if (ssp == NULL || slice >= ssp->dss_nslices
1033 || !dschkmask(&ssp->dss_slices[slice], part)) {
1034 if (dev_dopen(dev, FREAD, S_IFCHR, proc0.p_ucred) != 0)
1035 return (-1);
1036 dev_dclose(dev, FREAD, S_IFCHR);
1037 ssp = *sspp;
1039 lp = ssp->dss_slices[slice].ds_label;
1040 if (lp == NULL)
1041 return (-1);
1042 if (getpartbounds(lp, part, &start, &blocks))
1043 return (-1);
1044 return ((int64_t)blocks);
1047 static void
1048 free_ds_label(struct diskslices *ssp, int slice)
1050 struct disklabel *lp;
1051 struct diskslice *sp;
1053 sp = &ssp->dss_slices[slice];
1054 lp = sp->ds_label;
1055 if (lp == NULL)
1056 return;
1057 kfree(lp, M_DEVBUF);
1058 set_ds_label(ssp, slice, (struct disklabel *)NULL);
1061 static void
1062 set_ds_label(struct diskslices *ssp, int slice, struct disklabel *lp)
1064 struct diskslice *sp = &ssp->dss_slices[slice];
1066 sp->ds_label = lp;
1067 adjust_label_reserved(ssp, slice, sp);
1070 static void
1071 set_ds_wlabel(struct diskslices *ssp, int slice, int wlabel)
1073 ssp->dss_slices[slice].ds_wlabel = wlabel;