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$
47 */
48
49 #include "opt_devfs.h"
50
51 #include <stddef.h>
52
53 #include <sys/param.h>
54 #include <sys/buf.h>
55 #include <sys/conf.h>
56 #ifdef DEVFS
57 #include <sys/devfsext.h>
58 #endif
59 #include <sys/disklabel.h>
60 #include <sys/diskslice.h>
61 #include <sys/dkbad.h>
62 #include <sys/fcntl.h>
63 #include <sys/malloc.h>
64 #include <sys/stat.h>
65 #include <sys/syslog.h>
66 #include <sys/systm.h>
67 #include <sys/vnode.h>
68
69 #include <ufs/ffs/fs.h>
70
71 #define TRACE(str) do { if (ds_debug) printf str; } while (0)
72
73 typedef u_char bool_t;
74
75 static volatile bool_t ds_debug;
76
77 static struct disklabel *clone_label __P((struct disklabel *lp));
78 static void dsiodone __P((struct buf *bp));
79 static char *fixlabel __P((char *sname, struct diskslice *sp,
80 struct disklabel *lp, int writeflag));
81 static void free_ds_label __P((struct diskslices *ssp, int slice));
82 #ifdef DEVFS
83 static void free_ds_labeldevs __P((struct diskslices *ssp, int slice));
84 #endif
85 static void partition_info __P((char *sname, int part, struct partition *pp));
86 static void slice_info __P((char *sname, struct diskslice *sp));
87 static void set_ds_bad __P((struct diskslices *ssp, int slice,
88 struct dkbad_intern *btp));
89 static void set_ds_label __P((struct diskslices *ssp, int slice,
90 struct disklabel *lp));
91 #ifdef DEVFS
92 static void set_ds_labeldevs __P((char *dname, dev_t dev,
93 struct diskslices *ssp));
94 static void set_ds_labeldevs_unaliased __P((char *dname, dev_t dev,
95 struct diskslices *ssp));
96 #endif
97 static void set_ds_wlabel __P((struct diskslices *ssp, int slice,
98 int wlabel));
99
100 /*
101 * Duplicate a label for the whole disk, and initialize defaults in the
102 * copy for fields that are not already initialized. The caller only
103 * needs to initialize d_secsize and d_secperunit, and zero the fields
104 * that are to be defaulted.
105 */
106 static struct disklabel *
107 clone_label(lp)
108 struct disklabel *lp;
109 {
110 struct disklabel *lp1;
111
112 lp1 = malloc(sizeof *lp1, M_DEVBUF, M_WAITOK);
113 *lp1 = *lp;
114 lp = NULL;
115 if (lp1->d_typename[0] == '\0')
116 strncpy(lp1->d_typename, "amnesiac", sizeof(lp1->d_typename));
117 if (lp1->d_packname[0] == '\0')
118 strncpy(lp1->d_packname, "fictitious", sizeof(lp1->d_packname));
119 if (lp1->d_nsectors == 0)
120 lp1->d_nsectors = 32;
121 if (lp1->d_ntracks == 0)
122 lp1->d_ntracks = 64;
123 lp1->d_secpercyl = lp1->d_nsectors * lp1->d_ntracks;
124 lp1->d_ncylinders = lp1->d_secperunit / lp1->d_secpercyl;
125 if (lp1->d_rpm == 0)
126 lp1->d_rpm = 3600;
127 if (lp1->d_interleave == 0)
128 lp1->d_interleave = 1;
129 if (lp1->d_npartitions < RAW_PART + 1)
130 lp1->d_npartitions = MAXPARTITIONS;
131 if (lp1->d_bbsize == 0)
132 lp1->d_bbsize = BBSIZE;
133 if (lp1->d_sbsize == 0)
134 lp1->d_sbsize = SBSIZE;
135 lp1->d_partitions[RAW_PART].p_size = lp1->d_secperunit;
136 lp1->d_magic = DISKMAGIC;
137 lp1->d_magic2 = DISKMAGIC;
138 lp1->d_checksum = dkcksum(lp1);
139 return (lp1);
140 }
141
142 /*
143 * Determine the size of the transfer, and make sure it is
144 * within the boundaries of the partition. Adjust transfer
145 * if needed, and signal errors or early completion.
146 *
147 * XXX TODO:
148 * o Do bad sector remapping. May need to split buffer.
149 * o Split buffers that are too big for the device.
150 * o Check for overflow.
151 * o Finish cleaning this up.
152 */
153 int
154 dscheck(bp, ssp)
155 struct buf *bp;
156 struct diskslices *ssp;
157 {
158 daddr_t blkno;
159 u_long endsecno;
160 daddr_t labelsect;
161 struct disklabel *lp;
162 char *msg;
163 long nsec;
164 struct partition *pp;
165 daddr_t secno;
166 daddr_t slicerel_secno;
167 struct diskslice *sp;
168 int s;
169
170 blkno = bp->b_blkno;
171 if (blkno < 0) {
172 printf("dscheck: negative b_blkno %ld\n", (long)blkno);
173 bp->b_error = EINVAL;
174 goto bad;
175 }
176 sp = &ssp->dss_slices[dkslice(bp->b_dev)];
177 lp = sp->ds_label;
178 if (ssp->dss_secmult == 1) {
179 if (bp->b_bcount % (u_long)DEV_BSIZE)
180 goto bad_bcount;
181 secno = blkno;
182 nsec = bp->b_bcount >> DEV_BSHIFT;
183 } else if (ssp->dss_secshift != -1) {
184 if (bp->b_bcount & (ssp->dss_secsize - 1))
185 goto bad_bcount;
186 if (blkno & (ssp->dss_secmult - 1))
187 goto bad_blkno;
188 secno = blkno >> ssp->dss_secshift;
189 nsec = bp->b_bcount >> (DEV_BSHIFT + ssp->dss_secshift);
190 } else {
191 if (bp->b_bcount % ssp->dss_secsize)
192 goto bad_bcount;
193 if (blkno % ssp->dss_secmult)
194 goto bad_blkno;
195 secno = blkno / ssp->dss_secmult;
196 nsec = bp->b_bcount / ssp->dss_secsize;
197 }
198 if (lp == NULL) {
199 labelsect = -LABELSECTOR - 1;
200 endsecno = sp->ds_size;
201 slicerel_secno = secno;
202 } else {
203 labelsect = lp->d_partitions[LABEL_PART].p_offset;
204 if (labelsect != 0) Debugger("labelsect != 0 in dscheck()");
205 pp = &lp->d_partitions[dkpart(bp->b_dev)];
206 endsecno = pp->p_size;
207 slicerel_secno = pp->p_offset + secno;
208 if (sp->ds_bad != NULL && ds_debug) {
209 daddr_t newsecno;
210
211 newsecno = transbad144(sp->ds_bad, slicerel_secno);
212 if (newsecno != slicerel_secno)
213 printf("should map bad sector %ld -> %ld\n",
214 (long)slicerel_secno, (long)newsecno);
215 }
216 }
217
218 /* overwriting disk label ? */
219 /* XXX should also protect bootstrap in first 8K */
220 if (slicerel_secno <= LABELSECTOR + labelsect &&
221 #if LABELSECTOR != 0
222 slicerel_secno + nsec > LABELSECTOR + labelsect &&
223 #endif
224 (bp->b_flags & B_READ) == 0 && sp->ds_wlabel == 0) {
225 bp->b_error = EROFS;
226 goto bad;
227 }
228
229 #if defined(DOSBBSECTOR) && defined(notyet)
230 /* overwriting master boot record? */
231 if (slicerel_secno <= DOSBBSECTOR && (bp->b_flags & B_READ) == 0 &&
232 sp->ds_wlabel == 0) {
233 bp->b_error = EROFS;
234 goto bad;
235 }
236 #endif
237
238 /* beyond partition? */
239 if (secno + nsec > endsecno) {
240 /* if exactly at end of disk, return an EOF */
241 if (secno == endsecno) {
242 bp->b_resid = bp->b_bcount;
243 return (0);
244 }
245 /* or truncate if part of it fits */
246 nsec = endsecno - secno;
247 if (nsec <= 0) {
248 bp->b_error = EINVAL;
249 goto bad;
250 }
251 bp->b_bcount = nsec * ssp->dss_secsize;
252 }
253
254 bp->b_pblkno = sp->ds_offset + slicerel_secno;
255
256 /*
257 * Snoop on label accesses if the slice offset is nonzero. Fudge
258 * offsets in the label to keep the in-core label coherent with
259 * the on-disk one.
260 */
261 if (slicerel_secno <= LABELSECTOR + labelsect
262 #if LABELSECTOR != 0
263 && slicerel_secno + nsec > LABELSECTOR + labelsect
264 #endif
265 && sp->ds_offset != 0) {
266 struct iodone_chain *ic;
267
268 ic = malloc(sizeof *ic , M_DEVBUF, M_WAITOK);
269 ic->ic_prev_flags = bp->b_flags;
270 ic->ic_prev_iodone = bp->b_iodone;
271 ic->ic_prev_iodone_chain = bp->b_iodone_chain;
272 ic->ic_args[0].ia_long = (LABELSECTOR + labelsect -
273 slicerel_secno) * ssp->dss_secsize;
274 ic->ic_args[1].ia_ptr = sp;
275 bp->b_flags |= B_CALL;
276 bp->b_iodone = dsiodone;
277 bp->b_iodone_chain = ic;
278 if (!(bp->b_flags & B_READ)) {
279 /*
280 * XXX even disklabel(8) writes directly so we need
281 * to adjust writes. Perhaps we should drop support
282 * for DIOCWLABEL (always write protect labels) and
283 * require the use of DIOCWDINFO.
284 *
285 * XXX probably need to copy the data to avoid even
286 * temporarily corrupting the in-core copy.
287 */
288 if (bp->b_vp != NULL) {
289 s = splbio();
290 bp->b_vp->v_numoutput++;
291 splx(s);
292 }
293 /* XXX need name here. */
294 msg = fixlabel((char *)NULL, sp,
295 (struct disklabel *)
296 (bp->b_data + ic->ic_args[0].ia_long),
297 TRUE);
298 if (msg != NULL) {
299 printf("%s\n", msg);
300 bp->b_error = EROFS;
301 goto bad;
302 }
303 }
304 }
305 return (1);
306
307 bad_bcount:
308 printf("dscheck: b_bcount %ld is not on a sector boundary (ssize %d)\n",
309 bp->b_bcount, ssp->dss_secsize);
310 bp->b_error = EINVAL;
311 goto bad;
312
313 bad_blkno:
314 printf("dscheck: b_blkno %ld is not on a sector boundary (ssize %d)\n",
315 (long)blkno, ssp->dss_secsize);
316 bp->b_error = EINVAL;
317 goto bad;
318
319 bad:
320 bp->b_resid = bp->b_bcount;
321 bp->b_flags |= B_ERROR;
322 return (-1);
323 }
324
325 void
326 dsclose(dev, mode, ssp)
327 dev_t dev;
328 int mode;
329 struct diskslices *ssp;
330 {
331 u_char mask;
332 struct diskslice *sp;
333
334 sp = &ssp->dss_slices[dkslice(dev)];
335 mask = 1 << dkpart(dev);
336 switch (mode) {
337 case S_IFBLK:
338 sp->ds_bopenmask &= ~mask;
339 break;
340 case S_IFCHR:
341 sp->ds_copenmask &= ~mask;
342 break;
343 }
344 sp->ds_openmask = sp->ds_bopenmask | sp->ds_copenmask;
345 }
346
347 void
348 dsgone(sspp)
349 struct diskslices **sspp;
350 {
351 int slice;
352 struct diskslice *sp;
353 struct diskslices *ssp;
354
355 for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) {
356 sp = &ssp->dss_slices[slice];
357 if (sp->ds_bad != NULL) {
358 free(sp->ds_bad, M_DEVBUF);
359 set_ds_bad(ssp, slice, (struct dkbad_intern *)NULL);
360 }
361 #ifdef DEVFS
362 if (sp->ds_bdev != NULL)
363 devfs_remove_dev(sp->ds_bdev);
364 if (sp->ds_cdev != NULL)
365 devfs_remove_dev(sp->ds_cdev);
366 #endif
367 free_ds_label(ssp, slice);
368 }
369 free(ssp, M_DEVBUF);
370 *sspp = NULL;
371 }
372
373 /*
374 * For the "write" commands (DIOCSBAD, DIOCSDINFO and DIOCWDINFO), this
375 * is subject to the same restriction as dsopen().
376 */
377 int
378 dsioctl(dname, dev, cmd, data, flags, sspp, strat, setgeom)
379 char *dname;
380 dev_t dev;
381 u_long cmd;
382 caddr_t data;
383 int flags;
384 struct diskslices **sspp;
385 d_strategy_t *strat;
386 ds_setgeom_t *setgeom;
387 {
388 int error;
389 struct disklabel *lp;
390 int old_wlabel;
391 u_char openmask;
392 int part;
393 int slice;
394 struct diskslice *sp;
395 struct diskslices *ssp;
396
397 slice = dkslice(dev);
398 ssp = *sspp;
399 sp = &ssp->dss_slices[slice];
400 lp = sp->ds_label;
401 switch (cmd) {
402
403 case DIOCGDINFO:
404 if (lp == NULL)
405 return (EINVAL);
406 *(struct disklabel *)data = *lp;
407 return (0);
408
409 #ifdef notyet
410 case DIOCGDINFOP:
411 if (lp == NULL)
412 return (EINVAL);
413 *(struct disklabel **)data = lp;
414 return (0);
415 #endif
416
417 case DIOCGPART:
418 if (lp == NULL)
419 return (EINVAL);
420 ((struct partinfo *)data)->disklab = lp;
421 ((struct partinfo *)data)->part
422 = &lp->d_partitions[dkpart(dev)];
423 return (0);
424
425 case DIOCGSLICEINFO:
426 bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] -
427 (char *)ssp);
428 return (0);
429
430 case DIOCSBAD:
431 if (slice == WHOLE_DISK_SLICE)
432 return (ENODEV);
433 if (!(flags & FWRITE))
434 return (EBADF);
435 if (lp == NULL)
436 return (EINVAL);
437 if (sp->ds_bad != NULL)
438 free(sp->ds_bad, M_DEVBUF);
439 set_ds_bad(ssp, slice, internbad144((struct dkbad *)data, lp));
440 return (0);
441
442 case DIOCSDINFO:
443 if (slice == WHOLE_DISK_SLICE)
444 return (ENODEV);
445 if (!(flags & FWRITE))
446 return (EBADF);
447 lp = malloc(sizeof *lp, M_DEVBUF, M_WAITOK);
448 if (sp->ds_label == NULL)
449 bzero(lp, sizeof *lp);
450 else
451 bcopy(sp->ds_label, lp, sizeof *lp);
452 if (sp->ds_label == NULL)
453 openmask = 0;
454 else {
455 openmask = sp->ds_openmask;
456 if (slice == COMPATIBILITY_SLICE)
457 openmask |= ssp->dss_slices[
458 ssp->dss_first_bsd_slice].ds_openmask;
459 else if (slice == ssp->dss_first_bsd_slice)
460 openmask |= ssp->dss_slices[
461 COMPATIBILITY_SLICE].ds_openmask;
462 }
463 error = setdisklabel(lp, (struct disklabel *)data,
464 (u_long)openmask);
465 /* XXX why doesn't setdisklabel() check this? */
466 if (error == 0 && lp->d_partitions[RAW_PART].p_offset != 0)
467 error = EXDEV;
468 if (error == 0) {
469 if (lp->d_secperunit > sp->ds_size)
470 error = ENOSPC;
471 for (part = 0; part < lp->d_npartitions; part++)
472 if (lp->d_partitions[part].p_size > sp->ds_size)
473 error = ENOSPC;
474 }
475 #if 0 /* XXX */
476 if (error != 0 && setgeom != NULL)
477 error = setgeom(lp);
478 #endif
479 if (error != 0) {
480 free(lp, M_DEVBUF);
481 return (error);
482 }
483 free_ds_label(ssp, slice);
484 set_ds_label(ssp, slice, lp);
485 #ifdef DEVFS
486 set_ds_labeldevs(dname, dev, ssp);
487 #endif
488 return (0);
489
490 case DIOCSYNCSLICEINFO:
491 if (slice != WHOLE_DISK_SLICE || dkpart(dev) != RAW_PART)
492 return (EINVAL);
493 if (!*(int *)data)
494 for (slice = 0; slice < ssp->dss_nslices; slice++) {
495 openmask = ssp->dss_slices[slice].ds_openmask;
496 if (openmask
497 && (slice != WHOLE_DISK_SLICE
498 || openmask & ~(1 << RAW_PART)))
499 return (EBUSY);
500 }
501
502 /*
503 * Temporarily forget the current slices struct and read
504 * the current one.
505 * XXX should wait for current accesses on this disk to
506 * complete, then lock out future accesses and opens.
507 */
508 *sspp = NULL;
509 lp = malloc(sizeof *lp, M_DEVBUF, M_WAITOK);
510 *lp = *ssp->dss_slices[WHOLE_DISK_SLICE].ds_label;
511 error = dsopen(dname, dev,
512 ssp->dss_slices[WHOLE_DISK_SLICE].ds_copenmask
513 & (1 << RAW_PART) ? S_IFCHR : S_IFBLK,
514 ssp->dss_oflags, sspp, lp, strat, setgeom,
515 ssp->dss_cdevsw);
516 if (error != 0) {
517 free(lp, M_DEVBUF);
518 *sspp = ssp;
519 return (error);
520 }
521
522 /*
523 * Reopen everything. This is a no-op except in the "force"
524 * case and when the raw bdev and cdev are both open. Abort
525 * if anything fails.
526 */
527 for (slice = 0; slice < ssp->dss_nslices; slice++) {
528 for (openmask = ssp->dss_slices[slice].ds_bopenmask,
529 part = 0; openmask; openmask >>= 1, part++) {
530 if (!(openmask & 1))
531 continue;
532 error = dsopen(dname,
533 dkmodslice(dkmodpart(dev, part),
534 slice),
535 S_IFBLK, ssp->dss_oflags, sspp,
536 lp, strat, setgeom,
537 ssp->dss_cdevsw);
538 if (error != 0) {
539 /* XXX should free devfs toks. */
540 free(lp, M_DEVBUF);
541 /* XXX should restore devfs toks. */
542 *sspp = ssp;
543 return (EBUSY);
544 }
545 }
546 for (openmask = ssp->dss_slices[slice].ds_copenmask,
547 part = 0; openmask; openmask >>= 1, part++) {
548 if (!(openmask & 1))
549 continue;
550 error = dsopen(dname,
551 dkmodslice(dkmodpart(dev, part),
552 slice),
553 S_IFCHR, ssp->dss_oflags, sspp,
554 lp, strat, setgeom,
555 ssp->dss_cdevsw);
556 if (error != 0) {
557 /* XXX should free devfs toks. */
558 free(lp, M_DEVBUF);
559 /* XXX should restore devfs toks. */
560 *sspp = ssp;
561 return (EBUSY);
562 }
563 }
564 }
565
566 /* XXX devfs tokens? */
567 free(lp, M_DEVBUF);
568 dsgone(&ssp);
569 return (0);
570
571 case DIOCWDINFO:
572 error = dsioctl(dname, dev, DIOCSDINFO, data, flags, &ssp,
573 strat, setgeom);
574 if (error != 0)
575 return (error);
576 /*
577 * XXX this used to hack on dk_openpart to fake opening
578 * partition 0 in case that is used instead of dkpart(dev).
579 */
580 old_wlabel = sp->ds_wlabel;
581 set_ds_wlabel(ssp, slice, TRUE);
582 error = writedisklabel(dev, strat, sp->ds_label);
583 /* XXX should invalidate in-core label if write failed. */
584 set_ds_wlabel(ssp, slice, old_wlabel);
585 return (error);
586
587 case DIOCWLABEL:
588 #ifndef __alpha__
589 if (slice == WHOLE_DISK_SLICE)
590 return (ENODEV);
591 #endif
592 if (!(flags & FWRITE))
593 return (EBADF);
594 set_ds_wlabel(ssp, slice, *(int *)data != 0);
595 return (0);
596
597 default:
598 return (ENOIOCTL);
599 }
600 }
601
602 static void
603 dsiodone(bp)
604 struct buf *bp;
605 {
606 struct iodone_chain *ic;
607 char *msg;
608
609 ic = bp->b_iodone_chain;
610 bp->b_flags = (ic->ic_prev_flags & B_CALL)
611 | (bp->b_flags & ~(B_CALL | B_DONE));
612 bp->b_iodone = ic->ic_prev_iodone;
613 bp->b_iodone_chain = ic->ic_prev_iodone_chain;
614 if (!(bp->b_flags & B_READ)
615 || (!(bp->b_flags & B_ERROR) && bp->b_error == 0)) {
616 msg = fixlabel((char *)NULL, ic->ic_args[1].ia_ptr,
617 (struct disklabel *)
618 (bp->b_data + ic->ic_args[0].ia_long),
619 FALSE);
620 if (msg != NULL)
621 printf("%s\n", msg);
622 }
623 free(ic, M_DEVBUF);
624 biodone(bp);
625 }
626
627 int
628 dsisopen(ssp)
629 struct diskslices *ssp;
630 {
631 int slice;
632
633 if (ssp == NULL)
634 return (0);
635 for (slice = 0; slice < ssp->dss_nslices; slice++)
636 if (ssp->dss_slices[slice].ds_openmask)
637 return (1);
638 return (0);
639 }
640
641 /*
642 * Allocate a slices "struct" and initialize it to contain only an empty
643 * compatibility slice (pointing to itself), a whole disk slice (covering
644 * the disk as described by the label), and (nslices - BASE_SLICES) empty
645 * slices beginning at BASE_SLICE.
646 */
647 struct diskslices *
648 dsmakeslicestruct(nslices, lp)
649 int nslices;
650 struct disklabel *lp;
651 {
652 struct diskslice *sp;
653 struct diskslices *ssp;
654
655 ssp = malloc(offsetof(struct diskslices, dss_slices) +
656 nslices * sizeof *sp, M_DEVBUF, M_WAITOK);
657 ssp->dss_cdevsw = NULL;
658 ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE;
659 ssp->dss_nslices = nslices;
660 ssp->dss_oflags = 0;
661 ssp->dss_secmult = lp->d_secsize / DEV_BSIZE;
662 if (ssp->dss_secmult & (ssp->dss_secmult - 1))
663 ssp->dss_secshift = -1;
664 else
665 ssp->dss_secshift = ffs(ssp->dss_secmult) - 1;
666 ssp->dss_secsize = lp->d_secsize;
667 sp = &ssp->dss_slices[0];
668 bzero(sp, nslices * sizeof *sp);
669 sp[WHOLE_DISK_SLICE].ds_size = lp->d_secperunit;
670 return (ssp);
671 }
672
673 char *
674 dsname(dname, unit, slice, part, partname)
675 char *dname;
676 int unit;
677 int slice;
678 int part;
679 char *partname;
680 {
681 static char name[32];
682
683 if (strlen(dname) > 16)
684 dname = "nametoolong";
685 snprintf(name, sizeof(name), "%s%d", dname, unit);
686 partname[0] = '\0';
687 if (slice != WHOLE_DISK_SLICE || part != RAW_PART) {
688 partname[0] = 'a' + part;
689 partname[1] = '\0';
690 if (slice != COMPATIBILITY_SLICE)
691 snprintf(name + strlen(name),
692 sizeof(name) - strlen(name), "s%d", slice - 1);
693 }
694 return (name);
695 }
696
697 /*
698 * This should only be called when the unit is inactive and the strategy
699 * routine should not allow it to become active unless we call it. Our
700 * strategy routine must be special to allow activity.
701 */
702 int
703 dsopen(dname, dev, mode, flags, sspp, lp, strat, setgeom, cdevsw)
704 char *dname;
705 dev_t dev;
706 int mode;
707 u_int flags;
708 struct diskslices **sspp;
709 struct disklabel *lp;
710 d_strategy_t *strat;
711 ds_setgeom_t *setgeom;
712 struct cdevsw *cdevsw;
713 {
714 struct dkbad *btp;
715 dev_t dev1;
716 int error;
717 struct disklabel *lp1;
718 char *msg;
719 u_char mask;
720 #ifdef DEVFS
721 int mynor;
722 #endif
723 bool_t need_init;
724 int part;
725 char partname[2];
726 int slice;
727 char *sname;
728 struct diskslice *sp;
729 struct diskslices *ssp;
730 int unit;
731
732 if (lp->d_secsize % DEV_BSIZE)
733 return (EINVAL);
734
735 /*
736 * XXX reinitialize the slice table unless there is an open device
737 * on the unit. This should only be done if the media has changed.
738 */
739 ssp = *sspp;
740 need_init = !dsisopen(ssp);
741 if (ssp != NULL && need_init)
742 dsgone(sspp);
743 if (need_init) {
744 /*
745 * Allocate a minimal slices "struct". This will become
746 * the final slices "struct" if we don't want real slices
747 * or if we can't find any real slices.
748 */
749 *sspp = dsmakeslicestruct(BASE_SLICE, lp);
750
751 if (!(flags & DSO_ONESLICE)) {
752 TRACE(("dsinit\n"));
753 error = dsinit(dname, dev, strat, lp, sspp);
754 if (error != 0) {
755 dsgone(sspp);
756 return (error);
757 }
758 }
759 ssp = *sspp;
760 ssp->dss_oflags = flags;
761 #ifdef DEVFS
762 ssp->dss_cdevsw = cdevsw;
763 #endif
764
765 /*
766 * If there are no real slices, then make the compatiblity
767 * slice cover the whole disk.
768 */
769 if (ssp->dss_nslices == BASE_SLICE)
770 ssp->dss_slices[COMPATIBILITY_SLICE].ds_size
771 = lp->d_secperunit;
772
773 /* Point the compatibility slice at the BSD slice, if any. */
774 for (slice = BASE_SLICE; slice < ssp->dss_nslices; slice++) {
775 sp = &ssp->dss_slices[slice];
776 if (sp->ds_type == DOSPTYP_386BSD /* XXX */) {
777 ssp->dss_first_bsd_slice = slice;
778 ssp->dss_slices[COMPATIBILITY_SLICE].ds_offset
779 = sp->ds_offset;
780 ssp->dss_slices[COMPATIBILITY_SLICE].ds_size
781 = sp->ds_size;
782 ssp->dss_slices[COMPATIBILITY_SLICE].ds_type
783 = sp->ds_type;
784 break;
785 }
786 }
787
788 ssp->dss_slices[WHOLE_DISK_SLICE].ds_label = clone_label(lp);
789 ssp->dss_slices[WHOLE_DISK_SLICE].ds_wlabel = TRUE;
790 if (setgeom != NULL) {
791 error = setgeom(lp);
792 if (error != 0) {
793 dsgone(sspp);
794 return (error);
795 }
796 }
797 }
798
799 unit = dkunit(dev);
800
801 /*
802 * Initialize secondary info for all slices. It is needed for more
803 * than the current slice in the DEVFS case.
804 */
805 for (slice = 0; slice < ssp->dss_nslices; slice++) {
806 sp = &ssp->dss_slices[slice];
807 if (sp->ds_label != NULL
808 #ifdef __alpha__
809 && slice != WHOLE_DISK_SLICE
810 #endif
811 )
812 continue;
813 dev1 = dkmodslice(dkmodpart(dev, RAW_PART), slice);
814 sname = dsname(dname, unit, slice, RAW_PART, partname);
815 #ifdef DEVFS
816 if (slice != COMPATIBILITY_SLICE && sp->ds_bdev == NULL
817 && sp->ds_size != 0) {
818 mynor = minor(dev1);
819 sp->ds_bdev =
820 devfs_add_devswf(bdevsw, mynor, DV_BLK,
821 UID_ROOT, GID_OPERATOR, 0640,
822 "%s", sname);
823 sp->ds_cdev =
824 devfs_add_devswf(cdevsw, mynor, DV_CHR,
825 UID_ROOT, GID_OPERATOR, 0640,
826 "r%s", sname);
827 }
828 #endif
829 /*
830 * XXX this should probably only be done for the need_init
831 * case, but there may be a problem with DIOCSYNCSLICEINFO.
832 */
833 set_ds_wlabel(ssp, slice, TRUE); /* XXX invert */
834 lp1 = clone_label(lp);
835 TRACE(("readdisklabel\n"));
836 if (flags & DSO_NOLABELS)
837 msg = NULL;
838 else
839 msg = readdisklabel(dev1, strat, lp1);
840 #if 0 /* XXX */
841 if (msg == NULL && setgeom != NULL && setgeom(lp1) != 0)
842 msg = "setgeom failed";
843 #endif
844 if (msg == NULL)
845 msg = fixlabel(sname, sp, lp1, FALSE);
846 if (msg == NULL && lp1->d_secsize != ssp->dss_secsize)
847 msg = "inconsistent sector size";
848 if (msg != NULL) {
849 free(lp1, M_DEVBUF);
850 if (sp->ds_type == DOSPTYP_386BSD /* XXX */)
851 log(LOG_WARNING, "%s: cannot find label (%s)\n",
852 sname, msg);
853 continue;
854 }
855 if (lp1->d_flags & D_BADSECT) {
856 btp = malloc(sizeof *btp, M_DEVBUF, M_WAITOK);
857 TRACE(("readbad144\n"));
858 msg = readbad144(dev1, strat, lp1, btp);
859 if (msg != NULL) {
860 log(LOG_WARNING,
861 "%s: cannot find bad sector table (%s)\n",
862 sname, msg);
863 free(btp, M_DEVBUF);
864 free(lp1, M_DEVBUF);
865 continue;
866 }
867 set_ds_bad(ssp, slice, internbad144(btp, lp1));
868 free(btp, M_DEVBUF);
869 if (sp->ds_bad == NULL) {
870 free(lp1, M_DEVBUF);
871 continue;
872 }
873 }
874 set_ds_label(ssp, slice, lp1);
875 #ifdef DEVFS
876 set_ds_labeldevs(dname, dev1, ssp);
877 #endif
878 set_ds_wlabel(ssp, slice, FALSE);
879 }
880
881 slice = dkslice(dev);
882 if (slice >= ssp->dss_nslices)
883 return (ENXIO);
884 sp = &ssp->dss_slices[slice];
885 part = dkpart(dev);
886 if (part != RAW_PART
887 && (sp->ds_label == NULL || part >= sp->ds_label->d_npartitions))
888 return (EINVAL); /* XXX needs translation */
889 mask = 1 << part;
890 switch (mode) {
891 case S_IFBLK:
892 sp->ds_bopenmask |= mask;
893 break;
894 case S_IFCHR:
895 sp->ds_copenmask |= mask;
896 break;
897 }
898 sp->ds_openmask = sp->ds_bopenmask | sp->ds_copenmask;
899 return (0);
900 }
901
902 int
903 dssize(dev, sspp, dopen, dclose)
904 dev_t dev;
905 struct diskslices **sspp;
906 d_open_t dopen;
907 d_close_t dclose;
908 {
909 struct disklabel *lp;
910 int part;
911 int slice;
912 struct diskslices *ssp;
913
914 slice = dkslice(dev);
915 part = dkpart(dev);
916 ssp = *sspp;
917 if (ssp == NULL || slice >= ssp->dss_nslices
918 || !(ssp->dss_slices[slice].ds_bopenmask & (1 << part))) {
919 if (dopen(dev, FREAD, S_IFBLK, (struct proc *)NULL) != 0)
920 return (-1);
921 dclose(dev, FREAD, S_IFBLK, (struct proc *)NULL);
922 ssp = *sspp;
923 }
924 lp = ssp->dss_slices[slice].ds_label;
925 if (lp == NULL)
926 return (-1);
927 return ((int)lp->d_partitions[part].p_size);
928 }
929
930 static void
931 free_ds_label(ssp, slice)
932 struct diskslices *ssp;
933 int slice;
934 {
935 struct disklabel *lp;
936 struct diskslice *sp;
937
938 sp = &ssp->dss_slices[slice];
939 lp = sp->ds_label;
940 if (lp == NULL)
941 return;
942 #ifdef DEVFS
943 free_ds_labeldevs(ssp, slice);
944 if (slice == COMPATIBILITY_SLICE)
945 free_ds_labeldevs(ssp, ssp->dss_first_bsd_slice);
946 else if (slice == ssp->dss_first_bsd_slice)
947 free_ds_labeldevs(ssp, COMPATIBILITY_SLICE);
948 #endif
949 free(lp, M_DEVBUF);
950 set_ds_label(ssp, slice, (struct disklabel *)NULL);
951 }
952
953 #ifdef DEVFS
954 static void
955 free_ds_labeldevs(ssp, slice)
956 struct diskslices *ssp;
957 int slice;
958 {
959 struct disklabel *lp;
960 int part;
961 struct diskslice *sp;
962
963 sp = &ssp->dss_slices[slice];
964 lp = sp->ds_label;
965 if (lp == NULL)
966 return;
967 for (part = 0; part < lp->d_npartitions; part++) {
968 if (sp->ds_bdevs[part] != NULL) {
969 devfs_remove_dev(sp->ds_bdevs[part]);
970 sp->ds_bdevs[part] = NULL;
971 }
972 if (sp->ds_cdevs[part] != NULL) {
973 devfs_remove_dev(sp->ds_cdevs[part]);
974 sp->ds_cdevs[part] = NULL;
975 }
976 }
977 }
978 #endif
979
980 static char *
981 fixlabel(sname, sp, lp, writeflag)
982 char *sname;
983 struct diskslice *sp;
984 struct disklabel *lp;
985 int writeflag;
986 {
987 u_long end;
988 u_long offset;
989 int part;
990 struct partition *pp;
991 u_long start;
992 bool_t warned;
993
994 /* These errors "can't happen" so don't bother reporting details. */
995 if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC)
996 return ("fixlabel: invalid magic");
997 if (dkcksum(lp) != 0)
998 return ("fixlabel: invalid checksum");
999
1000 pp = &lp->d_partitions[RAW_PART];
1001 if (writeflag) {
1002 start = 0;
1003 offset = sp->ds_offset;
1004 } else {
1005 start = sp->ds_offset;
1006 offset = -sp->ds_offset;
1007 }
1008 if (pp->p_offset != start) {
1009 if (sname != NULL) {
1010 printf(
1011 "%s: rejecting BSD label: raw partition offset != slice offset\n",
1012 sname);
1013 slice_info(sname, sp);
1014 partition_info(sname, RAW_PART, pp);
1015 }
1016 return ("fixlabel: raw partition offset != slice offset");
1017 }
1018 if (pp->p_size != sp->ds_size) {
1019 if (sname != NULL) {
1020 printf("%s: raw partition size != slice size\n", sname);
1021 slice_info(sname, sp);
1022 partition_info(sname, RAW_PART, pp);
1023 }
1024 if (pp->p_size > sp->ds_size) {
1025 if (sname == NULL)
1026 return ("fixlabel: raw partition size > slice size");
1027 printf("%s: truncating raw partition\n", sname);
1028 pp->p_size = sp->ds_size;
1029 }
1030 }
1031 end = start + sp->ds_size;
1032 if (start > end)
1033 return ("fixlabel: slice wraps");
1034 if (lp->d_secpercyl <= 0)
1035 return ("fixlabel: d_secpercyl <= 0");
1036 pp -= RAW_PART;
1037 warned = FALSE;
1038 for (part = 0; part < lp->d_npartitions; part++, pp++) {
1039 if (pp->p_offset != 0 || pp->p_size != 0) {
1040 if (pp->p_offset < start
1041 || pp->p_offset + pp->p_size > end
1042 || pp->p_offset + pp->p_size < pp->p_offset) {
1043 if (sname != NULL) {
1044 printf(
1045 "%s: rejecting partition in BSD label: it isn't entirely within the slice\n",
1046 sname);
1047 if (!warned) {
1048 slice_info(sname, sp);
1049 warned = TRUE;
1050 }
1051 partition_info(sname, part, pp);
1052 }
1053 /* XXX else silently discard junk. */
1054 bzero(pp, sizeof *pp);
1055 } else
1056 pp->p_offset += offset;
1057 }
1058 }
1059 lp->d_ncylinders = sp->ds_size / lp->d_secpercyl;
1060 lp->d_secperunit = sp->ds_size;
1061 lp->d_checksum = 0;
1062 lp->d_checksum = dkcksum(lp);
1063 return (NULL);
1064 }
1065
1066 static void
1067 partition_info(sname, part, pp)
1068 char *sname;
1069 int part;
1070 struct partition *pp;
1071 {
1072 printf("%s%c: start %lu, end %lu, size %lu\n", sname, 'a' + part,
1073 (u_long)pp->p_offset, (u_long)(pp->p_offset + pp->p_size - 1),
1074 (u_long)pp->p_size);
1075 }
1076
1077 static void
1078 slice_info(sname, sp)
1079 char *sname;
1080 struct diskslice *sp;
1081 {
1082 printf("%s: start %lu, end %lu, size %lu\n", sname,
1083 sp->ds_offset, sp->ds_offset + sp->ds_size - 1, sp->ds_size);
1084 }
1085
1086 /*
1087 * Most changes to ds_bad, ds_label and ds_wlabel are made using the
1088 * following functions to ensure coherency of the compatibility slice
1089 * with the first BSD slice. The openmask fields are _not_ shared and
1090 * the other fields (ds_offset and ds_size) aren't changed after they
1091 * are initialized.
1092 */
1093 static void
1094 set_ds_bad(ssp, slice, btp)
1095 struct diskslices *ssp;
1096 int slice;
1097 struct dkbad_intern *btp;
1098 {
1099 ssp->dss_slices[slice].ds_bad = btp;
1100 if (slice == COMPATIBILITY_SLICE)
1101 ssp->dss_slices[ssp->dss_first_bsd_slice].ds_bad = btp;
1102 else if (slice == ssp->dss_first_bsd_slice)
1103 ssp->dss_slices[COMPATIBILITY_SLICE].ds_bad = btp;
1104 }
1105
1106 static void
1107 set_ds_label(ssp, slice, lp)
1108 struct diskslices *ssp;
1109 int slice;
1110 struct disklabel *lp;
1111 {
1112 ssp->dss_slices[slice].ds_label = lp;
1113 if (slice == COMPATIBILITY_SLICE)
1114 ssp->dss_slices[ssp->dss_first_bsd_slice].ds_label = lp;
1115 else if (slice == ssp->dss_first_bsd_slice)
1116 ssp->dss_slices[COMPATIBILITY_SLICE].ds_label = lp;
1117 }
1118
1119 #ifdef DEVFS
1120 static void
1121 set_ds_labeldevs(dname, dev, ssp)
1122 char *dname;
1123 dev_t dev;
1124 struct diskslices *ssp;
1125 {
1126 int slice;
1127
1128 set_ds_labeldevs_unaliased(dname, dev, ssp);
1129 if (ssp->dss_first_bsd_slice == COMPATIBILITY_SLICE)
1130 return;
1131 slice = dkslice(dev);
1132 if (slice == COMPATIBILITY_SLICE)
1133 set_ds_labeldevs_unaliased(dname,
1134 dkmodslice(dev, ssp->dss_first_bsd_slice), ssp);
1135 else if (slice == ssp->dss_first_bsd_slice)
1136 set_ds_labeldevs_unaliased(dname,
1137 dkmodslice(dev, COMPATIBILITY_SLICE), ssp);
1138 }
1139
1140 static void
1141 set_ds_labeldevs_unaliased(dname, dev, ssp)
1142 char *dname;
1143 dev_t dev;
1144 struct diskslices *ssp;
1145 {
1146 struct disklabel *lp;
1147 int mynor;
1148 int part;
1149 char partname[2];
1150 struct partition *pp;
1151 int slice;
1152 char *sname;
1153 struct diskslice *sp;
1154
1155 slice = dkslice(dev);
1156 sp = &ssp->dss_slices[slice];
1157 if (sp->ds_size == 0)
1158 return;
1159 lp = sp->ds_label;
1160 for (part = 0; part < lp->d_npartitions; part++) {
1161 pp = &lp->d_partitions[part];
1162 if (pp->p_size == 0)
1163 continue;
1164 sname = dsname(dname, dkunit(dev), slice, part, partname);
1165 if (part == RAW_PART && sp->ds_bdev != NULL) {
1166 sp->ds_bdevs[part] =
1167 devfs_makelink(sp->ds_bdev,
1168 "%s%s", sname, partname);
1169 sp->ds_cdevs[part] =
1170 devfs_makelink(sp->ds_cdev,
1171 "r%s%s", sname, partname);
1172 } else {
1173 mynor = minor(dkmodpart(dev, part));
1174 sp->ds_bdevs[part] =
1175 devfs_add_devswf(ssp->dss_cdevsw, mynor, DV_BLK,
1176 UID_ROOT, GID_OPERATOR, 0640,
1177 "%s%s", sname, partname);
1178 sp->ds_cdevs[part] =
1179 devfs_add_devswf(ssp->dss_cdevsw, mynor, DV_CHR,
1180 UID_ROOT, GID_OPERATOR, 0640,
1181 "r%s%s", sname, partname);
1182 }
1183 }
1184 }
1185 #endif /* DEVFS */
1186
1187 static void
1188 set_ds_wlabel(ssp, slice, wlabel)
1189 struct diskslices *ssp;
1190 int slice;
1191 int wlabel;
1192 {
1193 ssp->dss_slices[slice].ds_wlabel = wlabel;
1194 if (slice == COMPATIBILITY_SLICE)
1195 ssp->dss_slices[ssp->dss_first_bsd_slice].ds_wlabel = wlabel;
1196 else if (slice == ssp->dss_first_bsd_slice)
1197 ssp->dss_slices[COMPATIBILITY_SLICE].ds_wlabel = wlabel;
1198 }
Cache object: 43e426421406aaa9246a1cc603b47671
|