| @@ -1,723 +1,723 @@ | | | @@ -1,723 +1,723 @@ |
1 | /* $NetBSD: device-mapper.c,v 1.43 2019/12/04 15:31:12 tkusumi Exp $ */ | | 1 | /* $NetBSD: device-mapper.c,v 1.44 2019/12/04 16:55:30 tkusumi Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2010 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2010 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Adam Hamsik. | | 8 | * by Adam Hamsik. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * I want to say thank you to all people who helped me with this project. | | 33 | * I want to say thank you to all people who helped me with this project. |
34 | */ | | 34 | */ |
35 | | | 35 | |
36 | #include <sys/types.h> | | 36 | #include <sys/types.h> |
37 | #include <sys/param.h> | | 37 | #include <sys/param.h> |
38 | | | 38 | |
39 | #include <sys/buf.h> | | 39 | #include <sys/buf.h> |
40 | #include <sys/conf.h> | | 40 | #include <sys/conf.h> |
41 | #include <sys/device.h> | | 41 | #include <sys/device.h> |
42 | #include <sys/dkio.h> | | 42 | #include <sys/dkio.h> |
43 | #include <sys/disk.h> | | 43 | #include <sys/disk.h> |
44 | #include <sys/disklabel.h> | | 44 | #include <sys/disklabel.h> |
45 | #include <sys/ioctl.h> | | 45 | #include <sys/ioctl.h> |
46 | #include <sys/ioccom.h> | | 46 | #include <sys/ioccom.h> |
47 | #include <sys/kmem.h> | | 47 | #include <sys/kmem.h> |
48 | #include <sys/kauth.h> | | 48 | #include <sys/kauth.h> |
49 | | | 49 | |
50 | #include "netbsd-dm.h" | | 50 | #include "netbsd-dm.h" |
51 | #include "dm.h" | | 51 | #include "dm.h" |
52 | #include "ioconf.h" | | 52 | #include "ioconf.h" |
53 | | | 53 | |
54 | static dev_type_open(dmopen); | | 54 | static dev_type_open(dmopen); |
55 | static dev_type_close(dmclose); | | 55 | static dev_type_close(dmclose); |
56 | static dev_type_read(dmread); | | 56 | static dev_type_read(dmread); |
57 | static dev_type_write(dmwrite); | | 57 | static dev_type_write(dmwrite); |
58 | static dev_type_ioctl(dmioctl); | | 58 | static dev_type_ioctl(dmioctl); |
59 | static dev_type_strategy(dmstrategy); | | 59 | static dev_type_strategy(dmstrategy); |
60 | static dev_type_size(dmsize); | | 60 | static dev_type_size(dmsize); |
61 | | | 61 | |
62 | /* attach and detach routines */ | | 62 | /* attach and detach routines */ |
63 | #ifdef _MODULE | | 63 | #ifdef _MODULE |
64 | static int dmdestroy(void); | | 64 | static int dmdestroy(void); |
65 | #endif | | 65 | #endif |
66 | | | 66 | |
67 | static void dm_doinit(void); | | 67 | static void dm_doinit(void); |
68 | | | 68 | |
69 | static int dm_cmd_to_fun(prop_dictionary_t); | | 69 | static int dm_cmd_to_fun(prop_dictionary_t); |
70 | static int disk_ioctl_switch(dev_t, u_long, void *); | | 70 | static int disk_ioctl_switch(dev_t, u_long, void *); |
71 | static int dm_ioctl_switch(u_long); | | 71 | static int dm_ioctl_switch(u_long); |
72 | static void dmminphys(struct buf *); | | 72 | static void dmminphys(struct buf *); |
73 | | | 73 | |
74 | /* CF attach/detach functions used for power management */ | | 74 | /* CF attach/detach functions used for power management */ |
75 | static int dm_detach(device_t, int); | | 75 | static int dm_detach(device_t, int); |
76 | static void dm_attach(device_t, device_t, void *); | | 76 | static void dm_attach(device_t, device_t, void *); |
77 | static int dm_match(device_t, cfdata_t, void *); | | 77 | static int dm_match(device_t, cfdata_t, void *); |
78 | | | 78 | |
79 | /* ***Variable-definitions*** */ | | 79 | /* ***Variable-definitions*** */ |
80 | const struct bdevsw dm_bdevsw = { | | 80 | const struct bdevsw dm_bdevsw = { |
81 | .d_open = dmopen, | | 81 | .d_open = dmopen, |
82 | .d_close = dmclose, | | 82 | .d_close = dmclose, |
83 | .d_strategy = dmstrategy, | | 83 | .d_strategy = dmstrategy, |
84 | .d_ioctl = dmioctl, | | 84 | .d_ioctl = dmioctl, |
85 | .d_dump = nodump, | | 85 | .d_dump = nodump, |
86 | .d_psize = dmsize, | | 86 | .d_psize = dmsize, |
87 | .d_discard = nodiscard, | | 87 | .d_discard = nodiscard, |
88 | .d_flag = D_DISK | D_MPSAFE | | 88 | .d_flag = D_DISK | D_MPSAFE |
89 | }; | | 89 | }; |
90 | | | 90 | |
91 | const struct cdevsw dm_cdevsw = { | | 91 | const struct cdevsw dm_cdevsw = { |
92 | .d_open = dmopen, | | 92 | .d_open = dmopen, |
93 | .d_close = dmclose, | | 93 | .d_close = dmclose, |
94 | .d_read = dmread, | | 94 | .d_read = dmread, |
95 | .d_write = dmwrite, | | 95 | .d_write = dmwrite, |
96 | .d_ioctl = dmioctl, | | 96 | .d_ioctl = dmioctl, |
97 | .d_stop = nostop, | | 97 | .d_stop = nostop, |
98 | .d_tty = notty, | | 98 | .d_tty = notty, |
99 | .d_poll = nopoll, | | 99 | .d_poll = nopoll, |
100 | .d_mmap = nommap, | | 100 | .d_mmap = nommap, |
101 | .d_kqfilter = nokqfilter, | | 101 | .d_kqfilter = nokqfilter, |
102 | .d_discard = nodiscard, | | 102 | .d_discard = nodiscard, |
103 | .d_flag = D_DISK | D_MPSAFE | | 103 | .d_flag = D_DISK | D_MPSAFE |
104 | }; | | 104 | }; |
105 | | | 105 | |
106 | const struct dkdriver dmdkdriver = { | | 106 | const struct dkdriver dmdkdriver = { |
107 | .d_strategy = dmstrategy | | 107 | .d_strategy = dmstrategy |
108 | }; | | 108 | }; |
109 | | | 109 | |
110 | CFATTACH_DECL3_NEW(dm, 0, | | 110 | CFATTACH_DECL3_NEW(dm, 0, |
111 | dm_match, dm_attach, dm_detach, NULL, NULL, NULL, | | 111 | dm_match, dm_attach, dm_detach, NULL, NULL, NULL, |
112 | DVF_DETACH_SHUTDOWN); | | 112 | DVF_DETACH_SHUTDOWN); |
113 | | | 113 | |
114 | extern uint32_t dm_dev_counter; | | 114 | extern uint32_t dm_dev_counter; |
115 | | | 115 | |
116 | /* | | 116 | /* |
117 | * This structure is used to translate command sent to kernel driver in | | 117 | * This structure is used to translate command sent to kernel driver in |
118 | * <key>command</key> | | 118 | * <key>command</key> |
119 | * <value></value> | | 119 | * <value></value> |
120 | * to function which I can call, and if the command is allowed for | | 120 | * to function which I can call, and if the command is allowed for |
121 | * non-superusers. | | 121 | * non-superusers. |
122 | */ | | 122 | */ |
123 | /* | | 123 | /* |
124 | * This array is used to translate cmd to function pointer. | | 124 | * This array is used to translate cmd to function pointer. |
125 | * | | 125 | * |
126 | * Interface between libdevmapper and lvm2tools uses different | | 126 | * Interface between libdevmapper and lvm2tools uses different |
127 | * names for one IOCTL call because libdevmapper do another thing | | 127 | * names for one IOCTL call because libdevmapper do another thing |
128 | * then. When I run "info" or "mknodes" libdevmapper will send same | | 128 | * then. When I run "info" or "mknodes" libdevmapper will send same |
129 | * ioctl to kernel but will do another things in userspace. | | 129 | * ioctl to kernel but will do another things in userspace. |
130 | * | | 130 | * |
131 | */ | | 131 | */ |
132 | static const struct cmd_function { | | 132 | static const struct cmd_function { |
133 | const char *cmd; | | 133 | const char *cmd; |
134 | int (*fn)(prop_dictionary_t); | | 134 | int (*fn)(prop_dictionary_t); |
135 | int allowed; | | 135 | int allowed; |
136 | } cmd_fn[] = { | | 136 | } cmd_fn[] = { |
137 | { .cmd = "version", .fn = dm_get_version_ioctl, .allowed = 1 }, | | 137 | { .cmd = "version", .fn = dm_get_version_ioctl, .allowed = 1 }, |
138 | { .cmd = "targets", .fn = dm_list_versions_ioctl, .allowed = 1 }, | | 138 | { .cmd = "targets", .fn = dm_list_versions_ioctl, .allowed = 1 }, |
139 | { .cmd = "create", .fn = dm_dev_create_ioctl, .allowed = 0 }, | | 139 | { .cmd = "create", .fn = dm_dev_create_ioctl, .allowed = 0 }, |
140 | { .cmd = "info", .fn = dm_dev_status_ioctl, .allowed = 1 }, | | 140 | { .cmd = "info", .fn = dm_dev_status_ioctl, .allowed = 1 }, |
141 | { .cmd = "mknodes", .fn = dm_dev_status_ioctl, .allowed = 1 }, | | 141 | { .cmd = "mknodes", .fn = dm_dev_status_ioctl, .allowed = 1 }, |
142 | { .cmd = "names", .fn = dm_dev_list_ioctl, .allowed = 1 }, | | 142 | { .cmd = "names", .fn = dm_dev_list_ioctl, .allowed = 1 }, |
143 | { .cmd = "suspend", .fn = dm_dev_suspend_ioctl, .allowed = 0 }, | | 143 | { .cmd = "suspend", .fn = dm_dev_suspend_ioctl, .allowed = 0 }, |
144 | { .cmd = "remove", .fn = dm_dev_remove_ioctl, .allowed = 0 }, | | 144 | { .cmd = "remove", .fn = dm_dev_remove_ioctl, .allowed = 0 }, |
145 | { .cmd = "rename", .fn = dm_dev_rename_ioctl, .allowed = 0 }, | | 145 | { .cmd = "rename", .fn = dm_dev_rename_ioctl, .allowed = 0 }, |
146 | { .cmd = "resume", .fn = dm_dev_resume_ioctl, .allowed = 0 }, | | 146 | { .cmd = "resume", .fn = dm_dev_resume_ioctl, .allowed = 0 }, |
147 | { .cmd = "clear", .fn = dm_table_clear_ioctl, .allowed = 0 }, | | 147 | { .cmd = "clear", .fn = dm_table_clear_ioctl, .allowed = 0 }, |
148 | { .cmd = "deps", .fn = dm_table_deps_ioctl, .allowed = 1 }, | | 148 | { .cmd = "deps", .fn = dm_table_deps_ioctl, .allowed = 1 }, |
149 | { .cmd = "reload", .fn = dm_table_load_ioctl, .allowed = 0 }, | | 149 | { .cmd = "reload", .fn = dm_table_load_ioctl, .allowed = 0 }, |
150 | { .cmd = "status", .fn = dm_table_status_ioctl, .allowed = 1 }, | | 150 | { .cmd = "status", .fn = dm_table_status_ioctl, .allowed = 1 }, |
151 | { .cmd = "table", .fn = dm_table_status_ioctl, .allowed = 1 }, | | 151 | { .cmd = "table", .fn = dm_table_status_ioctl, .allowed = 1 }, |
152 | { .cmd = NULL, .fn = NULL, .allowed = 0 } | | 152 | { .cmd = NULL, .fn = NULL, .allowed = 0 } |
153 | }; | | 153 | }; |
154 | | | 154 | |
155 | #ifdef _MODULE | | 155 | #ifdef _MODULE |
156 | #include <sys/module.h> | | 156 | #include <sys/module.h> |
157 | | | 157 | |
158 | /* Autoconf defines */ | | 158 | /* Autoconf defines */ |
159 | CFDRIVER_DECL(dm, DV_DISK, NULL); | | 159 | CFDRIVER_DECL(dm, DV_DISK, NULL); |
160 | | | 160 | |
161 | MODULE(MODULE_CLASS_DRIVER, dm, "dk_subr"); | | 161 | MODULE(MODULE_CLASS_DRIVER, dm, "dk_subr"); |
162 | | | 162 | |
163 | /* New module handle routine */ | | 163 | /* New module handle routine */ |
164 | static int | | 164 | static int |
165 | dm_modcmd(modcmd_t cmd, void *arg) | | 165 | dm_modcmd(modcmd_t cmd, void *arg) |
166 | { | | 166 | { |
167 | #ifdef _MODULE | | 167 | #ifdef _MODULE |
168 | int error; | | 168 | int error; |
169 | devmajor_t bmajor, cmajor; | | 169 | devmajor_t bmajor, cmajor; |
170 | | | 170 | |
171 | error = 0; | | 171 | error = 0; |
172 | bmajor = -1; | | 172 | bmajor = -1; |
173 | cmajor = -1; | | 173 | cmajor = -1; |
174 | | | 174 | |
175 | switch (cmd) { | | 175 | switch (cmd) { |
176 | case MODULE_CMD_INIT: | | 176 | case MODULE_CMD_INIT: |
177 | error = config_cfdriver_attach(&dm_cd); | | 177 | error = config_cfdriver_attach(&dm_cd); |
178 | if (error) | | 178 | if (error) |
179 | break; | | 179 | break; |
180 | | | 180 | |
181 | error = config_cfattach_attach(dm_cd.cd_name, &dm_ca); | | 181 | error = config_cfattach_attach(dm_cd.cd_name, &dm_ca); |
182 | if (error) { | | 182 | if (error) { |
183 | aprint_error("%s: unable to register cfattach\n", | | 183 | aprint_error("%s: unable to register cfattach\n", |
184 | dm_cd.cd_name); | | 184 | dm_cd.cd_name); |
185 | return error; | | 185 | return error; |
186 | } | | 186 | } |
187 | | | 187 | |
188 | error = devsw_attach(dm_cd.cd_name, &dm_bdevsw, &bmajor, | | 188 | error = devsw_attach(dm_cd.cd_name, &dm_bdevsw, &bmajor, |
189 | &dm_cdevsw, &cmajor); | | 189 | &dm_cdevsw, &cmajor); |
190 | if (error == EEXIST) | | 190 | if (error == EEXIST) |
191 | error = 0; | | 191 | error = 0; |
192 | if (error) { | | 192 | if (error) { |
193 | config_cfattach_detach(dm_cd.cd_name, &dm_ca); | | 193 | config_cfattach_detach(dm_cd.cd_name, &dm_ca); |
194 | config_cfdriver_detach(&dm_cd); | | 194 | config_cfdriver_detach(&dm_cd); |
195 | break; | | 195 | break; |
196 | } | | 196 | } |
197 | dm_doinit(); | | 197 | dm_doinit(); |
198 | break; | | 198 | break; |
199 | case MODULE_CMD_FINI: | | 199 | case MODULE_CMD_FINI: |
200 | /* | | 200 | /* |
201 | * Disable unloading of dm module if there are any devices | | 201 | * Disable unloading of dm module if there are any devices |
202 | * defined in driver. This is probably too strong we need | | 202 | * defined in driver. This is probably too strong we need |
203 | * to disable auto-unload only if there is mounted dm device | | 203 | * to disable auto-unload only if there is mounted dm device |
204 | * present. | | 204 | * present. |
205 | */ | | 205 | */ |
206 | if (dm_dev_counter > 0) | | 206 | if (dm_dev_counter > 0) |
207 | return EBUSY; | | 207 | return EBUSY; |
208 | /* race window here */ | | 208 | /* race window here */ |
209 | | | 209 | |
210 | error = dmdestroy(); | | 210 | error = dmdestroy(); |
211 | if (error) | | 211 | if (error) |
212 | break; | | 212 | break; |
213 | | | 213 | |
214 | config_cfdriver_detach(&dm_cd); | | 214 | config_cfdriver_detach(&dm_cd); |
215 | | | 215 | |
216 | devsw_detach(&dm_bdevsw, &dm_cdevsw); | | 216 | devsw_detach(&dm_bdevsw, &dm_cdevsw); |
217 | break; | | 217 | break; |
218 | case MODULE_CMD_STAT: | | 218 | case MODULE_CMD_STAT: |
219 | return ENOTTY; | | 219 | return ENOTTY; |
220 | default: | | 220 | default: |
221 | return ENOTTY; | | 221 | return ENOTTY; |
222 | } | | 222 | } |
223 | | | 223 | |
224 | return error; | | 224 | return error; |
225 | #else | | 225 | #else |
226 | return ENOTTY; | | 226 | return ENOTTY; |
227 | #endif | | 227 | #endif |
228 | } | | 228 | } |
229 | #endif /* _MODULE */ | | 229 | #endif /* _MODULE */ |
230 | | | 230 | |
231 | /* | | 231 | /* |
232 | * dm_match: | | 232 | * dm_match: |
233 | * | | 233 | * |
234 | * Autoconfiguration match function for pseudo-device glue. | | 234 | * Autoconfiguration match function for pseudo-device glue. |
235 | */ | | 235 | */ |
236 | static int | | 236 | static int |
237 | dm_match(device_t parent, cfdata_t match, void *aux) | | 237 | dm_match(device_t parent, cfdata_t match, void *aux) |
238 | { | | 238 | { |
239 | | | 239 | |
240 | /* Pseudo-device; always present. */ | | 240 | /* Pseudo-device; always present. */ |
241 | return (1); | | 241 | return (1); |
242 | } | | 242 | } |
243 | | | 243 | |
244 | /* | | 244 | /* |
245 | * dm_attach: | | 245 | * dm_attach: |
246 | * | | 246 | * |
247 | * Autoconfiguration attach function for pseudo-device glue. | | 247 | * Autoconfiguration attach function for pseudo-device glue. |
248 | */ | | 248 | */ |
249 | static void | | 249 | static void |
250 | dm_attach(device_t parent, device_t self, void *aux) | | 250 | dm_attach(device_t parent, device_t self, void *aux) |
251 | { | | 251 | { |
252 | return; | | 252 | return; |
253 | } | | 253 | } |
254 | | | 254 | |
255 | | | 255 | |
256 | /* | | 256 | /* |
257 | * dm_detach: | | 257 | * dm_detach: |
258 | * | | 258 | * |
259 | * Autoconfiguration detach function for pseudo-device glue. | | 259 | * Autoconfiguration detach function for pseudo-device glue. |
260 | * This routine is called by dm_ioctl::dm_dev_remove_ioctl and by autoconf to | | 260 | * This routine is called by dm_ioctl::dm_dev_remove_ioctl and by autoconf to |
261 | * remove devices created in device-mapper. | | 261 | * remove devices created in device-mapper. |
262 | */ | | 262 | */ |
263 | static int | | 263 | static int |
264 | dm_detach(device_t self, int flags) | | 264 | dm_detach(device_t self, int flags) |
265 | { | | 265 | { |
266 | dm_dev_t *dmv; | | 266 | dm_dev_t *dmv; |
267 | | | 267 | |
268 | /* Detach device from global device list */ | | 268 | /* Detach device from global device list */ |
269 | if ((dmv = dm_dev_detach(self)) == NULL) | | 269 | if ((dmv = dm_dev_detach(self)) == NULL) |
270 | return ENOENT; | | 270 | return ENOENT; |
271 | | | 271 | |
272 | /* Destroy active table first. */ | | 272 | /* Destroy active table first. */ |
273 | dm_table_destroy(&dmv->table_head, DM_TABLE_ACTIVE); | | 273 | dm_table_destroy(&dmv->table_head, DM_TABLE_ACTIVE); |
274 | | | 274 | |
275 | /* Destroy inactive table if exits, too. */ | | 275 | /* Destroy inactive table if exits, too. */ |
276 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); | | 276 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); |
277 | | | 277 | |
278 | dm_table_head_destroy(&dmv->table_head); | | 278 | dm_table_head_destroy(&dmv->table_head); |
279 | | | 279 | |
280 | /* Destroy disk device structure */ | | 280 | /* Destroy disk device structure */ |
281 | disk_detach(dmv->diskp); | | 281 | disk_detach(dmv->diskp); |
282 | disk_destroy(dmv->diskp); | | 282 | disk_destroy(dmv->diskp); |
283 | | | 283 | |
284 | /* Destroy device */ | | 284 | /* Destroy device */ |
285 | (void)dm_dev_free(dmv); | | 285 | (void)dm_dev_free(dmv); |
286 | | | 286 | |
287 | /* Decrement device counter After removing device */ | | 287 | /* Decrement device counter After removing device */ |
288 | atomic_dec_32(&dm_dev_counter); | | 288 | atomic_dec_32(&dm_dev_counter); |
289 | | | 289 | |
290 | return 0; | | 290 | return 0; |
291 | } | | 291 | } |
292 | | | 292 | |
293 | static void | | 293 | static void |
294 | dm_doinit(void) | | 294 | dm_doinit(void) |
295 | { | | 295 | { |
296 | dm_target_init(); | | 296 | dm_target_init(); |
297 | dm_dev_init(); | | 297 | dm_dev_init(); |
298 | dm_pdev_init(); | | 298 | dm_pdev_init(); |
299 | } | | 299 | } |
300 | | | 300 | |
301 | /* attach routine */ | | 301 | /* attach routine */ |
302 | void | | 302 | void |
303 | dmattach(int n) | | 303 | dmattach(int n) |
304 | { | | 304 | { |
305 | int error; | | 305 | int error; |
306 | | | 306 | |
307 | error = config_cfattach_attach(dm_cd.cd_name, &dm_ca); | | 307 | error = config_cfattach_attach(dm_cd.cd_name, &dm_ca); |
308 | if (error) { | | 308 | if (error) { |
309 | aprint_error("%s: unable to register cfattach\n", | | 309 | aprint_error("%s: unable to register cfattach\n", |
310 | dm_cd.cd_name); | | 310 | dm_cd.cd_name); |
311 | } else { | | 311 | } else { |
312 | dm_doinit(); | | 312 | dm_doinit(); |
313 | } | | 313 | } |
314 | } | | 314 | } |
315 | | | 315 | |
316 | #ifdef _MODULE | | 316 | #ifdef _MODULE |
317 | /* Destroy routine */ | | 317 | /* Destroy routine */ |
318 | static int | | 318 | static int |
319 | dmdestroy(void) | | 319 | dmdestroy(void) |
320 | { | | 320 | { |
321 | int error; | | 321 | int error; |
322 | | | 322 | |
323 | error = config_cfattach_detach(dm_cd.cd_name, &dm_ca); | | 323 | error = config_cfattach_detach(dm_cd.cd_name, &dm_ca); |
324 | if (error) | | 324 | if (error) |
325 | return error; | | 325 | return error; |
326 | | | 326 | |
327 | dm_dev_destroy(); | | 327 | dm_dev_destroy(); |
328 | dm_pdev_destroy(); | | 328 | dm_pdev_destroy(); |
329 | dm_target_destroy(); | | 329 | dm_target_destroy(); |
330 | | | 330 | |
331 | return 0; | | 331 | return 0; |
332 | } | | 332 | } |
333 | #endif /* _MODULE */ | | 333 | #endif /* _MODULE */ |
334 | | | 334 | |
335 | static int | | 335 | static int |
336 | dmopen(dev_t dev, int flags, int mode, struct lwp *l) | | 336 | dmopen(dev_t dev, int flags, int mode, struct lwp *l) |
337 | { | | 337 | { |
338 | | | 338 | |
339 | aprint_debug("dm open routine called %" PRIu32 "\n", minor(dev)); | | 339 | aprint_debug("dm open routine called %" PRIu32 "\n", minor(dev)); |
340 | return 0; | | 340 | return 0; |
341 | } | | 341 | } |
342 | | | 342 | |
343 | static int | | 343 | static int |
344 | dmclose(dev_t dev, int flags, int mode, struct lwp *l) | | 344 | dmclose(dev_t dev, int flags, int mode, struct lwp *l) |
345 | { | | 345 | { |
346 | | | 346 | |
347 | aprint_debug("dm close routine called %" PRIu32 "\n", minor(dev)); | | 347 | aprint_debug("dm close routine called %" PRIu32 "\n", minor(dev)); |
348 | return 0; | | 348 | return 0; |
349 | } | | 349 | } |
350 | | | 350 | |
351 | | | 351 | |
352 | static int | | 352 | static int |
353 | dmioctl(dev_t dev, const u_long cmd, void *data, int flag, struct lwp *l) | | 353 | dmioctl(dev_t dev, const u_long cmd, void *data, int flag, struct lwp *l) |
354 | { | | 354 | { |
355 | int r; | | 355 | int r; |
356 | prop_dictionary_t dm_dict_in; | | 356 | prop_dictionary_t dm_dict_in; |
357 | | | 357 | |
358 | r = 0; | | 358 | r = 0; |
359 | | | 359 | |
360 | aprint_debug("dmioctl called\n"); | | 360 | aprint_debug("dmioctl called\n"); |
361 | KASSERT(data != NULL); | | 361 | KASSERT(data != NULL); |
362 | | | 362 | |
363 | if ((r = disk_ioctl_switch(dev, cmd, data)) == ENOTTY) { | | 363 | if ((r = disk_ioctl_switch(dev, cmd, data)) == ENOTTY) { |
364 | struct plistref *pref = (struct plistref *) data; | | 364 | struct plistref *pref = (struct plistref *) data; |
365 | | | 365 | |
366 | /* Check if we were called with NETBSD_DM_IOCTL ioctl | | 366 | /* Check if we were called with NETBSD_DM_IOCTL ioctl |
367 | otherwise quit. */ | | 367 | otherwise quit. */ |
368 | if ((r = dm_ioctl_switch(cmd)) != 0) | | 368 | if ((r = dm_ioctl_switch(cmd)) != 0) |
369 | return r; | | 369 | return r; |
370 | | | 370 | |
371 | if((r = prop_dictionary_copyin_ioctl(pref, cmd, &dm_dict_in)) | | 371 | if((r = prop_dictionary_copyin_ioctl(pref, cmd, &dm_dict_in)) |
372 | != 0) | | 372 | != 0) |
373 | return r; | | 373 | return r; |
374 | | | 374 | |
375 | if ((r = dm_check_version(dm_dict_in)) != 0) | | 375 | if ((r = dm_check_version(dm_dict_in)) != 0) |
376 | goto cleanup_exit; | | 376 | goto cleanup_exit; |
377 | | | 377 | |
378 | /* run ioctl routine */ | | 378 | /* run ioctl routine */ |
379 | if ((r = dm_cmd_to_fun(dm_dict_in)) != 0) | | 379 | if ((r = dm_cmd_to_fun(dm_dict_in)) != 0) |
380 | goto cleanup_exit; | | 380 | goto cleanup_exit; |
381 | | | 381 | |
382 | cleanup_exit: | | 382 | cleanup_exit: |
383 | r = prop_dictionary_copyout_ioctl(pref, cmd, dm_dict_in); | | 383 | r = prop_dictionary_copyout_ioctl(pref, cmd, dm_dict_in); |
384 | prop_object_release(dm_dict_in); | | 384 | prop_object_release(dm_dict_in); |
385 | } | | 385 | } |
386 | | | 386 | |
387 | return r; | | 387 | return r; |
388 | } | | 388 | } |
389 | | | 389 | |
390 | /* | | 390 | /* |
391 | * Translate command sent from libdevmapper to func. | | 391 | * Translate command sent from libdevmapper to func. |
392 | */ | | 392 | */ |
393 | static int | | 393 | static int |
394 | dm_cmd_to_fun(prop_dictionary_t dm_dict) | | 394 | dm_cmd_to_fun(prop_dictionary_t dm_dict) |
395 | { | | 395 | { |
396 | int i, r; | | 396 | int i, r; |
397 | prop_string_t command; | | 397 | prop_string_t command; |
398 | | | 398 | |
399 | r = 0; | | 399 | r = 0; |
400 | | | 400 | |
401 | if ((command = prop_dictionary_get(dm_dict, DM_IOCTL_COMMAND)) == NULL) | | 401 | if ((command = prop_dictionary_get(dm_dict, DM_IOCTL_COMMAND)) == NULL) |
402 | return EINVAL; | | 402 | return EINVAL; |
403 | | | 403 | |
404 | for(i = 0; cmd_fn[i].cmd != NULL; i++) | | 404 | for(i = 0; cmd_fn[i].cmd != NULL; i++) |
405 | if (prop_string_equals_cstring(command, cmd_fn[i].cmd)) | | 405 | if (prop_string_equals_cstring(command, cmd_fn[i].cmd)) |
406 | break; | | 406 | break; |
407 | | | 407 | |
408 | if (!cmd_fn[i].allowed && | | 408 | if (!cmd_fn[i].allowed && |
409 | (r = kauth_authorize_system(kauth_cred_get(), | | 409 | (r = kauth_authorize_system(kauth_cred_get(), |
410 | KAUTH_SYSTEM_DEVMAPPER, 0, NULL, NULL, NULL)) != 0) | | 410 | KAUTH_SYSTEM_DEVMAPPER, 0, NULL, NULL, NULL)) != 0) |
411 | return r; | | 411 | return r; |
412 | | | 412 | |
413 | if (cmd_fn[i].cmd == NULL) | | 413 | if (cmd_fn[i].cmd == NULL) |
414 | return EINVAL; | | 414 | return EINVAL; |
415 | | | 415 | |
416 | aprint_debug("ioctl %s called\n", cmd_fn[i].cmd); | | 416 | aprint_debug("ioctl %s called\n", cmd_fn[i].cmd); |
417 | r = cmd_fn[i].fn(dm_dict); | | 417 | r = cmd_fn[i].fn(dm_dict); |
418 | | | 418 | |
419 | return r; | | 419 | return r; |
420 | } | | 420 | } |
421 | | | 421 | |
422 | /* Call apropriate ioctl handler function. */ | | 422 | /* Call apropriate ioctl handler function. */ |
423 | static int | | 423 | static int |
424 | dm_ioctl_switch(u_long cmd) | | 424 | dm_ioctl_switch(u_long cmd) |
425 | { | | 425 | { |
426 | | | 426 | |
427 | switch(cmd) { | | 427 | switch(cmd) { |
428 | case NETBSD_DM_IOCTL: | | 428 | case NETBSD_DM_IOCTL: |
429 | aprint_debug("dm NetBSD_DM_IOCTL called\n"); | | 429 | aprint_debug("dm NetBSD_DM_IOCTL called\n"); |
430 | break; | | 430 | break; |
431 | default: | | 431 | default: |
432 | aprint_debug("dm unknown ioctl called\n"); | | 432 | aprint_debug("dm unknown ioctl called\n"); |
433 | return ENOTTY; | | 433 | return ENOTTY; |
434 | break; /* NOT REACHED */ | | 434 | break; /* NOT REACHED */ |
435 | } | | 435 | } |
436 | | | 436 | |
437 | return 0; | | 437 | return 0; |
438 | } | | 438 | } |
439 | | | 439 | |
440 | /* | | 440 | /* |
441 | * Check for disk specific ioctls. | | 441 | * Check for disk specific ioctls. |
442 | */ | | 442 | */ |
443 | | | 443 | |
444 | static int | | 444 | static int |
445 | disk_ioctl_switch(dev_t dev, u_long cmd, void *data) | | 445 | disk_ioctl_switch(dev_t dev, u_long cmd, void *data) |
446 | { | | 446 | { |
447 | dm_dev_t *dmv; | | 447 | dm_dev_t *dmv; |
448 | | | 448 | |
449 | /* disk ioctls make sense only on block devices */ | | 449 | /* disk ioctls make sense only on block devices */ |
450 | if (minor(dev) == 0) | | 450 | if (minor(dev) == 0) |
451 | return ENOTTY; | | 451 | return ENOTTY; |
452 | | | 452 | |
453 | switch(cmd) { | | 453 | switch(cmd) { |
454 | case DIOCGWEDGEINFO: | | 454 | case DIOCGWEDGEINFO: |
455 | { | | 455 | { |
456 | struct dkwedge_info *dkw = (void *) data; | | 456 | struct dkwedge_info *dkw = (void *) data; |
457 | unsigned secsize; | | 457 | unsigned secsize; |
458 | | | 458 | |
459 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) | | 459 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) |
460 | return ENODEV; | | 460 | return ENODEV; |
461 | | | 461 | |
462 | aprint_debug("DIOCGWEDGEINFO ioctl called\n"); | | 462 | aprint_debug("DIOCGWEDGEINFO ioctl called\n"); |
463 | | | 463 | |
464 | strlcpy(dkw->dkw_devname, dmv->name, 16); | | 464 | strlcpy(dkw->dkw_devname, dmv->name, 16); |
465 | strlcpy(dkw->dkw_wname, dmv->name, DM_NAME_LEN); | | 465 | strlcpy(dkw->dkw_wname, dmv->name, DM_NAME_LEN); |
466 | strlcpy(dkw->dkw_parent, dmv->name, 16); | | 466 | strlcpy(dkw->dkw_parent, dmv->name, 16); |
467 | | | 467 | |
468 | dkw->dkw_offset = 0; | | 468 | dkw->dkw_offset = 0; |
469 | dm_table_disksize(&dmv->table_head, &dkw->dkw_size, &secsize); | | 469 | dm_table_disksize(&dmv->table_head, &dkw->dkw_size, &secsize); |
470 | strcpy(dkw->dkw_ptype, DKW_PTYPE_FFS); | | 470 | strcpy(dkw->dkw_ptype, DKW_PTYPE_FFS); |
471 | | | 471 | |
472 | dm_dev_unbusy(dmv); | | 472 | dm_dev_unbusy(dmv); |
473 | break; | | 473 | break; |
474 | } | | 474 | } |
475 | | | 475 | |
476 | case DIOCGDISKINFO: | | 476 | case DIOCGDISKINFO: |
477 | { | | 477 | { |
478 | struct plistref *pref = (struct plistref *) data; | | 478 | struct plistref *pref = (struct plistref *) data; |
479 | | | 479 | |
480 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) | | 480 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) |
481 | return ENODEV; | | 481 | return ENODEV; |
482 | | | 482 | |
483 | if (dmv->diskp->dk_info == NULL) { | | 483 | if (dmv->diskp->dk_info == NULL) { |
484 | dm_dev_unbusy(dmv); | | 484 | dm_dev_unbusy(dmv); |
485 | return ENOTSUP; | | 485 | return ENOTSUP; |
486 | } else | | 486 | } else |
487 | prop_dictionary_copyout_ioctl(pref, cmd, | | 487 | prop_dictionary_copyout_ioctl(pref, cmd, |
488 | dmv->diskp->dk_info); | | 488 | dmv->diskp->dk_info); |
489 | | | 489 | |
490 | dm_dev_unbusy(dmv); | | 490 | dm_dev_unbusy(dmv); |
491 | break; | | 491 | break; |
492 | } | | 492 | } |
493 | | | 493 | |
494 | case DIOCCACHESYNC: | | 494 | case DIOCCACHESYNC: |
495 | { | | 495 | { |
496 | dm_table_entry_t *table_en; | | 496 | dm_table_entry_t *table_en; |
497 | dm_table_t *tbl; | | 497 | dm_table_t *tbl; |
498 | | | 498 | |
499 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) | | 499 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) |
500 | return ENODEV; | | 500 | return ENODEV; |
501 | | | 501 | |
502 | /* Select active table */ | | 502 | /* Select active table */ |
503 | tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE); | | 503 | tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE); |
504 | | | 504 | |
505 | /* | | 505 | /* |
506 | * Call sync target routine for all table entries. Target sync | | 506 | * Call sync target routine for all table entries. Target sync |
507 | * routine basically call DIOCCACHESYNC on underlying devices. | | 507 | * routine basically call DIOCCACHESYNC on underlying devices. |
508 | */ | | 508 | */ |
509 | SLIST_FOREACH(table_en, tbl, next) { | | 509 | SLIST_FOREACH(table_en, tbl, next) { |
510 | (void)table_en->target->sync(table_en); | | 510 | (void)table_en->target->sync(table_en); |
511 | } | | 511 | } |
512 | dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE); | | 512 | dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE); |
513 | dm_dev_unbusy(dmv); | | 513 | dm_dev_unbusy(dmv); |
514 | break; | | 514 | break; |
515 | } | | 515 | } |
516 | | | 516 | |
517 | case DIOCGSECTORSIZE: | | 517 | case DIOCGSECTORSIZE: |
518 | { | | 518 | { |
519 | u_int *valp = data; | | 519 | u_int *valp = data; |
520 | uint64_t numsec; | | 520 | uint64_t numsec; |
521 | unsigned int secsize; | | 521 | unsigned int secsize; |
522 | | | 522 | |
523 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) | | 523 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) |
524 | return ENODEV; | | 524 | return ENODEV; |
525 | | | 525 | |
526 | aprint_debug("DIOCGSECTORSIZE ioctl called\n"); | | 526 | aprint_debug("DIOCGSECTORSIZE ioctl called\n"); |
527 | | | 527 | |
528 | dm_table_disksize(&dmv->table_head, &numsec, &secsize); | | 528 | dm_table_disksize(&dmv->table_head, &numsec, &secsize); |
529 | *valp = secsize; | | 529 | *valp = secsize; |
530 | | | 530 | |
531 | dm_dev_unbusy(dmv); | | 531 | dm_dev_unbusy(dmv); |
532 | break; | | 532 | break; |
533 | } | | 533 | } |
534 | | | 534 | |
535 | case DIOCGMEDIASIZE: | | 535 | case DIOCGMEDIASIZE: |
536 | { | | 536 | { |
537 | off_t *valp = data; | | 537 | off_t *valp = data; |
538 | uint64_t numsec; | | 538 | uint64_t numsec; |
539 | unsigned int secsize; | | 539 | unsigned int secsize; |
540 | | | 540 | |
541 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) | | 541 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) |
542 | return ENODEV; | | 542 | return ENODEV; |
543 | | | 543 | |
544 | aprint_debug("DIOCGMEDIASIZE ioctl called\n"); | | 544 | aprint_debug("DIOCGMEDIASIZE ioctl called\n"); |
545 | | | 545 | |
546 | dm_table_disksize(&dmv->table_head, &numsec, &secsize); | | 546 | dm_table_disksize(&dmv->table_head, &numsec, &secsize); |
547 | *valp = numsec; | | 547 | *valp = numsec; |
548 | | | 548 | |
549 | dm_dev_unbusy(dmv); | | 549 | dm_dev_unbusy(dmv); |
550 | break; | | 550 | break; |
551 | } | | 551 | } |
552 | | | 552 | |
553 | default: | | 553 | default: |
554 | aprint_debug("unknown disk_ioctl called\n"); | | 554 | aprint_debug("unknown disk_ioctl called\n"); |
555 | return ENOTTY; | | 555 | return ENOTTY; |
556 | break; /* NOT REACHED */ | | 556 | break; /* NOT REACHED */ |
557 | } | | 557 | } |
558 | | | 558 | |
559 | return 0; | | 559 | return 0; |
560 | } | | 560 | } |
561 | | | 561 | |
562 | /* | | 562 | /* |
563 | * Do all IO operations on dm logical devices. | | 563 | * Do all IO operations on dm logical devices. |
564 | */ | | 564 | */ |
565 | static void | | 565 | static void |
566 | dmstrategy(struct buf *bp) | | 566 | dmstrategy(struct buf *bp) |
567 | { | | 567 | { |
568 | dm_dev_t *dmv; | | 568 | dm_dev_t *dmv; |
569 | dm_table_t *tbl; | | 569 | dm_table_t *tbl; |
570 | dm_table_entry_t *table_en; | | 570 | dm_table_entry_t *table_en; |
571 | struct buf *nestbuf; | | 571 | struct buf *nestbuf; |
572 | | | 572 | |
573 | uint64_t buf_start, buf_len, issued_len; | | 573 | uint64_t buf_start, buf_len, issued_len; |
574 | uint64_t table_start, table_end; | | 574 | uint64_t table_start, table_end; |
575 | uint64_t start, end; | | 575 | uint64_t start, end; |
576 | | | 576 | |
577 | buf_start = bp->b_blkno * DEV_BSIZE; | | 577 | buf_start = bp->b_blkno * DEV_BSIZE; |
578 | buf_len = bp->b_bcount; | | 578 | buf_len = bp->b_bcount; |
579 | | | 579 | |
580 | tbl = NULL; | | 580 | tbl = NULL; |
581 | | | 581 | |
582 | table_end = 0; | | 582 | table_end = 0; |
583 | issued_len = 0; | | 583 | issued_len = 0; |
584 | | | 584 | |
585 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(bp->b_dev))) == NULL) { | | 585 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(bp->b_dev))) == NULL) { |
586 | bp->b_error = EIO; | | 586 | bp->b_error = EIO; |
587 | bp->b_resid = bp->b_bcount; | | 587 | bp->b_resid = bp->b_bcount; |
588 | biodone(bp); | | 588 | biodone(bp); |
589 | return; | | 589 | return; |
590 | } | | 590 | } |
591 | | | 591 | |
592 | if (bounds_check_with_mediasize(bp, DEV_BSIZE, | | 592 | if (bounds_check_with_mediasize(bp, DEV_BSIZE, |
593 | dm_table_size(&dmv->table_head)) <= 0) { | | 593 | dm_table_size(&dmv->table_head)) <= 0) { |
594 | dm_dev_unbusy(dmv); | | 594 | dm_dev_unbusy(dmv); |
595 | bp->b_resid = bp->b_bcount; | | 595 | bp->b_resid = bp->b_bcount; |
596 | biodone(bp); | | 596 | biodone(bp); |
597 | return; | | 597 | return; |
598 | } | | 598 | } |
599 | | | 599 | |
600 | /* | | 600 | /* |
601 | * disk(9) is part of device structure and it can't be used without | | 601 | * disk(9) is part of device structure and it can't be used without |
602 | * mutual exclusion, use diskp_mtx until it will be fixed. | | 602 | * mutual exclusion, use diskp_mtx until it will be fixed. |
603 | */ | | 603 | */ |
604 | mutex_enter(&dmv->diskp_mtx); | | 604 | mutex_enter(&dmv->diskp_mtx); |
605 | disk_busy(dmv->diskp); | | 605 | disk_busy(dmv->diskp); |
606 | mutex_exit(&dmv->diskp_mtx); | | 606 | mutex_exit(&dmv->diskp_mtx); |
607 | | | 607 | |
608 | /* Select active table */ | | 608 | /* Select active table */ |
609 | tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE); | | 609 | tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE); |
610 | | | 610 | |
611 | /* Nested buffers count down to zero therefore I have | | 611 | /* Nested buffers count down to zero therefore I have |
612 | to set bp->b_resid to maximal value. */ | | 612 | to set bp->b_resid to maximal value. */ |
613 | bp->b_resid = bp->b_bcount; | | 613 | bp->b_resid = bp->b_bcount; |
614 | | | 614 | |
615 | /* | | 615 | /* |
616 | * Find out what tables I want to select. | | 616 | * Find out what tables I want to select. |
617 | */ | | 617 | */ |
618 | SLIST_FOREACH(table_en, tbl, next) { | | 618 | SLIST_FOREACH(table_en, tbl, next) { |
619 | /* I need need number of bytes not blocks. */ | | 619 | /* I need number of bytes not blocks. */ |
620 | table_start = table_en->start * DEV_BSIZE; | | 620 | table_start = table_en->start * DEV_BSIZE; |
621 | /* | | 621 | /* |
622 | * I have to sub 1 from table_en->length to prevent | | 622 | * I have to sub 1 from table_en->length to prevent |
623 | * off by one error | | 623 | * off by one error |
624 | */ | | 624 | */ |
625 | table_end = table_start + (table_en->length)* DEV_BSIZE; | | 625 | table_end = table_start + table_en->length * DEV_BSIZE; |
626 | | | 626 | |
627 | start = MAX(table_start, buf_start); | | 627 | start = MAX(table_start, buf_start); |
628 | | | 628 | |
629 | end = MIN(table_end, buf_start + buf_len); | | 629 | end = MIN(table_end, buf_start + buf_len); |
630 | | | 630 | |
631 | aprint_debug("----------------------------------------\n"); | | 631 | aprint_debug("----------------------------------------\n"); |
632 | aprint_debug("table_start %010" PRIu64", table_end %010" | | 632 | aprint_debug("table_start %010" PRIu64", table_end %010" |
633 | PRIu64 "\n", table_start, table_end); | | 633 | PRIu64 "\n", table_start, table_end); |
634 | aprint_debug("buf_start %010" PRIu64", buf_len %010" | | 634 | aprint_debug("buf_start %010" PRIu64", buf_len %010" |
635 | PRIu64"\n", buf_start, buf_len); | | 635 | PRIu64"\n", buf_start, buf_len); |
636 | aprint_debug("start-buf_start %010"PRIu64", end %010" | | 636 | aprint_debug("start-buf_start %010"PRIu64", end %010" |
637 | PRIu64"\n", start - buf_start, end); | | 637 | PRIu64"\n", start - buf_start, end); |
638 | aprint_debug("start %010" PRIu64" , end %010" | | 638 | aprint_debug("start %010" PRIu64" , end %010" |
639 | PRIu64"\n", start, end); | | 639 | PRIu64"\n", start, end); |
640 | aprint_debug("\n----------------------------------------\n"); | | 640 | aprint_debug("\n----------------------------------------\n"); |
641 | | | 641 | |
642 | if (start < end) { | | 642 | if (start < end) { |
643 | /* create nested buffer */ | | 643 | /* create nested buffer */ |
644 | nestbuf = getiobuf(NULL, true); | | 644 | nestbuf = getiobuf(NULL, true); |
645 | | | 645 | |
646 | nestiobuf_setup(bp, nestbuf, start - buf_start, | | 646 | nestiobuf_setup(bp, nestbuf, start - buf_start, |
647 | (end - start)); | | 647 | (end - start)); |
648 | | | 648 | |
649 | issued_len += end - start; | | 649 | issued_len += end - start; |
650 | | | 650 | |
651 | /* I need number of blocks. */ | | 651 | /* I need number of blocks. */ |
652 | nestbuf->b_blkno = (start - table_start) / DEV_BSIZE; | | 652 | nestbuf->b_blkno = (start - table_start) / DEV_BSIZE; |
653 | | | 653 | |
654 | table_en->target->strategy(table_en, nestbuf); | | 654 | table_en->target->strategy(table_en, nestbuf); |
655 | } | | 655 | } |
656 | } | | 656 | } |
657 | | | 657 | |
658 | if (issued_len < buf_len) | | 658 | if (issued_len < buf_len) |
659 | nestiobuf_done(bp, buf_len - issued_len, EINVAL); | | 659 | nestiobuf_done(bp, buf_len - issued_len, EINVAL); |
660 | | | 660 | |
661 | mutex_enter(&dmv->diskp_mtx); | | 661 | mutex_enter(&dmv->diskp_mtx); |
662 | disk_unbusy(dmv->diskp, buf_len, bp != NULL ? bp->b_flags & B_READ : 0); | | 662 | disk_unbusy(dmv->diskp, buf_len, bp != NULL ? bp->b_flags & B_READ : 0); |
663 | mutex_exit(&dmv->diskp_mtx); | | 663 | mutex_exit(&dmv->diskp_mtx); |
664 | | | 664 | |
665 | dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE); | | 665 | dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE); |
666 | dm_dev_unbusy(dmv); | | 666 | dm_dev_unbusy(dmv); |
667 | } | | 667 | } |
668 | | | 668 | |
669 | | | 669 | |
670 | static int | | 670 | static int |
671 | dmread(dev_t dev, struct uio *uio, int flag) | | 671 | dmread(dev_t dev, struct uio *uio, int flag) |
672 | { | | 672 | { |
673 | | | 673 | |
674 | return (physio(dmstrategy, NULL, dev, B_READ, dmminphys, uio)); | | 674 | return (physio(dmstrategy, NULL, dev, B_READ, dmminphys, uio)); |
675 | } | | 675 | } |
676 | | | 676 | |
677 | static int | | 677 | static int |
678 | dmwrite(dev_t dev, struct uio *uio, int flag) | | 678 | dmwrite(dev_t dev, struct uio *uio, int flag) |
679 | { | | 679 | { |
680 | | | 680 | |
681 | return (physio(dmstrategy, NULL, dev, B_WRITE, dmminphys, uio)); | | 681 | return (physio(dmstrategy, NULL, dev, B_WRITE, dmminphys, uio)); |
682 | } | | 682 | } |
683 | | | 683 | |
684 | static int | | 684 | static int |
685 | dmsize(dev_t dev) | | 685 | dmsize(dev_t dev) |
686 | { | | 686 | { |
687 | dm_dev_t *dmv; | | 687 | dm_dev_t *dmv; |
688 | uint64_t size; | | 688 | uint64_t size; |
689 | | | 689 | |
690 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) | | 690 | if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) |
691 | return -ENOENT; | | 691 | return -ENOENT; |
692 | | | 692 | |
693 | size = dm_table_size(&dmv->table_head); | | 693 | size = dm_table_size(&dmv->table_head); |
694 | dm_dev_unbusy(dmv); | | 694 | dm_dev_unbusy(dmv); |
695 | | | 695 | |
696 | return size; | | 696 | return size; |
697 | } | | 697 | } |
698 | | | 698 | |
699 | static void | | 699 | static void |
700 | dmminphys(struct buf *bp) | | 700 | dmminphys(struct buf *bp) |
701 | { | | 701 | { |
702 | | | 702 | |
703 | bp->b_bcount = MIN(bp->b_bcount, MAXPHYS); | | 703 | bp->b_bcount = MIN(bp->b_bcount, MAXPHYS); |
704 | } | | 704 | } |
705 | | | 705 | |
706 | void | | 706 | void |
707 | dmgetproperties(struct disk *disk, dm_table_head_t *head) | | 707 | dmgetproperties(struct disk *disk, dm_table_head_t *head) |
708 | { | | 708 | { |
709 | uint64_t numsec; | | 709 | uint64_t numsec; |
710 | unsigned secsize; | | 710 | unsigned secsize; |
711 | | | 711 | |
712 | dm_table_disksize(head, &numsec, &secsize); | | 712 | dm_table_disksize(head, &numsec, &secsize); |
713 | | | 713 | |
714 | struct disk_geom *dg = &disk->dk_geom; | | 714 | struct disk_geom *dg = &disk->dk_geom; |
715 | | | 715 | |
716 | memset(dg, 0, sizeof(*dg)); | | 716 | memset(dg, 0, sizeof(*dg)); |
717 | dg->dg_secperunit = numsec; | | 717 | dg->dg_secperunit = numsec; |
718 | dg->dg_secsize = secsize; | | 718 | dg->dg_secsize = secsize; |
719 | dg->dg_nsectors = 32; | | 719 | dg->dg_nsectors = 32; |
720 | dg->dg_ntracks = 64; | | 720 | dg->dg_ntracks = 64; |
721 | | | 721 | |
722 | disk_set_info(NULL, disk, "ESDI"); | | 722 | disk_set_info(NULL, disk, "ESDI"); |
723 | } | | 723 | } |