xref: /dragonfly/sys/kern/subr_diskslice.c (revision 28feafc7)
1 /*-
2  * Copyright (c) 1994 Bruce D. Evans.
3  * All rights reserved.
4  *
5  * Copyright (c) 1990 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * William Jolitz.
10  *
11  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
12  * All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. All advertising materials mentioning features or use of this software
23  *    must display the following acknowledgement:
24  *	This product includes software developed by the University of
25  *	California, Berkeley and its contributors.
26  * 4. Neither the name of the University nor the names of its contributors
27  *    may be used to endorse or promote products derived from this software
28  *    without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  *
42  *	from: @(#)wd.c	7.2 (Berkeley) 5/9/91
43  *	from: wd.c,v 1.55 1994/10/22 01:57:12 phk Exp $
44  *	from: @(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
45  *	from: ufs_disksubr.c,v 1.8 1994/06/07 01:21:39 phk Exp $
46  * $FreeBSD: src/sys/kern/subr_diskslice.c,v 1.82.2.6 2001/07/24 09:49:41 dd Exp $
47  * $DragonFly: src/sys/kern/subr_diskslice.c,v 1.37 2007/05/19 09:46:18 dillon Exp $
48  */
49 
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>
66 
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 */
69 
70 #define TRACE(str)	do { if (ds_debug) kprintf str; } while (0)
71 
72 typedef	u_char	bool_t;
73 
74 static volatile bool_t ds_debug;
75 
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 (const char *sname, struct diskslice *sp,
80 			   struct disklabel *lp, int writeflag);
81 static int  dsreadandsetlabel(cdev_t dev, u_int flags,
82 			   struct diskslices *ssp, struct diskslice *sp,
83 			   struct disk_info *info);
84 static void free_ds_label (struct diskslices *ssp, int slice);
85 static void partition_info (const char *sname, int part, struct partition *pp);
86 static void slice_info (const char *sname, struct diskslice *sp);
87 static void set_ds_label (struct diskslices *ssp, int slice,
88 			      struct disklabel *lp);
89 static void set_ds_wlabel (struct diskslices *ssp, int slice, int wlabel);
90 
91 /*
92  * Create a disklabel based on a disk_info structure, initializing
93  * the appropriate fields and creating a raw partition that covers the
94  * whole disk.
95  *
96  * If a diskslice is passed, the label is truncated to the slice
97  */
98 static struct disklabel *
99 clone_label(struct disk_info *info, struct diskslice *sp)
100 {
101 	struct disklabel *lp1;
102 
103 	lp1 = kmalloc(sizeof *lp1, M_DEVBUF, M_WAITOK | M_ZERO);
104 	lp1->d_nsectors = info->d_secpertrack;
105 	lp1->d_ntracks = info->d_nheads;
106 	lp1->d_secpercyl = info->d_secpercyl;
107 	lp1->d_secsize = info->d_media_blksize;
108 
109 	if (sp) {
110 		lp1->d_secperunit = (u_int)sp->ds_size;
111 		lp1->d_partitions[RAW_PART].p_size = lp1->d_secperunit;
112 	} else {
113 		lp1->d_secperunit = (u_int)info->d_media_blocks;
114 		lp1->d_partitions[RAW_PART].p_size = lp1->d_secperunit;
115 	}
116 
117 	/*
118 	 * Used by the CD driver to create a compatibility slice which
119 	 * allows us to mount root from the CD.
120 	 */
121 	if (info->d_dsflags & DSO_COMPATPARTA) {
122 		lp1->d_partitions[0].p_size = lp1->d_secperunit;
123 		lp1->d_partitions[0].p_fstype = FS_OTHER;
124 	}
125 
126 	if (lp1->d_typename[0] == '\0')
127 		strncpy(lp1->d_typename, "amnesiac", sizeof(lp1->d_typename));
128 	if (lp1->d_packname[0] == '\0')
129 		strncpy(lp1->d_packname, "fictitious", sizeof(lp1->d_packname));
130 	if (lp1->d_nsectors == 0)
131 		lp1->d_nsectors = 32;
132 	if (lp1->d_ntracks == 0)
133 		lp1->d_ntracks = 64;
134 	lp1->d_secpercyl = lp1->d_nsectors * lp1->d_ntracks;
135 	lp1->d_ncylinders = lp1->d_secperunit / lp1->d_secpercyl;
136 	if (lp1->d_rpm == 0)
137 		lp1->d_rpm = 3600;
138 	if (lp1->d_interleave == 0)
139 		lp1->d_interleave = 1;
140 	if (lp1->d_npartitions < RAW_PART + 1)
141 		lp1->d_npartitions = MAXPARTITIONS;
142 	if (lp1->d_bbsize == 0)
143 		lp1->d_bbsize = BBSIZE;
144 	if (lp1->d_sbsize == 0)
145 		lp1->d_sbsize = SBSIZE;
146 	lp1->d_partitions[RAW_PART].p_size = lp1->d_secperunit;
147 	lp1->d_magic = DISKMAGIC;
148 	lp1->d_magic2 = DISKMAGIC;
149 	lp1->d_checksum = dkcksum(lp1);
150 	return (lp1);
151 }
152 
153 /*
154  * Determine the size of the transfer, and make sure it is
155  * within the boundaries of the partition. Adjust transfer
156  * if needed, and signal errors or early completion.
157  *
158  * XXX TODO:
159  *	o Split buffers that are too big for the device.
160  *	o Check for overflow.
161  *	o Finish cleaning this up.
162  *
163  * This function returns 1 on success, 0 if transfer equates
164  * to EOF (end of disk) or -1 on failure.  The appropriate
165  * 'errno' value is also set in bp->b_error and bp->b_flags
166  * is marked with B_ERROR.
167  */
168 struct bio *
169 dscheck(cdev_t dev, struct bio *bio, struct diskslices *ssp)
170 {
171 	struct buf *bp = bio->bio_buf;
172 	struct bio *nbio;
173 	struct disklabel *lp;
174 	char *msg;
175 	long nsec;
176 	u_int64_t secno;
177 	u_int64_t endsecno;
178 	u_int64_t labelsect;
179 	u_int64_t slicerel_secno;
180 	struct diskslice *sp;
181 	u_int32_t part;
182 	u_int32_t slice;
183 	int shift;
184 	int mask;
185 
186 	slice = dkslice(dev);
187 	part  = dkpart(dev);
188 
189 	if (bio->bio_offset < 0) {
190 		kprintf("dscheck(%s): negative bio_offset %lld\n",
191 			devtoname(dev), bio->bio_offset);
192 		goto bad;
193 	}
194 	if (slice >= ssp->dss_nslices) {
195 		kprintf("dscheck(%s): slice too large %d/%d\n",
196 			devtoname(dev), slice, ssp->dss_nslices);
197 		goto bad;
198 	}
199 	sp = &ssp->dss_slices[slice];
200 
201 	/*
202 	 * Calculate secno and nsec
203 	 */
204 	if (ssp->dss_secmult == 1) {
205 		shift = DEV_BSHIFT;
206 		goto doshift;
207 	} else if (ssp->dss_secshift != -1) {
208 		shift = DEV_BSHIFT + ssp->dss_secshift;
209 doshift:
210 		mask = (1 << shift) - 1;
211 		if ((int)bp->b_bcount & mask)
212 			goto bad_bcount;
213 		if ((int)bio->bio_offset & mask)
214 			goto bad_blkno;
215 		secno = bio->bio_offset >> shift;
216 		nsec = bp->b_bcount >> shift;
217 	} else {
218 		if (bp->b_bcount % ssp->dss_secsize)
219 			goto bad_bcount;
220 		if (bio->bio_offset % ssp->dss_secsize)
221 			goto bad_blkno;
222 		secno = bio->bio_offset / ssp->dss_secsize;
223 		nsec = bp->b_bcount / ssp->dss_secsize;
224 	}
225 
226 	/*
227 	 * Calculate slice-relative sector number end slice-relative
228 	 * limit.
229 	 */
230 	if (slice == WHOLE_DISK_SLICE) {
231 		/*
232 		 * Labels have not been allowed on whole-disks for a while.
233 		 * This really puts the nail in the coffin... no disk
234 		 * snooping will occur even if you tried to write a label
235 		 * without a slice structure.
236 		 *
237 		 * Accesses to the WHOLE_DISK_SLICE do not use a disklabel
238 		 * and partition numbers are special-cased.  Currently numbers
239 		 * less then 128 are not allowed.  Partition numbers >= 128
240 		 * are encoded in the high 8 bits of the 64 bit buffer offset
241 		 * and are fed directly through to the device with no
242 		 * further interpretation.  In particular, no sector
243 		 * translation interpretation should occur because the
244 		 * sector size for the special raw access may not be the
245 		 * same as the nominal sector size for the device.
246 		 */
247 		lp = NULL;
248 		if (part < 128) {
249 			kprintf("dscheck(%s): illegal partition number (%d) "
250 				"for WHOLE_DISK_SLICE access\n",
251 				devtoname(dev), part);
252 			goto bad;
253 		} else if (part != WHOLE_SLICE_PART) {
254 			nbio = push_bio(bio);
255 			nbio->bio_offset = bio->bio_offset |
256 					   (u_int64_t)part << 56;
257 			return(nbio);
258 		}
259 
260 		/*
261 		 * sp->ds_size is for the whole disk in the WHOLE_DISK_SLICE.
262 		 */
263 		labelsect = 0;	/* ignore any reserved sectors, do not sniff */
264 		endsecno = sp->ds_size;
265 		slicerel_secno = secno;
266 	} else if (part == WHOLE_SLICE_PART) {
267 		/*
268 		 * We are accessing a slice.  Snoop the label and check
269 		 * reserved blocks only if a label is present, otherwise
270 		 * do not.  A label may be present if (1) there are active
271 		 * opens on the disk (not necessarily this slice) or
272 		 * (2) the disklabel program has written an in-core label
273 		 * and now wants to write it out, or (3) the management layer
274 		 * is trying to write out an in-core layer.  In case (2) and
275 		 * (3) we MUST snoop the write or the on-disk version of the
276 		 * disklabel will not be properly translated.
277 		 *
278 		 * NOTE! opens on a whole-slice partition will not attempt
279 		 * to read a disklabel in.
280 		 */
281 		if ((lp = sp->ds_label) != NULL) {
282 			labelsect = sp->ds_skip_bsdlabel;
283 		} else {
284 			labelsect = 0;
285 		}
286 		endsecno = sp->ds_size;
287 		slicerel_secno = secno;
288 	} else if ((lp = sp->ds_label) && part < lp->d_npartitions) {
289 		/*
290 		 * Acesss through disklabel, partition present.
291 		 */
292 		struct partition *pp;
293 
294 		labelsect = sp->ds_skip_bsdlabel;
295 		pp = &lp->d_partitions[dkpart(dev)];
296 		endsecno = pp->p_size;
297 		slicerel_secno = pp->p_offset + secno;
298 	} else if (lp) {
299 		/*
300 		 * Partition out of bounds
301 		 */
302 		kprintf("dscheck(%s): partition out of bounds %d/%d\n",
303 			devtoname(dev),
304 			part, lp->d_npartitions);
305 		goto bad;
306 	} else {
307 		/*
308 		 * Attempt to access partition when no disklabel present
309 		 */
310 		kprintf("dscheck(%s): attempt to access non-existant partition\n",
311 			devtoname(dev));
312 		goto bad;
313 	}
314 
315 	/*
316 	 * labelsect will reflect the extent of any reserved blocks from
317 	 * the beginning of the slice.  We only check the slice reserved
318 	 * fields (sp->ds_skip_platform and sp->ds_skip_bsdlabel) if
319 	 * labelsect is non-zero, otherwise we ignore them.  When labelsect
320 	 * is non-zero, sp->ds_skip_platform indicates the sector where the
321 	 * disklabel begins.
322 	 *
323 	 * First determine if an attempt is being made to write to a
324 	 * reserved area when such writes are not allowed.
325 	 */
326 #if 0
327 	if (slicerel_secno < 16 && nsec &&
328 	    bp->b_cmd != BUF_CMD_READ) {
329 		kprintf("Attempt to write to reserved sector %lld labelsect %lld label %p/%p skip_plat %d skip_bsd %d WLABEL %d\n",
330 			slicerel_secno,
331 			labelsect,
332 			sp->ds_label, lp,
333 			sp->ds_skip_platform,
334 			sp->ds_skip_bsdlabel,
335 			sp->ds_wlabel);
336 	}
337 #endif
338 	if (slicerel_secno < labelsect && nsec &&
339 	    bp->b_cmd != BUF_CMD_READ && sp->ds_wlabel == 0) {
340 		bp->b_error = EROFS;
341 		goto error;
342 	}
343 
344 	/*
345 	 * If we get here, bio_offset must be on a block boundary and
346 	 * the sector size must be a power of 2.
347 	 */
348 	if ((bio->bio_offset & (ssp->dss_secsize - 1)) ||
349 	    (ssp->dss_secsize ^ (ssp->dss_secsize - 1)) !=
350 	    ((ssp->dss_secsize << 1) - 1)) {
351 		kprintf("%s: invalid BIO offset, not sector aligned or"
352 			" invalid sector size (not power of 2) %08llx %d\n",
353 			devtoname(dev), bio->bio_offset, ssp->dss_secsize);
354 		goto bad;
355 	}
356 
357 	/*
358 	 * EOF handling
359 	 */
360 	if (secno + nsec > endsecno) {
361 		/*
362 		 * Return an error if beyond the end of the disk, or
363 		 * if B_BNOCLIP is set.  Tell the system that we do not
364 		 * need to keep the buffer around.
365 		 */
366 		if (secno > endsecno || (bp->b_flags & B_BNOCLIP))
367 			goto bad;
368 
369 		/*
370 		 * If exactly at end of disk, return an EOF.  Throw away
371 		 * the buffer contents, if any, by setting B_INVAL.
372 		 */
373 		if (secno == endsecno) {
374 			bp->b_resid = bp->b_bcount;
375 			bp->b_flags |= B_INVAL;
376 			goto done;
377 		}
378 
379 		/*
380 		 * Else truncate
381 		 */
382 		nsec = endsecno - secno;
383 		bp->b_bcount = nsec * ssp->dss_secsize;
384 	}
385 
386 	nbio = push_bio(bio);
387 	nbio->bio_offset = (off_t)(sp->ds_offset + slicerel_secno) *
388 			   ssp->dss_secsize;
389 
390 	/*
391 	 * Snoop writes to the label area when labelsect is non-zero.
392 	 * The label sector starts at sector sp->ds_skip_platform within
393 	 * the slice and ends before sector sp->ds_skip_bsdlabel.  The
394 	 * write must contain the label sector for us to be able to snoop it.
395 	 *
396 	 * We have to adjust the label's fields to the on-disk format on
397 	 * a write and then adjust them back on completion of the write,
398 	 * or on a read.
399 	 *
400 	 * SNOOPs are required for disklabel -r and the DIOC* ioctls also
401 	 * depend on it on the backend for label operations.  XXX
402 	 *
403 	 * NOTE! ds_skip_platform is usually set to non-zero by the slice
404 	 * scanning code, indicating that the slice has reserved boot
405 	 * sector(s).  It is also set for compatibility reasons via
406 	 * the DSO_COMPATMBR flag.  But it is not a requirement and it
407 	 * can be 0, indicating that the disklabel (if present) is stored
408 	 * at the beginning of the slice.  In most cases ds_skip_platform
409 	 * will be '1'.
410 	 *
411 	 * ds_skip_bsdlabel is inclusive of ds_skip_platform.  If they are
412 	 * the same then there is no label present, even if non-zero.
413 	 */
414 	if (slicerel_secno < labelsect &&	/* also checks labelsect!=0 */
415 	    sp->ds_skip_platform < labelsect && /* degenerate case */
416 	    slicerel_secno <= sp->ds_skip_platform &&
417 	    slicerel_secno + nsec > sp->ds_skip_platform) {
418 		/*
419 		 * Set up our own callback on I/O completion to handle
420 		 * undoing the fixup we did for the write as well as
421 		 * doing the fixup for a read.
422 		 */
423 		nbio->bio_done = dsiodone;
424 		nbio->bio_caller_info1.ptr = sp;
425 		nbio->bio_caller_info2.offset =
426 		    (sp->ds_skip_platform - slicerel_secno) * ssp->dss_secsize;
427 		if (bp->b_cmd != BUF_CMD_READ) {
428 			msg = fixlabel(
429 				NULL, sp,
430 			       (struct disklabel *)
431 			       (bp->b_data + (int)nbio->bio_caller_info2.offset),
432 			       TRUE);
433 			if (msg != NULL) {
434 				kprintf("dscheck(%s): %s\n",
435 				    devtoname(dev), msg);
436 				bp->b_error = EROFS;
437 				pop_bio(nbio);
438 				goto error;
439 			}
440 		}
441 	}
442 	return (nbio);
443 
444 bad_bcount:
445 	kprintf(
446 	"dscheck(%s): b_bcount %d is not on a sector boundary (ssize %d)\n",
447 	    devtoname(dev), bp->b_bcount, ssp->dss_secsize);
448 	goto bad;
449 
450 bad_blkno:
451 	kprintf(
452 	"dscheck(%s): bio_offset %lld is not on a sector boundary (ssize %d)\n",
453 	    devtoname(dev), bio->bio_offset, ssp->dss_secsize);
454 bad:
455 	bp->b_error = EINVAL;
456 	/* fall through */
457 error:
458 	/*
459 	 * Terminate the I/O with a ranging error.  Since the buffer is
460 	 * either illegal or beyond the file EOF, mark it B_INVAL as well.
461 	 */
462 	bp->b_resid = bp->b_bcount;
463 	bp->b_flags |= B_ERROR | B_INVAL;
464 done:
465 	/*
466 	 * Caller must biodone() the originally passed bio if NULL is
467 	 * returned.
468 	 */
469 	return (NULL);
470 }
471 
472 void
473 dsclose(cdev_t dev, int mode, struct diskslices *ssp)
474 {
475 	u_int32_t part;
476 	u_int32_t slice;
477 	struct diskslice *sp;
478 
479 	slice = dkslice(dev);
480 	part  = dkpart(dev);
481 	if (slice < ssp->dss_nslices) {
482 		sp = &ssp->dss_slices[slice];
483 		if (part < sizeof(sp->ds_openmask) * 8)
484 			sp->ds_openmask &= ~(1 << part);
485 	}
486 }
487 
488 void
489 dsgone(struct diskslices **sspp)
490 {
491 	int slice;
492 	struct diskslice *sp;
493 	struct diskslices *ssp;
494 
495 	for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) {
496 		sp = &ssp->dss_slices[slice];
497 		free_ds_label(ssp, slice);
498 	}
499 	kfree(ssp, M_DEVBUF);
500 	*sspp = NULL;
501 }
502 
503 /*
504  * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this
505  * is subject to the same restriction as dsopen().
506  */
507 int
508 dsioctl(cdev_t dev, u_long cmd, caddr_t data, int flags,
509 	struct diskslices **sspp, struct disk_info *info)
510 {
511 	int error;
512 	struct disklabel *lp;
513 	int old_wlabel;
514 	u_char openmask;
515 	int part;
516 	int slice;
517 	struct diskslice *sp;
518 	struct diskslices *ssp;
519 	struct partition *pp;
520 
521 	slice = dkslice(dev);
522 	part = dkpart(dev);
523 	ssp = *sspp;
524 	if (slice >= ssp->dss_nslices)
525 		return (EINVAL);
526 	sp = &ssp->dss_slices[slice];
527 	lp = sp->ds_label;
528 	switch (cmd) {
529 
530 	case DIOCGDVIRGIN:
531 		/*
532 		 * You can only retrieve a virgin disklabel on the whole
533 		 * disk slice or whole-slice partition.
534 		 */
535 		if (slice != WHOLE_DISK_SLICE &&
536 		    part != WHOLE_SLICE_PART) {
537 			return(EINVAL);
538 		}
539 
540 		lp = (struct disklabel *)data;
541 		if (ssp->dss_slices[WHOLE_DISK_SLICE].ds_label) {
542 			*lp = *ssp->dss_slices[WHOLE_DISK_SLICE].ds_label;
543 		} else {
544 			bzero(lp, sizeof(struct disklabel));
545 		}
546 
547 		lp->d_magic = DISKMAGIC;
548 		lp->d_magic2 = DISKMAGIC;
549 		pp = &lp->d_partitions[RAW_PART];
550 		pp->p_offset = 0;
551 		pp->p_size = sp->ds_size;
552 
553 		lp->d_npartitions = MAXPARTITIONS;
554 		if (lp->d_interleave == 0)
555 			lp->d_interleave = 1;
556 		if (lp->d_rpm == 0)
557 			lp->d_rpm = 3600;
558 		if (lp->d_nsectors == 0)
559 			lp->d_nsectors = 32;
560 		if (lp->d_ntracks == 0)
561 			lp->d_ntracks = 64;
562 
563 		lp->d_bbsize = BBSIZE;
564 		lp->d_sbsize = SBSIZE;
565 		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
566 		lp->d_ncylinders = sp->ds_size / lp->d_secpercyl;
567 		lp->d_secperunit = sp->ds_size;
568 		lp->d_checksum = 0;
569 		lp->d_checksum = dkcksum(lp);
570 		return (0);
571 
572 	case DIOCGDINFO:
573 		/*
574 		 * You can only retrieve a disklabel on the whole
575 		 * slice partition.
576 		 *
577 		 * We do not support labels directly on whole-disks
578 		 * any more (that is, disks without slices), unless the
579 		 * device driver has asked for a compatible label (e.g.
580 		 * for a CD) to allow booting off of storage that is
581 		 * otherwise unlabeled.
582 		 */
583 		error = 0;
584 		if (part != WHOLE_SLICE_PART)
585 			return(EINVAL);
586 		if (slice == WHOLE_DISK_SLICE &&
587 		    (info->d_dsflags & DSO_COMPATLABEL) == 0) {
588 			return (ENODEV);
589 		}
590 		if (sp->ds_label == NULL) {
591 			error = dsreadandsetlabel(dev, info->d_dsflags,
592 						  ssp, sp, info);
593 		}
594 		if (error == 0)
595 			*(struct disklabel *)data = *sp->ds_label;
596 		return (error);
597 
598 	case DIOCGPART:
599 		{
600 			struct partinfo *dpart = (void *)data;
601 
602 			/*
603 			 * If accessing a whole-slice partition the disk
604 			 * management layer may not have tried to read the
605 			 * disklabel.  We have to try to read the label
606 			 * in order to properly initialize the ds_skip_*
607 			 * fields.
608 			 *
609 			 * We ignore any error.
610 			 */
611 			if (sp->ds_label == NULL && part == WHOLE_SLICE_PART &&
612 			    slice != WHOLE_DISK_SLICE) {
613 				dsreadandsetlabel(dev, info->d_dsflags,
614 						  ssp, sp, info);
615 			}
616 
617 			bzero(dpart, sizeof(*dpart));
618 			dpart->media_offset   = (u_int64_t)sp->ds_offset *
619 						info->d_media_blksize;
620 			dpart->media_size     = (u_int64_t)sp->ds_size *
621 						info->d_media_blksize;
622 			dpart->media_blocks   = sp->ds_size;
623 			dpart->media_blksize  = info->d_media_blksize;
624 			dpart->skip_platform = sp->ds_skip_platform;
625 			dpart->skip_bsdlabel = sp->ds_skip_bsdlabel;
626 
627 			if (slice != WHOLE_DISK_SLICE &&
628 			    part != WHOLE_SLICE_PART) {
629 				struct partition *p;
630 
631 				if (lp == NULL || part >= lp->d_npartitions)
632 					return(EINVAL);
633 
634 				p = &lp->d_partitions[part];
635 				dpart->fstype = p->p_fstype;
636 				dpart->media_offset += (u_int64_t)p->p_offset *
637 						       info->d_media_blksize;
638 				dpart->media_size = (u_int64_t)p->p_size *
639 						    info->d_media_blksize;
640 				dpart->media_blocks = (u_int64_t)p->p_size;
641 
642 				/*
643 				 * partition starting sector (p_offset)
644 				 * requires slice's reserved areas to be
645 				 * adjusted.
646 				 */
647 				if (dpart->skip_platform > p->p_offset)
648 					dpart->skip_platform -= p->p_offset;
649 				else
650 					dpart->skip_platform = 0;
651 				if (dpart->skip_bsdlabel > p->p_offset)
652 					dpart->skip_bsdlabel -= p->p_offset;
653 				else
654 					dpart->skip_bsdlabel = 0;
655 			}
656 		}
657 		return (0);
658 
659 	case DIOCGSLICEINFO:
660 		bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] -
661 				 (char *)ssp);
662 		return (0);
663 
664 	case DIOCSDINFO:
665 		/*
666 		 * You can write a disklabel on the whole disk slice or
667 		 * whole-slice partition.
668 		 */
669 		if (slice != WHOLE_DISK_SLICE &&
670 		    part != WHOLE_SLICE_PART) {
671 			return(EINVAL);
672 		}
673 
674 		/*
675 		 * We no longer support writing disklabels directly to media
676 		 * without there being a slice.  Keep this as a separate
677 		 * conditional.
678 		 */
679 		if (slice == WHOLE_DISK_SLICE)
680 			return (ENODEV);
681 
682 		if (!(flags & FWRITE))
683 			return (EBADF);
684 		lp = kmalloc(sizeof *lp, M_DEVBUF, M_WAITOK);
685 		if (sp->ds_label == NULL)
686 			bzero(lp, sizeof *lp);
687 		else
688 			bcopy(sp->ds_label, lp, sizeof *lp);
689 		if (sp->ds_label == NULL) {
690 			openmask = 0;
691 		} else {
692 			openmask = sp->ds_openmask;
693 			if (slice == COMPATIBILITY_SLICE) {
694 				openmask |= ssp->dss_slices[
695 				    ssp->dss_first_bsd_slice].ds_openmask;
696 			} else if (slice == ssp->dss_first_bsd_slice) {
697 				openmask |= ssp->dss_slices[
698 				    COMPATIBILITY_SLICE].ds_openmask;
699 			}
700 		}
701 		error = setdisklabel(lp, (struct disklabel *)data,
702 				     (u_long)openmask);
703 		/* XXX why doesn't setdisklabel() check this? */
704 		if (error == 0 && lp->d_partitions[RAW_PART].p_offset != 0)
705 			error = EXDEV;
706 		if (error == 0) {
707 			if (lp->d_secperunit > sp->ds_size)
708 				error = ENOSPC;
709 			for (part = 0; part < lp->d_npartitions; part++)
710 				if (lp->d_partitions[part].p_size > sp->ds_size)
711 					error = ENOSPC;
712 		}
713 		if (error != 0) {
714 			kfree(lp, M_DEVBUF);
715 			return (error);
716 		}
717 		free_ds_label(ssp, slice);
718 		set_ds_label(ssp, slice, lp);
719 		return (0);
720 
721 	case DIOCSYNCSLICEINFO:
722 		/*
723 		 * This ioctl can only be done on the whole disk
724 		 */
725 		if (slice != WHOLE_DISK_SLICE || part != WHOLE_SLICE_PART)
726 			return (EINVAL);
727 
728 		if (*(int *)data == 0) {
729 			for (slice = 0; slice < ssp->dss_nslices; slice++) {
730 				openmask = ssp->dss_slices[slice].ds_openmask;
731 				if (openmask &&
732 				    (slice != WHOLE_DISK_SLICE ||
733 				     openmask & ~(1 << RAW_PART))) {
734 					return (EBUSY);
735 				}
736 			}
737 		}
738 
739 		/*
740 		 * Temporarily forget the current slices struct and read
741 		 * the current one.
742 		 *
743 		 * NOTE:
744 		 *
745 		 * XXX should wait for current accesses on this disk to
746 		 * complete, then lock out future accesses and opens.
747 		 */
748 		*sspp = NULL;
749 		lp = kmalloc(sizeof *lp, M_DEVBUF, M_WAITOK);
750 		*lp = *ssp->dss_slices[WHOLE_DISK_SLICE].ds_label;
751 		error = dsopen(dev, S_IFCHR, ssp->dss_oflags, sspp, info);
752 		if (error != 0) {
753 			kfree(lp, M_DEVBUF);
754 			*sspp = ssp;
755 			return (error);
756 		}
757 
758 		/*
759 		 * Reopen everything.  This is a no-op except in the "force"
760 		 * case and when the raw bdev and cdev are both open.  Abort
761 		 * if anything fails.
762 		 */
763 		for (slice = 0; slice < ssp->dss_nslices; slice++) {
764 			for (openmask = ssp->dss_slices[slice].ds_openmask,
765 			     part = 0; openmask; openmask >>= 1, part++) {
766 				if (!(openmask & 1))
767 					continue;
768 				error = dsopen(dkmodslice(dkmodpart(dev, part),
769 							  slice),
770 					       S_IFCHR, ssp->dss_oflags, sspp,
771 					       info);
772 				if (error != 0) {
773 					kfree(lp, M_DEVBUF);
774 					*sspp = ssp;
775 					return (EBUSY);
776 				}
777 			}
778 		}
779 
780 		kfree(lp, M_DEVBUF);
781 		dsgone(&ssp);
782 		return (0);
783 
784 	case DIOCWDINFO:
785 		error = dsioctl(dev, DIOCSDINFO, data, flags, &ssp, info);
786 		if (error != 0)
787 			return (error);
788 		/*
789 		 * XXX this used to hack on dk_openpart to fake opening
790 		 * partition 0 in case that is used instead of dkpart(dev).
791 		 */
792 		old_wlabel = sp->ds_wlabel;
793 		set_ds_wlabel(ssp, slice, TRUE);
794 		error = writedisklabel(dev, sp->ds_label);
795 		/* XXX should invalidate in-core label if write failed. */
796 		set_ds_wlabel(ssp, slice, old_wlabel);
797 		return (error);
798 
799 	case DIOCWLABEL:
800 		if (slice == WHOLE_DISK_SLICE)
801 			return (ENODEV);
802 		if (!(flags & FWRITE))
803 			return (EBADF);
804 		set_ds_wlabel(ssp, slice, *(int *)data != 0);
805 		return (0);
806 
807 	default:
808 		return (ENOIOCTL);
809 	}
810 }
811 
812 /*
813  * Chain the bio_done.  b_cmd remains valid through such chaining.
814  */
815 static void
816 dsiodone(struct bio *bio)
817 {
818 	struct buf *bp = bio->bio_buf;
819 	char *msg;
820 
821 	if (bp->b_cmd != BUF_CMD_READ
822 	    || (!(bp->b_flags & B_ERROR) && bp->b_error == 0)) {
823 		msg = fixlabel(NULL, bio->bio_caller_info1.ptr,
824 			       (struct disklabel *)
825 			       (bp->b_data + (int)bio->bio_caller_info2.offset),
826 			       FALSE);
827 		if (msg != NULL)
828 			kprintf("%s\n", msg);
829 	}
830 	biodone(bio->bio_prev);
831 }
832 
833 int
834 dsisopen(struct diskslices *ssp)
835 {
836 	int slice;
837 
838 	if (ssp == NULL)
839 		return (0);
840 	for (slice = 0; slice < ssp->dss_nslices; slice++) {
841 		if (ssp->dss_slices[slice].ds_openmask)
842 			return (1);
843 	}
844 	return (0);
845 }
846 
847 /*
848  * Allocate a slices "struct" and initialize it to contain only an empty
849  * compatibility slice (pointing to itself), a whole disk slice (covering
850  * the disk as described by the label), and (nslices - BASE_SLICES) empty
851  * slices beginning at BASE_SLICE.
852  */
853 struct diskslices *
854 dsmakeslicestruct(int nslices, struct disk_info *info)
855 {
856 	struct diskslice *sp;
857 	struct diskslices *ssp;
858 
859 	ssp = kmalloc(offsetof(struct diskslices, dss_slices) +
860 		     nslices * sizeof *sp, M_DEVBUF, M_WAITOK);
861 	ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE;
862 	ssp->dss_nslices = nslices;
863 	ssp->dss_oflags = 0;
864 
865 	/*
866 	 * Figure out if we can use shifts or whether we have to
867 	 * use mod/multply to translate byte offsets into sector numbers.
868 	 */
869 	if ((info->d_media_blksize ^ (info->d_media_blksize - 1)) ==
870 	     (info->d_media_blksize << 1) - 1) {
871 		ssp->dss_secmult = info->d_media_blksize / DEV_BSIZE;
872 		if (ssp->dss_secmult & (ssp->dss_secmult - 1))
873 			ssp->dss_secshift = -1;
874 		else
875 			ssp->dss_secshift = ffs(ssp->dss_secmult) - 1;
876 	} else {
877 		ssp->dss_secmult = 0;
878 		ssp->dss_secshift = -1;
879 	}
880 	ssp->dss_secsize = info->d_media_blksize;
881 	sp = &ssp->dss_slices[0];
882 	bzero(sp, nslices * sizeof *sp);
883 	sp[WHOLE_DISK_SLICE].ds_size = info->d_media_blocks;
884 	return (ssp);
885 }
886 
887 char *
888 dsname(cdev_t dev, int unit, int slice, int part, char *partname)
889 {
890 	static char name[32];
891 	const char *dname;
892 	int used;
893 
894 	dname = dev_dname(dev);
895 	if (strlen(dname) > 16)
896 		dname = "nametoolong";
897 	ksnprintf(name, sizeof(name), "%s%d", dname, unit);
898 	partname[0] = '\0';
899 	used = strlen(name);
900 
901 	if (slice != WHOLE_DISK_SLICE) {
902 		if (slice != COMPATIBILITY_SLICE) {
903 			used += ksnprintf(name + used, sizeof(name) - used,
904 					  "s%d", slice - BASE_SLICE + 1);
905 		}
906 		if (part != WHOLE_SLICE_PART) {
907 			used += ksnprintf(name + used, sizeof(name) - used,
908 					  "%c", 'a' + part);
909 			partname[0] = 'a' + part;
910 			partname[1] = 0;
911 		}
912 	} else if (part > 128) {
913 		/*
914 		 * Special access via the whole-disk-device (used to access
915 		 * CD audio tracks).
916 		 */
917 		used += ksnprintf(name + used, sizeof(name) - used,
918 					  "t%d", part - 128);
919 	}
920 	return (name);
921 }
922 
923 /*
924  * This should only be called when the unit is inactive and the strategy
925  * routine should not allow it to become active unless we call it.  Our
926  * strategy routine must be special to allow activity.
927  */
928 int
929 dsopen(cdev_t dev, int mode, u_int flags,
930 	struct diskslices **sspp, struct disk_info *info)
931 {
932 	cdev_t dev1;
933 	int error;
934 	bool_t need_init;
935 	struct diskslice *sp;
936 	struct diskslices *ssp;
937 	int slice;
938 	int part;
939 
940 	dev->si_bsize_phys = info->d_media_blksize;
941 
942 	/*
943 	 * Do not attempt to read the slice table or disk label when
944 	 * accessing the whole-disk slice or a while-slice partition.
945 	 */
946 	if (dkslice(dev) == WHOLE_DISK_SLICE)
947 		flags |= DSO_ONESLICE | DSO_NOLABELS;
948 	if (dkpart(dev) == WHOLE_SLICE_PART)
949 		flags |= DSO_NOLABELS;
950 
951 	/*
952 	 * Reinitialize the slice table unless there is an open device
953 	 * on the unit.
954 	 *
955 	 * It would be nice if we didn't have to do this but when a
956 	 * user is slicing and partitioning up a disk it is a lot safer
957 	 * to not take any chances.
958 	 */
959 	ssp = *sspp;
960 	need_init = !dsisopen(ssp);
961 	if (ssp != NULL && need_init)
962 		dsgone(sspp);
963 	if (need_init) {
964 		/*
965 		 * Allocate a minimal slices "struct".  This will become
966 		 * the final slices "struct" if we don't want real slices
967 		 * or if we can't find any real slices.
968 		 *
969 		 * Then scan the disk
970 		 */
971 		*sspp = dsmakeslicestruct(BASE_SLICE, info);
972 
973 		if ((flags & DSO_ONESLICE) == 0) {
974 			TRACE(("mbrinit\n"));
975 			error = mbrinit(dev, info, sspp);
976 			if (error != 0) {
977 				dsgone(sspp);
978 				return (error);
979 			}
980 		}
981 		ssp = *sspp;
982 		ssp->dss_oflags = flags;
983 
984 		/*
985 		 * If there are no real slices, then make the compatiblity
986 		 * slice cover the whole disk.
987 		 *
988 		 * no sectors are reserved for the platform (ds_skip_platform
989 		 * will be 0) in this case.  This means that if a disklabel
990 		 * is installed it will be directly installed in sector 0
991 		 * unless DSO_COMPATMBR is requested.
992 		 */
993 		if (ssp->dss_nslices == BASE_SLICE) {
994 			sp = &ssp->dss_slices[COMPATIBILITY_SLICE];
995 
996 			sp->ds_size = info->d_media_blocks;
997 			if (info->d_dsflags & DSO_COMPATMBR) {
998 				sp->ds_skip_platform = 1;
999 				sp->ds_skip_bsdlabel = sp->ds_skip_platform;
1000 			}
1001 		}
1002 
1003 		/*
1004 		 * Point the compatibility slice at the BSD slice, if any.
1005 		 */
1006 		for (slice = BASE_SLICE; slice < ssp->dss_nslices; slice++) {
1007 			sp = &ssp->dss_slices[slice];
1008 			if (sp->ds_type == DOSPTYP_386BSD /* XXX */) {
1009 				struct diskslice *csp;
1010 
1011 				csp = &ssp->dss_slices[COMPATIBILITY_SLICE];
1012 				ssp->dss_first_bsd_slice = slice;
1013 				csp->ds_offset = sp->ds_offset;
1014 				csp->ds_size = sp->ds_size;
1015 				csp->ds_type = sp->ds_type;
1016 				csp->ds_skip_platform = sp->ds_skip_platform;
1017 				csp->ds_skip_bsdlabel = sp->ds_skip_bsdlabel;
1018 				break;
1019 			}
1020 		}
1021 
1022 		/*
1023 		 * By definition accesses via the whole-disk device do not
1024 		 * specify any reserved areas.  The whole disk may be read
1025 		 * or written by the whole-disk device.
1026 		 *
1027 		 * ds_label for a whole-disk device is only used as a
1028 		 * template.
1029 		 */
1030 		sp = &ssp->dss_slices[WHOLE_DISK_SLICE];
1031 		sp->ds_label = clone_label(info, NULL);
1032 		sp->ds_wlabel = TRUE;
1033 		sp->ds_skip_platform = 0;
1034 		sp->ds_skip_bsdlabel = 0;
1035 	}
1036 
1037 	/*
1038 	 * Load the disklabel for the slice being accessed unless it is
1039 	 * a whole-disk-slice or a whole-slice-partition (as determined
1040 	 * by DSO_NOLABELS).
1041 	 *
1042 	 * We could scan all slices here and try to load up their
1043 	 * disklabels, but that would cause us to access slices that
1044 	 * the user may otherwise not intend us to access, or corrupted
1045 	 * slices, etc.
1046 	 *
1047 	 * XXX if there are no opens on the slice we may want to re-read
1048 	 * the disklabel anyway, even if we have one cached.
1049 	 */
1050 	slice = dkslice(dev);
1051 	if (slice >= ssp->dss_nslices)
1052 		return (ENXIO);
1053 	sp = &ssp->dss_slices[slice];
1054 	part = dkpart(dev);
1055 
1056 	if ((flags & DSO_NOLABELS) == 0 && sp->ds_label == NULL) {
1057 		dev1 = dkmodslice(dkmodpart(dev, WHOLE_SLICE_PART), slice);
1058 
1059 		/*
1060 		 * If opening a raw disk we do not try to
1061 		 * read the disklabel now.  No interpretation of raw disks
1062 		 * (e.g. like 'da0') ever occurs.  We will try to read the
1063 		 * disklabel for a raw slice if asked to via DIOC* ioctls.
1064 		 *
1065 		 * Access to the label area is disallowed by default.  Note
1066 		 * however that accesses via WHOLE_DISK_SLICE, and accesses
1067 		 * via WHOLE_SLICE_PART for slices without valid disklabels,
1068 		 * will allow writes and ignore the flag.
1069 		 */
1070 		set_ds_wlabel(ssp, slice, FALSE);
1071 		dsreadandsetlabel(dev1, flags, ssp, sp, info);
1072 	}
1073 
1074 	/*
1075 	 * If opening a particular partition the disklabel must exist and
1076 	 * the partition must be present in the label.
1077 	 *
1078 	 * If the partition is the special whole-disk-slice no partition
1079 	 * table need exist.
1080 	 */
1081 	if (part != WHOLE_SLICE_PART && slice != WHOLE_DISK_SLICE) {
1082 		if (sp->ds_label == NULL || part >= sp->ds_label->d_npartitions)
1083 			return (EINVAL);
1084 		if (part < sizeof(sp->ds_openmask) * 8) {
1085 			sp->ds_openmask |= 1 << part;
1086 		}
1087 	}
1088 
1089 	/*
1090 	 * Do not allow special raw-extension partitions to be opened
1091 	 * if the device doesn't support them.  Raw-extension partitions
1092 	 * are typically used to handle CD tracks.
1093 	 */
1094 	if (slice == WHOLE_DISK_SLICE && part >= 128 &&
1095 	    part != WHOLE_SLICE_PART) {
1096 		if ((info->d_dsflags & DSO_RAWEXTENSIONS) == 0)
1097 			return (EINVAL);
1098 	}
1099 	return (0);
1100 }
1101 
1102 /*
1103  * Attempt to read the disklabel.  If successful, store it in sp->ds_label.
1104  *
1105  * If we cannot read the disklabel and DSO_COMPATLABEL is set, we construct
1106  * a fake label covering the whole disk.
1107  */
1108 static
1109 int
1110 dsreadandsetlabel(cdev_t dev, u_int flags,
1111 		  struct diskslices *ssp, struct diskslice *sp,
1112 		  struct disk_info *info)
1113 {
1114 	struct disklabel *lp1;
1115 	const char *msg;
1116 	const char *sname;
1117 	char partname[2];
1118 	int slice = dkslice(dev);
1119 
1120 	sname = dsname(dev, dkunit(dev), slice, WHOLE_SLICE_PART, partname);
1121 	lp1 = clone_label(info, sp);
1122 	msg = readdisklabel(dev, lp1);
1123 
1124 	if (msg != NULL && (flags & DSO_COMPATLABEL)) {
1125 		msg = NULL;
1126 		kfree(lp1, M_DEVBUF);
1127 		lp1 = clone_label(info, sp);
1128 	}
1129 	if (msg == NULL)
1130 		msg = fixlabel(sname, sp, lp1, FALSE);
1131 	if (msg == NULL && lp1->d_secsize != info->d_media_blksize)
1132 		msg = "inconsistent sector size";
1133 	if (msg != NULL) {
1134 		if (sp->ds_type == DOSPTYP_386BSD /* XXX */)
1135 			log(LOG_WARNING, "%s: cannot find label (%s)\n",
1136 			    sname, msg);
1137 		kfree(lp1, M_DEVBUF);
1138 	} else {
1139 		set_ds_label(ssp, slice, lp1);
1140 		set_ds_wlabel(ssp, slice, FALSE);
1141 	}
1142 	return (msg ? EINVAL : 0);
1143 }
1144 
1145 int64_t
1146 dssize(cdev_t dev, struct diskslices **sspp)
1147 {
1148 	struct disklabel *lp;
1149 	int part;
1150 	int slice;
1151 	struct diskslices *ssp;
1152 
1153 	slice = dkslice(dev);
1154 	part = dkpart(dev);
1155 	ssp = *sspp;
1156 	if (ssp == NULL || slice >= ssp->dss_nslices
1157 	    || !(ssp->dss_slices[slice].ds_openmask & (1 << part))) {
1158 		if (dev_dopen(dev, FREAD, S_IFCHR, proc0.p_ucred) != 0)
1159 			return (-1);
1160 		dev_dclose(dev, FREAD, S_IFCHR);
1161 		ssp = *sspp;
1162 	}
1163 	lp = ssp->dss_slices[slice].ds_label;
1164 	if (lp == NULL)
1165 		return (-1);
1166 	return ((int64_t)lp->d_partitions[part].p_size);
1167 }
1168 
1169 static void
1170 free_ds_label(struct diskslices *ssp, int slice)
1171 {
1172 	struct disklabel *lp;
1173 	struct diskslice *sp;
1174 
1175 	sp = &ssp->dss_slices[slice];
1176 	lp = sp->ds_label;
1177 	if (lp == NULL)
1178 		return;
1179 	kfree(lp, M_DEVBUF);
1180 	set_ds_label(ssp, slice, (struct disklabel *)NULL);
1181 }
1182 
1183 static char *
1184 fixlabel(const char *sname, struct diskslice *sp, struct disklabel *lp, int writeflag)
1185 {
1186 	u_int64_t start;
1187 	u_int64_t end;
1188 	u_int64_t offset;
1189 	int part;
1190 	struct partition *pp;
1191 	bool_t warned;
1192 
1193 	/* These errors "can't happen" so don't bother reporting details. */
1194 	if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC)
1195 		return ("fixlabel: invalid magic");
1196 	if (dkcksum(lp) != 0)
1197 		return ("fixlabel: invalid checksum");
1198 
1199 	pp = &lp->d_partitions[RAW_PART];
1200 
1201 	/*
1202 	 * What a mess.  For ages old backwards compatibility the disklabel
1203 	 * on-disk stores absolute offsets instead of slice-relative offsets.
1204 	 * So fix it up when reading, writing, or snooping.
1205 	 *
1206 	 * The in-core label is always slice-relative.
1207 	 */
1208 	if (writeflag) {
1209 		start = 0;
1210 		offset = sp->ds_offset;
1211 	} else {
1212 		start = sp->ds_offset;
1213 		offset = -sp->ds_offset;
1214 	}
1215 	if (pp->p_offset != start) {
1216 		if (sname != NULL) {
1217 			kprintf(
1218 "%s: rejecting BSD label: raw partition offset != slice offset\n",
1219 			       sname);
1220 			slice_info(sname, sp);
1221 			partition_info(sname, RAW_PART, pp);
1222 		}
1223 		return ("fixlabel: raw partition offset != slice offset");
1224 	}
1225 	if (pp->p_size != sp->ds_size) {
1226 		if (sname != NULL) {
1227 			kprintf("%s: raw partition size != slice size\n", sname);
1228 			slice_info(sname, sp);
1229 			partition_info(sname, RAW_PART, pp);
1230 		}
1231 		if (pp->p_size > sp->ds_size) {
1232 			if (sname == NULL)
1233 				return ("fixlabel: raw partition size > slice size");
1234 			kprintf("%s: truncating raw partition\n", sname);
1235 			pp->p_size = sp->ds_size;
1236 		}
1237 	}
1238 	end = start + sp->ds_size;
1239 	if (start > end)
1240 		return ("fixlabel: slice wraps");
1241 	if (lp->d_secpercyl <= 0)
1242 		return ("fixlabel: d_secpercyl <= 0");
1243 	pp -= RAW_PART;
1244 	warned = FALSE;
1245 	for (part = 0; part < lp->d_npartitions; part++, pp++) {
1246 		if (pp->p_offset != 0 || pp->p_size != 0) {
1247 			if (pp->p_offset < start
1248 			    || pp->p_offset + pp->p_size > end
1249 			    || pp->p_offset + pp->p_size < pp->p_offset) {
1250 				if (sname != NULL) {
1251 					kprintf(
1252 "%s: rejecting partition in BSD label: it isn't entirely within the slice\n",
1253 					       sname);
1254 					if (!warned) {
1255 						slice_info(sname, sp);
1256 						warned = TRUE;
1257 					}
1258 					partition_info(sname, part, pp);
1259 				}
1260 				/* XXX else silently discard junk. */
1261 				bzero(pp, sizeof *pp);
1262 			} else {
1263 				pp->p_offset += offset;
1264 			}
1265 		}
1266 	}
1267 	lp->d_ncylinders = sp->ds_size / lp->d_secpercyl;
1268 	lp->d_secperunit = sp->ds_size;
1269  	lp->d_checksum = 0;
1270  	lp->d_checksum = dkcksum(lp);
1271 	return (NULL);
1272 }
1273 
1274 static void
1275 partition_info(const char *sname, int part, struct partition *pp)
1276 {
1277 	kprintf("%s%c: start %lu, end %lu, size %lu\n", sname, 'a' + part,
1278 	       (u_long)pp->p_offset, (u_long)(pp->p_offset + pp->p_size - 1),
1279 	       (u_long)pp->p_size);
1280 }
1281 
1282 static void
1283 slice_info(const char *sname, struct diskslice *sp)
1284 {
1285 	kprintf("%s: start %llu, end %llu, size %llu\n", sname,
1286 	       sp->ds_offset, sp->ds_offset + sp->ds_size - 1, sp->ds_size);
1287 }
1288 
1289 static void
1290 set_ds_label(struct diskslices *ssp, int slice, struct disklabel *lp)
1291 {
1292 	struct diskslice *sp1 = &ssp->dss_slices[slice];
1293 	struct diskslice *sp2;
1294 
1295 	if (slice == COMPATIBILITY_SLICE)
1296 		sp2 = &ssp->dss_slices[ssp->dss_first_bsd_slice];
1297 	else if (slice == ssp->dss_first_bsd_slice)
1298 		sp2 = &ssp->dss_slices[COMPATIBILITY_SLICE];
1299 	else
1300 		sp2 = NULL;
1301 	sp1->ds_label = lp;
1302 	if (sp2)
1303 		sp2->ds_label = lp;
1304 
1305 	/*
1306 	 * If the slice is not the whole-disk slice, setup the reserved
1307 	 * area(s).
1308 	 *
1309 	 * The reserved area for the original bsd disklabel, inclusive of
1310 	 * the label and space for boot2, is 15 sectors.  If you've
1311 	 * noticed people traditionally skipping 16 sectors its because
1312 	 * the sector numbers start at the beginning of the slice rather
1313 	 * then the beginning of the disklabel and traditional dos slices
1314 	 * reserve a sector at the beginning for the boot code.
1315 	 *
1316 	 * NOTE! With the traditional bsdlabel, the first N bytes of boot2
1317 	 * overlap with the disklabel.  The disklabel program checks that
1318 	 * they are 0.
1319 	 *
1320 	 * When clearing a label, the bsdlabel reserved area is reset.
1321 	 */
1322 	if (slice != WHOLE_DISK_SLICE) {
1323 		if (lp) {
1324 			sp1->ds_skip_bsdlabel = sp1->ds_skip_platform + 15;
1325 			if (sp2)
1326 				sp2->ds_skip_bsdlabel = sp1->ds_skip_bsdlabel;
1327 		} else {
1328 			sp1->ds_skip_bsdlabel = sp1->ds_skip_platform;
1329 			if (sp2)
1330 				sp2->ds_skip_bsdlabel = sp1->ds_skip_platform;
1331 		}
1332 	}
1333 }
1334 
1335 static void
1336 set_ds_wlabel(struct diskslices *ssp, int slice, int wlabel)
1337 {
1338 	ssp->dss_slices[slice].ds_wlabel = wlabel;
1339 	if (slice == COMPATIBILITY_SLICE)
1340 		ssp->dss_slices[ssp->dss_first_bsd_slice].ds_wlabel = wlabel;
1341 	else if (slice == ssp->dss_first_bsd_slice)
1342 		ssp->dss_slices[COMPATIBILITY_SLICE].ds_wlabel = wlabel;
1343 }
1344