Commit | Line | Data |
---|---|---|
ff56536e AH |
1 | /* $NetBSD: dm_ioctl.c,v 1.21 2010/02/25 20:48:58 jakllsch Exp $ */ |
2 | ||
3 | /* | |
ba2ce341 | 4 | * Copyright (c) 2010-2011 Alex Hornung <alex@alexhornung.com> |
ff56536e AH |
5 | * Copyright (c) 2008 The NetBSD Foundation, Inc. |
6 | * All rights reserved. | |
7 | * | |
8 | * This code is derived from software contributed to The NetBSD Foundation | |
9 | * by Adam Hamsik. | |
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 | * Locking is used to synchronise between ioctl calls and between dm_table's | |
35 | * users. | |
36 | * | |
37 | * ioctl locking: | |
38 | * Simple reference counting, to count users of device will be used routines | |
39 | * dm_dev_busy/dm_dev_unbusy are used for that. | |
40 | * dm_dev_lookup/dm_dev_rem call dm_dev_busy before return(caller is therefore | |
41 | * holder of reference_counter last). | |
42 | * | |
43 | * ioctl routines which change/remove dm_dev parameters must wait on | |
44 | * dm_dev::dev_cv and when last user will call dm_dev_unbusy they will wake | |
45 | * up them. | |
46 | * | |
47 | * table_head locking: | |
48 | * To access table entries dm_table_* routines must be used. | |
49 | * | |
50 | * dm_table_get_entry will increment table users reference | |
5b279a20 | 51 | * counter. It will return active or inactive table depends |
ff56536e AH |
52 | * on uint8_t argument. |
53 | * | |
54 | * dm_table_release must be called for every table_entry from | |
55 | * dm_table_get_entry. Between these to calls tables can'tbe switched | |
56 | * or destroyed. | |
57 | * | |
3cd1dc08 | 58 | * dm_table_head_init initialize talbe_entries TAILQS and io_cv. |
ff56536e AH |
59 | * |
60 | * dm_table_head_destroy destroy cv. | |
61 | * | |
62 | * There are two types of users for dm_table_head first type will | |
63 | * only read list and try to do anything with it e.g. dmstrategy, | |
64 | * dm_table_size etc. There is another user for table_head which wants | |
65 | * to change table lists e.g. dm_dev_resume_ioctl, dm_dev_remove_ioctl, | |
66 | * dm_table_clear_ioctl. | |
67 | * | |
68 | * NOTE: It is not allowed to call dm_table_destroy, dm_table_switch_tables | |
69 | * with hold table reference counter. Table reference counter is hold | |
70 | * after calling dm_table_get_entry routine. After calling this | |
71 | * function user must call dm_table_release before any writer table | |
72 | * operation. | |
73 | * | |
74 | * Example: dm_table_get_entry | |
75 | * dm_table_destroy/dm_table_switch_tables | |
76 | * This exaple will lead to deadlock situation because after dm_table_get_entry | |
77 | * table reference counter is != 0 and dm_table_destroy have to wait on cv until | |
78 | * reference counter is 0. | |
79 | * | |
80 | */ | |
81 | ||
ff56536e | 82 | #include <sys/device.h> |
5b279a20 | 83 | #include <sys/malloc.h> |
30ef4508 | 84 | #include <cpu/atomic.h> |
a84e173e | 85 | #include <dev/disk/dm/dm.h> |
30ef4508 | 86 | #include <dev/disk/dm/netbsd-dm.h> |
ff56536e | 87 | |
d471f1f9 TK |
88 | static int |
89 | dm_table_deps(dm_table_entry_t *, prop_array_t); | |
f28e17b7 TK |
90 | static int |
91 | dm_table_init(dm_target_t *, dm_table_entry_t *, char *); | |
e243a4fb | 92 | static int |
895c8e52 | 93 | dm_table_status(dm_table_entry_t *, prop_dictionary_t, uint32_t); |
d471f1f9 | 94 | |
157bcf9e TK |
95 | static __inline |
96 | void dm_add_flag(prop_dictionary_t dp, uint32_t *fp, const uint32_t val) | |
97 | { | |
98 | KKASSERT(dp != NULL); | |
99 | prop_dictionary_get_uint32(dp, DM_IOCTL_FLAGS, fp); | |
100 | (*fp) |= val; | |
101 | prop_dictionary_set_uint32(dp, DM_IOCTL_FLAGS, *fp); | |
102 | KKASSERT((*fp) & val); | |
103 | } | |
104 | ||
105 | static __inline | |
106 | void dm_remove_flag(prop_dictionary_t dp, uint32_t *fp, const uint32_t val) | |
107 | { | |
108 | KKASSERT(dp != NULL); | |
109 | prop_dictionary_get_uint32(dp, DM_IOCTL_FLAGS, fp); | |
110 | (*fp) &= ~val; | |
111 | prop_dictionary_set_uint32(dp, DM_IOCTL_FLAGS, *fp); | |
112 | KKASSERT(!((*fp) & val)); | |
113 | } | |
114 | ||
ff56536e | 115 | /* |
b7c11cda | 116 | * Print flags sent to the kernel from libdevmapper. |
ff56536e AH |
117 | */ |
118 | static int | |
895c8e52 | 119 | dm_dbg_print_flags(uint32_t flags) |
ff56536e | 120 | { |
5f3bf2b2 TK |
121 | if (dm_debug_level == 0) |
122 | return 1; | |
ff56536e | 123 | |
5f3bf2b2 | 124 | kprintf("%s --- flags=%08X\n", __func__, flags); |
ff56536e | 125 | |
5f3bf2b2 TK |
126 | if (flags & DM_READONLY_FLAG) |
127 | kprintf(" DM_READONLY_FLAG\n"); | |
ff56536e | 128 | if (flags & DM_SUSPEND_FLAG) |
5f3bf2b2 TK |
129 | kprintf(" DM_SUSPEND_FLAG\n"); |
130 | if (flags & DM_EXISTS_FLAG) | |
131 | kprintf(" DM_EXISTS_FLAG\n"); | |
ff56536e | 132 | if (flags & DM_PERSISTENT_DEV_FLAG) |
5f3bf2b2 | 133 | kprintf(" DM_PERSISTENT_DEV_FLAG\n"); |
ff56536e | 134 | if (flags & DM_STATUS_TABLE_FLAG) |
5f3bf2b2 | 135 | kprintf(" DM_STATUS_TABLE_FLAG\n"); |
ff56536e | 136 | if (flags & DM_ACTIVE_PRESENT_FLAG) |
5f3bf2b2 | 137 | kprintf(" DM_ACTIVE_PRESENT_FLAG\n"); |
ff56536e | 138 | if (flags & DM_INACTIVE_PRESENT_FLAG) |
5f3bf2b2 | 139 | kprintf(" DM_INACTIVE_PRESENT_FLAG\n"); |
ff56536e | 140 | if (flags & DM_BUFFER_FULL_FLAG) |
5f3bf2b2 | 141 | kprintf(" DM_BUFFER_FULL_FLAG\n"); |
ff56536e | 142 | if (flags & DM_SKIP_BDGET_FLAG) |
5f3bf2b2 | 143 | kprintf(" DM_SKIP_BDGET_FLAG\n"); |
ff56536e | 144 | if (flags & DM_SKIP_LOCKFS_FLAG) |
5f3bf2b2 | 145 | kprintf(" DM_SKIP_LOCKFS_FLAG\n"); |
ff56536e | 146 | if (flags & DM_NOFLUSH_FLAG) |
5f3bf2b2 TK |
147 | kprintf(" DM_NOFLUSH_FLAG\n"); |
148 | if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) | |
149 | kprintf(" DM_QUERY_INACTIVE_TABLE_FLAG\n"); | |
150 | if (flags & DM_UUID_FLAG) | |
151 | kprintf(" DM_UUID_FLAG\n"); | |
152 | if (flags & DM_SECURE_DATA_FLAG) | |
153 | kprintf(" DM_SECURE_DATA_FLAG\n"); | |
ff56536e AH |
154 | |
155 | return 0; | |
156 | } | |
b7c11cda | 157 | |
ff56536e AH |
158 | /* |
159 | * Get list of all available targets from global | |
160 | * target list and sent them back to libdevmapper. | |
161 | */ | |
162 | int | |
163 | dm_list_versions_ioctl(prop_dictionary_t dm_dict) | |
164 | { | |
165 | prop_array_t target_list; | |
166 | uint32_t flags; | |
167 | ||
168 | flags = 0; | |
169 | ||
170 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
171 | ||
172 | dm_dbg_print_flags(flags); | |
173 | target_list = dm_target_prop_list(); | |
174 | ||
175 | prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, target_list); | |
176 | prop_object_release(target_list); | |
177 | ||
178 | return 0; | |
179 | } | |
b7c11cda | 180 | |
ff56536e AH |
181 | /* |
182 | * Create in-kernel entry for device. Device attributes such as name, uuid are | |
183 | * taken from proplib dictionary. | |
ff56536e AH |
184 | */ |
185 | int | |
186 | dm_dev_create_ioctl(prop_dictionary_t dm_dict) | |
187 | { | |
188 | dm_dev_t *dmv; | |
189 | const char *name, *uuid; | |
895c8e52 TK |
190 | int r; |
191 | uint32_t flags; | |
ff56536e AH |
192 | |
193 | r = 0; | |
194 | flags = 0; | |
195 | name = NULL; | |
196 | uuid = NULL; | |
197 | ||
198 | /* Get needed values from dictionary. */ | |
199 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | |
200 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | |
201 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
202 | ||
203 | dm_dbg_print_flags(flags); | |
204 | ||
205 | /* Lookup name and uuid if device already exist quit. */ | |
206 | if ((dmv = dm_dev_lookup(name, uuid, -1)) != NULL) { | |
157bcf9e | 207 | dm_add_flag(dm_dict, &flags, DM_EXISTS_FLAG); /* Device already exists */ |
ff56536e AH |
208 | dm_dev_unbusy(dmv); |
209 | return EEXIST; | |
210 | } | |
b878986e | 211 | |
9fada28a | 212 | r = dm_dev_create(&dmv, name, uuid, flags); |
9fada28a AH |
213 | if (r == 0) { |
214 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | |
157bcf9e TK |
215 | dm_add_flag(dm_dict, &flags, DM_EXISTS_FLAG); |
216 | dm_remove_flag(dm_dict, &flags, DM_INACTIVE_PRESENT_FLAG); | |
9fada28a | 217 | } |
ff56536e AH |
218 | |
219 | return r; | |
220 | } | |
b7c11cda | 221 | |
ff56536e | 222 | /* |
b7c11cda | 223 | * Get list of created device-mapper devices from global list and |
ff56536e AH |
224 | * send it to kernel. |
225 | * | |
226 | * Output dictionary: | |
227 | * | |
228 | * <key>cmd_data</key> | |
229 | * <array> | |
230 | * <dict> | |
231 | * <key>name<key> | |
232 | * <string>...</string> | |
233 | * | |
234 | * <key>dev</key> | |
235 | * <integer>...</integer> | |
236 | * </dict> | |
237 | * </array> | |
ff56536e AH |
238 | */ |
239 | int | |
240 | dm_dev_list_ioctl(prop_dictionary_t dm_dict) | |
241 | { | |
242 | prop_array_t dev_list; | |
243 | ||
244 | uint32_t flags; | |
245 | ||
246 | flags = 0; | |
247 | ||
248 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
249 | ||
250 | dm_dbg_print_flags(flags); | |
251 | ||
252 | dev_list = dm_dev_prop_list(); | |
253 | ||
254 | prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list); | |
255 | prop_object_release(dev_list); | |
256 | ||
257 | return 0; | |
258 | } | |
b7c11cda | 259 | |
ff56536e AH |
260 | /* |
261 | * Rename selected devices old name is in struct dm_ioctl. | |
b7c11cda | 262 | * new name is taken from dictionary. |
ff56536e AH |
263 | * |
264 | * <key>cmd_data</key> | |
265 | * <array> | |
266 | * <string>...</string> | |
267 | * </array> | |
268 | */ | |
269 | int | |
270 | dm_dev_rename_ioctl(prop_dictionary_t dm_dict) | |
271 | { | |
9fada28a | 272 | #if 0 |
ff56536e AH |
273 | prop_array_t cmd_array; |
274 | dm_dev_t *dmv; | |
275 | ||
276 | const char *name, *uuid, *n_name; | |
277 | uint32_t flags, minor; | |
278 | ||
279 | name = NULL; | |
280 | uuid = NULL; | |
281 | minor = 0; | |
282 | ||
283 | /* Get needed values from dictionary. */ | |
284 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | |
285 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | |
286 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
287 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | |
288 | ||
289 | dm_dbg_print_flags(flags); | |
290 | ||
291 | cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA); | |
292 | ||
293 | prop_array_get_cstring_nocopy(cmd_array, 0, &n_name); | |
294 | ||
295 | if (strlen(n_name) + 1 > DM_NAME_LEN) | |
296 | return EINVAL; | |
297 | ||
12f3b163 | 298 | if ((dmv = dm_dev_lookup_evict(name, uuid, minor)) == NULL) { |
157bcf9e | 299 | dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); |
ff56536e AH |
300 | return ENOENT; |
301 | } | |
302 | /* change device name */ | |
303 | /* | |
304 | * XXX How to deal with this change, name only used in | |
305 | * dm_dev_routines, should I add dm_dev_change_name which will run | |
306 | * under the dm_dev_list mutex ? | |
307 | */ | |
308 | strlcpy(dmv->name, n_name, DM_NAME_LEN); | |
309 | ||
310 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); | |
311 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | |
312 | prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); | |
313 | ||
314 | dm_dev_insert(dmv); | |
9fada28a | 315 | #endif |
ff56536e | 316 | |
9fada28a AH |
317 | /* |
318 | * XXX: the rename is not yet implemented. The main complication | |
319 | * here is devfs. We'd probably need a new function, rename_dev() | |
320 | * that would trigger a node rename in devfs. | |
321 | */ | |
322 | kprintf("dm_dev_rename_ioctl called, but not implemented!\n"); | |
83eeaffa | 323 | return ENOSYS; |
ff56536e | 324 | } |
9fada28a | 325 | |
ff56536e | 326 | /* |
9fada28a | 327 | * Remove device |
ff56536e AH |
328 | */ |
329 | int | |
330 | dm_dev_remove_ioctl(prop_dictionary_t dm_dict) | |
331 | { | |
332 | dm_dev_t *dmv; | |
333 | const char *name, *uuid; | |
ba65987c | 334 | uint32_t flags, minor, is_open; |
ff56536e AH |
335 | |
336 | flags = 0; | |
337 | name = NULL; | |
338 | uuid = NULL; | |
339 | ||
340 | /* Get needed values from dictionary. */ | |
341 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | |
342 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | |
343 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
344 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | |
345 | ||
346 | dm_dbg_print_flags(flags); | |
347 | ||
ff56536e | 348 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { |
157bcf9e | 349 | dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); |
ff56536e AH |
350 | return ENOENT; |
351 | } | |
ff56536e | 352 | |
ba65987c AH |
353 | is_open = dmv->is_open; |
354 | ||
ff56536e AH |
355 | dm_dev_unbusy(dmv); |
356 | ||
ba65987c | 357 | if (is_open) |
956c8d71 AH |
358 | return EBUSY; |
359 | ||
9fada28a | 360 | return dm_dev_remove(dmv); |
ff56536e | 361 | } |
9fada28a AH |
362 | |
363 | /* | |
364 | * Try to remove all devices | |
365 | */ | |
366 | int | |
367 | dm_dev_remove_all_ioctl(prop_dictionary_t dm_dict) | |
368 | { | |
369 | uint32_t flags = 0; | |
370 | ||
371 | /* Get needed values from dictionary. */ | |
372 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
373 | ||
374 | dm_dbg_print_flags(flags); | |
375 | ||
376 | /* Gently remove all devices, if possible */ | |
377 | return dm_dev_remove_all(1); | |
378 | } | |
379 | ||
ff56536e AH |
380 | /* |
381 | * Return actual state of device to libdevmapper. | |
382 | */ | |
383 | int | |
384 | dm_dev_status_ioctl(prop_dictionary_t dm_dict) | |
385 | { | |
386 | dm_dev_t *dmv; | |
387 | const char *name, *uuid; | |
388 | uint32_t flags, j, minor; | |
389 | ||
390 | name = NULL; | |
391 | uuid = NULL; | |
392 | flags = 0; | |
393 | j = 0; | |
394 | ||
395 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | |
396 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | |
397 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
398 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | |
399 | ||
400 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | |
157bcf9e | 401 | dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); |
ff56536e AH |
402 | return ENOENT; |
403 | } | |
404 | dm_dbg_print_flags(dmv->flags); | |
405 | ||
406 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); | |
407 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | |
408 | prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); | |
409 | ||
410 | if (dmv->flags & DM_SUSPEND_FLAG) | |
157bcf9e | 411 | dm_add_flag(dm_dict, &flags, DM_SUSPEND_FLAG); |
ff56536e AH |
412 | |
413 | /* | |
414 | * Add status flags for tables I have to check both active and | |
415 | * inactive tables. | |
416 | */ | |
b7c11cda | 417 | if ((j = dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE))) |
157bcf9e | 418 | dm_add_flag(dm_dict, &flags, DM_ACTIVE_PRESENT_FLAG); |
b7c11cda | 419 | else |
157bcf9e | 420 | dm_remove_flag(dm_dict, &flags, DM_ACTIVE_PRESENT_FLAG); |
ff56536e AH |
421 | |
422 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_TARGET_COUNT, j); | |
423 | ||
424 | if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE)) | |
157bcf9e | 425 | dm_add_flag(dm_dict, &flags, DM_INACTIVE_PRESENT_FLAG); |
ff56536e | 426 | else |
157bcf9e | 427 | dm_remove_flag(dm_dict, &flags, DM_INACTIVE_PRESENT_FLAG); |
ff56536e AH |
428 | |
429 | dm_dev_unbusy(dmv); | |
430 | ||
431 | return 0; | |
432 | } | |
b7c11cda | 433 | |
ff56536e AH |
434 | /* |
435 | * Set only flag to suggest that device is suspended. This call is | |
436 | * not supported in NetBSD. | |
ff56536e AH |
437 | */ |
438 | int | |
439 | dm_dev_suspend_ioctl(prop_dictionary_t dm_dict) | |
440 | { | |
441 | dm_dev_t *dmv; | |
442 | const char *name, *uuid; | |
443 | uint32_t flags, minor; | |
444 | ||
445 | name = NULL; | |
446 | uuid = NULL; | |
447 | flags = 0; | |
448 | ||
449 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | |
450 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | |
451 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
452 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | |
453 | ||
454 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | |
157bcf9e | 455 | dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); |
ff56536e AH |
456 | return ENOENT; |
457 | } | |
5b279a20 | 458 | atomic_set_int(&dmv->flags, DM_SUSPEND_FLAG); |
ff56536e AH |
459 | |
460 | dm_dbg_print_flags(dmv->flags); | |
461 | ||
462 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); | |
463 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags); | |
464 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | |
465 | ||
466 | dm_dev_unbusy(dmv); | |
467 | ||
468 | /* Add flags to dictionary flag after dmv -> dict copy */ | |
157bcf9e | 469 | dm_add_flag(dm_dict, &flags, DM_EXISTS_FLAG); |
ff56536e AH |
470 | |
471 | return 0; | |
472 | } | |
b7c11cda | 473 | |
ff56536e AH |
474 | /* |
475 | * Simulate Linux behaviour better and switch tables here and not in | |
476 | * dm_table_load_ioctl. | |
477 | */ | |
478 | int | |
479 | dm_dev_resume_ioctl(prop_dictionary_t dm_dict) | |
480 | { | |
481 | dm_dev_t *dmv; | |
482 | const char *name, *uuid; | |
483 | uint32_t flags, minor; | |
484 | ||
485 | name = NULL; | |
486 | uuid = NULL; | |
487 | flags = 0; | |
488 | ||
489 | /* | |
490 | * char *xml; xml = prop_dictionary_externalize(dm_dict); | |
323b0fc1 | 491 | * kprintf("%s\n",xml); |
ff56536e AH |
492 | */ |
493 | ||
494 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | |
495 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | |
496 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
497 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | |
498 | ||
499 | /* Remove device from global device list */ | |
500 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | |
157bcf9e | 501 | dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); |
ff56536e AH |
502 | return ENOENT; |
503 | } | |
5b279a20 AH |
504 | atomic_clear_int(&dmv->flags, (DM_SUSPEND_FLAG | DM_INACTIVE_PRESENT_FLAG)); |
505 | atomic_set_int(&dmv->flags, DM_ACTIVE_PRESENT_FLAG); | |
ff56536e AH |
506 | |
507 | dm_table_switch_tables(&dmv->table_head); | |
508 | ||
157bcf9e | 509 | dm_add_flag(dm_dict, &flags, DM_EXISTS_FLAG); |
ff56536e | 510 | |
5b279a20 | 511 | dmsetdiskinfo(dmv->diskp, &dmv->table_head); |
ff56536e AH |
512 | |
513 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); | |
514 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags); | |
515 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | |
516 | ||
517 | dm_dev_unbusy(dmv); | |
518 | ||
519 | /* Destroy inactive table after resume. */ | |
520 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); | |
521 | ||
522 | return 0; | |
523 | } | |
b7c11cda | 524 | |
ff56536e AH |
525 | /* |
526 | * Table management routines | |
527 | * lvm2tools doens't send name/uuid to kernel with table | |
528 | * for lookup I have to use minor number. | |
529 | */ | |
530 | ||
531 | /* | |
532 | * Remove inactive table from device. Routines which work's with inactive tables | |
533 | * doesn't need to synchronise with dmstrategy. They can synchronise themselves with mutex?. | |
ff56536e AH |
534 | */ |
535 | int | |
536 | dm_table_clear_ioctl(prop_dictionary_t dm_dict) | |
537 | { | |
538 | dm_dev_t *dmv; | |
539 | const char *name, *uuid; | |
540 | uint32_t flags, minor; | |
541 | ||
542 | dmv = NULL; | |
543 | name = NULL; | |
544 | uuid = NULL; | |
545 | flags = 0; | |
546 | minor = 0; | |
547 | ||
548 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | |
549 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | |
550 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
551 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | |
552 | ||
26798264 | 553 | dmdebug("Clearing inactive table from device: %s--%s\n", |
ff56536e AH |
554 | name, uuid); |
555 | ||
556 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | |
157bcf9e | 557 | dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); |
ff56536e AH |
558 | return ENOENT; |
559 | } | |
560 | /* Select unused table */ | |
561 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); | |
562 | ||
5b279a20 | 563 | atomic_clear_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG); |
ff56536e AH |
564 | |
565 | dm_dev_unbusy(dmv); | |
566 | ||
567 | return 0; | |
568 | } | |
b7c11cda | 569 | |
ff56536e AH |
570 | /* |
571 | * Get list of physical devices for active table. | |
572 | * Get dev_t from pdev vnode and insert it into cmd_array. | |
573 | * | |
574 | * XXX. This function is called from lvm2tools to get information | |
575 | * about physical devices, too e.g. during vgcreate. | |
576 | */ | |
577 | int | |
578 | dm_table_deps_ioctl(prop_dictionary_t dm_dict) | |
579 | { | |
580 | dm_dev_t *dmv; | |
581 | dm_table_t *tbl; | |
582 | dm_table_entry_t *table_en; | |
583 | ||
584 | prop_array_t cmd_array; | |
585 | const char *name, *uuid; | |
586 | uint32_t flags, minor; | |
587 | ||
588 | int table_type; | |
ff56536e AH |
589 | |
590 | name = NULL; | |
591 | uuid = NULL; | |
592 | dmv = NULL; | |
593 | flags = 0; | |
594 | ||
ff56536e AH |
595 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); |
596 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | |
597 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
598 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | |
599 | ||
600 | /* create array for dev_t's */ | |
601 | cmd_array = prop_array_create(); | |
602 | ||
603 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | |
157bcf9e | 604 | dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); |
ff56536e AH |
605 | return ENOENT; |
606 | } | |
607 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | |
608 | prop_dictionary_set_cstring(dm_dict, DM_IOCTL_NAME, dmv->name); | |
609 | prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); | |
610 | ||
26798264 | 611 | dmdebug("Getting table deps for device: %s\n", dmv->name); |
ff56536e AH |
612 | |
613 | /* | |
614 | * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query | |
615 | * INACTIVE TABLE | |
616 | */ | |
617 | if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) | |
618 | table_type = DM_TABLE_INACTIVE; | |
619 | else | |
620 | table_type = DM_TABLE_ACTIVE; | |
621 | ||
622 | tbl = dm_table_get_entry(&dmv->table_head, table_type); | |
623 | ||
3cd1dc08 | 624 | TAILQ_FOREACH(table_en, tbl, next) |
d471f1f9 | 625 | dm_table_deps(table_en, cmd_array); |
ff56536e AH |
626 | |
627 | dm_table_release(&dmv->table_head, table_type); | |
628 | dm_dev_unbusy(dmv); | |
629 | ||
630 | prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array); | |
631 | prop_object_release(cmd_array); | |
632 | ||
633 | return 0; | |
634 | } | |
d471f1f9 TK |
635 | |
636 | static int | |
637 | dm_table_deps(dm_table_entry_t *table_en, prop_array_t array) | |
638 | { | |
639 | dm_mapping_t *map; | |
640 | int i, size; | |
641 | uint64_t ret, tmp; | |
642 | ||
643 | size = prop_array_count(array); | |
644 | ||
645 | TAILQ_FOREACH(map, &table_en->pdev_maps, next) { | |
4f398b7b | 646 | ret = map->data.pdev->udev; |
d471f1f9 TK |
647 | for (i = 0; i < size; i++) { |
648 | if (prop_array_get_uint64(array, i, &tmp) == true) | |
649 | if (ret == tmp) | |
650 | break; /* exists */ | |
651 | } | |
652 | /* | |
653 | * Ignore if the device has already been added by | |
654 | * other tables. | |
655 | */ | |
656 | if (i == size) | |
657 | prop_array_add_uint64(array, ret); | |
658 | } | |
659 | ||
660 | return 0; | |
661 | } | |
662 | ||
ff56536e AH |
663 | /* |
664 | * Load new table/tables to device. | |
665 | * Call apropriate target init routine open all physical pdev's and | |
333a8a0c | 666 | * link them to device. For other targets mirror, strip, snapshot etc. |
ff56536e AH |
667 | * |
668 | * Load table to inactive slot table are switched in dm_device_resume_ioctl. | |
669 | * This simulates Linux behaviour better there should not be any difference. | |
ff56536e AH |
670 | */ |
671 | int | |
672 | dm_table_load_ioctl(prop_dictionary_t dm_dict) | |
673 | { | |
674 | dm_dev_t *dmv; | |
3cd1dc08 | 675 | dm_table_entry_t *table_en; |
ff56536e AH |
676 | dm_table_t *tbl; |
677 | dm_target_t *target; | |
678 | ||
679 | prop_object_iterator_t iter; | |
680 | prop_array_t cmd_array; | |
681 | prop_dictionary_t target_dict; | |
682 | ||
683 | const char *name, *uuid, *type; | |
684 | ||
685 | uint32_t flags, ret, minor; | |
686 | ||
687 | char *str; | |
688 | ||
689 | ret = 0; | |
690 | flags = 0; | |
691 | name = NULL; | |
692 | uuid = NULL; | |
693 | dmv = NULL; | |
ff56536e AH |
694 | str = NULL; |
695 | ||
696 | /* | |
697 | * char *xml; xml = prop_dictionary_externalize(dm_dict); | |
323b0fc1 | 698 | * kprintf("%s\n",xml); |
ff56536e AH |
699 | */ |
700 | ||
701 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | |
702 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | |
703 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
704 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | |
705 | ||
706 | cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA); | |
707 | iter = prop_array_iterator(cmd_array); | |
708 | dm_dbg_print_flags(flags); | |
709 | ||
710 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | |
157bcf9e | 711 | dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); |
ff56536e AH |
712 | return ENOENT; |
713 | } | |
26798264 | 714 | dmdebug("Loading table to device: %s--%d\n", name, |
ff56536e AH |
715 | dmv->table_head.cur_active_table); |
716 | ||
717 | /* | |
718 | * I have to check if this table slot is not used by another table list. | |
719 | * if it is used I should free them. | |
720 | */ | |
721 | if (dmv->flags & DM_INACTIVE_PRESENT_FLAG) | |
722 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); | |
723 | ||
724 | dm_dbg_print_flags(dmv->flags); | |
725 | tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_INACTIVE); | |
726 | ||
26798264 | 727 | dmdebug("dmv->name = %s\n", dmv->name); |
ff56536e AH |
728 | |
729 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | |
730 | ||
731 | while ((target_dict = prop_object_iterator_next(iter)) != NULL) { | |
ff56536e AH |
732 | prop_dictionary_get_cstring_nocopy(target_dict, |
733 | DM_TABLE_TYPE, &type); | |
734 | /* | |
735 | * If we want to deny table with 2 or more different | |
736 | * target we should do it here | |
737 | */ | |
7115a22b AH |
738 | if (((target = dm_target_lookup(type)) == NULL) && |
739 | ((target = dm_target_autoload(type)) == NULL)) { | |
ff56536e AH |
740 | dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); |
741 | dm_dev_unbusy(dmv); | |
742 | return ENOENT; | |
743 | } | |
5b279a20 AH |
744 | if ((table_en = kmalloc(sizeof(dm_table_entry_t), |
745 | M_DM, M_WAITOK)) == NULL) { | |
ff56536e AH |
746 | dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); |
747 | dm_dev_unbusy(dmv); | |
12a49c9b | 748 | dm_target_unbusy(target); |
ff56536e AH |
749 | return ENOMEM; |
750 | } | |
751 | prop_dictionary_get_uint64(target_dict, DM_TABLE_START, | |
752 | &table_en->start); | |
753 | prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH, | |
754 | &table_en->length); | |
755 | ||
26798264 | 756 | dmdebug("dm_ioctl.c... table_en->start = %ju, " |
e8e2bcda AH |
757 | "table_en->length = %ju\n", |
758 | (uintmax_t)table_en->start, | |
759 | (uintmax_t)table_en->length); | |
5b279a20 | 760 | |
ff56536e | 761 | table_en->target = target; |
2d59555f | 762 | table_en->dev = dmv; |
ff56536e | 763 | table_en->target_config = NULL; |
d471f1f9 | 764 | TAILQ_INIT(&table_en->pdev_maps); |
ff56536e AH |
765 | |
766 | /* | |
767 | * There is a parameter string after dm_target_spec | |
768 | * structure which points to /dev/wd0a 284 part of | |
769 | * table. String str points to this text. This can be | |
770 | * null and therefore it should be checked before we try to | |
771 | * use it. | |
772 | */ | |
773 | prop_dictionary_get_cstring(target_dict, | |
8062d810 | 774 | DM_TABLE_PARAMS, &str); |
ff56536e | 775 | |
3cd1dc08 | 776 | TAILQ_INSERT_TAIL(tbl, table_en, next); |
ff56536e AH |
777 | |
778 | /* | |
779 | * Params string is different for every target, | |
780 | * therfore I have to pass it to target init | |
781 | * routine and parse parameters there. | |
782 | */ | |
26798264 | 783 | dmdebug("DM: str passed in is: \"%s\"\n", str); |
ff56536e | 784 | |
f28e17b7 | 785 | if ((ret = dm_table_init(target, table_en, str)) != 0) { |
ff56536e AH |
786 | dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); |
787 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); | |
5b279a20 | 788 | kfree(str, M_TEMP); |
ff56536e AH |
789 | |
790 | dm_dev_unbusy(dmv); | |
791 | return ret; | |
792 | } | |
5b279a20 | 793 | kfree(str, M_TEMP); |
ff56536e AH |
794 | } |
795 | prop_object_iterator_release(iter); | |
796 | ||
157bcf9e | 797 | dm_add_flag(dm_dict, &flags, DM_INACTIVE_PRESENT_FLAG); |
5b279a20 | 798 | atomic_set_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG); |
ff56536e AH |
799 | |
800 | dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); | |
3b48c3c1 | 801 | |
ff56536e | 802 | dm_dev_unbusy(dmv); |
3b48c3c1 AH |
803 | #if 0 |
804 | dmsetdiskinfo(dmv->diskp, &dmv->table_head); | |
805 | #endif | |
ff56536e AH |
806 | return 0; |
807 | } | |
f28e17b7 TK |
808 | |
809 | static int | |
810 | dm_table_init(dm_target_t *target, dm_table_entry_t *table_en, char *params) | |
811 | { | |
812 | int i, n, ret, argc; | |
813 | char **ap, **argv; | |
814 | ||
815 | if (params == NULL) | |
816 | return EINVAL; | |
817 | ||
818 | n = target->max_argc; | |
819 | if (n) { | |
26798264 | 820 | dmdebug("Max argc %d for %s target\n", n, target->name); |
f28e17b7 TK |
821 | } else { |
822 | n = 20; /* large enough slots for most targets */ | |
823 | } | |
824 | ||
825 | argv = kmalloc(sizeof(*argv) * n, M_DM, M_WAITOK | M_ZERO); | |
826 | ||
827 | for (ap = argv; | |
828 | ap < &argv[n] && (*ap = strsep(¶ms, " \t")) != NULL;) { | |
829 | if (**ap != '\0') | |
830 | ap++; | |
831 | } | |
832 | argc = ap - argv; | |
833 | ||
834 | if (dm_debug_level) { | |
835 | for (i = 0; i < argc; i++) | |
836 | kprintf("DM: argv[%d] = \"%s\"\n", i, argv[i]); | |
837 | } | |
838 | ||
839 | KKASSERT(target->init); | |
840 | ret = target->init(table_en, argc, argv); | |
841 | ||
842 | kfree(argv, M_DM); | |
843 | ||
844 | return ret; | |
845 | } | |
846 | ||
ff56536e AH |
847 | /* |
848 | * Get description of all tables loaded to device from kernel | |
849 | * and send it to libdevmapper. | |
850 | * | |
851 | * Output dictionary for every table: | |
852 | * | |
853 | * <key>cmd_data</key> | |
854 | * <array> | |
855 | * <dict> | |
856 | * <key>type<key> | |
857 | * <string>...</string> | |
858 | * | |
859 | * <key>start</key> | |
860 | * <integer>...</integer> | |
861 | * | |
862 | * <key>length</key> | |
863 | * <integer>...</integer> | |
864 | * | |
865 | * <key>params</key> | |
866 | * <string>...</string> | |
867 | * </dict> | |
868 | * </array> | |
ff56536e AH |
869 | */ |
870 | int | |
871 | dm_table_status_ioctl(prop_dictionary_t dm_dict) | |
872 | { | |
873 | dm_dev_t *dmv; | |
874 | dm_table_t *tbl; | |
875 | dm_table_entry_t *table_en; | |
876 | ||
877 | prop_array_t cmd_array; | |
878 | prop_dictionary_t target_dict; | |
879 | ||
3d089c23 | 880 | uint32_t minor; |
ff56536e AH |
881 | |
882 | const char *name, *uuid; | |
895c8e52 | 883 | uint32_t flags; |
ff56536e AH |
884 | int table_type; |
885 | ||
886 | dmv = NULL; | |
887 | uuid = NULL; | |
888 | name = NULL; | |
ff56536e | 889 | flags = 0; |
ff56536e AH |
890 | |
891 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | |
892 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | |
893 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
894 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | |
895 | ||
896 | cmd_array = prop_array_create(); | |
897 | ||
898 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | |
157bcf9e | 899 | dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); |
ff56536e AH |
900 | return ENOENT; |
901 | } | |
902 | /* | |
903 | * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query | |
904 | * INACTIVE TABLE | |
905 | */ | |
906 | if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) | |
907 | table_type = DM_TABLE_INACTIVE; | |
908 | else | |
909 | table_type = DM_TABLE_ACTIVE; | |
910 | ||
911 | if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE)) | |
157bcf9e | 912 | dm_add_flag(dm_dict, &flags, DM_ACTIVE_PRESENT_FLAG); |
ff56536e | 913 | else { |
157bcf9e | 914 | dm_remove_flag(dm_dict, &flags, DM_ACTIVE_PRESENT_FLAG); |
ff56536e AH |
915 | |
916 | if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE)) | |
157bcf9e | 917 | dm_add_flag(dm_dict, &flags, DM_INACTIVE_PRESENT_FLAG); |
b7c11cda | 918 | else |
157bcf9e | 919 | dm_remove_flag(dm_dict, &flags, DM_INACTIVE_PRESENT_FLAG); |
ff56536e AH |
920 | } |
921 | ||
922 | if (dmv->flags & DM_SUSPEND_FLAG) | |
157bcf9e | 923 | dm_add_flag(dm_dict, &flags, DM_SUSPEND_FLAG); |
ff56536e AH |
924 | |
925 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | |
926 | ||
26798264 | 927 | dmdebug("Status of device tables: %s--%d\n", |
ff56536e AH |
928 | name, dmv->table_head.cur_active_table); |
929 | ||
930 | tbl = dm_table_get_entry(&dmv->table_head, table_type); | |
931 | ||
3cd1dc08 | 932 | TAILQ_FOREACH(table_en, tbl, next) { |
ff56536e | 933 | target_dict = prop_dictionary_create(); |
26798264 | 934 | dmdebug("%016" PRIu64 ", length %016" PRIu64 |
ff56536e AH |
935 | ", target %s\n", table_en->start, table_en->length, |
936 | table_en->target->name); | |
937 | ||
938 | prop_dictionary_set_uint64(target_dict, DM_TABLE_START, | |
939 | table_en->start); | |
940 | prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH, | |
941 | table_en->length); | |
942 | ||
943 | prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE, | |
944 | table_en->target->name); | |
945 | ||
946 | /* dm_table_get_cur_actv.table ?? */ | |
947 | prop_dictionary_set_int32(target_dict, DM_TABLE_STAT, | |
948 | dmv->table_head.cur_active_table); | |
949 | ||
e243a4fb | 950 | dm_table_status(table_en, target_dict, flags); |
f134a703 | 951 | |
ff56536e AH |
952 | prop_array_add(cmd_array, target_dict); |
953 | prop_object_release(target_dict); | |
954 | } | |
955 | ||
956 | dm_table_release(&dmv->table_head, table_type); | |
957 | dm_dev_unbusy(dmv); | |
958 | ||
959 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags); | |
960 | prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array); | |
961 | prop_object_release(cmd_array); | |
962 | ||
963 | return 0; | |
964 | } | |
965 | ||
e243a4fb TK |
966 | static int |
967 | dm_table_status(dm_table_entry_t *table_en, | |
895c8e52 | 968 | prop_dictionary_t target_dict, uint32_t flags) |
e243a4fb TK |
969 | { |
970 | void *cfg; | |
971 | char *params; | |
f3c99fce | 972 | int is_table; |
e243a4fb TK |
973 | |
974 | cfg = table_en->target_config; | |
975 | params = NULL; | |
976 | ||
f3c99fce TK |
977 | is_table = (flags & DM_STATUS_TABLE_FLAG) ? 1 : 0; |
978 | ||
979 | if (is_table && table_en->target->table) { | |
e243a4fb | 980 | params = table_en->target->table(cfg); |
f3c99fce | 981 | } else if (!is_table && table_en->target->info) { |
e243a4fb TK |
982 | params = table_en->target->info(cfg); |
983 | } else { | |
984 | prop_dictionary_set_cstring(target_dict, DM_TABLE_PARAMS, ""); | |
985 | return ENOTSUP; | |
986 | } | |
987 | ||
988 | if (params == NULL) { | |
989 | prop_dictionary_set_cstring(target_dict, DM_TABLE_PARAMS, ""); | |
990 | return ENOMEM; | |
991 | } | |
992 | ||
993 | prop_dictionary_set_cstring(target_dict, DM_TABLE_PARAMS, params); | |
994 | kfree(params, M_DM); | |
995 | return 0; | |
996 | } | |
997 | ||
51292ec6 AH |
998 | int |
999 | dm_message_ioctl(prop_dictionary_t dm_dict) | |
1000 | { | |
1001 | dm_table_t *tbl; | |
1002 | dm_table_entry_t *table_en; | |
1003 | dm_dev_t *dmv; | |
1004 | const char *name, *uuid; | |
1005 | uint32_t flags, minor; | |
1006 | uint64_t table_start, table_end, sector; | |
1007 | char *msg; | |
1008 | int ret, found = 0; | |
1009 | ||
1010 | flags = 0; | |
1011 | name = NULL; | |
1012 | uuid = NULL; | |
1013 | ||
1014 | /* Get needed values from dictionary. */ | |
1015 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | |
1016 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | |
1017 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | |
1018 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | |
1019 | prop_dictionary_get_uint64(dm_dict, DM_MESSAGE_SECTOR, §or); | |
1020 | ||
1021 | dm_dbg_print_flags(flags); | |
1022 | ||
1023 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | |
157bcf9e | 1024 | dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); |
51292ec6 AH |
1025 | return ENOENT; |
1026 | } | |
1027 | ||
1028 | /* Get message string */ | |
1029 | prop_dictionary_get_cstring(dm_dict, DM_MESSAGE_STR, &msg); | |
1030 | ||
1031 | tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE); | |
1032 | ||
1033 | ret = EINVAL; | |
1034 | ||
1035 | if (sector == 0) { | |
3cd1dc08 TK |
1036 | if (!TAILQ_EMPTY(tbl)) { |
1037 | table_en = TAILQ_FIRST(tbl); | |
51292ec6 AH |
1038 | found = 1; |
1039 | } | |
1040 | } else { | |
3cd1dc08 | 1041 | TAILQ_FOREACH(table_en, tbl, next) { |
51292ec6 | 1042 | table_start = table_en->start; |
0338193e | 1043 | table_end = table_start + table_en->length; |
51292ec6 AH |
1044 | |
1045 | if ((sector >= table_start) && (sector < table_end)) { | |
1046 | found = 1; | |
1047 | break; | |
1048 | } | |
1049 | } | |
1050 | } | |
1051 | ||
1052 | if (found) { | |
1053 | if (table_en->target->message != NULL) | |
1054 | ret = table_en->target->message(table_en, msg); | |
1055 | } | |
1056 | ||
1057 | dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE); | |
1058 | ||
51292ec6 AH |
1059 | kfree(msg, M_TEMP); |
1060 | dm_dev_unbusy(dmv); | |
1061 | ||
1062 | return ret; | |
1063 | } | |
ff56536e AH |
1064 | |
1065 | /* | |
1066 | * For every call I have to set kernel driver version. | |
1067 | * Because I can have commands supported only in other | |
1068 | * newer/later version. This routine is called for every | |
1069 | * ioctl command. | |
1070 | */ | |
1071 | int | |
1072 | dm_check_version(prop_dictionary_t dm_dict) | |
1073 | { | |
1074 | size_t i; | |
1075 | int dm_version[3]; | |
1076 | prop_array_t ver; | |
1077 | ||
1078 | ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION); | |
1079 | ||
1080 | for (i = 0; i < 3; i++) | |
1081 | prop_array_get_uint32(ver, i, &dm_version[i]); | |
1082 | ||
1083 | if (DM_VERSION_MAJOR != dm_version[0] || DM_VERSION_MINOR < dm_version[1]) { | |
26798264 | 1084 | dmdebug("libdevmapper/kernel version mismatch " |
ff56536e AH |
1085 | "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n", |
1086 | DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, | |
1087 | dm_version[0], dm_version[1], dm_version[2]); | |
1088 | ||
1089 | return EIO; | |
1090 | } | |
1091 | prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR); | |
1092 | prop_array_set_uint32(ver, 1, DM_VERSION_MINOR); | |
1093 | prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL); | |
1094 | ||
1095 | prop_dictionary_set(dm_dict, DM_IOCTL_VERSION, ver); | |
1096 | ||
1097 | return 0; | |
1098 | } |