1 | /* $NetBSD: subr_disk.c,v 1.116 2016/01/06 00:22:30 christos 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.116 2016/01/06 00:22:30 christos 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/disk.h> |
80 | #include <sys/sysctl.h> |
81 | #include <lib/libkern/libkern.h> |
82 | |
83 | /* |
84 | * Compute checksum for disk label. |
85 | */ |
86 | u_int |
87 | dkcksum(struct disklabel *lp) |
88 | { |
89 | |
90 | return dkcksum_sized(lp, lp->d_npartitions); |
91 | } |
92 | |
93 | u_int |
94 | dkcksum_sized(struct disklabel *lp, size_t npartitions) |
95 | { |
96 | uint16_t *start, *end; |
97 | uint16_t sum = 0; |
98 | |
99 | start = (uint16_t *)lp; |
100 | end = (uint16_t *)&lp->d_partitions[npartitions]; |
101 | while (start < end) |
102 | sum ^= *start++; |
103 | return sum; |
104 | } |
105 | |
106 | /* |
107 | * Disk error is the preface to plaintive error messages |
108 | * about failing disk transfers. It prints messages of the form |
109 | |
110 | hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d) |
111 | |
112 | * if the offset of the error in the transfer and a disk label |
113 | * are both available. blkdone should be -1 if the position of the error |
114 | * is unknown; the disklabel pointer may be null from drivers that have not |
115 | * been converted to use them. The message is printed with printf |
116 | * if pri is LOG_PRINTF, otherwise it uses log at the specified priority. |
117 | * The message should be completed (with at least a newline) with printf |
118 | * or addlog, respectively. There is no trailing space. |
119 | */ |
120 | #ifndef PRIdaddr |
121 | #define PRIdaddr PRId64 |
122 | #endif |
123 | void |
124 | diskerr(const struct buf *bp, const char *dname, const char *what, int pri, |
125 | int blkdone, const struct disklabel *lp) |
126 | { |
127 | int unit = DISKUNIT(bp->b_dev), part = DISKPART(bp->b_dev); |
128 | void (*pr)(const char *, ...) __printflike(1, 2); |
129 | char partname = 'a' + part; |
130 | daddr_t sn; |
131 | |
132 | if (/*CONSTCOND*/0) |
133 | /* Compiler will error this is the format is wrong... */ |
134 | printf("%" PRIdaddr, bp->b_blkno); |
135 | |
136 | if (pri != LOG_PRINTF) { |
137 | static const char fmt[] = "" ; |
138 | log(pri, fmt); |
139 | pr = addlog; |
140 | } else |
141 | pr = printf; |
142 | (*pr)("%s%d%c: %s %sing fsbn " , dname, unit, partname, what, |
143 | bp->b_flags & B_READ ? "read" : "writ" ); |
144 | sn = bp->b_blkno; |
145 | if (bp->b_bcount <= DEV_BSIZE) |
146 | (*pr)("%" PRIdaddr, sn); |
147 | else { |
148 | if (blkdone >= 0) { |
149 | sn += blkdone; |
150 | (*pr)("%" PRIdaddr " of " , sn); |
151 | } |
152 | (*pr)("%" PRIdaddr "-%" PRIdaddr "" , bp->b_blkno, |
153 | bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE); |
154 | } |
155 | if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) { |
156 | sn += lp->d_partitions[part].p_offset; |
157 | (*pr)(" (%s%d bn %" PRIdaddr "; cn %" PRIdaddr "" , |
158 | dname, unit, sn, sn / lp->d_secpercyl); |
159 | sn %= lp->d_secpercyl; |
160 | (*pr)(" tn %" PRIdaddr " sn %" PRIdaddr ")" , |
161 | sn / lp->d_nsectors, sn % lp->d_nsectors); |
162 | } |
163 | } |
164 | |
165 | /* |
166 | * Searches the iostatlist for the disk corresponding to the |
167 | * name provided. |
168 | */ |
169 | struct disk * |
170 | disk_find(const char *name) |
171 | { |
172 | struct io_stats *stat; |
173 | |
174 | stat = iostat_find(name); |
175 | |
176 | if ((stat != NULL) && (stat->io_type == IOSTAT_DISK)) |
177 | return stat->io_parent; |
178 | |
179 | return (NULL); |
180 | } |
181 | |
182 | void |
183 | disk_init(struct disk *diskp, const char *name, const struct dkdriver *driver) |
184 | { |
185 | u_int blocksize = DEV_BSIZE; |
186 | |
187 | /* |
188 | * Initialize the wedge-related locks and other fields. |
189 | */ |
190 | mutex_init(&diskp->dk_rawlock, MUTEX_DEFAULT, IPL_NONE); |
191 | mutex_init(&diskp->dk_openlock, MUTEX_DEFAULT, IPL_NONE); |
192 | LIST_INIT(&diskp->dk_wedges); |
193 | diskp->dk_nwedges = 0; |
194 | diskp->dk_labelsector = LABELSECTOR; |
195 | diskp->dk_blkshift = DK_BSIZE2BLKSHIFT(blocksize); |
196 | diskp->dk_byteshift = DK_BSIZE2BYTESHIFT(blocksize); |
197 | diskp->dk_name = name; |
198 | diskp->dk_driver = driver; |
199 | } |
200 | |
201 | /* |
202 | * Attach a disk. |
203 | */ |
204 | void |
205 | disk_attach(struct disk *diskp) |
206 | { |
207 | |
208 | /* |
209 | * Allocate and initialize the disklabel structures. |
210 | */ |
211 | diskp->dk_label = kmem_zalloc(sizeof(struct disklabel), KM_SLEEP); |
212 | diskp->dk_cpulabel = kmem_zalloc(sizeof(struct cpu_disklabel), |
213 | KM_SLEEP); |
214 | if ((diskp->dk_label == NULL) || (diskp->dk_cpulabel == NULL)) |
215 | panic("disk_attach: can't allocate storage for disklabel" ); |
216 | |
217 | /* |
218 | * Set up the stats collection. |
219 | */ |
220 | diskp->dk_stats = iostat_alloc(IOSTAT_DISK, diskp, diskp->dk_name); |
221 | } |
222 | |
223 | int |
224 | disk_begindetach(struct disk *dk, int (*lastclose)(device_t), |
225 | device_t self, int flags) |
226 | { |
227 | int rc; |
228 | |
229 | rc = 0; |
230 | mutex_enter(&dk->dk_openlock); |
231 | if (dk->dk_openmask == 0) |
232 | ; /* nothing to do */ |
233 | else if ((flags & DETACH_FORCE) == 0) |
234 | rc = EBUSY; |
235 | else if (lastclose != NULL) |
236 | rc = (*lastclose)(self); |
237 | mutex_exit(&dk->dk_openlock); |
238 | |
239 | return rc; |
240 | } |
241 | |
242 | /* |
243 | * Detach a disk. |
244 | */ |
245 | void |
246 | disk_detach(struct disk *diskp) |
247 | { |
248 | |
249 | /* |
250 | * Remove from the drivelist. |
251 | */ |
252 | iostat_free(diskp->dk_stats); |
253 | |
254 | /* |
255 | * Release the disk-info dictionary. |
256 | */ |
257 | if (diskp->dk_info) { |
258 | prop_object_release(diskp->dk_info); |
259 | diskp->dk_info = NULL; |
260 | } |
261 | |
262 | /* |
263 | * Free the space used by the disklabel structures. |
264 | */ |
265 | kmem_free(diskp->dk_label, sizeof(*diskp->dk_label)); |
266 | kmem_free(diskp->dk_cpulabel, sizeof(*diskp->dk_cpulabel)); |
267 | } |
268 | |
269 | void |
270 | disk_destroy(struct disk *diskp) |
271 | { |
272 | |
273 | mutex_destroy(&diskp->dk_openlock); |
274 | mutex_destroy(&diskp->dk_rawlock); |
275 | } |
276 | |
277 | /* |
278 | * Mark the disk as busy for metrics collection. |
279 | */ |
280 | void |
281 | disk_busy(struct disk *diskp) |
282 | { |
283 | |
284 | iostat_busy(diskp->dk_stats); |
285 | } |
286 | |
287 | /* |
288 | * Finished disk operations, gather metrics. |
289 | */ |
290 | void |
291 | disk_unbusy(struct disk *diskp, long bcount, int read) |
292 | { |
293 | |
294 | iostat_unbusy(diskp->dk_stats, bcount, read); |
295 | } |
296 | |
297 | /* |
298 | * Return true if disk has an I/O operation in flight. |
299 | */ |
300 | bool |
301 | disk_isbusy(struct disk *diskp) |
302 | { |
303 | |
304 | return iostat_isbusy(diskp->dk_stats); |
305 | } |
306 | |
307 | /* |
308 | * Bounds checking against the media size, used for the raw partition. |
309 | * secsize, mediasize and b_blkno must all be the same units. |
310 | * Possibly this has to be DEV_BSIZE (512). |
311 | */ |
312 | int |
313 | bounds_check_with_mediasize(struct buf *bp, int secsize, uint64_t mediasize) |
314 | { |
315 | int64_t sz; |
316 | |
317 | if (bp->b_blkno < 0) { |
318 | /* Reject negative offsets immediately. */ |
319 | bp->b_error = EINVAL; |
320 | return 0; |
321 | } |
322 | |
323 | sz = howmany((int64_t)bp->b_bcount, secsize); |
324 | |
325 | /* |
326 | * bp->b_bcount is a 32-bit value, and we rejected a negative |
327 | * bp->b_blkno already, so "bp->b_blkno + sz" cannot overflow. |
328 | */ |
329 | |
330 | if (bp->b_blkno + sz > mediasize) { |
331 | sz = mediasize - bp->b_blkno; |
332 | if (sz == 0) { |
333 | /* If exactly at end of disk, return EOF. */ |
334 | bp->b_resid = bp->b_bcount; |
335 | return 0; |
336 | } |
337 | if (sz < 0) { |
338 | /* If past end of disk, return EINVAL. */ |
339 | bp->b_error = EINVAL; |
340 | return 0; |
341 | } |
342 | /* Otherwise, truncate request. */ |
343 | bp->b_bcount = sz * secsize; |
344 | } |
345 | |
346 | return 1; |
347 | } |
348 | |
349 | /* |
350 | * Determine the size of the transfer, and make sure it is |
351 | * within the boundaries of the partition. Adjust transfer |
352 | * if needed, and signal errors or early completion. |
353 | */ |
354 | int |
355 | bounds_check_with_label(struct disk *dk, struct buf *bp, int wlabel) |
356 | { |
357 | struct disklabel *lp = dk->dk_label; |
358 | struct partition *p = lp->d_partitions + DISKPART(bp->b_dev); |
359 | uint64_t p_size, p_offset, labelsector; |
360 | int64_t sz; |
361 | |
362 | if (bp->b_blkno < 0) { |
363 | /* Reject negative offsets immediately. */ |
364 | bp->b_error = EINVAL; |
365 | return -1; |
366 | } |
367 | |
368 | /* Protect against division by zero. XXX: Should never happen?!?! */ |
369 | if (lp->d_secpercyl == 0) { |
370 | bp->b_error = EINVAL; |
371 | return -1; |
372 | } |
373 | |
374 | p_size = (uint64_t)p->p_size << dk->dk_blkshift; |
375 | p_offset = (uint64_t)p->p_offset << dk->dk_blkshift; |
376 | #if RAW_PART == 3 |
377 | labelsector = lp->d_partitions[2].p_offset; |
378 | #else |
379 | labelsector = lp->d_partitions[RAW_PART].p_offset; |
380 | #endif |
381 | labelsector = (labelsector + dk->dk_labelsector) << dk->dk_blkshift; |
382 | |
383 | sz = howmany((int64_t)bp->b_bcount, DEV_BSIZE); |
384 | |
385 | /* |
386 | * bp->b_bcount is a 32-bit value, and we rejected a negative |
387 | * bp->b_blkno already, so "bp->b_blkno + sz" cannot overflow. |
388 | */ |
389 | |
390 | if (bp->b_blkno + sz > p_size) { |
391 | sz = p_size - bp->b_blkno; |
392 | if (sz == 0) { |
393 | /* If exactly at end of disk, return EOF. */ |
394 | bp->b_resid = bp->b_bcount; |
395 | return 0; |
396 | } |
397 | if (sz < 0) { |
398 | /* If past end of disk, return EINVAL. */ |
399 | bp->b_error = EINVAL; |
400 | return -1; |
401 | } |
402 | /* Otherwise, truncate request. */ |
403 | bp->b_bcount = sz << DEV_BSHIFT; |
404 | } |
405 | |
406 | /* Overwriting disk label? */ |
407 | if (bp->b_blkno + p_offset <= labelsector && |
408 | bp->b_blkno + p_offset + sz > labelsector && |
409 | (bp->b_flags & B_READ) == 0 && !wlabel) { |
410 | bp->b_error = EROFS; |
411 | return -1; |
412 | } |
413 | |
414 | /* calculate cylinder for disksort to order transfers with */ |
415 | bp->b_cylinder = (bp->b_blkno + p->p_offset) / |
416 | (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl; |
417 | return 1; |
418 | } |
419 | |
420 | int |
421 | disk_read_sectors(void (*strat)(struct buf *), const struct disklabel *lp, |
422 | struct buf *bp, unsigned int sector, int count) |
423 | { |
424 | bp->b_blkno = btodb((off_t)sector * lp->d_secsize); |
425 | bp->b_bcount = count * lp->d_secsize; |
426 | bp->b_flags = (bp->b_flags & ~B_WRITE) | B_READ; |
427 | bp->b_oflags &= ~BO_DONE; |
428 | bp->b_cylinder = sector / lp->d_secpercyl; |
429 | (*strat)(bp); |
430 | return biowait(bp); |
431 | } |
432 | |
433 | const char * |
434 | convertdisklabel(struct disklabel *lp, void (*strat)(struct buf *), |
435 | struct buf *bp, uint32_t secperunit) |
436 | { |
437 | struct partition rp, *altp, *p; |
438 | int geom_ok; |
439 | const char *str; |
440 | |
441 | memset(&rp, 0, sizeof(rp)); |
442 | rp.p_size = secperunit; |
443 | rp.p_fstype = FS_UNUSED; |
444 | |
445 | /* If we can seek to d_secperunit - 1, believe the disk geometry. */ |
446 | if (secperunit != 0 && |
447 | disk_read_sectors(strat, lp, bp, secperunit - 1, 1) == 0) |
448 | geom_ok = 1; |
449 | else |
450 | geom_ok = 0; |
451 | |
452 | #if 0 |
453 | printf("%s: secperunit (%" PRIu32 ") %s\n" , __func__, |
454 | secperunit, geom_ok ? "ok" : "not ok" ); |
455 | #endif |
456 | |
457 | p = &lp->d_partitions[RAW_PART]; |
458 | if (RAW_PART == 'c' - 'a') |
459 | altp = &lp->d_partitions['d' - 'a']; |
460 | else |
461 | altp = &lp->d_partitions['c' - 'a']; |
462 | |
463 | if (lp->d_npartitions > RAW_PART && p->p_offset == 0 && p->p_size != 0) |
464 | return NULL; /* already a raw partition */ |
465 | else if (lp->d_npartitions > MAX('c', 'd') - 'a' && |
466 | altp->p_offset == 0 && altp->p_size != 0) { |
467 | /* alternate partition ('c' or 'd') is suitable for raw slot, |
468 | * swap with 'd' or 'c'. |
469 | */ |
470 | rp = *p; |
471 | *p = *altp; |
472 | *altp = rp; |
473 | return NULL; |
474 | } else if (lp->d_npartitions <= RAW_PART && |
475 | lp->d_npartitions > 'c' - 'a') { |
476 | /* No raw partition is present, but the alternate is present. |
477 | * Copy alternate to raw partition. |
478 | */ |
479 | lp->d_npartitions = RAW_PART + 1; |
480 | *p = *altp; |
481 | return NULL; |
482 | } else if (!geom_ok) |
483 | str = "no raw partition and disk reports bad geometry" ; |
484 | else if (lp->d_npartitions <= RAW_PART) { |
485 | memset(&lp->d_partitions[lp->d_npartitions], 0, |
486 | sizeof(struct partition) * (RAW_PART - lp->d_npartitions)); |
487 | *p = rp; |
488 | lp->d_npartitions = RAW_PART + 1; |
489 | return NULL; |
490 | } else if (lp->d_npartitions < MAXPARTITIONS) { |
491 | memmove(p + 1, p, |
492 | sizeof(struct partition) * (lp->d_npartitions - RAW_PART)); |
493 | *p = rp; |
494 | lp->d_npartitions++; |
495 | return NULL; |
496 | } else |
497 | str = "no raw partition and partition table is full" ; |
498 | #ifdef DIAGNOSTIC |
499 | printf("Bad partition: %s\n" , str); |
500 | printf("type = %u, subtype = %u, typename = %s\n" , |
501 | lp->d_type, lp->d_subtype, lp->d_typename); |
502 | printf("secsize = %u, nsectors = %u, ntracks = %u\n" , |
503 | lp->d_secsize, lp->d_nsectors, lp->d_ntracks); |
504 | printf("ncylinders = %u, secpercyl = %u, secperunit = %u\n" , |
505 | lp->d_ncylinders, lp->d_secpercyl, lp->d_secperunit); |
506 | printf("npartitions = %u\n" , lp->d_npartitions); |
507 | |
508 | for (size_t i = 0; i < MIN(lp->d_npartitions, MAXPARTITIONS); i++) { |
509 | p = &lp->d_partitions[i]; |
510 | printf("\t%c: offset = %u size = %u fstype = %u\n" , |
511 | (char)(i + 'a'), p->p_offset, p->p_size, p->p_fstype); |
512 | } |
513 | #endif |
514 | return str; |
515 | } |
516 | |
517 | /* |
518 | * disk_ioctl -- |
519 | * Generic disk ioctl handling. |
520 | */ |
521 | int |
522 | disk_ioctl(struct disk *dk, dev_t dev, u_long cmd, void *data, int flag, |
523 | struct lwp *l) |
524 | { |
525 | struct dkwedge_info *dkw; |
526 | struct partinfo *pi; |
527 | struct partition *dp; |
528 | #ifdef __HAVE_OLD_DISKLABEL |
529 | struct disklabel newlabel; |
530 | #endif |
531 | |
532 | switch (cmd) { |
533 | case DIOCGDISKINFO: |
534 | if (dk->dk_info == NULL) |
535 | return ENOTSUP; |
536 | return prop_dictionary_copyout_ioctl(data, cmd, dk->dk_info); |
537 | |
538 | case DIOCGSECTORSIZE: |
539 | *(u_int *)data = dk->dk_geom.dg_secsize; |
540 | return 0; |
541 | |
542 | case DIOCGMEDIASIZE: |
543 | *(off_t *)data = (off_t)dk->dk_geom.dg_secsize * |
544 | dk->dk_geom.dg_secperunit; |
545 | return 0; |
546 | default: |
547 | break; |
548 | } |
549 | |
550 | if (dev == NODEV) |
551 | return EPASSTHROUGH; |
552 | |
553 | /* The following should be moved to dk_ioctl */ |
554 | switch (cmd) { |
555 | case DIOCGDINFO: |
556 | if (dk->dk_label == NULL) |
557 | return EBUSY; |
558 | memcpy(data, dk->dk_label, sizeof (*dk->dk_label)); |
559 | return 0; |
560 | |
561 | #ifdef __HAVE_OLD_DISKLABEL |
562 | case ODIOCGDINFO: |
563 | if (dk->dk_label == NULL) |
564 | return EBUSY; |
565 | memcpy(&newlabel, dk->dk_label, sizeof(newlabel)); |
566 | if (newlabel.d_npartitions > OLDMAXPARTITIONS) |
567 | return ENOTTY; |
568 | memcpy(data, &newlabel, sizeof(struct olddisklabel)); |
569 | return 0; |
570 | #endif |
571 | |
572 | case DIOCGPARTINFO: |
573 | pi = data; |
574 | memset(pi, 0, sizeof(*pi)); |
575 | pi->pi_secsize = dk->dk_geom.dg_secsize; |
576 | pi->pi_bsize = BLKDEV_IOSIZE; |
577 | |
578 | if (DISKPART(dev) == RAW_PART) { |
579 | pi->pi_size = dk->dk_geom.dg_secperunit; |
580 | return 0; |
581 | } |
582 | |
583 | if (dk->dk_label == NULL) |
584 | return EBUSY; |
585 | |
586 | dp = &dk->dk_label->d_partitions[DISKPART(dev)]; |
587 | pi->pi_offset = dp->p_offset; |
588 | pi->pi_size = dp->p_size; |
589 | |
590 | pi->pi_fstype = dp->p_fstype; |
591 | pi->pi_frag = dp->p_frag; |
592 | pi->pi_fsize = dp->p_fsize; |
593 | pi->pi_cpg = dp->p_cpg; |
594 | |
595 | /* |
596 | * dholland 20130616: XXX this logic should not be |
597 | * here. It is here because the old buffer cache |
598 | * demands that all accesses to the same blocks need |
599 | * to be the same size; but it only works for FFS and |
600 | * nowadays I think it'll fail silently if the size |
601 | * info in the disklabel is wrong. (Or missing.) The |
602 | * buffer cache needs to be smarter; or failing that |
603 | * we need a reliable way here to get the right block |
604 | * size; or a reliable way to guarantee that (a) the |
605 | * fs is not mounted when we get here and (b) any |
606 | * buffers generated here will get purged when the fs |
607 | * does get mounted. |
608 | */ |
609 | if (dp->p_fstype == FS_BSDFFS && |
610 | dp->p_frag != 0 && dp->p_fsize != 0) |
611 | pi->pi_bsize = dp->p_frag * dp->p_fsize; |
612 | return 0; |
613 | |
614 | case DIOCAWEDGE: |
615 | if ((flag & FWRITE) == 0) |
616 | return EBADF; |
617 | |
618 | dkw = data; |
619 | strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent)); |
620 | return dkwedge_add(dkw); |
621 | |
622 | case DIOCDWEDGE: |
623 | if ((flag & FWRITE) == 0) |
624 | return EBADF; |
625 | |
626 | dkw = data; |
627 | strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent)); |
628 | return dkwedge_del(dkw); |
629 | |
630 | case DIOCLWEDGES: |
631 | return dkwedge_list(dk, data, l); |
632 | |
633 | case DIOCMWEDGES: |
634 | if ((flag & FWRITE) == 0) |
635 | return EBADF; |
636 | |
637 | dkwedge_discover(dk); |
638 | return 0; |
639 | |
640 | default: |
641 | return EPASSTHROUGH; |
642 | } |
643 | } |
644 | |
645 | void |
646 | disk_set_info(device_t dev, struct disk *dk, const char *type) |
647 | { |
648 | struct disk_geom *dg = &dk->dk_geom; |
649 | |
650 | if (dg->dg_secsize == 0) { |
651 | #ifdef DIAGNOSTIC |
652 | printf("%s: fixing 0 sector size\n" , dk->dk_name); |
653 | #endif |
654 | dg->dg_secsize = DEV_BSIZE; |
655 | } |
656 | |
657 | dk->dk_blkshift = DK_BSIZE2BLKSHIFT(dg->dg_secsize); |
658 | dk->dk_byteshift = DK_BSIZE2BYTESHIFT(dg->dg_secsize); |
659 | |
660 | if (dg->dg_secperunit == 0 && dg->dg_ncylinders == 0) { |
661 | #ifdef DIAGNOSTIC |
662 | printf("%s: secperunit and ncylinders are zero\n" , dk->dk_name); |
663 | #endif |
664 | return; |
665 | } |
666 | |
667 | if (dg->dg_secperunit == 0) { |
668 | if (dg->dg_nsectors == 0 || dg->dg_ntracks == 0) { |
669 | #ifdef DIAGNOSTIC |
670 | printf("%s: secperunit and (sectors or tracks) " |
671 | "are zero\n" , dk->dk_name); |
672 | #endif |
673 | return; |
674 | } |
675 | dg->dg_secperunit = (int64_t) dg->dg_nsectors * |
676 | dg->dg_ntracks * dg->dg_ncylinders; |
677 | } |
678 | |
679 | if (dg->dg_ncylinders == 0) { |
680 | if (dg->dg_ntracks && dg->dg_nsectors) |
681 | dg->dg_ncylinders = dg->dg_secperunit / |
682 | (dg->dg_ntracks * dg->dg_nsectors); |
683 | } |
684 | |
685 | prop_dictionary_t disk_info, odisk_info, geom; |
686 | |
687 | disk_info = prop_dictionary_create(); |
688 | geom = prop_dictionary_create(); |
689 | |
690 | prop_dictionary_set_uint64(geom, "sectors-per-unit" , |
691 | dg->dg_secperunit); |
692 | |
693 | prop_dictionary_set_uint32(geom, "sector-size" , dg->dg_secsize); |
694 | |
695 | if (dg->dg_nsectors) |
696 | prop_dictionary_set_uint16(geom, "sectors-per-track" , |
697 | dg->dg_nsectors); |
698 | |
699 | if (dg->dg_ntracks) |
700 | prop_dictionary_set_uint16(geom, "tracks-per-cylinder" , |
701 | dg->dg_ntracks); |
702 | |
703 | if (dg->dg_ncylinders) |
704 | prop_dictionary_set_uint64(geom, "cylinders-per-unit" , |
705 | dg->dg_ncylinders); |
706 | |
707 | prop_dictionary_set(disk_info, "geometry" , geom); |
708 | |
709 | if (type) |
710 | prop_dictionary_set_cstring_nocopy(disk_info, "type" , type); |
711 | |
712 | prop_object_release(geom); |
713 | |
714 | odisk_info = dk->dk_info; |
715 | dk->dk_info = disk_info; |
716 | |
717 | if (dev) |
718 | prop_dictionary_set(device_properties(dev), "disk-info" , |
719 | disk_info); |
720 | |
721 | /* |
722 | * Don't release disk_info here; we keep a reference to it. |
723 | * disk_detach() will release it when we go away. |
724 | */ |
725 | if (odisk_info) |
726 | prop_object_release(odisk_info); |
727 | } |
728 | |