Move all the code related to handling the current 32 bit disklabel
[dragonfly.git] / sys / kern / subr_diskslice.c
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.46 2007/06/18 05:13:42 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/disklabel32.h>
56 #include <sys/diskslice.h>
57 #include <sys/disk.h>
58 #include <sys/diskmbr.h>
59 #include <sys/fcntl.h>
60 #include <sys/malloc.h>
61 #include <sys/stat.h>
62 #include <sys/syslog.h>
63 #include <sys/proc.h>
64 #include <sys/vnode.h>
65 #include <sys/device.h>
66 #include <sys/thread2.h>
67
68 #include <vfs/ufs/dinode.h>     /* XXX used only for fs.h */
69 #include <vfs/ufs/fs.h>         /* XXX used only to get BBSIZE/SBSIZE */
70
71 static int  dsreadandsetlabel(cdev_t dev, u_int flags,
72                            struct diskslices *ssp, struct diskslice *sp,
73                            struct disk_info *info);
74 static void free_ds_label (struct diskslices *ssp, int slice);
75 static void set_ds_label (struct diskslices *ssp, int slice, disklabel_t lp);
76 static void set_ds_wlabel (struct diskslices *ssp, int slice, int wlabel);
77
78 #define ops     (&disklabel32_ops)
79
80 /*
81  * Determine the size of the transfer, and make sure it is
82  * within the boundaries of the partition. Adjust transfer
83  * if needed, and signal errors or early completion.
84  *
85  * XXX TODO:
86  *      o Split buffers that are too big for the device.
87  *      o Check for overflow.
88  *      o Finish cleaning this up.
89  *
90  * This function returns 1 on success, 0 if transfer equates
91  * to EOF (end of disk) or -1 on failure.  The appropriate 
92  * 'errno' value is also set in bp->b_error and bp->b_flags
93  * is marked with B_ERROR.
94  */
95 struct bio *
96 dscheck(cdev_t dev, struct bio *bio, struct diskslices *ssp)
97 {
98         struct buf *bp = bio->bio_buf;
99         struct bio *nbio;
100         disklabel_t lp;
101         long nsec;
102         u_int64_t secno;
103         u_int64_t endsecno;
104         u_int64_t slicerel_secno;
105         struct diskslice *sp;
106         u_int32_t part;
107         u_int32_t slice;
108         int shift;
109         int mask;
110
111         slice = dkslice(dev);
112         part  = dkpart(dev);
113
114         if (bio->bio_offset < 0) {
115                 kprintf("dscheck(%s): negative bio_offset %lld\n", 
116                         devtoname(dev), bio->bio_offset);
117                 goto bad;
118         }
119         if (slice >= ssp->dss_nslices) {
120                 kprintf("dscheck(%s): slice too large %d/%d\n",
121                         devtoname(dev), slice, ssp->dss_nslices);
122                 goto bad;
123         }
124         sp = &ssp->dss_slices[slice];
125
126         /*
127          * Calculate secno and nsec
128          */
129         if (ssp->dss_secmult == 1) {
130                 shift = DEV_BSHIFT;
131                 goto doshift;
132         } else if (ssp->dss_secshift != -1) {
133                 shift = DEV_BSHIFT + ssp->dss_secshift;
134 doshift:
135                 mask = (1 << shift) - 1;
136                 if ((int)bp->b_bcount & mask)
137                         goto bad_bcount;
138                 if ((int)bio->bio_offset & mask)
139                         goto bad_blkno;
140                 secno = bio->bio_offset >> shift;
141                 nsec = bp->b_bcount >> shift;
142         } else {
143                 if (bp->b_bcount % ssp->dss_secsize)
144                         goto bad_bcount;
145                 if (bio->bio_offset % ssp->dss_secsize)
146                         goto bad_blkno;
147                 secno = bio->bio_offset / ssp->dss_secsize;
148                 nsec = bp->b_bcount / ssp->dss_secsize;
149         }
150
151         /*
152          * Calculate slice-relative sector number end slice-relative
153          * limit.
154          */
155         if (slice == WHOLE_DISK_SLICE) {
156                 /*
157                  * Labels have not been allowed on whole-disks for a while.
158                  * This really puts the nail in the coffin.
159                  *
160                  * Accesses to the WHOLE_DISK_SLICE do not use a disklabel
161                  * and partition numbers are special-cased.  Currently numbers
162                  * less then 128 are not allowed.  Partition numbers >= 128
163                  * are encoded in the high 8 bits of the 64 bit buffer offset
164                  * and are fed directly through to the device with no
165                  * further interpretation.  In particular, no sector
166                  * translation interpretation should occur because the
167                  * sector size for the special raw access may not be the
168                  * same as the nominal sector size for the device.
169                  */
170                 lp.opaque = NULL;
171                 if (part < 128) {
172                         kprintf("dscheck(%s): illegal partition number (%d) "
173                                 "for WHOLE_DISK_SLICE access\n",
174                                 devtoname(dev), part);
175                         goto bad;
176                 } else if (part != WHOLE_SLICE_PART) {
177                         nbio = push_bio(bio);
178                         nbio->bio_offset = bio->bio_offset |
179                                            (u_int64_t)part << 56;
180                         return(nbio);
181                 }
182
183                 /*
184                  * sp->ds_size is for the whole disk in the WHOLE_DISK_SLICE,
185                  * there are no reserved areas.
186                  */
187                 endsecno = sp->ds_size;
188                 slicerel_secno = secno;
189         } else if (part == WHOLE_SLICE_PART) {
190                 /* 
191                  * NOTE! opens on a whole-slice partition will not attempt
192                  * to read a disklabel in, so there may not be an in-core
193                  * disklabel even if there is one on the disk.
194                  */
195                 endsecno = sp->ds_size;
196                 slicerel_secno = secno;
197         } else if ((lp = sp->ds_label).opaque != NULL) {
198                 /*
199                  * A label is present, extract the partition.  Snooping of
200                  * the disklabel is not supported even if accessible.  Of
201                  * course, the reserved area is still write protected.
202                  */
203                 if (ops->op_getpartbounds(lp, part, &slicerel_secno, &endsecno)) {
204                         kprintf("dscheck(%s): partition %d out of bounds\n",
205                                 devtoname(dev), part);
206                         goto bad;
207                 }
208                 slicerel_secno += secno;
209         } else {
210                 /*
211                  * Attempt to access partition when no disklabel present
212                  */
213                 kprintf("dscheck(%s): attempt to access non-existant partition\n",
214                         devtoname(dev));
215                 goto bad;
216         }
217
218         /*
219          * Disallow writes to reserved areas unless ds_wlabel allows it.
220          */
221         if (slicerel_secno < sp->ds_reserved && nsec &&
222             bp->b_cmd != BUF_CMD_READ && sp->ds_wlabel == 0) {
223                 bp->b_error = EROFS;
224                 goto error;
225         }
226
227         /*
228          * If we get here, bio_offset must be on a block boundary and
229          * the sector size must be a power of 2.
230          */
231         if ((bio->bio_offset & (ssp->dss_secsize - 1)) ||
232             (ssp->dss_secsize ^ (ssp->dss_secsize - 1)) !=
233             ((ssp->dss_secsize << 1) - 1)) {
234                 kprintf("%s: invalid BIO offset, not sector aligned or"
235                         " invalid sector size (not power of 2) %08llx %d\n",
236                         devtoname(dev), bio->bio_offset, ssp->dss_secsize);
237                 goto bad;
238         }
239
240         /*
241          * EOF handling
242          */
243         if (secno + nsec > endsecno) {
244                 /*
245                  * Return an error if beyond the end of the disk, or
246                  * if B_BNOCLIP is set.  Tell the system that we do not
247                  * need to keep the buffer around.
248                  */
249                 if (secno > endsecno || (bp->b_flags & B_BNOCLIP))
250                         goto bad;
251
252                 /*
253                  * If exactly at end of disk, return an EOF.  Throw away
254                  * the buffer contents, if any, by setting B_INVAL.
255                  */
256                 if (secno == endsecno) {
257                         bp->b_resid = bp->b_bcount;
258                         bp->b_flags |= B_INVAL;
259                         goto done;
260                 }
261
262                 /*
263                  * Else truncate
264                  */
265                 nsec = endsecno - secno;
266                 bp->b_bcount = nsec * ssp->dss_secsize;
267         }
268
269         nbio = push_bio(bio);
270         nbio->bio_offset = (off_t)(sp->ds_offset + slicerel_secno) * 
271                            ssp->dss_secsize;
272         return (nbio);
273
274 bad_bcount:
275         kprintf(
276         "dscheck(%s): b_bcount %d is not on a sector boundary (ssize %d)\n",
277             devtoname(dev), bp->b_bcount, ssp->dss_secsize);
278         goto bad;
279
280 bad_blkno:
281         kprintf(
282         "dscheck(%s): bio_offset %lld is not on a sector boundary (ssize %d)\n",
283             devtoname(dev), bio->bio_offset, ssp->dss_secsize);
284 bad:
285         bp->b_error = EINVAL;
286         /* fall through */
287 error:
288         /*
289          * Terminate the I/O with a ranging error.  Since the buffer is
290          * either illegal or beyond the file EOF, mark it B_INVAL as well.
291          */
292         bp->b_resid = bp->b_bcount;
293         bp->b_flags |= B_ERROR | B_INVAL;
294 done:
295         /*
296          * Caller must biodone() the originally passed bio if NULL is
297          * returned.
298          */
299         return (NULL);
300 }
301
302 void
303 dsclose(cdev_t dev, int mode, struct diskslices *ssp)
304 {
305         u_int32_t part;
306         u_int32_t slice;
307         struct diskslice *sp;
308
309         slice = dkslice(dev);
310         part  = dkpart(dev);
311         if (slice < ssp->dss_nslices) {
312                 sp = &ssp->dss_slices[slice];
313                 dsclrmask(sp, part);
314         }
315 }
316
317 void
318 dsgone(struct diskslices **sspp)
319 {
320         int slice;
321         struct diskslice *sp;
322         struct diskslices *ssp;
323
324         for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) {
325                 sp = &ssp->dss_slices[slice];
326                 free_ds_label(ssp, slice);
327         }
328         kfree(ssp, M_DEVBUF);
329         *sspp = NULL;
330 }
331
332 /*
333  * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this
334  * is subject to the same restriction as dsopen().
335  */
336 int
337 dsioctl(cdev_t dev, u_long cmd, caddr_t data, int flags,
338         struct diskslices **sspp, struct disk_info *info)
339 {
340         int error;
341         disklabel_t lp;
342         disklabel_t lptmp;
343         int old_wlabel;
344         u_int32_t openmask[DKMAXPARTITIONS/(sizeof(u_int32_t)*8)];
345         int part;
346         int slice;
347         struct diskslice *sp;
348         struct diskslices *ssp;
349
350         slice = dkslice(dev);
351         part = dkpart(dev);
352         ssp = *sspp;
353         if (slice >= ssp->dss_nslices)
354                 return (EINVAL);
355         sp = &ssp->dss_slices[slice];
356         lp = sp->ds_label;
357
358         switch (cmd) {
359         case DIOCGDVIRGIN32:
360                 /*
361                  * You can only retrieve a virgin disklabel on the whole
362                  * disk slice or whole-slice partition.
363                  */
364                 if (slice != WHOLE_DISK_SLICE &&
365                     part != WHOLE_SLICE_PART) {
366                         return(EINVAL);
367                 }
368
369                 lp.opaque = data;
370                 ops->op_makevirginlabel(lp, ssp, sp, info);
371                 return (0);
372
373         case DIOCGDINFO32:
374                 /*
375                  * You can only retrieve a disklabel on the whole
376                  * slice partition.
377                  *
378                  * We do not support labels directly on whole-disks
379                  * any more (that is, disks without slices), unless the
380                  * device driver has asked for a compatible label (e.g.
381                  * for a CD) to allow booting off of storage that is
382                  * otherwise unlabeled.
383                  */
384                 error = 0;
385                 if (part != WHOLE_SLICE_PART)
386                         return(EINVAL);
387                 if (slice == WHOLE_DISK_SLICE &&
388                     (info->d_dsflags & DSO_COMPATLABEL) == 0) {
389                         return (ENODEV);
390                 }
391                 if (sp->ds_label.opaque == NULL) {
392                         error = dsreadandsetlabel(dev, info->d_dsflags,
393                                                   ssp, sp, info);
394                 }
395                 if (error == 0)
396                         bcopy(sp->ds_label.opaque, data, ops->labelsize);
397                 return (error);
398
399         case DIOCGPART:
400                 {
401                         struct partinfo *dpart = (void *)data;
402
403                         /*
404                          * The disk management layer may not have read the
405                          * disklabel yet because simply opening a slice no
406                          * longer 'probes' the disk that way.  Be sure we
407                          * have tried.
408                          *
409                          * We ignore any error.
410                          */
411                         if (sp->ds_label.opaque == NULL &&
412                             part == WHOLE_SLICE_PART &&
413                             slice != WHOLE_DISK_SLICE) {
414                                 dsreadandsetlabel(dev, info->d_dsflags,
415                                                   ssp, sp, info);
416                         }
417
418                         bzero(dpart, sizeof(*dpart));
419                         dpart->media_offset   = (u_int64_t)sp->ds_offset *
420                                                 info->d_media_blksize;
421                         dpart->media_size     = (u_int64_t)sp->ds_size *
422                                                 info->d_media_blksize;
423                         dpart->media_blocks   = sp->ds_size;
424                         dpart->media_blksize  = info->d_media_blksize;
425                         dpart->reserved_blocks= sp->ds_reserved;
426
427                         if (slice != WHOLE_DISK_SLICE &&
428                             part != WHOLE_SLICE_PART) {
429                                 u_int64_t start;
430                                 u_int64_t blocks;
431                                 if (lp.opaque == NULL)
432                                         return(EINVAL);
433                                 if (ops->op_getpartbounds(lp, part, &start, &blocks))
434                                         return(EINVAL);
435                                 dpart->fstype = ops->op_getpartfstype(lp, part);
436                                 dpart->media_offset += start *
437                                                        info->d_media_blksize;
438                                 dpart->media_size = blocks *
439                                                     info->d_media_blksize;
440                                 dpart->media_blocks = blocks;
441
442                                 /*
443                                  * partition starting sector (p_offset)
444                                  * requires slice's reserved areas to be
445                                  * adjusted.
446                                  */
447                                 if (dpart->reserved_blocks > start)
448                                         dpart->reserved_blocks -= start;
449                                 else
450                                         dpart->reserved_blocks = 0;
451                         }
452
453                         /*
454                          * Load remaining fields from the info structure
455                          */
456                         dpart->d_nheads =       info->d_nheads;
457                         dpart->d_ncylinders =   info->d_ncylinders;
458                         dpart->d_secpertrack =  info->d_secpertrack;
459                         dpart->d_secpercyl =    info->d_secpercyl;
460                 }
461                 return (0);
462
463         case DIOCGSLICEINFO:
464                 bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] -
465                                  (char *)ssp);
466                 return (0);
467
468         case DIOCSDINFO32:
469                 /*
470                  * You can write a disklabel on the whole disk slice or
471                  * whole-slice partition.
472                  */
473                 if (slice != WHOLE_DISK_SLICE &&
474                     part != WHOLE_SLICE_PART) {
475                         return(EINVAL);
476                 }
477
478                 /*
479                  * We no longer support writing disklabels directly to media
480                  * without there being a slice.  Keep this as a separate
481                  * conditional.
482                  */
483                 if (slice == WHOLE_DISK_SLICE)
484                         return (ENODEV);
485
486                 if (!(flags & FWRITE))
487                         return (EBADF);
488                 lp.opaque = kmalloc(ops->labelsize, M_DEVBUF, M_WAITOK);
489                 if (sp->ds_label.opaque == NULL)
490                         bzero(lp.opaque, ops->labelsize);
491                 else
492                         bcopy(sp->ds_label.opaque, lp.opaque, ops->labelsize);
493                 if (sp->ds_label.opaque == NULL) {
494                         bzero(openmask, sizeof(openmask));
495                 } else {
496                         bcopy(sp->ds_openmask, openmask, sizeof(openmask));
497                 }
498                 lptmp.opaque = data;
499                 error = ops->op_setdisklabel(lp, lptmp, sp, openmask);
500                 if (error != 0) {
501                         kfree(lp.opaque, M_DEVBUF);
502                         return (error);
503                 }
504                 free_ds_label(ssp, slice);
505                 set_ds_label(ssp, slice, lp);
506                 return (0);
507
508         case DIOCSYNCSLICEINFO:
509                 /*
510                  * This ioctl can only be done on the whole disk
511                  */
512                 if (slice != WHOLE_DISK_SLICE || part != WHOLE_SLICE_PART)
513                         return (EINVAL);
514
515                 if (*(int *)data == 0) {
516                         for (slice = 0; slice < ssp->dss_nslices; slice++) {
517                                 struct diskslice *ds = &ssp->dss_slices[slice];
518
519                                 switch(dscountmask(ds)) {
520                                 case 0:
521                                         break;
522                                 case 1:
523                                         if (slice != WHOLE_DISK_SLICE)
524                                                 return (EBUSY);
525                                         if (!dschkmask(ds, RAW_PART))
526                                                 return (EBUSY);
527                                         break;
528                                 default:
529                                         return (EBUSY);
530                                 }
531                         }
532                 }
533
534                 /*
535                  * Temporarily forget the current slices struct and read
536                  * the current one.
537                  *
538                  * NOTE:
539                  *
540                  * XXX should wait for current accesses on this disk to
541                  * complete, then lock out future accesses and opens.
542                  */
543                 *sspp = NULL;
544                 error = dsopen(dev, S_IFCHR, ssp->dss_oflags, sspp, info);
545                 if (error != 0) {
546                         *sspp = ssp;
547                         return (error);
548                 }
549
550                 /*
551                  * Reopen everything.  This is a no-op except in the "force"
552                  * case and when the raw bdev and cdev are both open.  Abort
553                  * if anything fails.
554                  */
555                 for (slice = 0; slice < ssp->dss_nslices; slice++) {
556                         for (part = 0; part < DKMAXPARTITIONS; ++part) {
557                                 if (!dschkmask(&ssp->dss_slices[slice], part))
558                                         continue;
559                                 error = dsopen(dkmodslice(dkmodpart(dev, part),
560                                                           slice),
561                                                S_IFCHR, ssp->dss_oflags, sspp,
562                                                info);
563                                 if (error != 0) {
564                                         *sspp = ssp;
565                                         return (EBUSY);
566                                 }
567                         }
568                 }
569
570                 dsgone(&ssp);
571                 return (0);
572
573         case DIOCWDINFO32:
574                 error = dsioctl(dev, DIOCSDINFO32, data, flags, &ssp, info);
575                 if (error != 0)
576                         return (error);
577
578                 /*
579                  * Set the reserved area
580                  */
581                 old_wlabel = sp->ds_wlabel;
582                 set_ds_wlabel(ssp, slice, TRUE);
583                 error = ops->op_writedisklabel(dev, sp, sp->ds_label);
584                 set_ds_wlabel(ssp, slice, old_wlabel);
585                 /* XXX should invalidate in-core label if write failed. */
586                 return (error);
587
588         case DIOCWLABEL:
589                 if (slice == WHOLE_DISK_SLICE)
590                         return (ENODEV);
591                 if (!(flags & FWRITE))
592                         return (EBADF);
593                 set_ds_wlabel(ssp, slice, *(int *)data != 0);
594                 return (0);
595
596         default:
597                 return (ENOIOCTL);
598         }
599 }
600
601 int
602 dsisopen(struct diskslices *ssp)
603 {
604         int slice;
605
606         if (ssp == NULL)
607                 return (0);
608         for (slice = 0; slice < ssp->dss_nslices; slice++) {
609                 if (dscountmask(&ssp->dss_slices[slice]))
610                         return (1);
611         }
612         return (0);
613 }
614
615 /*
616  * Allocate a slices "struct" and initialize it to contain only an empty
617  * compatibility slice (pointing to itself), a whole disk slice (covering
618  * the disk as described by the label), and (nslices - BASE_SLICES) empty
619  * slices beginning at BASE_SLICE.
620  *
621  * Note that the compatibility slice is no longer really a compatibility
622  * slice.  It is slice 0 if a GPT label is present, and the dangerously
623  * dedicated slice if no slice table otherwise exists.  Else it is 0-sized.
624  */
625 struct diskslices *
626 dsmakeslicestruct(int nslices, struct disk_info *info)
627 {
628         struct diskslice *sp;
629         struct diskslices *ssp;
630
631         ssp = kmalloc(offsetof(struct diskslices, dss_slices) +
632                      nslices * sizeof *sp, M_DEVBUF, M_WAITOK);
633         ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE;
634         ssp->dss_nslices = nslices;
635         ssp->dss_oflags = 0;
636
637         /*
638          * Figure out if we can use shifts or whether we have to
639          * use mod/multply to translate byte offsets into sector numbers.
640          */
641         if ((info->d_media_blksize ^ (info->d_media_blksize - 1)) ==
642              (info->d_media_blksize << 1) - 1) {
643                 ssp->dss_secmult = info->d_media_blksize / DEV_BSIZE;
644                 if (ssp->dss_secmult & (ssp->dss_secmult - 1))
645                         ssp->dss_secshift = -1;
646                 else
647                         ssp->dss_secshift = ffs(ssp->dss_secmult) - 1;
648         } else {
649                 ssp->dss_secmult = 0;
650                 ssp->dss_secshift = -1;
651         }
652         ssp->dss_secsize = info->d_media_blksize;
653         sp = &ssp->dss_slices[0];
654         bzero(sp, nslices * sizeof *sp);
655         sp[WHOLE_DISK_SLICE].ds_size = info->d_media_blocks;
656         return (ssp);
657 }
658
659 char *
660 dsname(cdev_t dev, int unit, int slice, int part, char *partname)
661 {
662         static char name[32];
663         const char *dname;
664         int used;
665
666         dname = dev_dname(dev);
667         if (strlen(dname) > 16)
668                 dname = "nametoolong";
669         ksnprintf(name, sizeof(name), "%s%d", dname, unit);
670         partname[0] = '\0';
671         used = strlen(name);
672
673         if (slice != WHOLE_DISK_SLICE) {
674                 /*
675                  * slice or slice + partition.  BASE_SLICE is s1, but
676                  * the compatibility slice (0) needs to be s0.
677                  */
678                 used += ksnprintf(name + used, sizeof(name) - used,
679                                   "s%d", (slice ? slice - BASE_SLICE + 1 : 0));
680                 if (part != WHOLE_SLICE_PART) {
681                         used += ksnprintf(name + used, sizeof(name) - used,
682                                           "%c", 'a' + part);
683                         partname[0] = 'a' + part;
684                         partname[1] = 0;
685                 }
686         } else if (part == WHOLE_SLICE_PART) {
687                 /*
688                  * whole-disk-device, raw access to disk
689                  */
690                 /* no string extension */
691         } else if (part > 128) {
692                 /*
693                  * whole-disk-device, extended raw access partitions.
694                  * (typically used to access CD audio tracks)
695                  */
696                 used += ksnprintf(name + used, sizeof(name) - used,
697                                           "t%d", part - 128);
698         } else {
699                 /*
700                  * whole-disk-device, illegal partition number
701                  */
702                 used += ksnprintf(name + used, sizeof(name) - used,
703                                           "?%d", part);
704         }
705         return (name);
706 }
707
708 /*
709  * This should only be called when the unit is inactive and the strategy
710  * routine should not allow it to become active unless we call it.  Our
711  * strategy routine must be special to allow activity.
712  */
713 int
714 dsopen(cdev_t dev, int mode, u_int flags, 
715         struct diskslices **sspp, struct disk_info *info)
716 {
717         cdev_t dev1;
718         int error;
719         int need_init;
720         struct diskslice *sp;
721         struct diskslices *ssp;
722         int slice;
723         int part;
724
725         dev->si_bsize_phys = info->d_media_blksize;
726
727         /*
728          * Do not attempt to read the slice table or disk label when
729          * accessing the whole-disk slice or a while-slice partition.
730          */
731         if (dkslice(dev) == WHOLE_DISK_SLICE)
732                 flags |= DSO_ONESLICE | DSO_NOLABELS;
733         if (dkpart(dev) == WHOLE_SLICE_PART)
734                 flags |= DSO_NOLABELS;
735
736         /*
737          * Reinitialize the slice table unless there is an open device
738          * on the unit.
739          *
740          * It would be nice if we didn't have to do this but when a
741          * user is slicing and partitioning up a disk it is a lot safer
742          * to not take any chances.
743          */
744         ssp = *sspp;
745         need_init = !dsisopen(ssp);
746         if (ssp != NULL && need_init)
747                 dsgone(sspp);
748         if (need_init) {
749                 /*
750                  * Allocate a minimal slices "struct".  This will become
751                  * the final slices "struct" if we don't want real slices
752                  * or if we can't find any real slices.
753                  *
754                  * Then scan the disk
755                  */
756                 *sspp = dsmakeslicestruct(BASE_SLICE, info);
757
758                 if ((flags & DSO_ONESLICE) == 0) {
759                         error = mbrinit(dev, info, sspp);
760                         if (error != 0) {
761                                 dsgone(sspp);
762                                 return (error);
763                         }
764                 }
765                 ssp = *sspp;
766                 ssp->dss_oflags = flags;
767
768                 /*
769                  * If there are no real slices, then make the compatiblity
770                  * slice cover the whole disk.
771                  */
772                 if (ssp->dss_nslices == BASE_SLICE) {
773                         sp = &ssp->dss_slices[COMPATIBILITY_SLICE];
774
775                         sp->ds_size = info->d_media_blocks;
776                         sp->ds_reserved = 0;
777                 }
778
779                 /*
780                  * Set dss_first_bsd_slice to point at the first BSD
781                  * slice, if any.
782                  */
783                 for (slice = BASE_SLICE; slice < ssp->dss_nslices; slice++) {
784                         sp = &ssp->dss_slices[slice];
785                         if (sp->ds_type == DOSPTYP_386BSD /* XXX */) {
786 #if 0
787                                 struct diskslice *csp;
788 #endif
789
790                                 ssp->dss_first_bsd_slice = slice;
791 #if 0
792                                 /*
793                                  * no longer supported, s0 is a real slice
794                                  * for GPT
795                                  */
796                                 csp = &ssp->dss_slices[COMPATIBILITY_SLICE];
797                                 csp->ds_offset = sp->ds_offset;
798                                 csp->ds_size = sp->ds_size;
799                                 csp->ds_type = sp->ds_type;
800                                 csp->ds_reserved = sp->ds_reserved;
801 #endif
802                                 break;
803                         }
804                 }
805
806                 /*
807                  * By definition accesses via the whole-disk device do not
808                  * specify any reserved areas.  The whole disk may be read
809                  * or written by the whole-disk device.
810                  *
811                  * ds_label for a whole-disk device is only used as a
812                  * template.
813                  */
814                 sp = &ssp->dss_slices[WHOLE_DISK_SLICE];
815                 sp->ds_label = ops->op_clone_label(info, NULL);
816                 sp->ds_wlabel = TRUE;
817                 sp->ds_reserved = 0;
818         }
819
820         /*
821          * Load the disklabel for the slice being accessed unless it is
822          * a whole-disk-slice or a whole-slice-partition (as determined
823          * by DSO_NOLABELS).
824          *
825          * We could scan all slices here and try to load up their
826          * disklabels, but that would cause us to access slices that
827          * the user may otherwise not intend us to access, or corrupted
828          * slices, etc.
829          *
830          * XXX if there are no opens on the slice we may want to re-read
831          * the disklabel anyway, even if we have one cached.
832          */
833         slice = dkslice(dev);
834         if (slice >= ssp->dss_nslices)
835                 return (ENXIO);
836         sp = &ssp->dss_slices[slice];
837         part = dkpart(dev);
838
839         if ((flags & DSO_NOLABELS) == 0 && sp->ds_label.opaque == NULL) {
840                 dev1 = dkmodslice(dkmodpart(dev, WHOLE_SLICE_PART), slice);
841
842                 /*
843                  * If opening a raw disk we do not try to
844                  * read the disklabel now.  No interpretation of raw disks
845                  * (e.g. like 'da0') ever occurs.  We will try to read the
846                  * disklabel for a raw slice if asked to via DIOC* ioctls.
847                  *
848                  * Access to the label area is disallowed by default.  Note
849                  * however that accesses via WHOLE_DISK_SLICE, and accesses
850                  * via WHOLE_SLICE_PART for slices without valid disklabels,
851                  * will allow writes and ignore the flag.
852                  */
853                 set_ds_wlabel(ssp, slice, FALSE);
854                 dsreadandsetlabel(dev1, flags, ssp, sp, info);
855         }
856
857         /*
858          * If opening a particular partition the disklabel must exist and
859          * the partition must be present in the label.
860          *
861          * If the partition is the special whole-disk-slice no partition
862          * table need exist.
863          */
864         if (part != WHOLE_SLICE_PART && slice != WHOLE_DISK_SLICE) {
865                 if (sp->ds_label.opaque == NULL ||
866                     part >= ops->op_getnumparts(sp->ds_label)) {
867                         return (EINVAL);
868                 }
869         }
870         dssetmask(sp, part);
871
872         /*
873          * Do not allow special raw-extension partitions to be opened
874          * if the device doesn't support them.  Raw-extension partitions
875          * are typically used to handle CD tracks.
876          */
877         if (slice == WHOLE_DISK_SLICE && part >= 128 &&
878             part != WHOLE_SLICE_PART) {
879                 if ((info->d_dsflags & DSO_RAWEXTENSIONS) == 0)
880                         return (EINVAL);
881         }
882         return (0);
883 }
884
885 /*
886  * Attempt to read the disklabel.  If successful, store it in sp->ds_label.
887  *
888  * If we cannot read the disklabel and DSO_COMPATLABEL is set, we construct
889  * a fake label covering the whole disk.
890  */
891 static
892 int
893 dsreadandsetlabel(cdev_t dev, u_int flags,
894                   struct diskslices *ssp, struct diskslice *sp,
895                   struct disk_info *info)
896 {
897         disklabel_t lp;
898         const char *msg;
899         const char *sname;
900         char partname[2];
901         int slice = dkslice(dev);
902
903         lp.opaque = NULL;
904
905         sname = dsname(dev, dkunit(dev), slice, WHOLE_SLICE_PART, partname);
906         msg = ops->op_readdisklabel(dev, sp, &lp, info);
907
908         if (msg != NULL && (flags & DSO_COMPATLABEL)) {
909                 msg = NULL;
910                 lp = ops->op_clone_label(info, sp);
911         }
912         if (msg != NULL) {
913                 if (sp->ds_type == DOSPTYP_386BSD /* XXX */)
914                         log(LOG_WARNING, "%s: cannot find label (%s)\n",
915                             sname, msg);
916                 if (lp.opaque)
917                         kfree(lp.opaque, M_DEVBUF);
918         } else {
919                 set_ds_label(ssp, slice, lp);
920                 set_ds_wlabel(ssp, slice, FALSE);
921         }
922         return (msg ? EINVAL : 0);
923 }
924
925 int64_t
926 dssize(cdev_t dev, struct diskslices **sspp)
927 {
928         disklabel_t lp;
929         int part;
930         int slice;
931         struct diskslices *ssp;
932         u_int64_t start;
933         u_int64_t blocks;
934
935         slice = dkslice(dev);
936         part = dkpart(dev);
937         ssp = *sspp;
938         if (ssp == NULL || slice >= ssp->dss_nslices
939             || !dschkmask(&ssp->dss_slices[slice], part)) {
940                 if (dev_dopen(dev, FREAD, S_IFCHR, proc0.p_ucred) != 0)
941                         return (-1);
942                 dev_dclose(dev, FREAD, S_IFCHR);
943                 ssp = *sspp;
944         }
945         lp = ssp->dss_slices[slice].ds_label;
946         if (lp.opaque == NULL)
947                 return (-1);
948         if (ops->op_getpartbounds(lp, part, &start, &blocks))
949                 return (-1);
950         return ((int64_t)blocks);
951 }
952
953 static void
954 free_ds_label(struct diskslices *ssp, int slice)
955 {
956         struct diskslice *sp;
957         disklabel_t lp;
958
959         sp = &ssp->dss_slices[slice];
960         lp = sp->ds_label;
961         if (lp.opaque != NULL) {
962                 kfree(lp.opaque, M_DEVBUF);
963                 lp.opaque = NULL;
964                 set_ds_label(ssp, slice, lp);
965         }
966 }
967
968 static void
969 set_ds_label(struct diskslices *ssp, int slice, disklabel_t lp)
970 {
971         struct diskslice *sp = &ssp->dss_slices[slice];
972
973         sp->ds_label = lp;
974         ops->op_adjust_label_reserved(ssp, slice, sp);
975 }
976
977 static void
978 set_ds_wlabel(struct diskslices *ssp, int slice, int wlabel)
979 {
980         ssp->dss_slices[slice].ds_wlabel = wlabel;
981 }
982