subr_disk.c revision 1.100.18.7 1 /* $NetBSD: subr_disk.c,v 1.100.18.7 2017/12/03 11:38:45 jdolecek Exp $ */
2
3 /*-
4 * Copyright (c) 1996, 1997, 1999, 2000, 2009 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * Copyright (c) 1982, 1986, 1988, 1993
35 * The Regents of the University of California. All rights reserved.
36 * (c) UNIX System Laboratories, Inc.
37 * All or some portions of this file are derived from material licensed
38 * to the University of California by American Telephone and Telegraph
39 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
40 * the permission of UNIX System Laboratories, Inc.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 *
66 * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94
67 */
68
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: subr_disk.c,v 1.100.18.7 2017/12/03 11:38:45 jdolecek Exp $");
71
72 #include <sys/param.h>
73 #include <sys/kernel.h>
74 #include <sys/kmem.h>
75 #include <sys/buf.h>
76 #include <sys/fcntl.h>
77 #include <sys/syslog.h>
78 #include <sys/disklabel.h>
79 #include <sys/conf.h>
80 #include <sys/disk.h>
81 #include <sys/sysctl.h>
82 #include <lib/libkern/libkern.h>
83
84 unsigned int disk_serial;
85
86 /*
87 * Compute checksum for disk label.
88 */
89 u_int
90 dkcksum(struct disklabel *lp)
91 {
92
93 return dkcksum_sized(lp, lp->d_npartitions);
94 }
95
96 u_int
97 dkcksum_sized(struct disklabel *lp, size_t npartitions)
98 {
99 uint16_t *start, *end;
100 uint16_t sum = 0;
101
102 start = (uint16_t *)lp;
103 end = (uint16_t *)&lp->d_partitions[npartitions];
104 while (start < end)
105 sum ^= *start++;
106 return sum;
107 }
108
109 /*
110 * Disk error is the preface to plaintive error messages
111 * about failing disk transfers. It prints messages of the form
112
113 hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d)
114
115 * if the offset of the error in the transfer and a disk label
116 * are both available. blkdone should be -1 if the position of the error
117 * is unknown; the disklabel pointer may be null from drivers that have not
118 * been converted to use them. The message is printed with printf
119 * if pri is LOG_PRINTF, otherwise it uses log at the specified priority.
120 * The message should be completed (with at least a newline) with printf
121 * or addlog, respectively. There is no trailing space.
122 */
123 #ifndef PRIdaddr
124 #define PRIdaddr PRId64
125 #endif
126 void
127 diskerr(const struct buf *bp, const char *dname, const char *what, int pri,
128 int blkdone, const struct disklabel *lp)
129 {
130 int unit = DISKUNIT(bp->b_dev), part = DISKPART(bp->b_dev);
131 void (*pr)(const char *, ...) __printflike(1, 2);
132 char partname = 'a' + part;
133 daddr_t sn;
134
135 if (/*CONSTCOND*/0)
136 /* Compiler will error this is the format is wrong... */
137 printf("%" PRIdaddr, bp->b_blkno);
138
139 if (pri != LOG_PRINTF) {
140 static const char fmt[] = "";
141 log(pri, fmt);
142 pr = addlog;
143 } else
144 pr = printf;
145 (*pr)("%s%d%c: %s %sing fsbn ", dname, unit, partname, what,
146 bp->b_flags & B_READ ? "read" : "writ");
147 sn = bp->b_blkno;
148 if (bp->b_bcount <= DEV_BSIZE)
149 (*pr)("%" PRIdaddr, sn);
150 else {
151 if (blkdone >= 0) {
152 sn += blkdone;
153 (*pr)("%" PRIdaddr " of ", sn);
154 }
155 (*pr)("%" PRIdaddr "-%" PRIdaddr "", bp->b_blkno,
156 bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE);
157 }
158 if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) {
159 sn += lp->d_partitions[part].p_offset;
160 (*pr)(" (%s%d bn %" PRIdaddr "; cn %" PRIdaddr "",
161 dname, unit, sn, sn / lp->d_secpercyl);
162 sn %= lp->d_secpercyl;
163 (*pr)(" tn %" PRIdaddr " sn %" PRIdaddr ")",
164 sn / lp->d_nsectors, sn % lp->d_nsectors);
165 }
166 }
167
168 /*
169 * Searches the iostatlist for the disk corresponding to the
170 * name provided.
171 */
172 struct disk *
173 disk_find(const char *name)
174 {
175 struct io_stats *stat;
176
177 stat = iostat_find(name);
178
179 if ((stat != NULL) && (stat->io_type == IOSTAT_DISK))
180 return stat->io_parent;
181
182 return (NULL);
183 }
184
185 /*
186 * Searches for the disk corresponding to a supplied block device
187 * using major, minor, unit.
188 */
189 struct disk *
190 disk_find_blk(dev_t dev)
191 {
192 devmajor_t major;
193 int unit;
194 char name[16]; /* XXX */
195 const char *swname;
196
197 major = major(dev);
198 unit = DISKUNIT(dev);
199
200 if ((swname = devsw_blk2name(major)) == NULL) {
201 return NULL;
202 }
203
204 if (snprintf(name, sizeof(name), "%s%d",
205 swname, unit) > sizeof(name)) {
206 return NULL;
207 }
208
209 return disk_find(name);
210 }
211
212 int disk_maxphys(const struct disk *const diskp)
213 {
214 struct buf b = { b_bcount: MACHINE_MAXPHYS };
215
216 diskp->dk_driver->d_minphys(&b);
217
218 return b.b_bcount;
219 }
220
221 void
222 disk_init(struct disk *diskp, const char *name, const struct dkdriver *driver)
223 {
224 KASSERT(diskp != NULL);
225 KASSERT(name != NULL);
226 KASSERT(driver != NULL);
227 u_int blocksize = DEV_BSIZE;
228
229 /*
230 * Initialize the wedge-related locks and other fields.
231 */
232 mutex_init(&diskp->dk_rawlock, MUTEX_DEFAULT, IPL_NONE);
233 mutex_init(&diskp->dk_openlock, MUTEX_DEFAULT, IPL_NONE);
234 LIST_INIT(&diskp->dk_wedges);
235 diskp->dk_nwedges = 0;
236 diskp->dk_labelsector = LABELSECTOR;
237 diskp->dk_blkshift = DK_BSIZE2BLKSHIFT(blocksize);
238 diskp->dk_byteshift = DK_BSIZE2BYTESHIFT(blocksize);
239 diskp->dk_name = name;
240 diskp->dk_driver = driver;
241 }
242
243 /*
244 * Attach a disk.
245 */
246 void
247 disk_attach(struct disk *diskp)
248 {
249
250 /*
251 * Allocate and initialize the disklabel structures.
252 */
253 diskp->dk_label = kmem_zalloc(sizeof(struct disklabel), KM_SLEEP);
254 diskp->dk_cpulabel = kmem_zalloc(sizeof(struct cpu_disklabel),
255 KM_SLEEP);
256
257 /*
258 * Set up the stats collection.
259 */
260 diskp->dk_stats = iostat_alloc(IOSTAT_DISK, diskp, diskp->dk_name);
261 }
262
263 int
264 disk_begindetach(struct disk *dk, int (*lastclose)(device_t),
265 device_t self, int flags)
266 {
267 int rc;
268
269 rc = 0;
270 mutex_enter(&dk->dk_openlock);
271 if (dk->dk_openmask == 0)
272 ; /* nothing to do */
273 else if ((flags & DETACH_FORCE) == 0)
274 rc = EBUSY;
275 else if (lastclose != NULL)
276 rc = (*lastclose)(self);
277 mutex_exit(&dk->dk_openlock);
278
279 return rc;
280 }
281
282 /*
283 * Detach a disk.
284 */
285 void
286 disk_detach(struct disk *diskp)
287 {
288
289 /*
290 * Remove from the drivelist.
291 */
292 iostat_free(diskp->dk_stats);
293
294 /*
295 * Release the disk-info dictionary.
296 */
297 if (diskp->dk_info) {
298 prop_object_release(diskp->dk_info);
299 diskp->dk_info = NULL;
300 }
301
302 /*
303 * Free the space used by the disklabel structures.
304 */
305 kmem_free(diskp->dk_label, sizeof(*diskp->dk_label));
306 kmem_free(diskp->dk_cpulabel, sizeof(*diskp->dk_cpulabel));
307 }
308
309 void
310 disk_destroy(struct disk *diskp)
311 {
312
313 mutex_destroy(&diskp->dk_openlock);
314 mutex_destroy(&diskp->dk_rawlock);
315 }
316
317 /*
318 * Mark the disk as having work queued for metrics collection.
319 */
320 void
321 disk_wait(struct disk *diskp)
322 {
323
324 iostat_wait(diskp->dk_stats);
325 }
326
327 /*
328 * Mark the disk as busy for metrics collection.
329 */
330 void
331 disk_busy(struct disk *diskp)
332 {
333
334 iostat_busy(diskp->dk_stats);
335 }
336
337 /*
338 * Finished disk operations, gather metrics.
339 */
340 void
341 disk_unbusy(struct disk *diskp, long bcount, int read)
342 {
343
344 iostat_unbusy(diskp->dk_stats, bcount, read);
345 }
346
347 /*
348 * Return true if disk has an I/O operation in flight.
349 */
350 bool
351 disk_isbusy(struct disk *diskp)
352 {
353
354 return iostat_isbusy(diskp->dk_stats);
355 }
356
357 /*
358 * Bounds checking against the media size, used for the raw partition.
359 * secsize, mediasize and b_blkno must all be the same units.
360 * Possibly this has to be DEV_BSIZE (512).
361 */
362 int
363 bounds_check_with_mediasize(struct buf *bp, int secsize, uint64_t mediasize)
364 {
365 int64_t sz;
366
367 if (bp->b_blkno < 0) {
368 /* Reject negative offsets immediately. */
369 bp->b_error = EINVAL;
370 return 0;
371 }
372
373 sz = howmany((int64_t)bp->b_bcount, secsize);
374
375 /*
376 * bp->b_bcount is a 32-bit value, and we rejected a negative
377 * bp->b_blkno already, so "bp->b_blkno + sz" cannot overflow.
378 */
379
380 if (bp->b_blkno + sz > mediasize) {
381 sz = mediasize - bp->b_blkno;
382 if (sz == 0) {
383 /* If exactly at end of disk, return EOF. */
384 bp->b_resid = bp->b_bcount;
385 return 0;
386 }
387 if (sz < 0) {
388 /* If past end of disk, return EINVAL. */
389 bp->b_error = EINVAL;
390 return 0;
391 }
392 /* Otherwise, truncate request. */
393 bp->b_bcount = sz * secsize;
394 }
395
396 return 1;
397 }
398
399 /*
400 * Determine the size of the transfer, and make sure it is
401 * within the boundaries of the partition. Adjust transfer
402 * if needed, and signal errors or early completion.
403 */
404 int
405 bounds_check_with_label(struct disk *dk, struct buf *bp, int wlabel)
406 {
407 struct disklabel *lp = dk->dk_label;
408 struct partition *p = lp->d_partitions + DISKPART(bp->b_dev);
409 uint64_t p_size, p_offset, labelsector;
410 int64_t sz;
411
412 if (bp->b_blkno < 0) {
413 /* Reject negative offsets immediately. */
414 bp->b_error = EINVAL;
415 return -1;
416 }
417
418 /* Protect against division by zero. XXX: Should never happen?!?! */
419 if (lp->d_secpercyl == 0) {
420 bp->b_error = EINVAL;
421 return -1;
422 }
423
424 p_size = (uint64_t)p->p_size << dk->dk_blkshift;
425 p_offset = (uint64_t)p->p_offset << dk->dk_blkshift;
426 #if RAW_PART == 3
427 labelsector = lp->d_partitions[2].p_offset;
428 #else
429 labelsector = lp->d_partitions[RAW_PART].p_offset;
430 #endif
431 labelsector = (labelsector + dk->dk_labelsector) << dk->dk_blkshift;
432
433 sz = howmany((int64_t)bp->b_bcount, DEV_BSIZE);
434
435 /*
436 * bp->b_bcount is a 32-bit value, and we rejected a negative
437 * bp->b_blkno already, so "bp->b_blkno + sz" cannot overflow.
438 */
439
440 if (bp->b_blkno + sz > p_size) {
441 sz = p_size - bp->b_blkno;
442 if (sz == 0) {
443 /* If exactly at end of disk, return EOF. */
444 bp->b_resid = bp->b_bcount;
445 return 0;
446 }
447 if (sz < 0) {
448 /* If past end of disk, return EINVAL. */
449 bp->b_error = EINVAL;
450 return -1;
451 }
452 /* Otherwise, truncate request. */
453 bp->b_bcount = sz << DEV_BSHIFT;
454 }
455
456 /* Overwriting disk label? */
457 if (bp->b_blkno + p_offset <= labelsector &&
458 bp->b_blkno + p_offset + sz > labelsector &&
459 (bp->b_flags & B_READ) == 0 && !wlabel) {
460 bp->b_error = EROFS;
461 return -1;
462 }
463
464 /* calculate cylinder for disksort to order transfers with */
465 bp->b_cylinder = (bp->b_blkno + p->p_offset) /
466 (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl;
467 return 1;
468 }
469
470 int
471 disk_read_sectors(void (*strat)(struct buf *), const struct disklabel *lp,
472 struct buf *bp, unsigned int sector, int count)
473 {
474 bp->b_blkno = btodb((off_t)sector * lp->d_secsize);
475 bp->b_bcount = count * lp->d_secsize;
476 bp->b_flags = (bp->b_flags & ~B_WRITE) | B_READ;
477 bp->b_oflags &= ~BO_DONE;
478 bp->b_cylinder = sector / lp->d_secpercyl;
479 (*strat)(bp);
480 return biowait(bp);
481 }
482
483 const char *
484 convertdisklabel(struct disklabel *lp, void (*strat)(struct buf *),
485 struct buf *bp, uint32_t secperunit)
486 {
487 struct partition rp, *altp, *p;
488 int geom_ok;
489 const char *str;
490
491 memset(&rp, 0, sizeof(rp));
492 rp.p_size = secperunit;
493 rp.p_fstype = FS_UNUSED;
494
495 /* If we can seek to d_secperunit - 1, believe the disk geometry. */
496 if (secperunit != 0 &&
497 disk_read_sectors(strat, lp, bp, secperunit - 1, 1) == 0)
498 geom_ok = 1;
499 else
500 geom_ok = 0;
501
502 #if 0
503 printf("%s: secperunit (%" PRIu32 ") %s\n", __func__,
504 secperunit, geom_ok ? "ok" : "not ok");
505 #endif
506
507 p = &lp->d_partitions[RAW_PART];
508 if (RAW_PART == 'c' - 'a')
509 altp = &lp->d_partitions['d' - 'a'];
510 else
511 altp = &lp->d_partitions['c' - 'a'];
512
513 if (lp->d_npartitions > RAW_PART && p->p_offset == 0 && p->p_size != 0)
514 return NULL; /* already a raw partition */
515 else if (lp->d_npartitions > MAX('c', 'd') - 'a' &&
516 altp->p_offset == 0 && altp->p_size != 0) {
517 /* alternate partition ('c' or 'd') is suitable for raw slot,
518 * swap with 'd' or 'c'.
519 */
520 rp = *p;
521 *p = *altp;
522 *altp = rp;
523 return NULL;
524 } else if (lp->d_npartitions <= RAW_PART &&
525 lp->d_npartitions > 'c' - 'a') {
526 /* No raw partition is present, but the alternate is present.
527 * Copy alternate to raw partition.
528 */
529 lp->d_npartitions = RAW_PART + 1;
530 *p = *altp;
531 return NULL;
532 } else if (!geom_ok)
533 str = "no raw partition and disk reports bad geometry";
534 else if (lp->d_npartitions <= RAW_PART) {
535 memset(&lp->d_partitions[lp->d_npartitions], 0,
536 sizeof(struct partition) * (RAW_PART - lp->d_npartitions));
537 *p = rp;
538 lp->d_npartitions = RAW_PART + 1;
539 return NULL;
540 } else if (lp->d_npartitions < MAXPARTITIONS) {
541 memmove(p + 1, p,
542 sizeof(struct partition) * (lp->d_npartitions - RAW_PART));
543 *p = rp;
544 lp->d_npartitions++;
545 return NULL;
546 } else
547 str = "no raw partition and partition table is full";
548 #ifdef DIAGNOSTIC
549 printf("Bad partition: %s\n", str);
550 printf("type = %u, subtype = %u, typename = %s\n",
551 lp->d_type, lp->d_subtype, lp->d_typename);
552 printf("secsize = %u, nsectors = %u, ntracks = %u\n",
553 lp->d_secsize, lp->d_nsectors, lp->d_ntracks);
554 printf("ncylinders = %u, secpercyl = %u, secperunit = %u\n",
555 lp->d_ncylinders, lp->d_secpercyl, lp->d_secperunit);
556 printf("npartitions = %u\n", lp->d_npartitions);
557
558 for (size_t i = 0; i < MIN(lp->d_npartitions, MAXPARTITIONS); i++) {
559 p = &lp->d_partitions[i];
560 printf("\t%c: offset = %u size = %u fstype = %u\n",
561 (char)(i + 'a'), p->p_offset, p->p_size, p->p_fstype);
562 }
563 #endif
564 return str;
565 }
566
567 /*
568 * disk_ioctl --
569 * Generic disk ioctl handling.
570 */
571 int
572 disk_ioctl(struct disk *dk, dev_t dev, u_long cmd, void *data, int flag,
573 struct lwp *l)
574 {
575 struct dkwedge_info *dkw;
576 struct partinfo *pi;
577 struct partition *dp;
578 #ifdef __HAVE_OLD_DISKLABEL
579 struct disklabel newlabel;
580 #endif
581
582 switch (cmd) {
583 case DIOCGDISKINFO:
584 if (dk->dk_info == NULL)
585 return ENOTSUP;
586 return prop_dictionary_copyout_ioctl(data, cmd, dk->dk_info);
587
588 case DIOCGSECTORSIZE:
589 *(u_int *)data = dk->dk_geom.dg_secsize;
590 return 0;
591
592 case DIOCGMEDIASIZE:
593 *(off_t *)data = (off_t)dk->dk_geom.dg_secsize *
594 dk->dk_geom.dg_secperunit;
595 return 0;
596 default:
597 break;
598 }
599
600 if (dev == NODEV)
601 return EPASSTHROUGH;
602
603 /* The following should be moved to dk_ioctl */
604 switch (cmd) {
605 case DIOCGDINFO:
606 if (dk->dk_label == NULL)
607 return EBUSY;
608 memcpy(data, dk->dk_label, sizeof (*dk->dk_label));
609 return 0;
610
611 #ifdef __HAVE_OLD_DISKLABEL
612 case ODIOCGDINFO:
613 if (dk->dk_label == NULL)
614 return EBUSY;
615 memcpy(&newlabel, dk->dk_label, sizeof(newlabel));
616 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
617 return ENOTTY;
618 memcpy(data, &newlabel, sizeof(struct olddisklabel));
619 return 0;
620 #endif
621
622 case DIOCGPARTINFO:
623 pi = data;
624 memset(pi, 0, sizeof(*pi));
625 pi->pi_secsize = dk->dk_geom.dg_secsize;
626 pi->pi_bsize = MAX(BLKDEV_IOSIZE, pi->pi_secsize);
627
628 if (DISKPART(dev) == RAW_PART) {
629 pi->pi_size = dk->dk_geom.dg_secperunit;
630 return 0;
631 }
632
633 if (dk->dk_label == NULL)
634 return EBUSY;
635
636 dp = &dk->dk_label->d_partitions[DISKPART(dev)];
637 pi->pi_offset = dp->p_offset;
638 pi->pi_size = dp->p_size;
639
640 pi->pi_fstype = dp->p_fstype;
641 pi->pi_frag = dp->p_frag;
642 pi->pi_fsize = dp->p_fsize;
643 pi->pi_cpg = dp->p_cpg;
644
645 /*
646 * dholland 20130616: XXX this logic should not be
647 * here. It is here because the old buffer cache
648 * demands that all accesses to the same blocks need
649 * to be the same size; but it only works for FFS and
650 * nowadays I think it'll fail silently if the size
651 * info in the disklabel is wrong. (Or missing.) The
652 * buffer cache needs to be smarter; or failing that
653 * we need a reliable way here to get the right block
654 * size; or a reliable way to guarantee that (a) the
655 * fs is not mounted when we get here and (b) any
656 * buffers generated here will get purged when the fs
657 * does get mounted.
658 */
659 if (dp->p_fstype == FS_BSDFFS &&
660 dp->p_frag != 0 && dp->p_fsize != 0)
661 pi->pi_bsize = dp->p_frag * dp->p_fsize;
662 return 0;
663
664 case DIOCAWEDGE:
665 if ((flag & FWRITE) == 0)
666 return EBADF;
667
668 dkw = data;
669 strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent));
670 return dkwedge_add(dkw);
671
672 case DIOCDWEDGE:
673 if ((flag & FWRITE) == 0)
674 return EBADF;
675
676 dkw = data;
677 strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent));
678 return dkwedge_del(dkw);
679
680 case DIOCLWEDGES:
681 return dkwedge_list(dk, data, l);
682
683 case DIOCMWEDGES:
684 if ((flag & FWRITE) == 0)
685 return EBADF;
686
687 dkwedge_discover(dk);
688 return 0;
689
690 default:
691 return EPASSTHROUGH;
692 }
693 }
694
695 void
696 disk_set_info(device_t dev, struct disk *dk, const char *type)
697 {
698 struct disk_geom *dg = &dk->dk_geom;
699
700 if (dg->dg_secsize == 0) {
701 #ifdef DIAGNOSTIC
702 printf("%s: fixing 0 sector size\n", dk->dk_name);
703 #endif
704 dg->dg_secsize = DEV_BSIZE;
705 }
706
707 dk->dk_blkshift = DK_BSIZE2BLKSHIFT(dg->dg_secsize);
708 dk->dk_byteshift = DK_BSIZE2BYTESHIFT(dg->dg_secsize);
709
710 if (dg->dg_secperunit == 0 && dg->dg_ncylinders == 0) {
711 #ifdef DIAGNOSTIC
712 printf("%s: secperunit and ncylinders are zero\n", dk->dk_name);
713 #endif
714 return;
715 }
716
717 if (dg->dg_secperunit == 0) {
718 if (dg->dg_nsectors == 0 || dg->dg_ntracks == 0) {
719 #ifdef DIAGNOSTIC
720 printf("%s: secperunit and (sectors or tracks) "
721 "are zero\n", dk->dk_name);
722 #endif
723 return;
724 }
725 dg->dg_secperunit = (int64_t) dg->dg_nsectors *
726 dg->dg_ntracks * dg->dg_ncylinders;
727 }
728
729 if (dg->dg_ncylinders == 0) {
730 if (dg->dg_ntracks && dg->dg_nsectors)
731 dg->dg_ncylinders = dg->dg_secperunit /
732 (dg->dg_ntracks * dg->dg_nsectors);
733 }
734
735 prop_dictionary_t disk_info, odisk_info, geom;
736
737 disk_info = prop_dictionary_create();
738 geom = prop_dictionary_create();
739
740 prop_dictionary_set_uint64(geom, "sectors-per-unit",
741 dg->dg_secperunit);
742
743 prop_dictionary_set_uint32(geom, "sector-size", dg->dg_secsize);
744
745 if (dg->dg_nsectors)
746 prop_dictionary_set_uint16(geom, "sectors-per-track",
747 dg->dg_nsectors);
748
749 if (dg->dg_ntracks)
750 prop_dictionary_set_uint16(geom, "tracks-per-cylinder",
751 dg->dg_ntracks);
752
753 if (dg->dg_ncylinders)
754 prop_dictionary_set_uint64(geom, "cylinders-per-unit",
755 dg->dg_ncylinders);
756
757 prop_dictionary_set(disk_info, "geometry", geom);
758
759 if (type)
760 prop_dictionary_set_cstring_nocopy(disk_info, "type", type);
761
762 prop_object_release(geom);
763
764 odisk_info = dk->dk_info;
765 dk->dk_info = disk_info;
766
767 if (dev)
768 prop_dictionary_set(device_properties(dev), "disk-info",
769 disk_info);
770
771 /*
772 * Don't release disk_info here; we keep a reference to it.
773 * disk_detach() will release it when we go away.
774 */
775 if (odisk_info)
776 prop_object_release(odisk_info);
777 }
778