1 | /* $NetBSD: subr_disk_open.c,v 1.13 2015/12/08 20:36:15 christos Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2006 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 | * POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: subr_disk_open.c,v 1.13 2015/12/08 20:36:15 christos Exp $" ); |
31 | |
32 | #include <sys/param.h> |
33 | #include <sys/conf.h> |
34 | #include <sys/device.h> |
35 | #include <sys/disk.h> |
36 | #include <sys/disklabel.h> |
37 | #include <sys/fcntl.h> |
38 | #include <sys/kauth.h> |
39 | #include <sys/vnode.h> |
40 | #include <miscfs/specfs/specdev.h> |
41 | |
42 | struct vnode * |
43 | opendisk(device_t dv) |
44 | { |
45 | devmajor_t bmajor; |
46 | int unit; |
47 | struct vnode *tmpvn; |
48 | int error; |
49 | dev_t dev; |
50 | |
51 | /* |
52 | * Lookup major number for disk block device. |
53 | */ |
54 | bmajor = devsw_name2blk(device_xname(dv), NULL, 0); |
55 | if (bmajor == -1) |
56 | return NULL; |
57 | |
58 | unit = device_unit(dv); |
59 | /* |
60 | * Fake a temporary vnode for the disk, open it, and read |
61 | * and hash the sectors. |
62 | */ |
63 | dev = device_is_a(dv, "dk" ) ? makedev(bmajor, unit) : |
64 | MAKEDISKDEV(bmajor, unit, RAW_PART); |
65 | if (bdevvp(dev, &tmpvn)) |
66 | panic("%s: can't alloc vnode for %s" , __func__, |
67 | device_xname(dv)); |
68 | error = VOP_OPEN(tmpvn, FREAD | FSILENT, NOCRED); |
69 | if (error) { |
70 | /* |
71 | * Ignore errors caused by missing device, partition, |
72 | * medium, or busy [presumably because of a wedge covering it] |
73 | */ |
74 | switch (error) { |
75 | case ENXIO: |
76 | case ENODEV: |
77 | case EBUSY: |
78 | break; |
79 | default: |
80 | printf("%s: can't open dev %s (%d)\n" , |
81 | __func__, device_xname(dv), error); |
82 | break; |
83 | } |
84 | vput(tmpvn); |
85 | return NULL; |
86 | } |
87 | |
88 | return tmpvn; |
89 | } |
90 | |
91 | int |
92 | getdisksize(struct vnode *vp, uint64_t *numsecp, unsigned int *secsizep) |
93 | { |
94 | struct partinfo pi; |
95 | struct dkwedge_info dkw; |
96 | struct disk *pdk; |
97 | unsigned int secsize; |
98 | uint64_t numsec; |
99 | int error; |
100 | |
101 | /* |
102 | * We attempt to get the wedge information first if it exists, |
103 | * because the label does not support larger size disks. |
104 | */ |
105 | error = VOP_IOCTL(vp, DIOCGWEDGEINFO, &dkw, FREAD, NOCRED); |
106 | if (error == 0) { |
107 | pdk = disk_find(dkw.dkw_parent); |
108 | if (pdk != NULL) { |
109 | secsize = DEV_BSIZE << pdk->dk_blkshift; |
110 | numsec = dkw.dkw_size; |
111 | } else |
112 | error = ENODEV; |
113 | } |
114 | |
115 | if (error) { |
116 | error = VOP_IOCTL(vp, DIOCGPARTINFO, &pi, FREAD, NOCRED); |
117 | if (error == 0) { |
118 | secsize = pi.pi_secsize; |
119 | numsec = pi.pi_size; |
120 | } |
121 | } |
122 | |
123 | if (error == 0 && |
124 | (secsize == 0 || secsize > MAXBSIZE || !powerof2(secsize) || |
125 | numsec == 0)) { |
126 | #ifdef DIAGNOSTIC |
127 | printf("%s: %s returns invalid disksize values" |
128 | " (secsize = %u, numsec = %" PRIu64 ")\n" , |
129 | __func__, |
130 | devsw_blk2name(major(vp->v_specnode->sn_rdev)), |
131 | secsize, numsec); |
132 | #endif |
133 | error = EINVAL; |
134 | } |
135 | if (error == 0) { |
136 | *secsizep = secsize; |
137 | *numsecp = numsec; |
138 | } |
139 | |
140 | return error; |
141 | } |
142 | |
143 | int |
144 | getdiskinfo(struct vnode *vp, struct dkwedge_info *dkw) |
145 | { |
146 | struct partinfo pi; |
147 | int error; |
148 | dev_t dev = vp->v_specnode->sn_rdev; |
149 | |
150 | if (VOP_IOCTL(vp, DIOCGWEDGEINFO, dkw, FREAD, NOCRED) == 0) |
151 | return 0; |
152 | |
153 | if ((error = VOP_IOCTL(vp, DIOCGPARTINFO, &pi, FREAD, NOCRED)) != 0) |
154 | return error; |
155 | |
156 | snprintf(dkw->dkw_devname, sizeof(dkw->dkw_devname), "%s%" PRId32 "%c" , |
157 | devsw_blk2name(major(dev)), DISKUNIT(dev), (char)DISKPART(dev) + |
158 | 'a'); |
159 | |
160 | dkw->dkw_wname[0] = '\0'; |
161 | |
162 | strlcpy(dkw->dkw_parent, dkw->dkw_devname, sizeof(dkw->dkw_parent)); |
163 | |
164 | dkw->dkw_size = pi.pi_size; |
165 | dkw->dkw_offset = pi.pi_offset; |
166 | strlcpy(dkw->dkw_ptype, getfstypename(pi.pi_fstype), |
167 | sizeof(dkw->dkw_ptype)); |
168 | |
169 | return 0; |
170 | } |
171 | |