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: releng/5.0/sys/kern/subr_diskslice.c 105354 2002-10-17 20:03:38Z robert $
47 */
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/bio.h>
52 #include <sys/conf.h>
53 #include <sys/disk.h>
54 #include <sys/disklabel.h>
55 #include <sys/diskslice.h>
56 #if defined(PC98) && !defined(PC98_ATCOMPAT)
57 #include <sys/diskpc98.h>
58 #else
59 #include <sys/diskmbr.h>
60 #endif
61 #include <sys/fcntl.h>
62 #include <sys/malloc.h>
63 #include <sys/stat.h>
64 #include <sys/stdint.h>
65 #include <sys/syslog.h>
66 #include <sys/vnode.h>
67
68 #define TRACE(str) do { if (ds_debug) printf str; } while (0)
69
70 typedef u_char bool_t;
71
72 static volatile bool_t ds_debug;
73
74 static struct disklabel *clone_label(struct disklabel *lp);
75 static void dsiodone(struct bio *bp);
76 static char *fixlabel(char *sname, struct diskslice *sp,
77 struct disklabel *lp, int writeflag);
78 static void free_ds_label(struct diskslices *ssp, int slice);
79 static void partition_info(char *sname, int part, struct partition *pp);
80 static void slice_info(char *sname, struct diskslice *sp);
81 static void set_ds_label(struct diskslices *ssp, int slice,
82 struct disklabel *lp);
83 static void set_ds_labeldevs(dev_t dev, struct diskslices *ssp);
84 static void set_ds_wlabel(struct diskslices *ssp, int slice,
85 int wlabel);
86
87 /*
88 * Duplicate a label for the whole disk, and initialize defaults in the
89 * copy for fields that are not already initialized. The caller only
90 * needs to initialize d_secsize and d_secperunit, and zero the fields
91 * that are to be defaulted.
92 */
93 static struct disklabel *
94 clone_label(lp)
95 struct disklabel *lp;
96 {
97 struct disklabel *lp1;
98
99 lp1 = malloc(sizeof *lp1, M_DEVBUF, M_WAITOK);
100 *lp1 = *lp;
101 lp = NULL;
102 if (lp1->d_typename[0] == '\0')
103 strlcpy(lp1->d_typename, "amnesiac", sizeof(lp1->d_typename));
104 if (lp1->d_packname[0] == '\0')
105 strlcpy(lp1->d_packname, "fictitious", sizeof(lp1->d_packname));
106 if (lp1->d_nsectors == 0)
107 lp1->d_nsectors = 32;
108 if (lp1->d_ntracks == 0)
109 lp1->d_ntracks = 64;
110 lp1->d_secpercyl = lp1->d_nsectors * lp1->d_ntracks;
111 lp1->d_ncylinders = lp1->d_secperunit / lp1->d_secpercyl;
112 if (lp1->d_rpm == 0)
113 lp1->d_rpm = 3600;
114 if (lp1->d_interleave == 0)
115 lp1->d_interleave = 1;
116 if (lp1->d_npartitions < RAW_PART + 1)
117 lp1->d_npartitions = MAXPARTITIONS;
118 if (lp1->d_bbsize == 0)
119 lp1->d_bbsize = BBSIZE;
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);
124 return (lp1);
125 }
126
127 dev_t
128 dkmodpart(dev_t dev, int part)
129 {
130 return (makedev(major(dev), (minor(dev) & ~7) | part));
131 }
132
133 dev_t
134 dkmodslice(dev_t dev, int slice)
135 {
136 return (makedev(major(dev), (minor(dev) & ~0x1f0000) | (slice << 16)));
137 }
138
139 u_int
140 dkunit(dev_t dev)
141 {
142 return (((minor(dev) >> 16) & 0x1e0) | ((minor(dev) >> 3) & 0x1f));
143 }
144
145 /*
146 * Determine the size of the transfer, and make sure it is
147 * within the boundaries of the partition. Adjust transfer
148 * if needed, and signal errors or early completion.
149 *
150 * XXX TODO:
151 * o Split buffers that are too big for the device.
152 * o Check for overflow.
153 * o Finish cleaning this up.
154 */
155 int
156 dscheck(bp, ssp)
157 struct bio *bp;
158 struct diskslices *ssp;
159 {
160 daddr_t blkno;
161 daddr_t endsecno;
162 daddr_t labelsect;
163 struct disklabel *lp;
164 char *msg;
165 long nsec;
166 struct partition *pp;
167 daddr_t secno;
168 daddr_t slicerel_secno;
169 struct diskslice *sp;
170
171 blkno = bp->bio_blkno;
172 if (blkno < 0) {
173 printf("dscheck(%s): negative bio_blkno %ld\n",
174 devtoname(bp->bio_dev), (long)blkno);
175 bp->bio_error = EINVAL;
176 goto bad;
177 }
178 sp = &ssp->dss_slices[dkslice(bp->bio_dev)];
179 lp = sp->ds_label;
180 if (ssp->dss_secmult == 1) {
181 if (bp->bio_bcount % (u_long)DEV_BSIZE)
182 goto bad_bcount;
183 secno = blkno;
184 nsec = bp->bio_bcount >> DEV_BSHIFT;
185 } else if (ssp->dss_secshift != -1) {
186 if (bp->bio_bcount & (ssp->dss_secsize - 1))
187 goto bad_bcount;
188 if (blkno & (ssp->dss_secmult - 1))
189 goto bad_blkno;
190 secno = blkno >> ssp->dss_secshift;
191 nsec = bp->bio_bcount >> (DEV_BSHIFT + ssp->dss_secshift);
192 } else {
193 if (bp->bio_bcount % ssp->dss_secsize)
194 goto bad_bcount;
195 if (blkno % ssp->dss_secmult)
196 goto bad_blkno;
197 secno = blkno / ssp->dss_secmult;
198 nsec = bp->bio_bcount / ssp->dss_secsize;
199 }
200 if (lp == NULL) {
201 labelsect = -LABELSECTOR - 1;
202 endsecno = sp->ds_size;
203 slicerel_secno = secno;
204 } else {
205 labelsect = lp->d_partitions[LABEL_PART].p_offset;
206 if (labelsect != 0) Debugger("labelsect != 0 in dscheck()");
207 pp = &lp->d_partitions[dkpart(bp->bio_dev)];
208 endsecno = pp->p_size;
209 slicerel_secno = pp->p_offset + secno;
210 }
211
212 /* overwriting disk label ? */
213 /* XXX should also protect bootstrap in first 8K */
214 if (slicerel_secno <= LABELSECTOR + labelsect &&
215 #if LABELSECTOR != 0
216 slicerel_secno + nsec > LABELSECTOR + labelsect &&
217 #endif
218 (bp->bio_cmd == BIO_WRITE) && sp->ds_wlabel == 0) {
219 bp->bio_error = EROFS;
220 goto bad;
221 }
222
223 #if defined(DOSBBSECTOR) && defined(notyet)
224 /* overwriting master boot record? */
225 if (slicerel_secno <= DOSBBSECTOR && (bp->bio_cmd == BIO_WRITE) &&
226 sp->ds_wlabel == 0) {
227 bp->bio_error = EROFS;
228 goto bad;
229 }
230 #endif
231
232 /* beyond partition? */
233 if ((uintmax_t)secno + nsec > endsecno) {
234 /* if exactly at end of disk, return an EOF */
235 if (secno == endsecno) {
236 bp->bio_resid = bp->bio_bcount;
237 return (0);
238 }
239 /* or truncate if part of it fits */
240 if (secno > endsecno) {
241 bp->bio_error = EINVAL;
242 goto bad;
243 }
244 bp->bio_bcount = (endsecno - secno) * ssp->dss_secsize;
245 }
246
247 bp->bio_pblkno = sp->ds_offset + slicerel_secno;
248
249 /*
250 * Snoop on label accesses if the slice offset is nonzero. Fudge
251 * offsets in the label to keep the in-core label coherent with
252 * the on-disk one.
253 */
254 if (slicerel_secno <= LABELSECTOR + labelsect
255 #if LABELSECTOR != 0
256 && slicerel_secno + nsec > LABELSECTOR + labelsect
257 #endif
258 && sp->ds_offset != 0) {
259 struct iodone_chain *ic;
260
261 ic = malloc(sizeof *ic , M_DEVBUF, M_WAITOK);
262 ic->ic_prev_flags = bp->bio_flags;
263 ic->ic_prev_iodone = bp->bio_done;
264 ic->ic_prev_iodone_chain = bp->bio_done_chain;
265 ic->ic_args[0].ia_long = (LABELSECTOR + labelsect -
266 slicerel_secno) * ssp->dss_secsize;
267 ic->ic_args[1].ia_ptr = sp;
268 bp->bio_done = dsiodone;
269 bp->bio_done_chain = ic;
270 if (!(bp->bio_cmd == BIO_READ)) {
271 /*
272 * XXX even disklabel(8) writes directly so we need
273 * to adjust writes. Perhaps we should drop support
274 * for DIOCWLABEL (always write protect labels) and
275 * require the use of DIOCWDINFO.
276 *
277 * XXX probably need to copy the data to avoid even
278 * temporarily corrupting the in-core copy.
279 */
280 /* XXX need name here. */
281 msg = fixlabel((char *)NULL, sp,
282 (struct disklabel *)
283 (bp->bio_data + ic->ic_args[0].ia_long),
284 TRUE);
285 if (msg != NULL) {
286 printf("dscheck(%s): %s\n",
287 devtoname(bp->bio_dev), msg);
288 bp->bio_error = EROFS;
289 goto bad;
290 }
291 }
292 }
293 return (1);
294
295 bad_bcount:
296 printf(
297 "dscheck(%s): bio_bcount %ld is not on a sector boundary (ssize %d)\n",
298 devtoname(bp->bio_dev), bp->bio_bcount, ssp->dss_secsize);
299 bp->bio_error = EINVAL;
300 goto bad;
301
302 bad_blkno:
303 printf(
304 "dscheck(%s): bio_blkno %ld is not on a sector boundary (ssize %d)\n",
305 devtoname(bp->bio_dev), (long)blkno, ssp->dss_secsize);
306 bp->bio_error = EINVAL;
307 goto bad;
308
309 bad:
310 bp->bio_resid = bp->bio_bcount;
311 bp->bio_flags |= BIO_ERROR;
312 return (-1);
313 }
314
315 void
316 dsclose(dev, mode, ssp)
317 dev_t dev;
318 int mode;
319 struct diskslices *ssp;
320 {
321 u_char mask;
322 struct diskslice *sp;
323
324 sp = &ssp->dss_slices[dkslice(dev)];
325 mask = 1 << dkpart(dev);
326 sp->ds_openmask &= ~mask;
327 }
328
329 void
330 dsgone(sspp)
331 struct diskslices **sspp;
332 {
333 int slice;
334 struct diskslice *sp;
335 struct diskslices *ssp;
336
337 for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) {
338 sp = &ssp->dss_slices[slice];
339 free_ds_label(ssp, slice);
340 }
341 free(ssp, M_DEVBUF);
342 *sspp = NULL;
343 }
344
345 /*
346 * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this
347 * is subject to the same restriction as dsopen().
348 */
349 int
350 dsioctl(dev, cmd, data, flags, sspp)
351 dev_t dev;
352 u_long cmd;
353 caddr_t data;
354 int flags;
355 struct diskslices **sspp;
356 {
357 int error;
358 struct disklabel *lp;
359 int old_wlabel;
360 u_char openmask;
361 int part;
362 int slice;
363 struct diskslice *sp;
364 struct diskslices *ssp;
365
366 slice = dkslice(dev);
367 ssp = *sspp;
368 sp = &ssp->dss_slices[slice];
369 lp = sp->ds_label;
370 switch (cmd) {
371
372 case DIOCGDINFO:
373 if (lp == NULL)
374 return (EINVAL);
375 *(struct disklabel *)data = *lp;
376 return (0);
377
378 case DIOCGMEDIASIZE:
379 if (lp == NULL)
380 *(off_t *)data = (off_t)sp->ds_size * ssp->dss_secsize;
381 else
382 *(off_t *)data =
383 (off_t)lp->d_partitions[dkpart(dev)].p_size *
384 lp->d_secsize;
385 return (0);
386
387 case DIOCGSECTORSIZE:
388 *(u_int *)data = ssp->dss_secsize;
389 return (0);
390
391 case DIOCGSLICEINFO:
392 bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] -
393 (char *)ssp);
394 return (0);
395
396 case DIOCSDINFO:
397 if (slice == WHOLE_DISK_SLICE)
398 return (ENODEV);
399 if (!(flags & FWRITE))
400 return (EBADF);
401 lp = malloc(sizeof *lp, M_DEVBUF, M_WAITOK);
402 if (sp->ds_label == NULL)
403 bzero(lp, sizeof *lp);
404 else
405 bcopy(sp->ds_label, lp, sizeof *lp);
406 if (sp->ds_label == NULL)
407 openmask = 0;
408 else {
409 openmask = sp->ds_openmask;
410 if (slice == COMPATIBILITY_SLICE)
411 openmask |= ssp->dss_slices[
412 ssp->dss_first_bsd_slice].ds_openmask;
413 else if (slice == ssp->dss_first_bsd_slice)
414 openmask |= ssp->dss_slices[
415 COMPATIBILITY_SLICE].ds_openmask;
416 }
417 error = setdisklabel(lp, (struct disklabel *)data,
418 (u_long)openmask);
419 /* XXX why doesn't setdisklabel() check this? */
420 if (error == 0 && lp->d_partitions[RAW_PART].p_offset != 0)
421 error = EXDEV;
422 if (error == 0) {
423 if (lp->d_secperunit > sp->ds_size)
424 error = ENOSPC;
425 for (part = 0; part < lp->d_npartitions; part++)
426 if (lp->d_partitions[part].p_size > sp->ds_size)
427 error = ENOSPC;
428 }
429 if (error != 0) {
430 free(lp, M_DEVBUF);
431 return (error);
432 }
433 free_ds_label(ssp, slice);
434 set_ds_label(ssp, slice, lp);
435 set_ds_labeldevs(dev, ssp);
436 return (0);
437
438 case DIOCSYNCSLICEINFO:
439 if (slice != WHOLE_DISK_SLICE || dkpart(dev) != RAW_PART)
440 return (EINVAL);
441 if (!*(int *)data)
442 for (slice = 0; slice < ssp->dss_nslices; slice++) {
443 openmask = ssp->dss_slices[slice].ds_openmask;
444 if (openmask
445 && (slice != WHOLE_DISK_SLICE
446 || openmask & ~(1 << RAW_PART)))
447 return (EBUSY);
448 }
449
450 /*
451 * Temporarily forget the current slices struct and read
452 * the current one.
453 * XXX should wait for current accesses on this disk to
454 * complete, then lock out future accesses and opens.
455 */
456 *sspp = NULL;
457 lp = malloc(sizeof *lp, M_DEVBUF, M_WAITOK);
458 *lp = *ssp->dss_slices[WHOLE_DISK_SLICE].ds_label;
459 error = dsopen(dev, S_IFCHR, ssp->dss_oflags, sspp, lp);
460 if (error != 0) {
461 free(lp, M_DEVBUF);
462 *sspp = ssp;
463 return (error);
464 }
465
466 /*
467 * Reopen everything. This is a no-op except in the "force"
468 * case and when the raw bdev and cdev are both open. Abort
469 * if anything fails.
470 */
471 for (slice = 0; slice < ssp->dss_nslices; slice++) {
472 for (openmask = ssp->dss_slices[slice].ds_openmask,
473 part = 0; openmask; openmask >>= 1, part++) {
474 if (!(openmask & 1))
475 continue;
476 error = dsopen(dkmodslice(dkmodpart(dev, part),
477 slice),
478 S_IFCHR, ssp->dss_oflags, sspp,
479 lp);
480 if (error != 0) {
481 free(lp, M_DEVBUF);
482 *sspp = ssp;
483 return (EBUSY);
484 }
485 }
486 }
487
488 free(lp, M_DEVBUF);
489 dsgone(&ssp);
490 return (0);
491
492 case DIOCWDINFO:
493 error = dsioctl(dev, DIOCSDINFO, data, flags, &ssp);
494 if (error != 0)
495 return (error);
496 /*
497 * XXX this used to hack on dk_openpart to fake opening
498 * partition 0 in case that is used instead of dkpart(dev).
499 */
500 old_wlabel = sp->ds_wlabel;
501 set_ds_wlabel(ssp, slice, TRUE);
502 error = writedisklabel(dev, sp->ds_label);
503 /* XXX should invalidate in-core label if write failed. */
504 set_ds_wlabel(ssp, slice, old_wlabel);
505 return (error);
506
507 case DIOCWLABEL:
508 #ifndef __alpha__
509 if (slice == WHOLE_DISK_SLICE)
510 return (ENODEV);
511 #endif
512 if (!(flags & FWRITE))
513 return (EBADF);
514 set_ds_wlabel(ssp, slice, *(int *)data != 0);
515 return (0);
516
517 default:
518 return (ENOIOCTL);
519 }
520 }
521
522 static void
523 dsiodone(bp)
524 struct bio *bp;
525 {
526 struct iodone_chain *ic;
527 char *msg;
528
529 ic = bp->bio_done_chain;
530 bp->bio_done = ic->ic_prev_iodone;
531 bp->bio_done_chain = ic->ic_prev_iodone_chain;
532 if (!(bp->bio_cmd == BIO_READ)
533 || (!(bp->bio_flags & BIO_ERROR) && bp->bio_error == 0)) {
534 msg = fixlabel((char *)NULL, ic->ic_args[1].ia_ptr,
535 (struct disklabel *)
536 (bp->bio_data + ic->ic_args[0].ia_long),
537 FALSE);
538 if (msg != NULL)
539 printf("%s\n", msg);
540 }
541 free(ic, M_DEVBUF);
542 biodone(bp);
543 }
544
545 int
546 dsisopen(ssp)
547 struct diskslices *ssp;
548 {
549 int slice;
550
551 if (ssp == NULL)
552 return (0);
553 for (slice = 0; slice < ssp->dss_nslices; slice++)
554 if (ssp->dss_slices[slice].ds_openmask)
555 return (1);
556 return (0);
557 }
558
559 /*
560 * Allocate a slices "struct" and initialize it to contain only an empty
561 * compatibility slice (pointing to itself), a whole disk slice (covering
562 * the disk as described by the label), and (nslices - BASE_SLICES) empty
563 * slices beginning at BASE_SLICE.
564 */
565 struct diskslices *
566 dsmakeslicestruct(nslices, lp)
567 int nslices;
568 struct disklabel *lp;
569 {
570 struct diskslice *sp;
571 struct diskslices *ssp;
572
573 ssp = malloc(offsetof(struct diskslices, dss_slices) +
574 nslices * sizeof *sp, M_DEVBUF, M_WAITOK);
575 ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE;
576 ssp->dss_nslices = nslices;
577 ssp->dss_oflags = 0;
578 ssp->dss_secmult = lp->d_secsize / DEV_BSIZE;
579 if (ssp->dss_secmult & (ssp->dss_secmult - 1))
580 ssp->dss_secshift = -1;
581 else
582 ssp->dss_secshift = ffs(ssp->dss_secmult) - 1;
583 ssp->dss_secsize = lp->d_secsize;
584 sp = &ssp->dss_slices[0];
585 bzero(sp, nslices * sizeof *sp);
586 sp[WHOLE_DISK_SLICE].ds_size = lp->d_secperunit;
587 return (ssp);
588 }
589
590 char *
591 dsname(dev, unit, slice, part, partname)
592 dev_t dev;
593 int unit;
594 int slice;
595 int part;
596 char *partname;
597 {
598 static char name[32];
599 const char *dname;
600
601 dname = devsw(dev)->d_name;
602 if (strlen(dname) > 16)
603 dname = "nametoolong";
604 snprintf(name, sizeof(name), "%s%d", dname, unit);
605 partname[0] = '\0';
606 if (slice != WHOLE_DISK_SLICE || part != RAW_PART) {
607 partname[0] = 'a' + part;
608 partname[1] = '\0';
609 if (slice != COMPATIBILITY_SLICE)
610 snprintf(name + strlen(name),
611 sizeof(name) - strlen(name), "s%d", slice - 1);
612 }
613 return (name);
614 }
615
616 /*
617 * This should only be called when the unit is inactive and the strategy
618 * routine should not allow it to become active unless we call it. Our
619 * strategy routine must be special to allow activity.
620 */
621 int
622 dsopen(dev, mode, flags, sspp, lp)
623 dev_t dev;
624 int mode;
625 u_int flags;
626 struct diskslices **sspp;
627 struct disklabel *lp;
628 {
629 dev_t dev1;
630 int error;
631 struct disklabel *lp1;
632 char *msg;
633 u_char mask;
634 int part;
635 char partname[2];
636 int slice;
637 char *sname;
638 struct diskslice *sp;
639 struct diskslices *ssp;
640 int unit;
641
642 dev->si_bsize_phys = lp->d_secsize;
643
644 unit = dkunit(dev);
645 if (lp->d_secsize % DEV_BSIZE) {
646 printf("%s: invalid sector size %lu\n", devtoname(dev),
647 (u_long)lp->d_secsize);
648 return (EINVAL);
649 }
650
651 /*
652 * XXX reinitialize the slice table unless there is an open device
653 * on the unit. This should only be done if the media has changed.
654 */
655 ssp = *sspp;
656 if (!dsisopen(ssp)) {
657 if (ssp != NULL)
658 dsgone(sspp);
659 /*
660 * Allocate a minimal slices "struct". This will become
661 * the final slices "struct" if we don't want real slices
662 * or if we can't find any real slices.
663 */
664 *sspp = dsmakeslicestruct(BASE_SLICE, lp);
665
666 if (!(flags & DSO_ONESLICE)) {
667 TRACE(("dsinit\n"));
668 error = dsinit(dev, lp, sspp);
669 if (error != 0) {
670 dsgone(sspp);
671 return (error);
672 }
673 }
674 ssp = *sspp;
675 ssp->dss_oflags = flags;
676
677 /*
678 * If there are no real slices, then make the compatiblity
679 * slice cover the whole disk.
680 */
681 if (ssp->dss_nslices == BASE_SLICE)
682 ssp->dss_slices[COMPATIBILITY_SLICE].ds_size
683 = lp->d_secperunit;
684
685 /* Point the compatibility slice at the BSD slice, if any. */
686 for (slice = BASE_SLICE; slice < ssp->dss_nslices; slice++) {
687 sp = &ssp->dss_slices[slice];
688 if (sp->ds_type == DOSPTYP_386BSD /* XXX */) {
689 ssp->dss_first_bsd_slice = slice;
690 ssp->dss_slices[COMPATIBILITY_SLICE].ds_offset
691 = sp->ds_offset;
692 ssp->dss_slices[COMPATIBILITY_SLICE].ds_size
693 = sp->ds_size;
694 ssp->dss_slices[COMPATIBILITY_SLICE].ds_type
695 = sp->ds_type;
696 break;
697 }
698 }
699
700 ssp->dss_slices[WHOLE_DISK_SLICE].ds_label = clone_label(lp);
701 ssp->dss_slices[WHOLE_DISK_SLICE].ds_wlabel = TRUE;
702 }
703
704 /* Initialize secondary info for all slices. */
705 for (slice = 0; slice < ssp->dss_nslices; slice++) {
706 sp = &ssp->dss_slices[slice];
707 if (sp->ds_label != NULL
708 #ifdef __alpha__
709 && slice != WHOLE_DISK_SLICE
710 #endif
711 )
712 continue;
713 dev1 = dkmodslice(dkmodpart(dev, RAW_PART), slice);
714 #if 0
715 sname = dsname(dev, unit, slice, RAW_PART, partname);
716 #else
717 *partname='\0';
718 sname = dev1->si_name;
719 #endif
720 /*
721 * XXX this should probably only be done for the need_init
722 * case, but there may be a problem with DIOCSYNCSLICEINFO.
723 */
724 set_ds_wlabel(ssp, slice, TRUE); /* XXX invert */
725 lp1 = clone_label(lp);
726 TRACE(("readdisklabel\n"));
727 if (flags & DSO_NOLABELS)
728 msg = NULL;
729 else {
730 msg = readdisklabel(dev1, lp1);
731
732 /*
733 * readdisklabel() returns NULL for success, and an
734 * error string for failure.
735 *
736 * If there isn't a label on the disk, and if the
737 * DSO_COMPATLABEL is set, we want to use the
738 * faked-up label provided by the caller.
739 *
740 * So we set msg to NULL to indicate that there is
741 * no failure (since we have a faked-up label),
742 * free lp1, and then clone it again from lp.
743 * (In case readdisklabel() modified lp1.)
744 */
745 if (msg != NULL && (flags & DSO_COMPATLABEL)) {
746 msg = NULL;
747 free(lp1, M_DEVBUF);
748 lp1 = clone_label(lp);
749 }
750 }
751 if (msg == NULL)
752 msg = fixlabel(sname, sp, lp1, FALSE);
753 if (msg == NULL && lp1->d_secsize != ssp->dss_secsize)
754 msg = "inconsistent sector size";
755 if (msg != NULL) {
756 if (sp->ds_type == DOSPTYP_386BSD /* XXX */)
757 log(LOG_WARNING, "%s: cannot find label (%s)\n",
758 sname, msg);
759 free(lp1, M_DEVBUF);
760 continue;
761 }
762 if (lp1->d_flags & D_BADSECT) {
763 log(LOG_ERR, "%s: bad sector table not supported\n",
764 sname);
765 free(lp1, M_DEVBUF);
766 continue;
767 }
768 set_ds_label(ssp, slice, lp1);
769 set_ds_labeldevs(dev1, ssp);
770 set_ds_wlabel(ssp, slice, FALSE);
771 }
772
773 slice = dkslice(dev);
774 if (slice >= ssp->dss_nslices)
775 return (ENXIO);
776 sp = &ssp->dss_slices[slice];
777 part = dkpart(dev);
778 if (part != RAW_PART
779 && (sp->ds_label == NULL || part >= sp->ds_label->d_npartitions))
780 return (EINVAL); /* XXX needs translation */
781 mask = 1 << part;
782 sp->ds_openmask |= mask;
783 return (0);
784 }
785
786 int
787 dssize(dev, sspp)
788 dev_t dev;
789 struct diskslices **sspp;
790 {
791 struct disklabel *lp;
792 int part;
793 int slice;
794 struct diskslices *ssp;
795
796 slice = dkslice(dev);
797 part = dkpart(dev);
798 ssp = *sspp;
799 if (ssp == NULL || slice >= ssp->dss_nslices
800 || !(ssp->dss_slices[slice].ds_openmask & (1 << part))) {
801 if (devsw(dev)->d_open(dev, FREAD, S_IFCHR,
802 (struct thread *)NULL) != 0)
803 return (-1);
804 devsw(dev)->d_close(dev, FREAD, S_IFCHR, (struct thread *)NULL);
805 ssp = *sspp;
806 }
807 lp = ssp->dss_slices[slice].ds_label;
808 if (lp == NULL)
809 return (-1);
810 return ((int)lp->d_partitions[part].p_size);
811 }
812
813 static void
814 free_ds_label(ssp, slice)
815 struct diskslices *ssp;
816 int slice;
817 {
818 struct disklabel *lp;
819 struct diskslice *sp;
820
821 sp = &ssp->dss_slices[slice];
822 lp = sp->ds_label;
823 if (lp == NULL)
824 return;
825 free(lp, M_DEVBUF);
826 set_ds_label(ssp, slice, (struct disklabel *)NULL);
827 }
828
829
830 static char *
831 fixlabel(sname, sp, lp, writeflag)
832 char *sname;
833 struct diskslice *sp;
834 struct disklabel *lp;
835 int writeflag;
836 {
837 u_long end;
838 u_long offset;
839 int part;
840 struct partition *pp;
841 u_long start;
842 bool_t warned;
843
844 /* These errors "can't happen" so don't bother reporting details. */
845 if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC)
846 return ("fixlabel: invalid magic");
847 if (dkcksum(lp) != 0)
848 return ("fixlabel: invalid checksum");
849
850 pp = &lp->d_partitions[RAW_PART];
851 if (writeflag) {
852 start = 0;
853 offset = sp->ds_offset;
854 } else {
855 start = sp->ds_offset;
856 offset = -sp->ds_offset;
857 }
858 if (pp->p_offset != start) {
859 if (sname != NULL) {
860 printf(
861 "%s: rejecting BSD label: raw partition offset != slice offset\n",
862 sname);
863 slice_info(sname, sp);
864 partition_info(sname, RAW_PART, pp);
865 }
866 return ("fixlabel: raw partition offset != slice offset");
867 }
868 if (pp->p_size != sp->ds_size) {
869 if (sname != NULL) {
870 printf("%s: raw partition size != slice size\n", sname);
871 slice_info(sname, sp);
872 partition_info(sname, RAW_PART, pp);
873 }
874 if (pp->p_size > sp->ds_size) {
875 if (sname == NULL)
876 return ("fixlabel: raw partition size > slice size");
877 printf("%s: truncating raw partition\n", sname);
878 pp->p_size = sp->ds_size;
879 }
880 }
881 end = start + sp->ds_size;
882 if (start > end)
883 return ("fixlabel: slice wraps");
884 if (lp->d_secpercyl <= 0)
885 return ("fixlabel: d_secpercyl <= 0");
886 pp -= RAW_PART;
887 warned = FALSE;
888 for (part = 0; part < lp->d_npartitions; part++, pp++) {
889 if (pp->p_offset != 0 || pp->p_size != 0) {
890 if (pp->p_offset < start
891 || pp->p_offset + pp->p_size > end
892 || pp->p_offset + pp->p_size < pp->p_offset) {
893 if (sname != NULL) {
894 printf(
895 "%s: rejecting partition in BSD label: it isn't entirely within the slice\n",
896 sname);
897 if (!warned) {
898 slice_info(sname, sp);
899 warned = TRUE;
900 }
901 partition_info(sname, part, pp);
902 }
903 /* XXX else silently discard junk. */
904 bzero(pp, sizeof *pp);
905 } else
906 pp->p_offset += offset;
907 }
908 }
909 lp->d_ncylinders = sp->ds_size / lp->d_secpercyl;
910 lp->d_secperunit = sp->ds_size;
911 lp->d_checksum = 0;
912 lp->d_checksum = dkcksum(lp);
913 return (NULL);
914 }
915
916 static void
917 partition_info(sname, part, pp)
918 char *sname;
919 int part;
920 struct partition *pp;
921 {
922 printf("%s%c: start %lu, end %lu, size %lu\n", sname, 'a' + part,
923 (u_long)pp->p_offset, (u_long)(pp->p_offset + pp->p_size - 1),
924 (u_long)pp->p_size);
925 }
926
927 static void
928 slice_info(sname, sp)
929 char *sname;
930 struct diskslice *sp;
931 {
932 printf("%s: start %lu, end %lu, size %lu\n", sname,
933 sp->ds_offset, sp->ds_offset + sp->ds_size - 1, sp->ds_size);
934 }
935
936 static void
937 set_ds_label(ssp, slice, lp)
938 struct diskslices *ssp;
939 int slice;
940 struct disklabel *lp;
941 {
942 ssp->dss_slices[slice].ds_label = lp;
943 if (slice == COMPATIBILITY_SLICE)
944 ssp->dss_slices[ssp->dss_first_bsd_slice].ds_label = lp;
945 else if (slice == ssp->dss_first_bsd_slice)
946 ssp->dss_slices[COMPATIBILITY_SLICE].ds_label = lp;
947 }
948
949 static void
950 set_ds_labeldevs(dev, ssp)
951 dev_t dev;
952 struct diskslices *ssp;
953 {
954 }
955
956
957 static void
958 set_ds_wlabel(ssp, slice, wlabel)
959 struct diskslices *ssp;
960 int slice;
961 int wlabel;
962 {
963 ssp->dss_slices[slice].ds_wlabel = wlabel;
964 if (slice == COMPATIBILITY_SLICE)
965 ssp->dss_slices[ssp->dss_first_bsd_slice].ds_wlabel = wlabel;
966 else if (slice == ssp->dss_first_bsd_slice)
967 ssp->dss_slices[COMPATIBILITY_SLICE].ds_wlabel = wlabel;
968 }
Cache object: ff753709c1b920d5fb0a0f6b1bd168a7
|