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.32 2007/05/16 05:20:23 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 #define TRACE(str) do { if (ds_debug) kprintf str; } while (0)
72 typedef u_char bool_t
;
74 static volatile bool_t ds_debug
;
76 static struct disklabel
*clone_label (struct disk_info
*info
,
77 struct diskslice
*sp
);
78 static void dsiodone (struct bio
*bio
);
79 static char *fixlabel (char *sname
, struct diskslice
*sp
,
80 struct disklabel
*lp
, int writeflag
);
81 static void free_ds_label (struct diskslices
*ssp
, int slice
);
82 static void partition_info (char *sname
, int part
, struct partition
*pp
);
83 static void slice_info (char *sname
, struct diskslice
*sp
);
84 static void set_ds_label (struct diskslices
*ssp
, int slice
,
85 struct disklabel
*lp
);
86 static void set_ds_wlabel (struct diskslices
*ssp
, int slice
, int wlabel
);
89 * Create a disklabel based on a disk_info structure, initializing
90 * the appropriate fields and creating a raw partition that covers the
93 * If a diskslice is passed, the label is truncated to the slice
95 static struct disklabel
*
96 clone_label(struct disk_info
*info
, struct diskslice
*sp
)
98 struct disklabel
*lp1
;
100 lp1
= kmalloc(sizeof *lp1
, M_DEVBUF
, M_WAITOK
| M_ZERO
);
101 lp1
->d_nsectors
= info
->d_secpertrack
;
102 lp1
->d_ntracks
= info
->d_nheads
;
103 lp1
->d_secpercyl
= info
->d_secpercyl
;
104 lp1
->d_secsize
= info
->d_media_blksize
;
107 lp1
->d_secperunit
= (u_int
)sp
->ds_size
;
108 lp1
->d_partitions
[RAW_PART
].p_size
= lp1
->d_secperunit
;
110 lp1
->d_secperunit
= (u_int
)info
->d_media_blocks
;
111 lp1
->d_partitions
[RAW_PART
].p_size
= lp1
->d_secperunit
;
115 * Used by the CD driver to create a compatibility slice which
116 * allows us to mount root from the CD.
118 if (info
->d_dsflags
& DSO_COMPATPARTA
) {
119 lp1
->d_partitions
[0].p_size
= lp1
->d_secperunit
;
120 lp1
->d_partitions
[0].p_fstype
= FS_OTHER
;
123 if (lp1
->d_typename
[0] == '\0')
124 strncpy(lp1
->d_typename
, "amnesiac", sizeof(lp1
->d_typename
));
125 if (lp1
->d_packname
[0] == '\0')
126 strncpy(lp1
->d_packname
, "fictitious", sizeof(lp1
->d_packname
));
127 if (lp1
->d_nsectors
== 0)
128 lp1
->d_nsectors
= 32;
129 if (lp1
->d_ntracks
== 0)
131 lp1
->d_secpercyl
= lp1
->d_nsectors
* lp1
->d_ntracks
;
132 lp1
->d_ncylinders
= lp1
->d_secperunit
/ lp1
->d_secpercyl
;
135 if (lp1
->d_interleave
== 0)
136 lp1
->d_interleave
= 1;
137 if (lp1
->d_npartitions
< RAW_PART
+ 1)
138 lp1
->d_npartitions
= MAXPARTITIONS
;
139 if (lp1
->d_bbsize
== 0)
140 lp1
->d_bbsize
= BBSIZE
;
141 if (lp1
->d_sbsize
== 0)
142 lp1
->d_sbsize
= SBSIZE
;
143 lp1
->d_partitions
[RAW_PART
].p_size
= lp1
->d_secperunit
;
144 lp1
->d_magic
= DISKMAGIC
;
145 lp1
->d_magic2
= DISKMAGIC
;
146 lp1
->d_checksum
= dkcksum(lp1
);
151 * Determine the size of the transfer, and make sure it is
152 * within the boundaries of the partition. Adjust transfer
153 * if needed, and signal errors or early completion.
156 * o Split buffers that are too big for the device.
157 * o Check for overflow.
158 * o Finish cleaning this up.
160 * This function returns 1 on success, 0 if transfer equates
161 * to EOF (end of disk) or -1 on failure. The appropriate
162 * 'errno' value is also set in bp->b_error and bp->b_flags
163 * is marked with B_ERROR.
166 dscheck(cdev_t dev
, struct bio
*bio
, struct diskslices
*ssp
)
168 struct buf
*bp
= bio
->bio_buf
;
170 struct disklabel
*lp
;
173 struct partition
*pp
;
177 u_int64_t slicerel_secno
;
178 struct diskslice
*sp
;
182 if (bio
->bio_offset
< 0) {
183 kprintf("dscheck(%s): negative bio_offset %lld\n",
184 devtoname(dev
), bio
->bio_offset
);
187 sp
= &ssp
->dss_slices
[dkslice(dev
)];
190 if (ssp
->dss_secmult
== 1) {
193 } else if (ssp
->dss_secshift
!= -1) {
194 shift
= DEV_BSHIFT
+ ssp
->dss_secshift
;
196 mask
= (1 << shift
) - 1;
197 if ((int)bp
->b_bcount
& mask
)
199 if ((int)bio
->bio_offset
& mask
)
201 secno
= bio
->bio_offset
>> shift
;
202 nsec
= bp
->b_bcount
>> shift
;
204 if (bp
->b_bcount
% ssp
->dss_secsize
)
206 if (bio
->bio_offset
% ssp
->dss_secsize
)
208 secno
= bio
->bio_offset
/ ssp
->dss_secsize
;
209 nsec
= bp
->b_bcount
/ ssp
->dss_secsize
;
212 labelsect
= -LABELSECTOR
- 1;
213 endsecno
= sp
->ds_size
;
214 slicerel_secno
= secno
;
216 labelsect
= lp
->d_partitions
[LABEL_PART
].p_offset
;
218 Debugger("labelsect != 0 in dscheck()");
219 pp
= &lp
->d_partitions
[dkpart(dev
)];
220 endsecno
= pp
->p_size
;
221 slicerel_secno
= pp
->p_offset
+ secno
;
224 /* overwriting disk label ? */
225 /* XXX should also protect bootstrap in first 8K */
226 if (slicerel_secno
<= LABELSECTOR
+ labelsect
&&
228 slicerel_secno
+ nsec
> LABELSECTOR
+ labelsect
&&
230 bp
->b_cmd
!= BUF_CMD_READ
&& sp
->ds_wlabel
== 0) {
235 #if defined(DOSBBSECTOR) && defined(notyet)
236 /* overwriting master boot record? */
237 if (slicerel_secno
<= DOSBBSECTOR
&& bp
->b_cmd
!= BUF_CMD_READ
&&
238 sp
->ds_wlabel
== 0) {
247 if (secno
+ nsec
> endsecno
) {
249 * Return an error if beyond the end of the disk, or
250 * if B_BNOCLIP is set. Tell the system that we do not
251 * need to keep the buffer around.
253 if (secno
> endsecno
|| (bp
->b_flags
& B_BNOCLIP
))
257 * If exactly at end of disk, return an EOF. Throw away
258 * the buffer contents, if any, by setting B_INVAL.
260 if (secno
== endsecno
) {
261 bp
->b_resid
= bp
->b_bcount
;
262 bp
->b_flags
|= B_INVAL
;
269 nsec
= endsecno
- secno
;
270 bp
->b_bcount
= nsec
* ssp
->dss_secsize
;
273 nbio
= push_bio(bio
);
274 nbio
->bio_offset
= (off_t
)(sp
->ds_offset
+ slicerel_secno
) *
278 * Snoop on label accesses if the slice offset is nonzero. Fudge
279 * offsets in the label to keep the in-core label coherent with
282 if (slicerel_secno
<= LABELSECTOR
+ labelsect
284 && slicerel_secno
+ nsec
> LABELSECTOR
+ labelsect
286 && sp
->ds_offset
!= 0) {
287 nbio
->bio_done
= dsiodone
;
288 nbio
->bio_caller_info1
.ptr
= sp
;
289 nbio
->bio_caller_info2
.offset
=
290 (off_t
)(LABELSECTOR
+ labelsect
- slicerel_secno
) *
292 if (bp
->b_cmd
!= BUF_CMD_READ
) {
294 * XXX even disklabel(8) writes directly so we need
295 * to adjust writes. Perhaps we should drop support
296 * for DIOCWLABEL (always write protect labels) and
297 * require the use of DIOCWDINFO.
299 * XXX probably need to copy the data to avoid even
300 * temporarily corrupting the in-core copy.
302 /* XXX need name here. */
306 (bp
->b_data
+ (int)nbio
->bio_caller_info2
.offset
),
309 kprintf("dscheck(%s): %s\n",
310 devtoname(dev
), msg
);
321 "dscheck(%s): b_bcount %d is not on a sector boundary (ssize %d)\n",
322 devtoname(dev
), bp
->b_bcount
, ssp
->dss_secsize
);
327 "dscheck(%s): bio_offset %lld is not on a sector boundary (ssize %d)\n",
328 devtoname(dev
), bio
->bio_offset
, ssp
->dss_secsize
);
330 bp
->b_error
= EINVAL
;
334 * Terminate the I/O with a ranging error. Since the buffer is
335 * either illegal or beyond the file EOF, mark it B_INVAL as well.
337 bp
->b_resid
= bp
->b_bcount
;
338 bp
->b_flags
|= B_ERROR
| B_INVAL
;
341 * Caller must biodone() the originally passed bio if NULL is
348 dsclose(cdev_t dev
, int mode
, struct diskslices
*ssp
)
351 struct diskslice
*sp
;
353 sp
= &ssp
->dss_slices
[dkslice(dev
)];
354 mask
= 1 << dkpart(dev
);
355 sp
->ds_openmask
&= ~mask
;
359 dsgone(struct diskslices
**sspp
)
362 struct diskslice
*sp
;
363 struct diskslices
*ssp
;
365 for (slice
= 0, ssp
= *sspp
; slice
< ssp
->dss_nslices
; slice
++) {
366 sp
= &ssp
->dss_slices
[slice
];
367 free_ds_label(ssp
, slice
);
369 kfree(ssp
, M_DEVBUF
);
374 * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this
375 * is subject to the same restriction as dsopen().
378 dsioctl(cdev_t dev
, u_long cmd
, caddr_t data
, int flags
,
379 struct diskslices
**sspp
, struct disk_info
*info
)
382 struct disklabel
*lp
;
387 struct diskslice
*sp
;
388 struct diskslices
*ssp
;
389 struct partition
*pp
;
391 slice
= dkslice(dev
);
393 sp
= &ssp
->dss_slices
[slice
];
398 lp
= (struct disklabel
*)data
;
399 if (ssp
->dss_slices
[WHOLE_DISK_SLICE
].ds_label
) {
400 *lp
= *ssp
->dss_slices
[WHOLE_DISK_SLICE
].ds_label
;
402 bzero(lp
, sizeof(struct disklabel
));
405 lp
->d_magic
= DISKMAGIC
;
406 lp
->d_magic2
= DISKMAGIC
;
407 pp
= &lp
->d_partitions
[RAW_PART
];
409 pp
->p_size
= sp
->ds_size
;
411 lp
->d_npartitions
= MAXPARTITIONS
;
412 if (lp
->d_interleave
== 0)
413 lp
->d_interleave
= 1;
416 if (lp
->d_nsectors
== 0)
418 if (lp
->d_ntracks
== 0)
421 lp
->d_bbsize
= BBSIZE
;
422 lp
->d_sbsize
= SBSIZE
;
423 lp
->d_secpercyl
= lp
->d_nsectors
* lp
->d_ntracks
;
424 lp
->d_ncylinders
= sp
->ds_size
/ lp
->d_secpercyl
;
425 lp
->d_secperunit
= sp
->ds_size
;
427 lp
->d_checksum
= dkcksum(lp
);
433 *(struct disklabel
*)data
= *lp
;
440 *(struct disklabel
**)data
= lp
;
446 struct partinfo
*dpart
= (void *)data
;
448 bzero(dpart
, sizeof(*dpart
));
449 dpart
->media_offset
= (u_int64_t
)sp
->ds_offset
*
450 info
->d_media_blksize
;
451 dpart
->media_size
= (u_int64_t
)sp
->ds_size
*
452 info
->d_media_blksize
;
453 dpart
->media_blocks
= sp
->ds_size
;
454 dpart
->media_blksize
= info
->d_media_blksize
;
455 dpart
->skip_platform
= sp
->ds_skip_platform
;
456 dpart
->skip_bsdlabel
= sp
->ds_skip_bsdlabel
;
457 if (lp
&& slice
!= WHOLE_DISK_SLICE
) {
460 p
= &lp
->d_partitions
[dkpart(dev
)];
461 dpart
->fstype
= p
->p_fstype
;
462 dpart
->media_offset
+= (u_int64_t
)p
->p_offset
*
463 info
->d_media_blksize
;
464 dpart
->media_size
= (u_int64_t
)p
->p_size
*
465 info
->d_media_blksize
;
468 * partition starting sector (p_offset)
469 * requires slice's reserved areas to be
472 if (dpart
->skip_platform
> p
->p_offset
)
473 dpart
->skip_platform
-= p
->p_offset
;
475 dpart
->skip_platform
= 0;
476 if (dpart
->skip_bsdlabel
> p
->p_offset
)
477 dpart
->skip_bsdlabel
-= p
->p_offset
;
479 dpart
->skip_bsdlabel
= 0;
485 bcopy(ssp
, data
, (char *)&ssp
->dss_slices
[ssp
->dss_nslices
] -
490 if (slice
== WHOLE_DISK_SLICE
)
492 if (!(flags
& FWRITE
))
494 lp
= kmalloc(sizeof *lp
, M_DEVBUF
, M_WAITOK
);
495 if (sp
->ds_label
== NULL
)
496 bzero(lp
, sizeof *lp
);
498 bcopy(sp
->ds_label
, lp
, sizeof *lp
);
499 if (sp
->ds_label
== NULL
) {
502 openmask
= sp
->ds_openmask
;
503 if (slice
== COMPATIBILITY_SLICE
) {
504 openmask
|= ssp
->dss_slices
[
505 ssp
->dss_first_bsd_slice
].ds_openmask
;
506 } else if (slice
== ssp
->dss_first_bsd_slice
) {
507 openmask
|= ssp
->dss_slices
[
508 COMPATIBILITY_SLICE
].ds_openmask
;
511 error
= setdisklabel(lp
, (struct disklabel
*)data
,
513 /* XXX why doesn't setdisklabel() check this? */
514 if (error
== 0 && lp
->d_partitions
[RAW_PART
].p_offset
!= 0)
517 if (lp
->d_secperunit
> sp
->ds_size
)
519 for (part
= 0; part
< lp
->d_npartitions
; part
++)
520 if (lp
->d_partitions
[part
].p_size
> sp
->ds_size
)
527 free_ds_label(ssp
, slice
);
528 set_ds_label(ssp
, slice
, lp
);
531 case DIOCSYNCSLICEINFO
:
532 if (slice
!= WHOLE_DISK_SLICE
|| dkpart(dev
) != RAW_PART
)
534 if (*(int *)data
== 0) {
535 for (slice
= 0; slice
< ssp
->dss_nslices
; slice
++) {
536 openmask
= ssp
->dss_slices
[slice
].ds_openmask
;
538 (slice
!= WHOLE_DISK_SLICE
||
539 openmask
& ~(1 << RAW_PART
))) {
546 * Temporarily forget the current slices struct and read
551 * XXX should wait for current accesses on this disk to
552 * complete, then lock out future accesses and opens.
555 lp
= kmalloc(sizeof *lp
, M_DEVBUF
, M_WAITOK
);
556 *lp
= *ssp
->dss_slices
[WHOLE_DISK_SLICE
].ds_label
;
557 error
= dsopen(dev
, S_IFCHR
, ssp
->dss_oflags
, sspp
, info
);
565 * Reopen everything. This is a no-op except in the "force"
566 * case and when the raw bdev and cdev are both open. Abort
569 for (slice
= 0; slice
< ssp
->dss_nslices
; slice
++) {
570 for (openmask
= ssp
->dss_slices
[slice
].ds_openmask
,
571 part
= 0; openmask
; openmask
>>= 1, part
++) {
574 error
= dsopen(dkmodslice(dkmodpart(dev
, part
),
576 S_IFCHR
, ssp
->dss_oflags
, sspp
,
591 error
= dsioctl(dev
, DIOCSDINFO
, data
, flags
, &ssp
, info
);
595 * XXX this used to hack on dk_openpart to fake opening
596 * partition 0 in case that is used instead of dkpart(dev).
598 old_wlabel
= sp
->ds_wlabel
;
599 set_ds_wlabel(ssp
, slice
, TRUE
);
600 error
= writedisklabel(dev
, sp
->ds_label
);
601 /* XXX should invalidate in-core label if write failed. */
602 set_ds_wlabel(ssp
, slice
, old_wlabel
);
606 if (slice
== WHOLE_DISK_SLICE
)
608 if (!(flags
& FWRITE
))
610 set_ds_wlabel(ssp
, slice
, *(int *)data
!= 0);
619 * Chain the bio_done. b_cmd remains valid through such chaining.
622 dsiodone(struct bio
*bio
)
624 struct buf
*bp
= bio
->bio_buf
;
627 if (bp
->b_cmd
!= BUF_CMD_READ
628 || (!(bp
->b_flags
& B_ERROR
) && bp
->b_error
== 0)) {
629 msg
= fixlabel(NULL
, bio
->bio_caller_info1
.ptr
,
631 (bp
->b_data
+ (int)bio
->bio_caller_info2
.offset
),
634 kprintf("%s\n", msg
);
636 biodone(bio
->bio_prev
);
640 dsisopen(struct diskslices
*ssp
)
646 for (slice
= 0; slice
< ssp
->dss_nslices
; slice
++) {
647 if (ssp
->dss_slices
[slice
].ds_openmask
)
654 * Allocate a slices "struct" and initialize it to contain only an empty
655 * compatibility slice (pointing to itself), a whole disk slice (covering
656 * the disk as described by the label), and (nslices - BASE_SLICES) empty
657 * slices beginning at BASE_SLICE.
660 dsmakeslicestruct(int nslices
, struct disk_info
*info
)
662 struct diskslice
*sp
;
663 struct diskslices
*ssp
;
665 ssp
= kmalloc(offsetof(struct diskslices
, dss_slices
) +
666 nslices
* sizeof *sp
, M_DEVBUF
, M_WAITOK
);
667 ssp
->dss_first_bsd_slice
= COMPATIBILITY_SLICE
;
668 ssp
->dss_nslices
= nslices
;
670 ssp
->dss_secmult
= info
->d_media_blksize
/ DEV_BSIZE
;
671 if (ssp
->dss_secmult
& (ssp
->dss_secmult
- 1))
672 ssp
->dss_secshift
= -1;
674 ssp
->dss_secshift
= ffs(ssp
->dss_secmult
) - 1;
675 ssp
->dss_secsize
= info
->d_media_blksize
;
676 sp
= &ssp
->dss_slices
[0];
677 bzero(sp
, nslices
* sizeof *sp
);
678 sp
[WHOLE_DISK_SLICE
].ds_size
= info
->d_media_blocks
;
683 dsname(cdev_t dev
, int unit
, int slice
, int part
, char *partname
)
685 static char name
[32];
688 dname
= dev_dname(dev
);
689 if (strlen(dname
) > 16)
690 dname
= "nametoolong";
691 ksnprintf(name
, sizeof(name
), "%s%d", dname
, unit
);
693 if (slice
!= WHOLE_DISK_SLICE
|| part
!= RAW_PART
) {
694 partname
[0] = 'a' + part
;
696 if (slice
!= COMPATIBILITY_SLICE
) {
697 ksnprintf(name
+ strlen(name
),
698 sizeof(name
) - strlen(name
), "s%d", slice
- 1);
705 * This should only be called when the unit is inactive and the strategy
706 * routine should not allow it to become active unless we call it. Our
707 * strategy routine must be special to allow activity.
710 dsopen(cdev_t dev
, int mode
, u_int flags
,
711 struct diskslices
**sspp
, struct disk_info
*info
)
715 struct disklabel
*lp1
;
723 struct diskslice
*sp
;
724 struct diskslices
*ssp
;
727 dev
->si_bsize_phys
= info
->d_media_blksize
;
730 if (info
->d_media_blksize
% DEV_BSIZE
) {
731 kprintf("%s: invalid sector size %lu\n", devtoname(dev
),
732 (u_long
)info
->d_media_blksize
);
737 * Do not attempt to read the slice table or disk label when
738 * accessing the raw disk.
740 if (dkslice(dev
) == WHOLE_DISK_SLICE
&& dkpart(dev
) == RAW_PART
) {
741 flags
|= DSO_ONESLICE
| DSO_NOLABELS
;
745 * XXX reinitialize the slice table unless there is an open device
746 * on the unit. This should only be done if the media has changed.
749 need_init
= !dsisopen(ssp
);
750 if (ssp
!= NULL
&& need_init
)
754 * Allocate a minimal slices "struct". This will become
755 * the final slices "struct" if we don't want real slices
756 * or if we can't find any real slices.
760 *sspp
= dsmakeslicestruct(BASE_SLICE
, info
);
762 if (!(flags
& DSO_ONESLICE
)) {
763 TRACE(("mbrinit\n"));
764 error
= mbrinit(dev
, info
, sspp
);
771 ssp
->dss_oflags
= flags
;
774 * If there are no real slices, then make the compatiblity
775 * slice cover the whole disk.
777 * no sectors are reserved for the platform (ds_skip_platform
778 * will be 0) in this case. This means that if a disklabel
779 * is installed it will be directly installed in sector 0.
781 if (ssp
->dss_nslices
== BASE_SLICE
) {
782 ssp
->dss_slices
[COMPATIBILITY_SLICE
].ds_size
783 = info
->d_media_blocks
;
787 * Point the compatibility slice at the BSD slice, if any.
789 for (slice
= BASE_SLICE
; slice
< ssp
->dss_nslices
; slice
++) {
790 sp
= &ssp
->dss_slices
[slice
];
791 if (sp
->ds_type
== DOSPTYP_386BSD
/* XXX */) {
792 struct diskslice
*csp
;
794 csp
= &ssp
->dss_slices
[COMPATIBILITY_SLICE
];
795 ssp
->dss_first_bsd_slice
= slice
;
796 csp
->ds_offset
= sp
->ds_offset
;
797 csp
->ds_size
= sp
->ds_size
;
798 csp
->ds_type
= sp
->ds_type
;
799 csp
->ds_skip_platform
= sp
->ds_skip_platform
;
800 csp
->ds_skip_bsdlabel
= sp
->ds_skip_bsdlabel
;
806 * By definition accesses via the whole-disk device do not
807 * specify any reserved areas. The whole disk may be read
808 * or written by the whole-disk device.
810 * XXX do not set a label for the whole disk slice, the
811 * code should be able to operate without one once we
812 * fix the virgin label code.
814 sp
= &ssp
->dss_slices
[WHOLE_DISK_SLICE
];
815 sp
->ds_label
= clone_label(info
, NULL
);
816 sp
->ds_wlabel
= TRUE
;
817 sp
->ds_skip_platform
= 0;
818 sp
->ds_skip_bsdlabel
= 0;
822 * Initialize secondary info for all slices. It is needed for more
823 * than the current slice in the DEVFS case. XXX DEVFS is no more.
825 * Attempt to read the disklabel for each slice, creating a virgin
826 * label if a slice does not have one.
828 for (slice
= 0; slice
< ssp
->dss_nslices
; slice
++) {
829 sp
= &ssp
->dss_slices
[slice
];
830 if (sp
->ds_label
!= NULL
)
832 dev1
= dkmodslice(dkmodpart(dev
, RAW_PART
), slice
);
833 sname
= dsname(dev
, unit
, slice
, RAW_PART
, partname
);
835 * XXX this should probably only be done for the need_init
836 * case, but there may be a problem with DIOCSYNCSLICEINFO.
838 set_ds_wlabel(ssp
, slice
, TRUE
); /* XXX invert */
839 lp1
= clone_label(info
, sp
);
840 TRACE(("readdisklabel\n"));
841 if (flags
& DSO_NOLABELS
) {
844 msg
= readdisklabel(dev1
, lp1
);
847 * readdisklabel() returns NULL for success, and an
848 * error string for failure.
850 * If there isn't a label on the disk, and if the
851 * DSO_COMPATLABEL is set, we want to use the
852 * faked-up label provided by the caller.
854 * So we set msg to NULL to indicate that there is
855 * no failure (since we have a faked-up label),
856 * free lp1, and then clone it again from lp.
857 * (In case readdisklabel() modified lp1.)
859 if (msg
!= NULL
&& (flags
& DSO_COMPATLABEL
)) {
861 kfree(lp1
, M_DEVBUF
);
862 lp1
= clone_label(info
, sp
);
866 msg
= fixlabel(sname
, sp
, lp1
, FALSE
);
867 if (msg
== NULL
&& lp1
->d_secsize
!= ssp
->dss_secsize
)
868 msg
= "inconsistent sector size";
870 if (sp
->ds_type
== DOSPTYP_386BSD
/* XXX */)
871 log(LOG_WARNING
, "%s: cannot find label (%s)\n",
873 kfree(lp1
, M_DEVBUF
);
876 set_ds_label(ssp
, slice
, lp1
);
877 set_ds_wlabel(ssp
, slice
, FALSE
);
880 slice
= dkslice(dev
);
881 if (slice
>= ssp
->dss_nslices
)
883 sp
= &ssp
->dss_slices
[slice
];
886 && (sp
->ds_label
== NULL
|| part
>= sp
->ds_label
->d_npartitions
))
887 return (EINVAL
); /* XXX needs translation */
889 sp
->ds_openmask
|= mask
;
894 dssize(cdev_t dev
, struct diskslices
**sspp
)
896 struct disklabel
*lp
;
899 struct diskslices
*ssp
;
901 slice
= dkslice(dev
);
904 if (ssp
== NULL
|| slice
>= ssp
->dss_nslices
905 || !(ssp
->dss_slices
[slice
].ds_openmask
& (1 << part
))) {
906 if (dev_dopen(dev
, FREAD
, S_IFCHR
, proc0
.p_ucred
) != 0)
908 dev_dclose(dev
, FREAD
, S_IFCHR
);
911 lp
= ssp
->dss_slices
[slice
].ds_label
;
914 return ((int64_t)lp
->d_partitions
[part
].p_size
);
918 free_ds_label(struct diskslices
*ssp
, int slice
)
920 struct disklabel
*lp
;
921 struct diskslice
*sp
;
923 sp
= &ssp
->dss_slices
[slice
];
928 set_ds_label(ssp
, slice
, (struct disklabel
*)NULL
);
932 fixlabel(char *sname
, struct diskslice
*sp
, struct disklabel
*lp
, int writeflag
)
938 struct partition
*pp
;
941 /* These errors "can't happen" so don't bother reporting details. */
942 if (lp
->d_magic
!= DISKMAGIC
|| lp
->d_magic2
!= DISKMAGIC
)
943 return ("fixlabel: invalid magic");
944 if (dkcksum(lp
) != 0)
945 return ("fixlabel: invalid checksum");
947 pp
= &lp
->d_partitions
[RAW_PART
];
950 offset
= sp
->ds_offset
;
952 start
= sp
->ds_offset
;
953 offset
= -sp
->ds_offset
;
955 if (pp
->p_offset
!= start
) {
958 "%s: rejecting BSD label: raw partition offset != slice offset\n",
960 slice_info(sname
, sp
);
961 partition_info(sname
, RAW_PART
, pp
);
963 return ("fixlabel: raw partition offset != slice offset");
965 if (pp
->p_size
!= sp
->ds_size
) {
967 kprintf("%s: raw partition size != slice size\n", sname
);
968 slice_info(sname
, sp
);
969 partition_info(sname
, RAW_PART
, pp
);
971 if (pp
->p_size
> sp
->ds_size
) {
973 return ("fixlabel: raw partition size > slice size");
974 kprintf("%s: truncating raw partition\n", sname
);
975 pp
->p_size
= sp
->ds_size
;
978 end
= start
+ sp
->ds_size
;
980 return ("fixlabel: slice wraps");
981 if (lp
->d_secpercyl
<= 0)
982 return ("fixlabel: d_secpercyl <= 0");
985 for (part
= 0; part
< lp
->d_npartitions
; part
++, pp
++) {
986 if (pp
->p_offset
!= 0 || pp
->p_size
!= 0) {
987 if (pp
->p_offset
< start
988 || pp
->p_offset
+ pp
->p_size
> end
989 || pp
->p_offset
+ pp
->p_size
< pp
->p_offset
) {
992 "%s: rejecting partition in BSD label: it isn't entirely within the slice\n",
995 slice_info(sname
, sp
);
998 partition_info(sname
, part
, pp
);
1000 /* XXX else silently discard junk. */
1001 bzero(pp
, sizeof *pp
);
1003 pp
->p_offset
+= offset
;
1006 lp
->d_ncylinders
= sp
->ds_size
/ lp
->d_secpercyl
;
1007 lp
->d_secperunit
= sp
->ds_size
;
1009 lp
->d_checksum
= dkcksum(lp
);
1014 partition_info(char *sname
, int part
, struct partition
*pp
)
1016 kprintf("%s%c: start %lu, end %lu, size %lu\n", sname
, 'a' + part
,
1017 (u_long
)pp
->p_offset
, (u_long
)(pp
->p_offset
+ pp
->p_size
- 1),
1018 (u_long
)pp
->p_size
);
1022 slice_info(char *sname
, struct diskslice
*sp
)
1024 kprintf("%s: start %llu, end %llu, size %llu\n", sname
,
1025 sp
->ds_offset
, sp
->ds_offset
+ sp
->ds_size
- 1, sp
->ds_size
);
1029 set_ds_label(struct diskslices
*ssp
, int slice
, struct disklabel
*lp
)
1031 struct diskslice
*sp1
= &ssp
->dss_slices
[slice
];
1032 struct diskslice
*sp2
;
1034 if (slice
== COMPATIBILITY_SLICE
)
1035 sp2
= &ssp
->dss_slices
[ssp
->dss_first_bsd_slice
];
1036 else if (slice
== ssp
->dss_first_bsd_slice
)
1037 sp2
= &ssp
->dss_slices
[COMPATIBILITY_SLICE
];
1045 * If the slice is not the whole-disk slice, setup the reserved
1048 * The reserved area for the original bsd disklabel, inclusive of
1049 * the label and space for boot2, is 15 sectors. If you've
1050 * noticed people traditionally skipping 16 sectors its because
1051 * the sector numbers start at the beginning of the slice rather
1052 * then the beginning of the disklabel and traditional dos slices
1053 * reserve a sector at the beginning for the boot code.
1055 * NOTE! With the traditional bsdlabel, the first N bytes of boot2
1056 * overlap with the disklabel. The disklabel program checks that
1059 if (slice
!= WHOLE_DISK_SLICE
) {
1060 sp1
->ds_skip_bsdlabel
= sp1
->ds_skip_platform
+ 15;
1062 sp2
->ds_skip_bsdlabel
= sp1
->ds_skip_bsdlabel
;
1067 set_ds_wlabel(struct diskslices
*ssp
, int slice
, int wlabel
)
1069 ssp
->dss_slices
[slice
].ds_wlabel
= wlabel
;
1070 if (slice
== COMPATIBILITY_SLICE
)
1071 ssp
->dss_slices
[ssp
->dss_first_bsd_slice
].ds_wlabel
= wlabel
;
1072 else if (slice
== ssp
->dss_first_bsd_slice
)
1073 ssp
->dss_slices
[COMPATIBILITY_SLICE
].ds_wlabel
= wlabel
;