2 * Copyright (c) 1994 Bruce D. Evans.
5 * Copyright (c) 1990 The Regents of the University of California.
8 * This code is derived from software contributed to Berkeley by
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
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
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>
54 #include <sys/disklabel.h>
55 #include <sys/diskslice.h>
57 #include <sys/diskmbr.h>
58 #include <sys/fcntl.h>
59 #include <sys/malloc.h>
61 #include <sys/syslog.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.
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.
95 dscheck(cdev_t dev
, struct bio
*bio
, struct diskslices
*ssp
)
97 struct buf
*bp
= bio
->bio_buf
;
104 u_int64_t slicerel_secno
;
105 struct diskslice
*sp
;
112 slice
= dkslice(dev
);
115 if (bio
->bio_offset
< 0) {
116 kprintf("dscheck(%s): negative bio_offset %lld\n",
117 devtoname(dev
), bio
->bio_offset
);
120 if (slice
>= ssp
->dss_nslices
) {
121 kprintf("dscheck(%s): slice too large %d/%d\n",
122 devtoname(dev
), slice
, ssp
->dss_nslices
);
125 sp
= &ssp
->dss_slices
[slice
];
128 * Calculate secno and nsec
130 if (ssp
->dss_secmult
== 1) {
133 } else if (ssp
->dss_secshift
!= -1) {
134 shift
= DEV_BSHIFT
+ ssp
->dss_secshift
;
136 mask
= (1 << shift
) - 1;
137 if ((int)bp
->b_bcount
& mask
)
139 if ((int)bio
->bio_offset
& mask
)
141 secno
= bio
->bio_offset
>> shift
;
142 nsec
= bp
->b_bcount
>> shift
;
144 if (bp
->b_bcount
% ssp
->dss_secsize
)
146 if (bio
->bio_offset
% ssp
->dss_secsize
)
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
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.
175 kprintf("dscheck(%s): illegal partition number (%d) "
176 "for WHOLE_DISK_SLICE access\n",
177 devtoname(dev
), part
);
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;
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
;
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
;
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
);
219 slicerel_secno
+= secno
;
223 * Attempt to access partition when no disklabel present
225 kprintf("dscheck(%s): attempt to access non-existant partition\n",
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) {
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
);
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
))
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
;
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
) *
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
) {
309 (bp
->b_data
+ (int)nbio
->bio_caller_info2
.offset
),
312 kprintf("dscheck(%s): %s\n",
313 devtoname(dev
), msg
);
324 "dscheck(%s): b_bcount %d is not on a sector boundary (ssize %d)\n",
325 devtoname(dev
), bp
->b_bcount
, ssp
->dss_secsize
);
330 "dscheck(%s): bio_offset %lld is not on a sector boundary (ssize %d)\n",
331 devtoname(dev
), bio
->bio_offset
, ssp
->dss_secsize
);
333 bp
->b_error
= EINVAL
;
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
;
344 * Caller must biodone() the originally passed bio if NULL is
351 dsclose(cdev_t dev
, int mode
, struct diskslices
*ssp
)
355 struct diskslice
*sp
;
357 slice
= dkslice(dev
);
359 if (slice
< ssp
->dss_nslices
) {
360 sp
= &ssp
->dss_slices
[slice
];
366 dsgone(struct diskslices
**sspp
)
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
);
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
)
389 struct disklabel
*lp
;
391 u_int32_t openmask
[DKMAXPARTITIONS
/(sizeof(u_int32_t
)*8)];
392 u_int64_t old_reserved
;
395 struct diskslice
*sp
;
396 struct diskslices
*ssp
;
398 slice
= dkslice(dev
);
401 if (slice
>= ssp
->dss_nslices
)
403 sp
= &ssp
->dss_slices
[slice
];
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
) {
417 lp
= (struct disklabel
*)data
;
418 makevirginlabel(lp
, ssp
, sp
, info
);
423 * You can only retrieve a disklabel on the whole
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.
433 if (part
!= WHOLE_SLICE_PART
)
435 if (slice
== WHOLE_DISK_SLICE
&&
436 (info
->d_dsflags
& DSO_COMPATLABEL
) == 0) {
439 if (sp
->ds_label
== NULL
) {
440 error
= dsreadandsetlabel(dev
, info
->d_dsflags
,
444 *(struct disklabel
*)data
= *sp
->ds_label
;
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
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
,
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
) {
480 if (getpartbounds(lp
, part
, &start
, &blocks
))
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
494 if (dpart
->reserved_blocks
> start
)
495 dpart
->reserved_blocks
-= start
;
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
;
511 bcopy(ssp
, data
, (char *)&ssp
->dss_slices
[ssp
->dss_nslices
] -
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
) {
526 * We no longer support writing disklabels directly to media
527 * without there being a slice. Keep this as a separate
530 if (slice
== WHOLE_DISK_SLICE
)
533 if (!(flags
& FWRITE
))
535 lp
= kmalloc(sizeof *lp
, M_DEVBUF
, M_WAITOK
);
536 if (sp
->ds_label
== NULL
)
537 bzero(lp
, sizeof *lp
);
539 bcopy(sp
->ds_label
, lp
, sizeof *lp
);
540 if (sp
->ds_label
== NULL
) {
541 bzero(openmask
, sizeof(openmask
));
543 bcopy(sp
->ds_openmask
, openmask
, sizeof(openmask
));
545 error
= setdisklabel(lp
, (struct disklabel
*)data
,
551 free_ds_label(ssp
, slice
);
552 set_ds_label(ssp
, slice
, lp
);
555 case DIOCSYNCSLICEINFO
:
557 * This ioctl can only be done on the whole disk
559 if (slice
!= WHOLE_DISK_SLICE
|| part
!= WHOLE_SLICE_PART
)
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
)) {
570 if (slice
!= WHOLE_DISK_SLICE
)
572 if (!dschkmask(ds
, RAW_PART
))
582 * Temporarily forget the current slices struct and read
587 * XXX should wait for current accesses on this disk to
588 * complete, then lock out future accesses and opens.
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
);
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
605 for (slice
= 0; slice
< ssp
->dss_nslices
; slice
++) {
606 for (part
= 0; part
< DKMAXPARTITIONS
; ++part
) {
607 if (!dschkmask(&ssp
->dss_slices
[slice
], part
))
609 error
= dsopen(dkmodslice(dkmodpart(dev
, part
),
611 S_IFCHR
, ssp
->dss_oflags
, sspp
,
626 error
= dsioctl(dev
, DIOCSDINFO
, data
, flags
, &ssp
, info
);
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. */
645 * Set label snooping even if there is no label present.
647 if (slice
== WHOLE_DISK_SLICE
|| part
!= WHOLE_SLICE_PART
)
651 sp
->ds_reserved
= SBSIZE
/ ssp
->dss_secsize
;
659 if (slice
== WHOLE_DISK_SLICE
)
661 if (!(flags
& FWRITE
))
663 set_ds_wlabel(ssp
, slice
, *(int *)data
!= 0);
672 * Chain the bio_done. b_cmd remains valid through such chaining.
675 dsiodone(struct bio
*bio
)
677 struct buf
*bp
= bio
->bio_buf
;
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
,
684 (bp
->b_data
+ (int)bio
->bio_caller_info2
.offset
),
687 kprintf("%s\n", msg
);
689 biodone(bio
->bio_prev
);
693 dsisopen(struct diskslices
*ssp
)
699 for (slice
= 0; slice
< ssp
->dss_nslices
; slice
++) {
700 if (dscountmask(&ssp
->dss_slices
[slice
]))
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.
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
;
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;
738 ssp
->dss_secshift
= ffs(ssp
->dss_secmult
) - 1;
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
;
751 dsname(cdev_t dev
, int unit
, int slice
, int part
, char *partname
)
753 static char name
[32];
757 dname
= dev_dname(dev
);
758 if (strlen(dname
) > 16)
759 dname
= "nametoolong";
760 ksnprintf(name
, sizeof(name
), "%s%d", dname
, unit
);
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
,
774 partname
[0] = 'a' + part
;
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
,
791 * whole-disk-device, illegal partition number
793 used
+= ksnprintf(name
+ used
, sizeof(name
) - used
,
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
)
811 struct diskslice
*sp
;
812 struct diskslices
*ssp
;
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
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.
836 need_init
= !dsisopen(ssp
);
837 if (ssp
!= NULL
&& 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.
847 *sspp
= dsmakeslicestruct(BASE_SLICE
, info
);
849 if ((flags
& DSO_ONESLICE
) == 0) {
850 error
= mbrinit(dev
, info
, 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
;
871 * Set dss_first_bsd_slice to point at the first BSD
874 for (slice
= BASE_SLICE
; slice
< ssp
->dss_nslices
; slice
++) {
875 sp
= &ssp
->dss_slices
[slice
];
876 if (sp
->ds_type
== DOSPTYP_386BSD
/* XXX */) {
878 struct diskslice
*csp
;
881 ssp
->dss_first_bsd_slice
= slice
;
884 * no longer supported, s0 is a real slice
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
;
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
905 sp
= &ssp
->dss_slices
[WHOLE_DISK_SLICE
];
906 sp
->ds_label
= clone_label(info
, NULL
);
907 sp
->ds_wlabel
= TRUE
;
912 * Load the disklabel for the slice being accessed unless it is
913 * a whole-disk-slice or a whole-slice-partition (as determined
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
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
)
927 sp
= &ssp
->dss_slices
[slice
];
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
955 if (part
!= WHOLE_SLICE_PART
&& slice
!= WHOLE_DISK_SLICE
) {
956 if (sp
->ds_label
== NULL
|| part
>= getnumparts(sp
->ds_label
))
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)
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.
982 dsreadandsetlabel(cdev_t dev
, u_int flags
,
983 struct diskslices
*ssp
, struct diskslice
*sp
,
984 struct disk_info
*info
)
986 struct disklabel
*lp1
;
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
;
997 msg
= readdisklabel(dev
, lp1
);
998 sp
->ds_reserved
= old_reserved
;
1000 if (msg
!= NULL
&& (flags
& DSO_COMPATLABEL
)) {
1002 kfree(lp1
, M_DEVBUF
);
1003 lp1
= clone_label(info
, sp
);
1006 msg
= fixlabel(sname
, sp
, lp1
, FALSE
);
1008 if (sp
->ds_type
== DOSPTYP_386BSD
/* XXX */)
1009 log(LOG_WARNING
, "%s: cannot find label (%s)\n",
1011 kfree(lp1
, M_DEVBUF
);
1013 set_ds_label(ssp
, slice
, lp1
);
1014 set_ds_wlabel(ssp
, slice
, FALSE
);
1016 return (msg
? EINVAL
: 0);
1020 dssize(cdev_t dev
, struct diskslices
**sspp
)
1022 struct disklabel
*lp
;
1025 struct diskslices
*ssp
;
1029 slice
= dkslice(dev
);
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)
1036 dev_dclose(dev
, FREAD
, S_IFCHR
);
1039 lp
= ssp
->dss_slices
[slice
].ds_label
;
1042 if (getpartbounds(lp
, part
, &start
, &blocks
))
1044 return ((int64_t)blocks
);
1048 free_ds_label(struct diskslices
*ssp
, int slice
)
1050 struct disklabel
*lp
;
1051 struct diskslice
*sp
;
1053 sp
= &ssp
->dss_slices
[slice
];
1057 kfree(lp
, M_DEVBUF
);
1058 set_ds_label(ssp
, slice
, (struct disklabel
*)NULL
);
1062 set_ds_label(struct diskslices
*ssp
, int slice
, struct disklabel
*lp
)
1064 struct diskslice
*sp
= &ssp
->dss_slices
[slice
];
1067 adjust_label_reserved(ssp
, slice
, sp
);
1071 set_ds_wlabel(struct diskslices
*ssp
, int slice
, int wlabel
)
1073 ssp
->dss_slices
[slice
].ds_wlabel
= wlabel
;