kernel - add missing M_ZERO in taskqueue_create()
[dragonfly.git] / sys / kern / subr_diskslice.c
blob0031cf3e89cdf31bf1786ca1abacc865eb811669
1 /*-
2 * Copyright (c) 1994 Bruce D. Evans.
3 * All rights reserved.
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * William Jolitz.
11 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
12 * All rights reserved.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
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.
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.
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.51 2008/08/29 20:08:36 dillon Exp $
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/disklabel64.h>
57 #include <sys/diskslice.h>
58 #include <sys/disk.h>
59 #include <sys/diskmbr.h>
60 #include <sys/fcntl.h>
61 #include <sys/malloc.h>
62 #include <sys/stat.h>
63 #include <sys/syslog.h>
64 #include <sys/proc.h>
65 #include <sys/vnode.h>
66 #include <sys/device.h>
67 #include <sys/thread2.h>
69 #include <vfs/ufs/dinode.h> /* XXX used only for fs.h */
70 #include <vfs/ufs/fs.h> /* XXX used only to get BBSIZE/SBSIZE */
71 #include <sys/devfs.h>
73 static int dsreadandsetlabel(cdev_t dev, u_int flags,
74 struct diskslices *ssp, struct diskslice *sp,
75 struct disk_info *info);
76 static void free_ds_label (struct diskslices *ssp, int slice);
77 static void set_ds_label (struct diskslices *ssp, int slice, disklabel_t lp,
78 disklabel_ops_t ops);
79 static void set_ds_wlabel (struct diskslices *ssp, int slice, int wlabel);
82 * Determine the size of the transfer, and make sure it is
83 * within the boundaries of the partition. Adjust transfer
84 * if needed, and signal errors or early completion.
86 * XXX TODO:
87 * o Split buffers that are too big for the device.
88 * o Check for overflow.
89 * o Finish cleaning this up.
91 * This function returns 1 on success, 0 if transfer equates
92 * to EOF (end of disk) or -1 on failure. The appropriate
93 * 'errno' value is also set in bp->b_error and bp->b_flags
94 * is marked with B_ERROR.
96 struct bio *
97 dscheck(cdev_t dev, struct bio *bio, struct diskslices *ssp)
99 struct buf *bp = bio->bio_buf;
100 struct bio *nbio;
101 disklabel_t lp;
102 disklabel_ops_t ops;
103 long nsec;
104 u_int64_t secno;
105 u_int64_t endsecno;
106 u_int64_t slicerel_secno;
107 struct diskslice *sp;
108 u_int32_t part;
109 u_int32_t slice;
110 int shift;
111 int mask;
113 slice = dkslice(dev);
114 part = dkpart(dev);
116 if (bio->bio_offset < 0) {
117 kprintf("dscheck(%s): negative bio_offset %lld\n",
118 devtoname(dev), (long long)bio->bio_offset);
119 goto bad;
121 if (slice >= ssp->dss_nslices) {
122 kprintf("dscheck(%s): slice too large %d/%d\n",
123 devtoname(dev), slice, ssp->dss_nslices);
124 goto bad;
126 sp = &ssp->dss_slices[slice];
128 * Calculate secno and nsec
130 if (ssp->dss_secmult == 1) {
131 shift = DEV_BSHIFT;
132 goto doshift;
133 } else if (ssp->dss_secshift != -1) {
134 shift = DEV_BSHIFT + ssp->dss_secshift;
135 doshift:
136 mask = (1 << shift) - 1;
137 if ((int)bp->b_bcount & mask)
138 goto bad_bcount;
139 if ((int)bio->bio_offset & mask)
140 goto bad_blkno;
141 secno = bio->bio_offset >> shift;
142 nsec = bp->b_bcount >> shift;
143 } else {
144 if (bp->b_bcount % ssp->dss_secsize)
145 goto bad_bcount;
146 if (bio->bio_offset % ssp->dss_secsize)
147 goto bad_blkno;
148 secno = bio->bio_offset / ssp->dss_secsize;
149 nsec = bp->b_bcount / ssp->dss_secsize;
153 * Calculate slice-relative sector number end slice-relative
154 * limit.
156 if (slice == WHOLE_DISK_SLICE) {
158 * Labels have not been allowed on whole-disks for a while.
159 * This really puts the nail in the coffin.
161 * Accesses to the WHOLE_DISK_SLICE do not use a disklabel
162 * and partition numbers are special-cased. Currently numbers
163 * less then 128 are not allowed. Partition numbers >= 128
164 * are encoded in the high 8 bits of the 64 bit buffer offset
165 * and are fed directly through to the device with no
166 * further interpretation. In particular, no sector
167 * translation interpretation should occur because the
168 * sector size for the special raw access may not be the
169 * same as the nominal sector size for the device.
171 lp.opaque = NULL;
172 if (part < 128) {
173 kprintf("dscheck(%s): illegal partition number (%d) "
174 "for WHOLE_DISK_SLICE access\n",
175 devtoname(dev), part);
176 goto bad;
177 } else if (part != WHOLE_SLICE_PART) {
178 nbio = push_bio(bio);
179 nbio->bio_offset = bio->bio_offset |
180 (u_int64_t)part << 56;
181 return(nbio);
182 } else {
184 * If writing to the raw disk request a
185 * reprobe on the last close.
187 if (bp->b_cmd == BUF_CMD_WRITE)
188 sp->ds_flags |= DSF_REPROBE;
192 * sp->ds_size is for the whole disk in the WHOLE_DISK_SLICE,
193 * there are no reserved areas.
195 endsecno = sp->ds_size;
196 slicerel_secno = secno;
197 } else if (part == WHOLE_SLICE_PART) {
199 * NOTE! opens on a whole-slice partition will not attempt
200 * to read a disklabel in, so there may not be an in-core
201 * disklabel even if there is one on the disk.
203 endsecno = sp->ds_size;
204 slicerel_secno = secno;
205 } else if ((lp = sp->ds_label).opaque != NULL) {
207 * A label is present, extract the partition. Snooping of
208 * the disklabel is not supported even if accessible. Of
209 * course, the reserved area is still write protected.
211 ops = sp->ds_ops;
212 if (ops->op_getpartbounds(ssp, lp, part,
213 &slicerel_secno, &endsecno)) {
214 kprintf("dscheck(%s): partition %d out of bounds\n",
215 devtoname(dev), part);
216 goto bad;
218 slicerel_secno += secno;
219 } else {
221 * Attempt to access partition when no disklabel present
223 kprintf("dscheck(%s): attempt to access non-existent partition\n",
224 devtoname(dev));
225 goto bad;
229 * Disallow writes to reserved areas unless ds_wlabel allows it.
230 * If the reserved area is written to request a reprobe of the
231 * disklabel when the slice is closed.
233 if (slicerel_secno < sp->ds_reserved && nsec &&
234 bp->b_cmd == BUF_CMD_WRITE) {
235 if (sp->ds_wlabel == 0) {
236 bp->b_error = EROFS;
237 goto error;
239 sp->ds_flags |= DSF_REPROBE;
243 * If we get here, bio_offset must be on a block boundary and
244 * the sector size must be a power of 2.
246 if ((bio->bio_offset & (ssp->dss_secsize - 1)) ||
247 (ssp->dss_secsize ^ (ssp->dss_secsize - 1)) !=
248 ((ssp->dss_secsize << 1) - 1)) {
249 kprintf("%s: invalid BIO offset, not sector aligned or"
250 " invalid sector size (not power of 2) %08llx %d\n",
251 devtoname(dev), (long long)bio->bio_offset,
252 ssp->dss_secsize);
253 goto bad;
257 * EOF handling
259 if (secno + nsec > endsecno) {
261 * Return an error if beyond the end of the disk, or
262 * if B_BNOCLIP is set. Tell the system that we do not
263 * need to keep the buffer around.
265 if (secno > endsecno || (bp->b_flags & B_BNOCLIP))
266 goto bad;
269 * If exactly at end of disk, return an EOF. Throw away
270 * the buffer contents, if any, by setting B_INVAL.
272 if (secno == endsecno) {
273 bp->b_resid = bp->b_bcount;
274 bp->b_flags |= B_INVAL;
275 goto done;
279 * Else truncate
281 nsec = endsecno - secno;
282 bp->b_bcount = nsec * ssp->dss_secsize;
285 nbio = push_bio(bio);
286 nbio->bio_offset = (off_t)(sp->ds_offset + slicerel_secno) *
287 ssp->dss_secsize;
288 return (nbio);
290 bad_bcount:
291 kprintf(
292 "dscheck(%s): b_bcount %d is not on a sector boundary (ssize %d)\n",
293 devtoname(dev), bp->b_bcount, ssp->dss_secsize);
294 goto bad;
296 bad_blkno:
297 kprintf(
298 "dscheck(%s): bio_offset %lld is not on a sector boundary (ssize %d)\n",
299 devtoname(dev), (long long)bio->bio_offset, ssp->dss_secsize);
300 bad:
301 bp->b_error = EINVAL;
302 /* fall through */
303 error:
305 * Terminate the I/O with a ranging error. Since the buffer is
306 * either illegal or beyond the file EOF, mark it B_INVAL as well.
308 bp->b_resid = bp->b_bcount;
309 bp->b_flags |= B_ERROR | B_INVAL;
310 done:
312 * Caller must biodone() the originally passed bio if NULL is
313 * returned.
315 return (NULL);
319 * dsclose() - close a cooked disk slice.
321 * WARNING! The passed diskslices and related diskslice structures may
322 * be invalidated or replaced by this function, callers must
323 * reload from the disk structure for continued access.
325 void
326 dsclose(cdev_t dev, int mode, struct diskslices *ssp)
328 u_int32_t part;
329 u_int32_t slice;
330 struct diskslice *sp;
332 slice = dkslice(dev);
333 part = dkpart(dev);
334 if (slice < ssp->dss_nslices) {
335 sp = &ssp->dss_slices[slice];
336 dsclrmask(sp, part);
337 if (sp->ds_flags & DSF_REPROBE) {
338 sp->ds_flags &= ~DSF_REPROBE;
339 if (slice == WHOLE_DISK_SLICE) {
340 disk_msg_send_sync(DISK_DISK_REPROBE,
341 dev->si_disk, NULL);
342 devfs_config();
343 } else {
344 disk_msg_send_sync(DISK_SLICE_REPROBE,
345 dev->si_disk, sp);
346 devfs_config();
348 /* ssp and sp may both be invalid after reprobe */
353 void
354 dsgone(struct diskslices **sspp)
356 int slice;
357 struct diskslice *sp;
358 struct diskslices *ssp;
360 kprintf("dsgone is called... fear!\n");
362 for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) {
363 sp = &ssp->dss_slices[slice];
364 free_ds_label(ssp, slice);
366 kfree(ssp, M_DEVBUF);
367 *sspp = NULL;
371 * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this
372 * is subject to the same restriction as dsopen().
375 dsioctl(cdev_t dev, u_long cmd, caddr_t data, int flags,
376 struct diskslices **sspp, struct disk_info *info)
378 int error;
379 disklabel_t lp;
380 disklabel_t lptmp;
381 disklabel_ops_t ops;
382 int old_wlabel;
383 u_int32_t openmask[DKMAXPARTITIONS/(sizeof(u_int32_t)*8)];
384 int part;
385 int slice;
386 struct diskslice *sp;
387 struct diskslices *ssp;
389 slice = dkslice(dev);
390 part = dkpart(dev);
391 ssp = *sspp;
392 if (slice >= ssp->dss_nslices)
393 return (EINVAL);
394 sp = &ssp->dss_slices[slice];
395 lp = sp->ds_label;
396 ops = sp->ds_ops; /* may be NULL if no label */
398 switch (cmd) {
399 case DIOCGDVIRGIN32:
400 ops = &disklabel32_ops;
401 /* fall through */
402 case DIOCGDVIRGIN64:
403 if (cmd != DIOCGDVIRGIN32)
404 ops = &disklabel64_ops;
406 * You can only retrieve a virgin disklabel on the whole
407 * disk slice or whole-slice partition.
409 if (slice != WHOLE_DISK_SLICE &&
410 part != WHOLE_SLICE_PART) {
411 return(EINVAL);
414 lp.opaque = data;
415 ops->op_makevirginlabel(lp, ssp, sp, info);
416 return (0);
418 case DIOCGDINFO32:
419 case DIOCGDINFO64:
421 * You can only retrieve a disklabel on the whole
422 * slice partition.
424 * We do not support labels directly on whole-disks
425 * any more (that is, disks without slices), unless the
426 * device driver has asked for a compatible label (e.g.
427 * for a CD) to allow booting off of storage that is
428 * otherwise unlabeled.
430 error = 0;
431 if (part != WHOLE_SLICE_PART)
432 return(EINVAL);
433 if (slice == WHOLE_DISK_SLICE &&
434 (info->d_dsflags & DSO_COMPATLABEL) == 0) {
435 return (ENODEV);
437 if (sp->ds_label.opaque == NULL) {
438 error = dsreadandsetlabel(dev, info->d_dsflags,
439 ssp, sp, info);
440 ops = sp->ds_ops; /* may be NULL */
444 * The type of label we found must match the type of
445 * label requested.
447 if (error == 0 && IOCPARM_LEN(cmd) != ops->labelsize)
448 error = ENOATTR;
449 if (error == 0)
450 bcopy(sp->ds_label.opaque, data, ops->labelsize);
451 return (error);
453 case DIOCGPART:
455 struct partinfo *dpart = (void *)data;
458 * The disk management layer may not have read the
459 * disklabel yet because simply opening a slice no
460 * longer 'probes' the disk that way. Be sure we
461 * have tried.
463 * We ignore any error.
465 if (sp->ds_label.opaque == NULL &&
466 part == WHOLE_SLICE_PART &&
467 slice != WHOLE_DISK_SLICE) {
468 dsreadandsetlabel(dev, info->d_dsflags,
469 ssp, sp, info);
470 ops = sp->ds_ops; /* may be NULL */
473 bzero(dpart, sizeof(*dpart));
474 dpart->media_offset = (u_int64_t)sp->ds_offset *
475 info->d_media_blksize;
476 dpart->media_size = (u_int64_t)sp->ds_size *
477 info->d_media_blksize;
478 dpart->media_blocks = sp->ds_size;
479 dpart->media_blksize = info->d_media_blksize;
480 dpart->reserved_blocks= sp->ds_reserved;
481 dpart->fstype_uuid = sp->ds_type_uuid;
482 dpart->storage_uuid = sp->ds_stor_uuid;
484 if (slice != WHOLE_DISK_SLICE &&
485 part != WHOLE_SLICE_PART) {
486 u_int64_t start;
487 u_int64_t blocks;
488 if (lp.opaque == NULL)
489 return(EINVAL);
490 if (ops->op_getpartbounds(ssp, lp, part,
491 &start, &blocks)) {
492 return(EINVAL);
494 ops->op_loadpartinfo(lp, part, dpart);
495 dpart->media_offset += start *
496 info->d_media_blksize;
497 dpart->media_size = blocks *
498 info->d_media_blksize;
499 dpart->media_blocks = blocks;
502 * partition starting sector (p_offset)
503 * requires slice's reserved areas to be
504 * adjusted.
506 if (dpart->reserved_blocks > start)
507 dpart->reserved_blocks -= start;
508 else
509 dpart->reserved_blocks = 0;
513 * Load remaining fields from the info structure
515 dpart->d_nheads = info->d_nheads;
516 dpart->d_ncylinders = info->d_ncylinders;
517 dpart->d_secpertrack = info->d_secpertrack;
518 dpart->d_secpercyl = info->d_secpercyl;
520 return (0);
522 case DIOCGSLICEINFO:
523 bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] -
524 (char *)ssp);
525 return (0);
527 case DIOCSDINFO32:
528 ops = &disklabel32_ops;
529 /* fall through */
530 case DIOCSDINFO64:
531 if (cmd != DIOCSDINFO32)
532 ops = &disklabel64_ops;
534 * You can write a disklabel on the whole disk slice or
535 * whole-slice partition.
537 if (slice != WHOLE_DISK_SLICE &&
538 part != WHOLE_SLICE_PART) {
539 return(EINVAL);
543 * We no longer support writing disklabels directly to media
544 * without there being a slice. Keep this as a separate
545 * conditional.
547 if (slice == WHOLE_DISK_SLICE)
548 return (ENODEV);
549 if (!(flags & FWRITE))
550 return (EBADF);
553 * If an existing label is present it must be the same
554 * type as the label being passed by the ioctl.
556 if (sp->ds_label.opaque && sp->ds_ops != ops)
557 return (ENOATTR);
560 * Create a temporary copy of the existing label
561 * (if present) so setdisklabel can compare it against
562 * the new label.
564 lp.opaque = kmalloc(ops->labelsize, M_DEVBUF, M_WAITOK);
565 if (sp->ds_label.opaque == NULL)
566 bzero(lp.opaque, ops->labelsize);
567 else
568 bcopy(sp->ds_label.opaque, lp.opaque, ops->labelsize);
569 if (sp->ds_label.opaque == NULL) {
570 bzero(openmask, sizeof(openmask));
571 } else {
572 bcopy(sp->ds_openmask, openmask, sizeof(openmask));
574 lptmp.opaque = data;
575 error = ops->op_setdisklabel(lp, lptmp, ssp, sp, openmask);
576 disk_msg_send_sync(DISK_SLICE_REPROBE, dev->si_disk, sp);
577 devfs_config();
578 if (error != 0) {
579 kfree(lp.opaque, M_DEVBUF);
580 return (error);
582 free_ds_label(ssp, slice);
583 set_ds_label(ssp, slice, lp, ops);
584 return (0);
586 case DIOCSYNCSLICEINFO:
588 * This ioctl can only be done on the whole disk
590 if (slice != WHOLE_DISK_SLICE || part != WHOLE_SLICE_PART)
591 return (EINVAL);
593 if (*(int *)data == 0) {
594 for (slice = 0; slice < ssp->dss_nslices; slice++) {
595 struct diskslice *ds = &ssp->dss_slices[slice];
597 switch(dscountmask(ds)) {
598 case 0:
599 break;
600 case 1:
601 if (slice != WHOLE_DISK_SLICE)
602 return (EBUSY);
603 if (!dschkmask(ds, RAW_PART))
604 return (EBUSY);
605 break;
606 default:
607 return (EBUSY);
612 disk_msg_send_sync(DISK_DISK_REPROBE, dev->si_disk, NULL);
613 devfs_config();
614 return 0;
616 case DIOCWDINFO32:
617 case DIOCWDINFO64:
618 error = dsioctl(dev, ((cmd == DIOCWDINFO32) ?
619 DIOCSDINFO32 : DIOCSDINFO64),
620 data, flags, &ssp, info);
621 if (error == 0 && sp->ds_label.opaque == NULL)
622 error = EINVAL;
623 if (part != WHOLE_SLICE_PART)
624 error = EINVAL;
625 if (error != 0)
626 return (error);
629 * Allow the reserved area to be written, reload ops
630 * because the DIOCSDINFO op above may have installed
631 * a new label type.
633 ops = sp->ds_ops;
634 old_wlabel = sp->ds_wlabel;
635 set_ds_wlabel(ssp, slice, TRUE);
636 error = ops->op_writedisklabel(dev, ssp, sp, sp->ds_label);
637 disk_msg_send_sync(DISK_SLICE_REPROBE, dev->si_disk, sp);
638 devfs_config();
639 set_ds_wlabel(ssp, slice, old_wlabel);
640 /* XXX should invalidate in-core label if write failed. */
641 return (error);
643 case DIOCWLABEL:
644 if (slice == WHOLE_DISK_SLICE)
645 return (ENODEV);
646 if (!(flags & FWRITE))
647 return (EBADF);
648 set_ds_wlabel(ssp, slice, *(int *)data != 0);
649 return (0);
651 default:
652 return (ENOIOCTL);
657 dsisopen(struct diskslices *ssp)
659 int slice;
661 if (ssp == NULL)
662 return (0);
663 for (slice = 0; slice < ssp->dss_nslices; slice++) {
664 if (dscountmask(&ssp->dss_slices[slice]))
665 return (1);
667 return (0);
671 * Allocate a slices "struct" and initialize it to contain only an empty
672 * compatibility slice (pointing to itself), a whole disk slice (covering
673 * the disk as described by the label), and (nslices - BASE_SLICES) empty
674 * slices beginning at BASE_SLICE.
676 * Note that the compatibility slice is no longer really a compatibility
677 * slice. It is slice 0 if a GPT label is present, and the dangerously
678 * dedicated slice if no slice table otherwise exists. Else it is 0-sized.
680 struct diskslices *
681 dsmakeslicestruct(int nslices, struct disk_info *info)
683 struct diskslice *sp;
684 struct diskslices *ssp;
686 ssp = kmalloc(offsetof(struct diskslices, dss_slices) +
687 nslices * sizeof *sp, M_DEVBUF, M_WAITOK);
688 ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE;
689 ssp->dss_nslices = nslices;
690 ssp->dss_oflags = 0;
693 * Figure out if we can use shifts or whether we have to
694 * use mod/multply to translate byte offsets into sector numbers.
696 if ((info->d_media_blksize ^ (info->d_media_blksize - 1)) ==
697 (info->d_media_blksize << 1) - 1) {
698 ssp->dss_secmult = info->d_media_blksize / DEV_BSIZE;
699 if (ssp->dss_secmult & (ssp->dss_secmult - 1))
700 ssp->dss_secshift = -1;
701 else
702 ssp->dss_secshift = ffs(ssp->dss_secmult) - 1;
703 } else {
704 ssp->dss_secmult = 0;
705 ssp->dss_secshift = -1;
707 ssp->dss_secsize = info->d_media_blksize;
708 sp = &ssp->dss_slices[0];
709 bzero(sp, nslices * sizeof *sp);
710 sp[WHOLE_DISK_SLICE].ds_size = info->d_media_blocks;
711 return (ssp);
714 char *
715 dsname(cdev_t dev, int unit, int slice, int part, char *partname)
717 return dev->si_name;
721 * This should only be called when the unit is inactive and the strategy
722 * routine should not allow it to become active unless we call it. Our
723 * strategy routine must be special to allow activity.
726 dsopen(cdev_t dev, int mode, u_int flags,
727 struct diskslices **sspp, struct disk_info *info)
729 struct diskslice *sp;
730 struct diskslices *ssp;
731 int slice;
732 int part;
734 ssp = *sspp;
735 dev->si_bsize_phys = info->d_media_blksize;
736 slice = dkslice(dev);
737 part = dkpart(dev);
738 sp = &ssp->dss_slices[slice];
739 dssetmask(sp, part);
741 return 0;
745 * Attempt to read the disklabel. If successful, store it in sp->ds_label.
747 * If we cannot read the disklabel and DSO_COMPATLABEL is set, we construct
748 * a fake label covering the whole disk.
750 static
752 dsreadandsetlabel(cdev_t dev, u_int flags,
753 struct diskslices *ssp, struct diskslice *sp,
754 struct disk_info *info)
756 disklabel_t lp;
757 disklabel_ops_t ops;
758 const char *msg;
759 const char *sname;
760 char partname[2];
761 int slice = dkslice(dev);
764 * Probe the disklabel
766 lp.opaque = NULL;
767 sname = dsname(dev, dkunit(dev), slice, WHOLE_SLICE_PART, partname);
768 ops = &disklabel32_ops;
769 msg = ops->op_readdisklabel(dev, sp, &lp, info);
770 if (msg && strcmp(msg, "no disk label") == 0) {
771 ops = &disklabel64_ops;
772 msg = disklabel64_ops.op_readdisklabel(dev, sp, &lp, info);
776 * If we failed and COMPATLABEL is set, create a dummy disklabel.
778 if (msg != NULL && (flags & DSO_COMPATLABEL)) {
779 msg = NULL;
780 if (sp->ds_size >= 0x100000000ULL)
781 ops = &disklabel64_ops;
782 else
783 ops = &disklabel32_ops;
784 lp = ops->op_clone_label(info, sp);
786 if (msg != NULL) {
787 if (sp->ds_type == DOSPTYP_386BSD /* XXX */)
788 log(LOG_WARNING, "%s: cannot find label (%s)\n",
789 sname, msg);
790 if (lp.opaque)
791 kfree(lp.opaque, M_DEVBUF);
792 } else {
793 set_ds_label(ssp, slice, lp, ops);
794 set_ds_wlabel(ssp, slice, FALSE);
796 return (msg ? EINVAL : 0);
799 int64_t
800 dssize(cdev_t dev, struct diskslices **sspp)
802 disklabel_t lp;
803 disklabel_ops_t ops;
804 int part;
805 int slice;
806 struct diskslices *ssp;
807 u_int64_t start;
808 u_int64_t blocks;
810 slice = dkslice(dev);
811 part = dkpart(dev);
812 ssp = *sspp;
813 if (ssp == NULL || slice >= ssp->dss_nslices
814 || !dschkmask(&ssp->dss_slices[slice], part)) {
815 if (dev_dopen(dev, FREAD, S_IFCHR, proc0.p_ucred) != 0)
816 return (-1);
817 dev_dclose(dev, FREAD, S_IFCHR);
818 ssp = *sspp;
820 lp = ssp->dss_slices[slice].ds_label;
821 if (lp.opaque == NULL)
822 return (-1);
823 ops = ssp->dss_slices[slice].ds_ops;
824 if (ops->op_getpartbounds(ssp, lp, part, &start, &blocks))
825 return (-1);
826 return ((int64_t)blocks);
829 static void
830 free_ds_label(struct diskslices *ssp, int slice)
832 struct diskslice *sp;
833 disklabel_t lp;
835 sp = &ssp->dss_slices[slice];
836 lp = sp->ds_label;
837 if (lp.opaque != NULL) {
838 kfree(lp.opaque, M_DEVBUF);
839 lp.opaque = NULL;
840 set_ds_label(ssp, slice, lp, NULL);
844 static void
845 set_ds_label(struct diskslices *ssp, int slice,
846 disklabel_t lp, disklabel_ops_t ops)
848 struct diskslice *sp = &ssp->dss_slices[slice];
850 sp->ds_label = lp;
851 sp->ds_ops = ops;
852 if (lp.opaque && slice != WHOLE_DISK_SLICE)
853 ops->op_adjust_label_reserved(ssp, slice, sp);
854 else
855 sp->ds_reserved = 0;
858 static void
859 set_ds_wlabel(struct diskslices *ssp, int slice, int wlabel)
861 ssp->dss_slices[slice].ds_wlabel = wlabel;