1 /* $NetBSD: dm_ioctl.c,v 1.21 2010/02/25 20:48:58 jakllsch Exp $ */
4 * Copyright (c) 2010-2011 Alex Hornung <alex@alexhornung.com>
5 * Copyright (c) 2008 The NetBSD Foundation, Inc.
8 * This code is derived from software contributed to The NetBSD Foundation
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
34 * Locking is used to synchronise between ioctl calls and between dm_table's
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).
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
48 * To access table entries dm_table_* routines must be used.
50 * dm_table_get_entry will increment table users reference
51 * counter. It will return active or inactive table depends
52 * on uint8_t argument.
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
58 * dm_table_head_init initialize talbe_entries TAILQS and io_cv.
60 * dm_table_head_destroy destroy cv.
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.
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
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.
82 #include <sys/device.h>
83 #include <sys/malloc.h>
84 #include <cpu/atomic.h>
85 #include <dev/disk/dm/dm.h>
86 #include <dev/disk/dm/netbsd-dm.h>
89 dm_table_deps(dm_table_entry_t
*, prop_array_t
);
91 dm_table_init(dm_target_t
*, dm_table_entry_t
*, char *);
93 dm_table_status(dm_table_entry_t
*, prop_dictionary_t
, uint32_t);
96 void dm_add_flag(prop_dictionary_t dp
, uint32_t *fp
, const uint32_t val
)
99 prop_dictionary_get_uint32(dp
, DM_IOCTL_FLAGS
, fp
);
101 prop_dictionary_set_uint32(dp
, DM_IOCTL_FLAGS
, *fp
);
102 KKASSERT((*fp
) & val
);
106 void dm_remove_flag(prop_dictionary_t dp
, uint32_t *fp
, const uint32_t val
)
108 KKASSERT(dp
!= NULL
);
109 prop_dictionary_get_uint32(dp
, DM_IOCTL_FLAGS
, fp
);
111 prop_dictionary_set_uint32(dp
, DM_IOCTL_FLAGS
, *fp
);
112 KKASSERT(!((*fp
) & val
));
116 * Print flags sent to the kernel from libdevmapper.
119 dm_dbg_print_flags(uint32_t flags
)
121 if (dm_debug_level
== 0)
124 kprintf("%s --- flags=%08X\n", __func__
, flags
);
126 if (flags
& DM_READONLY_FLAG
)
127 kprintf(" DM_READONLY_FLAG\n");
128 if (flags
& DM_SUSPEND_FLAG
)
129 kprintf(" DM_SUSPEND_FLAG\n");
130 if (flags
& DM_EXISTS_FLAG
)
131 kprintf(" DM_EXISTS_FLAG\n");
132 if (flags
& DM_PERSISTENT_DEV_FLAG
)
133 kprintf(" DM_PERSISTENT_DEV_FLAG\n");
134 if (flags
& DM_STATUS_TABLE_FLAG
)
135 kprintf(" DM_STATUS_TABLE_FLAG\n");
136 if (flags
& DM_ACTIVE_PRESENT_FLAG
)
137 kprintf(" DM_ACTIVE_PRESENT_FLAG\n");
138 if (flags
& DM_INACTIVE_PRESENT_FLAG
)
139 kprintf(" DM_INACTIVE_PRESENT_FLAG\n");
140 if (flags
& DM_BUFFER_FULL_FLAG
)
141 kprintf(" DM_BUFFER_FULL_FLAG\n");
142 if (flags
& DM_SKIP_BDGET_FLAG
)
143 kprintf(" DM_SKIP_BDGET_FLAG\n");
144 if (flags
& DM_SKIP_LOCKFS_FLAG
)
145 kprintf(" DM_SKIP_LOCKFS_FLAG\n");
146 if (flags
& DM_NOFLUSH_FLAG
)
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");
159 * Get list of all available targets from global
160 * target list and sent them back to libdevmapper.
163 dm_list_versions_ioctl(prop_dictionary_t dm_dict
)
165 prop_array_t target_list
;
170 prop_dictionary_get_uint32(dm_dict
, DM_IOCTL_FLAGS
, &flags
);
172 dm_dbg_print_flags(flags
);
173 target_list
= dm_target_prop_list();
175 prop_dictionary_set(dm_dict
, DM_IOCTL_CMD_DATA
, target_list
);
176 prop_object_release(target_list
);
182 * Create in-kernel entry for device. Device attributes such as name, uuid are
183 * taken from proplib dictionary.
186 dm_dev_create_ioctl(prop_dictionary_t dm_dict
)
189 const char *name
, *uuid
;
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
);
203 dm_dbg_print_flags(flags
);
205 /* Lookup name and uuid if device already exist quit. */
206 if ((dmv
= dm_dev_lookup(name
, uuid
, -1)) != NULL
) {
207 dm_add_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
); /* Device already exists */
212 r
= dm_dev_create(&dmv
, name
, uuid
, flags
);
214 prop_dictionary_set_uint32(dm_dict
, DM_IOCTL_MINOR
, dmv
->minor
);
215 dm_add_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
);
216 dm_remove_flag(dm_dict
, &flags
, DM_INACTIVE_PRESENT_FLAG
);
223 * Get list of created device-mapper devices from global list and
228 * <key>cmd_data</key>
232 * <string>...</string>
235 * <integer>...</integer>
240 dm_dev_list_ioctl(prop_dictionary_t dm_dict
)
242 prop_array_t dev_list
;
248 prop_dictionary_get_uint32(dm_dict
, DM_IOCTL_FLAGS
, &flags
);
250 dm_dbg_print_flags(flags
);
252 dev_list
= dm_dev_prop_list();
254 prop_dictionary_set(dm_dict
, DM_IOCTL_CMD_DATA
, dev_list
);
255 prop_object_release(dev_list
);
261 * Rename selected devices old name is in struct dm_ioctl.
262 * new name is taken from dictionary.
264 * <key>cmd_data</key>
266 * <string>...</string>
270 dm_dev_rename_ioctl(prop_dictionary_t dm_dict
)
273 prop_array_t cmd_array
;
276 const char *name
, *uuid
, *n_name
;
277 uint32_t flags
, minor
;
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
);
289 dm_dbg_print_flags(flags
);
291 cmd_array
= prop_dictionary_get(dm_dict
, DM_IOCTL_CMD_DATA
);
293 prop_array_get_cstring_nocopy(cmd_array
, 0, &n_name
);
295 if (strlen(n_name
) + 1 > DM_NAME_LEN
)
298 if ((dmv
= dm_dev_lookup_evict(name
, uuid
, minor
)) == NULL
) {
299 dm_remove_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
);
302 /* change device name */
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 ?
308 strlcpy(dmv
->name
, n_name
, DM_NAME_LEN
);
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
);
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.
322 kprintf("dm_dev_rename_ioctl called, but not implemented!\n");
330 dm_dev_remove_ioctl(prop_dictionary_t dm_dict
)
333 const char *name
, *uuid
;
334 uint32_t flags
, minor
, is_open
;
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
);
346 dm_dbg_print_flags(flags
);
348 if ((dmv
= dm_dev_lookup(name
, uuid
, minor
)) == NULL
) {
349 dm_remove_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
);
353 is_open
= dmv
->is_open
;
360 return dm_dev_remove(dmv
);
364 * Try to remove all devices
367 dm_dev_remove_all_ioctl(prop_dictionary_t dm_dict
)
371 /* Get needed values from dictionary. */
372 prop_dictionary_get_uint32(dm_dict
, DM_IOCTL_FLAGS
, &flags
);
374 dm_dbg_print_flags(flags
);
376 /* Gently remove all devices, if possible */
377 return dm_dev_remove_all(1);
381 * Return actual state of device to libdevmapper.
384 dm_dev_status_ioctl(prop_dictionary_t dm_dict
)
387 const char *name
, *uuid
;
388 uint32_t flags
, j
, minor
;
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
);
400 if ((dmv
= dm_dev_lookup(name
, uuid
, minor
)) == NULL
) {
401 dm_remove_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
);
404 dm_dbg_print_flags(dmv
->flags
);
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
);
410 if (dmv
->flags
& DM_SUSPEND_FLAG
)
411 dm_add_flag(dm_dict
, &flags
, DM_SUSPEND_FLAG
);
414 * Add status flags for tables I have to check both active and
417 if ((j
= dm_table_get_target_count(&dmv
->table_head
, DM_TABLE_ACTIVE
)))
418 dm_add_flag(dm_dict
, &flags
, DM_ACTIVE_PRESENT_FLAG
);
420 dm_remove_flag(dm_dict
, &flags
, DM_ACTIVE_PRESENT_FLAG
);
422 prop_dictionary_set_uint32(dm_dict
, DM_IOCTL_TARGET_COUNT
, j
);
424 if (dm_table_get_target_count(&dmv
->table_head
, DM_TABLE_INACTIVE
))
425 dm_add_flag(dm_dict
, &flags
, DM_INACTIVE_PRESENT_FLAG
);
427 dm_remove_flag(dm_dict
, &flags
, DM_INACTIVE_PRESENT_FLAG
);
435 * Set only flag to suggest that device is suspended. This call is
436 * not supported in NetBSD.
439 dm_dev_suspend_ioctl(prop_dictionary_t dm_dict
)
442 const char *name
, *uuid
;
443 uint32_t flags
, minor
;
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
);
454 if ((dmv
= dm_dev_lookup(name
, uuid
, minor
)) == NULL
) {
455 dm_remove_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
);
458 atomic_set_int(&dmv
->flags
, DM_SUSPEND_FLAG
);
460 dm_dbg_print_flags(dmv
->flags
);
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
);
468 /* Add flags to dictionary flag after dmv -> dict copy */
469 dm_add_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
);
475 * Simulate Linux behaviour better and switch tables here and not in
476 * dm_table_load_ioctl.
479 dm_dev_resume_ioctl(prop_dictionary_t dm_dict
)
482 const char *name
, *uuid
;
483 uint32_t flags
, minor
;
490 * char *xml; xml = prop_dictionary_externalize(dm_dict);
491 * kprintf("%s\n",xml);
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
);
499 /* Remove device from global device list */
500 if ((dmv
= dm_dev_lookup(name
, uuid
, minor
)) == NULL
) {
501 dm_remove_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
);
504 atomic_clear_int(&dmv
->flags
, (DM_SUSPEND_FLAG
| DM_INACTIVE_PRESENT_FLAG
));
505 atomic_set_int(&dmv
->flags
, DM_ACTIVE_PRESENT_FLAG
);
507 dm_table_switch_tables(&dmv
->table_head
);
509 dm_add_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
);
511 dmsetdiskinfo(dmv
->diskp
, &dmv
->table_head
);
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
);
519 /* Destroy inactive table after resume. */
520 dm_table_destroy(&dmv
->table_head
, DM_TABLE_INACTIVE
);
526 * Table management routines
527 * lvm2tools doens't send name/uuid to kernel with table
528 * for lookup I have to use minor number.
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?.
536 dm_table_clear_ioctl(prop_dictionary_t dm_dict
)
539 const char *name
, *uuid
;
540 uint32_t flags
, minor
;
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
);
553 dmdebug("Clearing inactive table from device: %s--%s\n",
556 if ((dmv
= dm_dev_lookup(name
, uuid
, minor
)) == NULL
) {
557 dm_remove_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
);
560 /* Select unused table */
561 dm_table_destroy(&dmv
->table_head
, DM_TABLE_INACTIVE
);
563 atomic_clear_int(&dmv
->flags
, DM_INACTIVE_PRESENT_FLAG
);
571 * Get list of physical devices for active table.
572 * Get dev_t from pdev vnode and insert it into cmd_array.
574 * XXX. This function is called from lvm2tools to get information
575 * about physical devices, too e.g. during vgcreate.
578 dm_table_deps_ioctl(prop_dictionary_t dm_dict
)
582 dm_table_entry_t
*table_en
;
584 prop_array_t cmd_array
;
585 const char *name
, *uuid
;
586 uint32_t flags
, minor
;
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
);
600 /* create array for dev_t's */
601 cmd_array
= prop_array_create();
603 if ((dmv
= dm_dev_lookup(name
, uuid
, minor
)) == NULL
) {
604 dm_remove_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
);
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
);
611 dmdebug("Getting table deps for device: %s\n", dmv
->name
);
614 * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query
617 if (flags
& DM_QUERY_INACTIVE_TABLE_FLAG
)
618 table_type
= DM_TABLE_INACTIVE
;
620 table_type
= DM_TABLE_ACTIVE
;
622 tbl
= dm_table_get_entry(&dmv
->table_head
, table_type
);
624 TAILQ_FOREACH(table_en
, tbl
, next
)
625 dm_table_deps(table_en
, cmd_array
);
627 dm_table_release(&dmv
->table_head
, table_type
);
630 prop_dictionary_set(dm_dict
, DM_IOCTL_CMD_DATA
, cmd_array
);
631 prop_object_release(cmd_array
);
637 dm_table_deps(dm_table_entry_t
*table_en
, prop_array_t array
)
643 size
= prop_array_count(array
);
645 TAILQ_FOREACH(map
, &table_en
->pdev_maps
, next
) {
646 ret
= map
->data
.pdev
->udev
;
647 for (i
= 0; i
< size
; i
++) {
648 if (prop_array_get_uint64(array
, i
, &tmp
) == true)
653 * Ignore if the device has already been added by
657 prop_array_add_uint64(array
, ret
);
664 * Load new table/tables to device.
665 * Call apropriate target init routine open all physical pdev's and
666 * link them to device. For other targets mirror, strip, snapshot etc.
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.
672 dm_table_load_ioctl(prop_dictionary_t dm_dict
)
675 dm_table_entry_t
*table_en
;
679 prop_object_iterator_t iter
;
680 prop_array_t cmd_array
;
681 prop_dictionary_t target_dict
;
683 const char *name
, *uuid
, *type
;
685 uint32_t flags
, ret
, minor
;
697 * char *xml; xml = prop_dictionary_externalize(dm_dict);
698 * kprintf("%s\n",xml);
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
);
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
);
710 if ((dmv
= dm_dev_lookup(name
, uuid
, minor
)) == NULL
) {
711 dm_remove_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
);
714 dmdebug("Loading table to device: %s--%d\n", name
,
715 dmv
->table_head
.cur_active_table
);
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.
721 if (dmv
->flags
& DM_INACTIVE_PRESENT_FLAG
)
722 dm_table_destroy(&dmv
->table_head
, DM_TABLE_INACTIVE
);
724 dm_dbg_print_flags(dmv
->flags
);
725 tbl
= dm_table_get_entry(&dmv
->table_head
, DM_TABLE_INACTIVE
);
727 prop_dictionary_set_uint32(dm_dict
, DM_IOCTL_MINOR
, dmv
->minor
);
729 while ((target_dict
= prop_object_iterator_next(iter
)) != NULL
) {
730 prop_dictionary_get_cstring_nocopy(target_dict
,
731 DM_TABLE_TYPE
, &type
);
733 * If we want to deny table with 2 or more different
734 * target we should do it here
736 if (((target
= dm_target_lookup(type
)) == NULL
) &&
737 ((target
= dm_target_autoload(type
)) == NULL
)) {
738 dm_table_release(&dmv
->table_head
, DM_TABLE_INACTIVE
);
742 if ((table_en
= kmalloc(sizeof(dm_table_entry_t
),
743 M_DM
, M_WAITOK
)) == NULL
) {
744 dm_table_release(&dmv
->table_head
, DM_TABLE_INACTIVE
);
746 dm_target_unbusy(target
);
749 prop_dictionary_get_uint64(target_dict
, DM_TABLE_START
,
751 prop_dictionary_get_uint64(target_dict
, DM_TABLE_LENGTH
,
754 dmdebug("table_en->start = %ju, table_en->length = %ju\n",
755 (uintmax_t)table_en
->start
,
756 (uintmax_t)table_en
->length
);
758 table_en
->target
= target
;
760 table_en
->target_config
= NULL
;
761 TAILQ_INIT(&table_en
->pdev_maps
);
764 * There is a parameter string after dm_target_spec
765 * structure which points to /dev/wd0a 284 part of
766 * table. String str points to this text. This can be
767 * null and therefore it should be checked before we try to
770 prop_dictionary_get_cstring(target_dict
,
771 DM_TABLE_PARAMS
, &str
);
773 TAILQ_INSERT_TAIL(tbl
, table_en
, next
);
776 * Params string is different for every target,
777 * therfore I have to pass it to target init
778 * routine and parse parameters there.
780 dmdebug("String passed in is: \"%s\"\n", str
);
782 if ((ret
= dm_table_init(target
, table_en
, str
)) != 0) {
783 dm_table_release(&dmv
->table_head
, DM_TABLE_INACTIVE
);
784 dm_table_destroy(&dmv
->table_head
, DM_TABLE_INACTIVE
);
792 prop_object_iterator_release(iter
);
794 dm_add_flag(dm_dict
, &flags
, DM_INACTIVE_PRESENT_FLAG
);
795 atomic_set_int(&dmv
->flags
, DM_INACTIVE_PRESENT_FLAG
);
797 dm_table_release(&dmv
->table_head
, DM_TABLE_INACTIVE
);
801 dmsetdiskinfo(dmv
->diskp
, &dmv
->table_head
);
807 dm_table_init(dm_target_t
*target
, dm_table_entry_t
*table_en
, char *params
)
815 n
= target
->max_argc
;
817 dmdebug("Max argc %d for %s target\n", n
, target
->name
);
819 n
= 20; /* large enough slots for most targets */
822 argv
= kmalloc(sizeof(*argv
) * n
, M_DM
, M_WAITOK
| M_ZERO
);
825 ap
< &argv
[n
] && (*ap
= strsep(¶ms
, " \t")) != NULL
;) {
831 if (dm_debug_level
) {
832 for (i
= 0; i
< argc
; i
++)
833 kprintf("DM: argv[%d] = \"%s\"\n", i
, argv
[i
]);
836 KKASSERT(target
->init
);
837 ret
= target
->init(table_en
, argc
, argv
);
845 * Get description of all tables loaded to device from kernel
846 * and send it to libdevmapper.
848 * Output dictionary for every table:
850 * <key>cmd_data</key>
854 * <string>...</string>
857 * <integer>...</integer>
860 * <integer>...</integer>
863 * <string>...</string>
868 dm_table_status_ioctl(prop_dictionary_t dm_dict
)
872 dm_table_entry_t
*table_en
;
874 prop_array_t cmd_array
;
875 prop_dictionary_t target_dict
;
879 const char *name
, *uuid
;
888 prop_dictionary_get_cstring_nocopy(dm_dict
, DM_IOCTL_NAME
, &name
);
889 prop_dictionary_get_cstring_nocopy(dm_dict
, DM_IOCTL_UUID
, &uuid
);
890 prop_dictionary_get_uint32(dm_dict
, DM_IOCTL_FLAGS
, &flags
);
891 prop_dictionary_get_uint32(dm_dict
, DM_IOCTL_MINOR
, &minor
);
893 cmd_array
= prop_array_create();
895 if ((dmv
= dm_dev_lookup(name
, uuid
, minor
)) == NULL
) {
896 dm_remove_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
);
900 * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query
903 if (flags
& DM_QUERY_INACTIVE_TABLE_FLAG
)
904 table_type
= DM_TABLE_INACTIVE
;
906 table_type
= DM_TABLE_ACTIVE
;
908 if (dm_table_get_target_count(&dmv
->table_head
, DM_TABLE_ACTIVE
))
909 dm_add_flag(dm_dict
, &flags
, DM_ACTIVE_PRESENT_FLAG
);
911 dm_remove_flag(dm_dict
, &flags
, DM_ACTIVE_PRESENT_FLAG
);
913 if (dm_table_get_target_count(&dmv
->table_head
, DM_TABLE_INACTIVE
))
914 dm_add_flag(dm_dict
, &flags
, DM_INACTIVE_PRESENT_FLAG
);
916 dm_remove_flag(dm_dict
, &flags
, DM_INACTIVE_PRESENT_FLAG
);
919 if (dmv
->flags
& DM_SUSPEND_FLAG
)
920 dm_add_flag(dm_dict
, &flags
, DM_SUSPEND_FLAG
);
922 prop_dictionary_set_uint32(dm_dict
, DM_IOCTL_MINOR
, dmv
->minor
);
924 dmdebug("Status of device tables: %s--%d\n",
925 name
, dmv
->table_head
.cur_active_table
);
927 tbl
= dm_table_get_entry(&dmv
->table_head
, table_type
);
929 TAILQ_FOREACH(table_en
, tbl
, next
) {
930 target_dict
= prop_dictionary_create();
931 dmdebug("%016" PRIu64
", length %016" PRIu64
932 ", target %s\n", table_en
->start
, table_en
->length
,
933 table_en
->target
->name
);
935 prop_dictionary_set_uint64(target_dict
, DM_TABLE_START
,
937 prop_dictionary_set_uint64(target_dict
, DM_TABLE_LENGTH
,
940 prop_dictionary_set_cstring(target_dict
, DM_TABLE_TYPE
,
941 table_en
->target
->name
);
943 /* dm_table_get_cur_actv.table ?? */
944 prop_dictionary_set_int32(target_dict
, DM_TABLE_STAT
,
945 dmv
->table_head
.cur_active_table
);
947 dm_table_status(table_en
, target_dict
, flags
);
949 prop_array_add(cmd_array
, target_dict
);
950 prop_object_release(target_dict
);
953 dm_table_release(&dmv
->table_head
, table_type
);
956 prop_dictionary_set_uint32(dm_dict
, DM_IOCTL_FLAGS
, flags
);
957 prop_dictionary_set(dm_dict
, DM_IOCTL_CMD_DATA
, cmd_array
);
958 prop_object_release(cmd_array
);
964 dm_table_status(dm_table_entry_t
*table_en
,
965 prop_dictionary_t target_dict
, uint32_t flags
)
971 cfg
= table_en
->target_config
;
974 is_table
= (flags
& DM_STATUS_TABLE_FLAG
) ? 1 : 0;
976 if (is_table
&& table_en
->target
->table
) {
977 params
= table_en
->target
->table(cfg
);
978 } else if (!is_table
&& table_en
->target
->info
) {
979 params
= table_en
->target
->info(cfg
);
981 prop_dictionary_set_cstring(target_dict
, DM_TABLE_PARAMS
, "");
985 if (params
== NULL
) {
986 prop_dictionary_set_cstring(target_dict
, DM_TABLE_PARAMS
, "");
990 prop_dictionary_set_cstring(target_dict
, DM_TABLE_PARAMS
, params
);
996 dm_message_ioctl(prop_dictionary_t dm_dict
)
999 dm_table_entry_t
*table_en
;
1001 const char *name
, *uuid
;
1002 uint32_t flags
, minor
;
1003 uint64_t table_start
, table_end
, sector
;
1011 /* Get needed values from dictionary. */
1012 prop_dictionary_get_cstring_nocopy(dm_dict
, DM_IOCTL_NAME
, &name
);
1013 prop_dictionary_get_cstring_nocopy(dm_dict
, DM_IOCTL_UUID
, &uuid
);
1014 prop_dictionary_get_uint32(dm_dict
, DM_IOCTL_FLAGS
, &flags
);
1015 prop_dictionary_get_uint32(dm_dict
, DM_IOCTL_MINOR
, &minor
);
1016 prop_dictionary_get_uint64(dm_dict
, DM_MESSAGE_SECTOR
, §or
);
1018 dm_dbg_print_flags(flags
);
1020 if ((dmv
= dm_dev_lookup(name
, uuid
, minor
)) == NULL
) {
1021 dm_remove_flag(dm_dict
, &flags
, DM_EXISTS_FLAG
);
1025 /* Get message string */
1026 prop_dictionary_get_cstring(dm_dict
, DM_MESSAGE_STR
, &msg
);
1028 tbl
= dm_table_get_entry(&dmv
->table_head
, DM_TABLE_ACTIVE
);
1033 if (!TAILQ_EMPTY(tbl
)) {
1034 table_en
= TAILQ_FIRST(tbl
);
1038 TAILQ_FOREACH(table_en
, tbl
, next
) {
1039 table_start
= table_en
->start
;
1040 table_end
= table_start
+ table_en
->length
;
1042 if ((sector
>= table_start
) && (sector
< table_end
)) {
1050 if (table_en
->target
->message
!= NULL
)
1051 ret
= table_en
->target
->message(table_en
, msg
);
1054 dm_table_release(&dmv
->table_head
, DM_TABLE_ACTIVE
);
1063 * For every call I have to set kernel driver version.
1064 * Because I can have commands supported only in other
1065 * newer/later version. This routine is called for every
1069 dm_check_version(prop_dictionary_t dm_dict
)
1075 ver
= prop_dictionary_get(dm_dict
, DM_IOCTL_VERSION
);
1077 for (i
= 0; i
< 3; i
++)
1078 prop_array_get_uint32(ver
, i
, &dm_version
[i
]);
1080 if (DM_VERSION_MAJOR
!= dm_version
[0] || DM_VERSION_MINOR
< dm_version
[1]) {
1081 dmdebug("libdevmapper/kernel version mismatch "
1082 "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n",
1083 DM_VERSION_MAJOR
, DM_VERSION_MINOR
, DM_VERSION_PATCHLEVEL
,
1084 dm_version
[0], dm_version
[1], dm_version
[2]);
1088 prop_array_set_uint32(ver
, 0, DM_VERSION_MAJOR
);
1089 prop_array_set_uint32(ver
, 1, DM_VERSION_MINOR
);
1090 prop_array_set_uint32(ver
, 2, DM_VERSION_PATCHLEVEL
);
1092 prop_dictionary_set(dm_dict
, DM_IOCTL_VERSION
, ver
);