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.26 2006/12/23 01:35:04 swildner Exp $
50 #include <sys/param.h>
51 #include <sys/systm.h>
54 #include <sys/disklabel.h>
55 #include <sys/diskslice.h>
56 #include <sys/diskmbr.h>
57 #include <sys/fcntl.h>
58 #include <sys/malloc.h>
60 #include <sys/syslog.h>
62 #include <sys/vnode.h>
63 #include <sys/device.h>
64 #include <sys/thread2.h>
66 #include <vfs/ufs/dinode.h> /* XXX used only for fs.h */
67 #include <vfs/ufs/fs.h> /* XXX used only to get BBSIZE/SBSIZE */
69 #define TRACE(str) do { if (ds_debug) kprintf str; } while (0)
71 typedef u_char bool_t
;
73 static volatile bool_t ds_debug
;
75 static struct disklabel
*clone_label (struct disklabel
*lp
);
76 static void dsiodone (struct bio
*bio
);
77 static char *fixlabel (char *sname
, struct diskslice
*sp
,
78 struct disklabel
*lp
, int writeflag
);
79 static void free_ds_label (struct diskslices
*ssp
, int slice
);
80 static void partition_info (char *sname
, int part
, struct partition
*pp
);
81 static void slice_info (char *sname
, struct diskslice
*sp
);
82 static void set_ds_label (struct diskslices
*ssp
, int slice
,
83 struct disklabel
*lp
);
84 static void set_ds_wlabel (struct diskslices
*ssp
, int slice
, int wlabel
);
87 * Duplicate a label for the whole disk, and initialize defaults in the
88 * copy for fields that are not already initialized. The caller only
89 * needs to initialize d_secsize and d_secperunit, and zero the fields
90 * that are to be defaulted.
92 static struct disklabel
*
93 clone_label(struct disklabel
*lp
)
95 struct disklabel
*lp1
;
97 lp1
= kmalloc(sizeof *lp1
, M_DEVBUF
, M_WAITOK
);
100 if (lp1
->d_typename
[0] == '\0')
101 strncpy(lp1
->d_typename
, "amnesiac", sizeof(lp1
->d_typename
));
102 if (lp1
->d_packname
[0] == '\0')
103 strncpy(lp1
->d_packname
, "fictitious", sizeof(lp1
->d_packname
));
104 if (lp1
->d_nsectors
== 0)
105 lp1
->d_nsectors
= 32;
106 if (lp1
->d_ntracks
== 0)
108 lp1
->d_secpercyl
= lp1
->d_nsectors
* lp1
->d_ntracks
;
109 lp1
->d_ncylinders
= lp1
->d_secperunit
/ lp1
->d_secpercyl
;
112 if (lp1
->d_interleave
== 0)
113 lp1
->d_interleave
= 1;
114 if (lp1
->d_npartitions
< RAW_PART
+ 1)
115 lp1
->d_npartitions
= MAXPARTITIONS
;
116 if (lp1
->d_bbsize
== 0)
117 lp1
->d_bbsize
= BBSIZE
;
118 if (lp1
->d_sbsize
== 0)
119 lp1
->d_sbsize
= SBSIZE
;
120 lp1
->d_partitions
[RAW_PART
].p_size
= lp1
->d_secperunit
;
121 lp1
->d_magic
= DISKMAGIC
;
122 lp1
->d_magic2
= DISKMAGIC
;
123 lp1
->d_checksum
= dkcksum(lp1
);
128 * Determine the size of the transfer, and make sure it is
129 * within the boundaries of the partition. Adjust transfer
130 * if needed, and signal errors or early completion.
133 * o Split buffers that are too big for the device.
134 * o Check for overflow.
135 * o Finish cleaning this up.
137 * This function returns 1 on success, 0 if transfer equates
138 * to EOF (end of disk) or -1 on failure. The appropriate
139 * 'errno' value is also set in bp->b_error and bp->b_flags
140 * is marked with B_ERROR.
143 dscheck(cdev_t dev
, struct bio
*bio
, struct diskslices
*ssp
)
145 struct buf
*bp
= bio
->bio_buf
;
149 struct disklabel
*lp
;
152 struct partition
*pp
;
154 daddr_t slicerel_secno
;
155 struct diskslice
*sp
;
159 if (bio
->bio_offset
< 0) {
160 kprintf("dscheck(%s): negative bio_offset %lld\n",
161 devtoname(dev
), bio
->bio_offset
);
164 sp
= &ssp
->dss_slices
[dkslice(dev
)];
167 if (ssp
->dss_secmult
== 1) {
170 } else if (ssp
->dss_secshift
!= -1) {
171 shift
= DEV_BSHIFT
+ ssp
->dss_secshift
;
173 mask
= (1 << shift
) - 1;
174 if ((int)bp
->b_bcount
& mask
)
176 if ((int)bio
->bio_offset
& mask
)
178 secno
= (daddr_t
)(bio
->bio_offset
>> shift
);
179 nsec
= bp
->b_bcount
>> shift
;
181 if (bp
->b_bcount
% ssp
->dss_secsize
)
183 if (bio
->bio_offset
% ssp
->dss_secsize
)
185 secno
= (daddr_t
)(bio
->bio_offset
/ ssp
->dss_secsize
);
186 nsec
= bp
->b_bcount
/ ssp
->dss_secsize
;
189 labelsect
= -LABELSECTOR
- 1;
190 endsecno
= sp
->ds_size
;
191 slicerel_secno
= secno
;
193 labelsect
= lp
->d_partitions
[LABEL_PART
].p_offset
;
195 Debugger("labelsect != 0 in dscheck()");
196 pp
= &lp
->d_partitions
[dkpart(dev
)];
197 endsecno
= pp
->p_size
;
198 slicerel_secno
= pp
->p_offset
+ secno
;
201 /* overwriting disk label ? */
202 /* XXX should also protect bootstrap in first 8K */
203 if (slicerel_secno
<= LABELSECTOR
+ labelsect
&&
205 slicerel_secno
+ nsec
> LABELSECTOR
+ labelsect
&&
207 bp
->b_cmd
!= BUF_CMD_READ
&& sp
->ds_wlabel
== 0) {
212 #if defined(DOSBBSECTOR) && defined(notyet)
213 /* overwriting master boot record? */
214 if (slicerel_secno
<= DOSBBSECTOR
&& bp
->b_cmd
!= BUF_CMD_READ
&&
215 sp
->ds_wlabel
== 0) {
224 if (secno
+ nsec
> endsecno
) {
226 * Return an error if beyond the end of the disk, or
227 * if B_BNOCLIP is set. Tell the system that we do not
228 * need to keep the buffer around.
230 if (secno
> endsecno
|| (bp
->b_flags
& B_BNOCLIP
))
234 * If exactly at end of disk, return an EOF. Throw away
235 * the buffer contents, if any, by setting B_INVAL.
237 if (secno
== endsecno
) {
238 bp
->b_resid
= bp
->b_bcount
;
239 bp
->b_flags
|= B_INVAL
;
246 nsec
= endsecno
- secno
;
247 bp
->b_bcount
= nsec
* ssp
->dss_secsize
;
250 nbio
= push_bio(bio
);
251 nbio
->bio_offset
= (off_t
)(sp
->ds_offset
+ slicerel_secno
) *
255 * Snoop on label accesses if the slice offset is nonzero. Fudge
256 * offsets in the label to keep the in-core label coherent with
259 if (slicerel_secno
<= LABELSECTOR
+ labelsect
261 && slicerel_secno
+ nsec
> LABELSECTOR
+ labelsect
263 && sp
->ds_offset
!= 0) {
264 nbio
->bio_done
= dsiodone
;
265 nbio
->bio_caller_info1
.ptr
= sp
;
266 nbio
->bio_caller_info2
.offset
= (off_t
)(LABELSECTOR
+ labelsect
-
267 slicerel_secno
) * ssp
->dss_secsize
;
268 if (bp
->b_cmd
!= BUF_CMD_READ
) {
270 * XXX even disklabel(8) writes directly so we need
271 * to adjust writes. Perhaps we should drop support
272 * for DIOCWLABEL (always write protect labels) and
273 * require the use of DIOCWDINFO.
275 * XXX probably need to copy the data to avoid even
276 * temporarily corrupting the in-core copy.
278 /* XXX need name here. */
282 (bp
->b_data
+ (int)nbio
->bio_caller_info2
.offset
),
285 kprintf("dscheck(%s): %s\n",
286 devtoname(dev
), msg
);
297 "dscheck(%s): b_bcount %d is not on a sector boundary (ssize %d)\n",
298 devtoname(dev
), bp
->b_bcount
, ssp
->dss_secsize
);
303 "dscheck(%s): bio_offset %lld is not on a sector boundary (ssize %d)\n",
304 devtoname(dev
), bio
->bio_offset
, ssp
->dss_secsize
);
306 bp
->b_error
= EINVAL
;
310 * Terminate the I/O with a ranging error. Since the buffer is
311 * either illegal or beyond the file EOF, mark it B_INVAL as well.
313 bp
->b_resid
= bp
->b_bcount
;
314 bp
->b_flags
|= B_ERROR
| B_INVAL
;
317 * Caller must biodone() the originally passed bio if NULL is
324 dsclose(cdev_t dev
, int mode
, struct diskslices
*ssp
)
327 struct diskslice
*sp
;
329 sp
= &ssp
->dss_slices
[dkslice(dev
)];
330 mask
= 1 << dkpart(dev
);
331 sp
->ds_openmask
&= ~mask
;
335 dsgone(struct diskslices
**sspp
)
338 struct diskslice
*sp
;
339 struct diskslices
*ssp
;
341 for (slice
= 0, ssp
= *sspp
; slice
< ssp
->dss_nslices
; slice
++) {
342 sp
= &ssp
->dss_slices
[slice
];
343 free_ds_label(ssp
, slice
);
345 kfree(ssp
, M_DEVBUF
);
350 * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this
351 * is subject to the same restriction as dsopen().
354 dsioctl(cdev_t dev
, u_long cmd
, caddr_t data
,
355 int flags
, struct diskslices
**sspp
)
358 struct disklabel
*lp
;
363 struct diskslice
*sp
;
364 struct diskslices
*ssp
;
365 struct partition
*pp
;
367 slice
= dkslice(dev
);
369 sp
= &ssp
->dss_slices
[slice
];
374 lp
= (struct disklabel
*)data
;
375 if (ssp
->dss_slices
[WHOLE_DISK_SLICE
].ds_label
) {
376 *lp
= *ssp
->dss_slices
[WHOLE_DISK_SLICE
].ds_label
;
378 bzero(lp
, sizeof(struct disklabel
));
381 lp
->d_magic
= DISKMAGIC
;
382 lp
->d_magic2
= DISKMAGIC
;
383 pp
= &lp
->d_partitions
[RAW_PART
];
385 pp
->p_size
= sp
->ds_size
;
387 lp
->d_npartitions
= MAXPARTITIONS
;
388 if (lp
->d_interleave
== 0)
389 lp
->d_interleave
= 1;
392 if (lp
->d_nsectors
== 0)
394 if (lp
->d_ntracks
== 0)
397 lp
->d_bbsize
= BBSIZE
;
398 lp
->d_sbsize
= SBSIZE
;
399 lp
->d_secpercyl
= lp
->d_nsectors
* lp
->d_ntracks
;
400 lp
->d_ncylinders
= sp
->ds_size
/ lp
->d_secpercyl
;
401 lp
->d_secperunit
= sp
->ds_size
;
403 lp
->d_checksum
= dkcksum(lp
);
409 *(struct disklabel
*)data
= *lp
;
416 *(struct disklabel
**)data
= lp
;
423 ((struct partinfo
*)data
)->disklab
= lp
;
424 ((struct partinfo
*)data
)->part
425 = &lp
->d_partitions
[dkpart(dev
)];
429 bcopy(ssp
, data
, (char *)&ssp
->dss_slices
[ssp
->dss_nslices
] -
434 if (slice
== WHOLE_DISK_SLICE
)
436 if (!(flags
& FWRITE
))
438 lp
= kmalloc(sizeof *lp
, M_DEVBUF
, M_WAITOK
);
439 if (sp
->ds_label
== NULL
)
440 bzero(lp
, sizeof *lp
);
442 bcopy(sp
->ds_label
, lp
, sizeof *lp
);
443 if (sp
->ds_label
== NULL
)
446 openmask
= sp
->ds_openmask
;
447 if (slice
== COMPATIBILITY_SLICE
)
448 openmask
|= ssp
->dss_slices
[
449 ssp
->dss_first_bsd_slice
].ds_openmask
;
450 else if (slice
== ssp
->dss_first_bsd_slice
)
451 openmask
|= ssp
->dss_slices
[
452 COMPATIBILITY_SLICE
].ds_openmask
;
454 error
= setdisklabel(lp
, (struct disklabel
*)data
,
456 /* XXX why doesn't setdisklabel() check this? */
457 if (error
== 0 && lp
->d_partitions
[RAW_PART
].p_offset
!= 0)
460 if (lp
->d_secperunit
> sp
->ds_size
)
462 for (part
= 0; part
< lp
->d_npartitions
; part
++)
463 if (lp
->d_partitions
[part
].p_size
> sp
->ds_size
)
470 free_ds_label(ssp
, slice
);
471 set_ds_label(ssp
, slice
, lp
);
474 case DIOCSYNCSLICEINFO
:
475 if (slice
!= WHOLE_DISK_SLICE
|| dkpart(dev
) != RAW_PART
)
478 for (slice
= 0; slice
< ssp
->dss_nslices
; slice
++) {
479 openmask
= ssp
->dss_slices
[slice
].ds_openmask
;
481 && (slice
!= WHOLE_DISK_SLICE
482 || openmask
& ~(1 << RAW_PART
)))
487 * Temporarily forget the current slices struct and read
489 * XXX should wait for current accesses on this disk to
490 * complete, then lock out future accesses and opens.
493 lp
= kmalloc(sizeof *lp
, M_DEVBUF
, M_WAITOK
);
494 *lp
= *ssp
->dss_slices
[WHOLE_DISK_SLICE
].ds_label
;
495 error
= dsopen(dev
, S_IFCHR
, ssp
->dss_oflags
, sspp
, lp
);
503 * Reopen everything. This is a no-op except in the "force"
504 * case and when the raw bdev and cdev are both open. Abort
507 for (slice
= 0; slice
< ssp
->dss_nslices
; slice
++) {
508 for (openmask
= ssp
->dss_slices
[slice
].ds_openmask
,
509 part
= 0; openmask
; openmask
>>= 1, part
++) {
512 error
= dsopen(dkmodslice(dkmodpart(dev
, part
),
514 S_IFCHR
, ssp
->dss_oflags
, sspp
,
529 error
= dsioctl(dev
, DIOCSDINFO
, data
, flags
, &ssp
);
533 * XXX this used to hack on dk_openpart to fake opening
534 * partition 0 in case that is used instead of dkpart(dev).
536 old_wlabel
= sp
->ds_wlabel
;
537 set_ds_wlabel(ssp
, slice
, TRUE
);
538 error
= writedisklabel(dev
, sp
->ds_label
);
539 /* XXX should invalidate in-core label if write failed. */
540 set_ds_wlabel(ssp
, slice
, old_wlabel
);
544 if (slice
== WHOLE_DISK_SLICE
)
546 if (!(flags
& FWRITE
))
548 set_ds_wlabel(ssp
, slice
, *(int *)data
!= 0);
557 * Chain the bio_done. b_cmd remains valid through such chaining.
560 dsiodone(struct bio
*bio
)
562 struct buf
*bp
= bio
->bio_buf
;
565 if (bp
->b_cmd
!= BUF_CMD_READ
566 || (!(bp
->b_flags
& B_ERROR
) && bp
->b_error
== 0)) {
567 msg
= fixlabel(NULL
, bio
->bio_caller_info1
.ptr
,
569 (bp
->b_data
+ (int)bio
->bio_caller_info2
.offset
),
572 kprintf("%s\n", msg
);
574 biodone(bio
->bio_prev
);
578 dsisopen(struct diskslices
*ssp
)
584 for (slice
= 0; slice
< ssp
->dss_nslices
; slice
++) {
585 if (ssp
->dss_slices
[slice
].ds_openmask
)
592 * Allocate a slices "struct" and initialize it to contain only an empty
593 * compatibility slice (pointing to itself), a whole disk slice (covering
594 * the disk as described by the label), and (nslices - BASE_SLICES) empty
595 * slices beginning at BASE_SLICE.
598 dsmakeslicestruct(int nslices
, struct disklabel
*lp
)
600 struct diskslice
*sp
;
601 struct diskslices
*ssp
;
603 ssp
= kmalloc(offsetof(struct diskslices
, dss_slices
) +
604 nslices
* sizeof *sp
, M_DEVBUF
, M_WAITOK
);
605 ssp
->dss_first_bsd_slice
= COMPATIBILITY_SLICE
;
606 ssp
->dss_nslices
= nslices
;
608 ssp
->dss_secmult
= lp
->d_secsize
/ DEV_BSIZE
;
609 if (ssp
->dss_secmult
& (ssp
->dss_secmult
- 1))
610 ssp
->dss_secshift
= -1;
612 ssp
->dss_secshift
= ffs(ssp
->dss_secmult
) - 1;
613 ssp
->dss_secsize
= lp
->d_secsize
;
614 sp
= &ssp
->dss_slices
[0];
615 bzero(sp
, nslices
* sizeof *sp
);
616 sp
[WHOLE_DISK_SLICE
].ds_size
= lp
->d_secperunit
;
621 dsname(cdev_t dev
, int unit
, int slice
, int part
, char *partname
)
623 static char name
[32];
626 dname
= dev_dname(dev
);
627 if (strlen(dname
) > 16)
628 dname
= "nametoolong";
629 ksnprintf(name
, sizeof(name
), "%s%d", dname
, unit
);
631 if (slice
!= WHOLE_DISK_SLICE
|| part
!= RAW_PART
) {
632 partname
[0] = 'a' + part
;
634 if (slice
!= COMPATIBILITY_SLICE
) {
635 ksnprintf(name
+ strlen(name
),
636 sizeof(name
) - strlen(name
), "s%d", slice
- 1);
643 * This should only be called when the unit is inactive and the strategy
644 * routine should not allow it to become active unless we call it. Our
645 * strategy routine must be special to allow activity.
648 dsopen(cdev_t dev
, int mode
, u_int flags
,
649 struct diskslices
**sspp
, struct disklabel
*lp
)
653 struct disklabel
*lp1
;
661 struct diskslice
*sp
;
662 struct diskslices
*ssp
;
665 dev
->si_bsize_phys
= lp
->d_secsize
;
668 if (lp
->d_secsize
% DEV_BSIZE
) {
669 kprintf("%s: invalid sector size %lu\n", devtoname(dev
),
670 (u_long
)lp
->d_secsize
);
675 * Do not attempt to read the slice table or disk label when
676 * accessing the raw disk.
678 if (dkslice(dev
) == WHOLE_DISK_SLICE
&& dkpart(dev
) == RAW_PART
) {
679 flags
|= DSO_ONESLICE
| DSO_NOLABELS
;
683 * XXX reinitialize the slice table unless there is an open device
684 * on the unit. This should only be done if the media has changed.
687 need_init
= !dsisopen(ssp
);
688 if (ssp
!= NULL
&& need_init
)
692 * Allocate a minimal slices "struct". This will become
693 * the final slices "struct" if we don't want real slices
694 * or if we can't find any real slices.
696 *sspp
= dsmakeslicestruct(BASE_SLICE
, lp
);
698 if (!(flags
& DSO_ONESLICE
)) {
700 error
= dsinit(dev
, lp
, sspp
);
707 ssp
->dss_oflags
= flags
;
710 * If there are no real slices, then make the compatiblity
711 * slice cover the whole disk.
713 if (ssp
->dss_nslices
== BASE_SLICE
)
714 ssp
->dss_slices
[COMPATIBILITY_SLICE
].ds_size
717 /* Point the compatibility slice at the BSD slice, if any. */
718 for (slice
= BASE_SLICE
; slice
< ssp
->dss_nslices
; slice
++) {
719 sp
= &ssp
->dss_slices
[slice
];
720 if (sp
->ds_type
== DOSPTYP_386BSD
/* XXX */) {
721 ssp
->dss_first_bsd_slice
= slice
;
722 ssp
->dss_slices
[COMPATIBILITY_SLICE
].ds_offset
724 ssp
->dss_slices
[COMPATIBILITY_SLICE
].ds_size
726 ssp
->dss_slices
[COMPATIBILITY_SLICE
].ds_type
732 ssp
->dss_slices
[WHOLE_DISK_SLICE
].ds_label
= clone_label(lp
);
733 ssp
->dss_slices
[WHOLE_DISK_SLICE
].ds_wlabel
= TRUE
;
737 * Initialize secondary info for all slices. It is needed for more
738 * than the current slice in the DEVFS case. XXX DEVFS is no more.
740 for (slice
= 0; slice
< ssp
->dss_nslices
; slice
++) {
741 sp
= &ssp
->dss_slices
[slice
];
742 if (sp
->ds_label
!= NULL
)
744 dev1
= dkmodslice(dkmodpart(dev
, RAW_PART
), slice
);
745 sname
= dsname(dev
, unit
, slice
, RAW_PART
, partname
);
747 * XXX this should probably only be done for the need_init
748 * case, but there may be a problem with DIOCSYNCSLICEINFO.
750 set_ds_wlabel(ssp
, slice
, TRUE
); /* XXX invert */
751 lp1
= clone_label(lp
);
752 TRACE(("readdisklabel\n"));
753 if (flags
& DSO_NOLABELS
)
756 msg
= readdisklabel(dev1
, lp1
);
759 * readdisklabel() returns NULL for success, and an
760 * error string for failure.
762 * If there isn't a label on the disk, and if the
763 * DSO_COMPATLABEL is set, we want to use the
764 * faked-up label provided by the caller.
766 * So we set msg to NULL to indicate that there is
767 * no failure (since we have a faked-up label),
768 * free lp1, and then clone it again from lp.
769 * (In case readdisklabel() modified lp1.)
771 if (msg
!= NULL
&& (flags
& DSO_COMPATLABEL
)) {
773 kfree(lp1
, M_DEVBUF
);
774 lp1
= clone_label(lp
);
778 msg
= fixlabel(sname
, sp
, lp1
, FALSE
);
779 if (msg
== NULL
&& lp1
->d_secsize
!= ssp
->dss_secsize
)
780 msg
= "inconsistent sector size";
782 if (sp
->ds_type
== DOSPTYP_386BSD
/* XXX */)
783 log(LOG_WARNING
, "%s: cannot find label (%s)\n",
785 kfree(lp1
, M_DEVBUF
);
788 if (lp1
->d_flags
& D_BADSECT
) {
789 log(LOG_ERR
, "%s: bad sector table not supported\n",
791 kfree(lp1
, M_DEVBUF
);
794 set_ds_label(ssp
, slice
, lp1
);
795 set_ds_wlabel(ssp
, slice
, FALSE
);
798 slice
= dkslice(dev
);
799 if (slice
>= ssp
->dss_nslices
)
801 sp
= &ssp
->dss_slices
[slice
];
804 && (sp
->ds_label
== NULL
|| part
>= sp
->ds_label
->d_npartitions
))
805 return (EINVAL
); /* XXX needs translation */
807 sp
->ds_openmask
|= mask
;
812 dssize(cdev_t dev
, struct diskslices
**sspp
)
814 struct disklabel
*lp
;
817 struct diskslices
*ssp
;
819 slice
= dkslice(dev
);
822 if (ssp
== NULL
|| slice
>= ssp
->dss_nslices
823 || !(ssp
->dss_slices
[slice
].ds_openmask
& (1 << part
))) {
824 if (dev_dopen(dev
, FREAD
, S_IFCHR
, proc0
.p_ucred
) != 0)
826 dev_dclose(dev
, FREAD
, S_IFCHR
);
829 lp
= ssp
->dss_slices
[slice
].ds_label
;
832 return ((int)lp
->d_partitions
[part
].p_size
);
836 free_ds_label(struct diskslices
*ssp
, int slice
)
838 struct disklabel
*lp
;
839 struct diskslice
*sp
;
841 sp
= &ssp
->dss_slices
[slice
];
846 set_ds_label(ssp
, slice
, (struct disklabel
*)NULL
);
850 fixlabel(char *sname
, struct diskslice
*sp
, struct disklabel
*lp
, int writeflag
)
855 struct partition
*pp
;
859 /* These errors "can't happen" so don't bother reporting details. */
860 if (lp
->d_magic
!= DISKMAGIC
|| lp
->d_magic2
!= DISKMAGIC
)
861 return ("fixlabel: invalid magic");
862 if (dkcksum(lp
) != 0)
863 return ("fixlabel: invalid checksum");
865 pp
= &lp
->d_partitions
[RAW_PART
];
868 offset
= sp
->ds_offset
;
870 start
= sp
->ds_offset
;
871 offset
= -sp
->ds_offset
;
873 if (pp
->p_offset
!= start
) {
876 "%s: rejecting BSD label: raw partition offset != slice offset\n",
878 slice_info(sname
, sp
);
879 partition_info(sname
, RAW_PART
, pp
);
881 return ("fixlabel: raw partition offset != slice offset");
883 if (pp
->p_size
!= sp
->ds_size
) {
885 kprintf("%s: raw partition size != slice size\n", sname
);
886 slice_info(sname
, sp
);
887 partition_info(sname
, RAW_PART
, pp
);
889 if (pp
->p_size
> sp
->ds_size
) {
891 return ("fixlabel: raw partition size > slice size");
892 kprintf("%s: truncating raw partition\n", sname
);
893 pp
->p_size
= sp
->ds_size
;
896 end
= start
+ sp
->ds_size
;
898 return ("fixlabel: slice wraps");
899 if (lp
->d_secpercyl
<= 0)
900 return ("fixlabel: d_secpercyl <= 0");
903 for (part
= 0; part
< lp
->d_npartitions
; part
++, pp
++) {
904 if (pp
->p_offset
!= 0 || pp
->p_size
!= 0) {
905 if (pp
->p_offset
< start
906 || pp
->p_offset
+ pp
->p_size
> end
907 || pp
->p_offset
+ pp
->p_size
< pp
->p_offset
) {
910 "%s: rejecting partition in BSD label: it isn't entirely within the slice\n",
913 slice_info(sname
, sp
);
916 partition_info(sname
, part
, pp
);
918 /* XXX else silently discard junk. */
919 bzero(pp
, sizeof *pp
);
921 pp
->p_offset
+= offset
;
924 lp
->d_ncylinders
= sp
->ds_size
/ lp
->d_secpercyl
;
925 lp
->d_secperunit
= sp
->ds_size
;
927 lp
->d_checksum
= dkcksum(lp
);
932 partition_info(char *sname
, int part
, struct partition
*pp
)
934 kprintf("%s%c: start %lu, end %lu, size %lu\n", sname
, 'a' + part
,
935 (u_long
)pp
->p_offset
, (u_long
)(pp
->p_offset
+ pp
->p_size
- 1),
940 slice_info(char *sname
, struct diskslice
*sp
)
942 kprintf("%s: start %lu, end %lu, size %lu\n", sname
,
943 sp
->ds_offset
, sp
->ds_offset
+ sp
->ds_size
- 1, sp
->ds_size
);
947 set_ds_label(struct diskslices
*ssp
, int slice
, struct disklabel
*lp
)
949 ssp
->dss_slices
[slice
].ds_label
= lp
;
950 if (slice
== COMPATIBILITY_SLICE
)
951 ssp
->dss_slices
[ssp
->dss_first_bsd_slice
].ds_label
= lp
;
952 else if (slice
== ssp
->dss_first_bsd_slice
)
953 ssp
->dss_slices
[COMPATIBILITY_SLICE
].ds_label
= lp
;
957 set_ds_wlabel(struct diskslices
*ssp
, int slice
, int wlabel
)
959 ssp
->dss_slices
[slice
].ds_wlabel
= wlabel
;
960 if (slice
== COMPATIBILITY_SLICE
)
961 ssp
->dss_slices
[ssp
->dss_first_bsd_slice
].ds_wlabel
= wlabel
;
962 else if (slice
== ssp
->dss_first_bsd_slice
)
963 ssp
->dss_slices
[COMPATIBILITY_SLICE
].ds_wlabel
= wlabel
;