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 SLISTS 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/types.h>
83 #include <sys/device.h>
84 #include <sys/malloc.h>
85 #include <sys/vnode.h>
86 #include <dev/disk/dm/dm.h>
88 #include "netbsd-dm.h"
90 #define DM_REMOVE_FLAG(flag, name) do { \
91 prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \
93 prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \
94 } while (/*CONSTCOND*/0)
96 #define DM_ADD_FLAG(flag, name) do { \
97 prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \
99 prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \
100 } while (/*CONSTCOND*/0)
103 * Print flags sent to the kernel from libevmapper.
106 dm_dbg_print_flags(int flags)
108 aprint_debug("dbg_print --- %d\n", flags);
110 if (flags & DM_READONLY_FLAG)
111 aprint_debug("dbg_flags: DM_READONLY_FLAG set In/Out\n");
113 if (flags & DM_SUSPEND_FLAG)
114 aprint_debug("dbg_flags: DM_SUSPEND_FLAG set In/Out\n");
116 if (flags & DM_PERSISTENT_DEV_FLAG)
117 aprint_debug("dbg_flags: DM_PERSISTENT_DEV_FLAG set In\n");
119 if (flags & DM_STATUS_TABLE_FLAG)
120 aprint_debug("dbg_flags: DM_STATUS_TABLE_FLAG set In\n");
122 if (flags & DM_ACTIVE_PRESENT_FLAG)
123 aprint_debug("dbg_flags: DM_ACTIVE_PRESENT_FLAG set Out\n");
125 if (flags & DM_INACTIVE_PRESENT_FLAG)
126 aprint_debug("dbg_flags: DM_INACTIVE_PRESENT_FLAG set Out\n");
128 if (flags & DM_BUFFER_FULL_FLAG)
129 aprint_debug("dbg_flags: DM_BUFFER_FULL_FLAG set Out\n");
131 if (flags & DM_SKIP_BDGET_FLAG)
132 aprint_debug("dbg_flags: DM_SKIP_BDGET_FLAG set In\n");
134 if (flags & DM_SKIP_LOCKFS_FLAG)
135 aprint_debug("dbg_flags: DM_SKIP_LOCKFS_FLAG set In\n");
137 if (flags & DM_NOFLUSH_FLAG)
138 aprint_debug("dbg_flags: DM_NOFLUSH_FLAG set In\n");
143 * Get version ioctl call I do it as default therefore this
144 * function is unused now.
147 dm_get_version_ioctl(prop_dictionary_t dm_dict)
152 * Get list of all available targets from global
153 * target list and sent them back to libdevmapper.
156 dm_list_versions_ioctl(prop_dictionary_t dm_dict)
158 prop_array_t target_list;
163 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
165 dm_dbg_print_flags(flags);
166 target_list = dm_target_prop_list();
168 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, target_list);
169 prop_object_release(target_list);
174 * Create in-kernel entry for device. Device attributes such as name, uuid are
175 * taken from proplib dictionary.
179 dm_dev_create_ioctl(prop_dictionary_t dm_dict)
182 const char *name, *uuid;
190 /* Get needed values from dictionary. */
191 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
192 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
193 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
195 dm_dbg_print_flags(flags);
197 /* Lookup name and uuid if device already exist quit. */
198 if ((dmv = dm_dev_lookup(name, uuid, -1)) != NULL) {
199 DM_ADD_FLAG(flags, DM_EXISTS_FLAG); /* Device already exists */
204 r = dm_dev_create(&dmv, name, uuid, flags);
206 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
207 DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
208 DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
214 * Get list of created device-mapper devices fromglobal list and
219 * <key>cmd_data</key>
223 * <string>...</string>
226 * <integer>...</integer>
232 dm_dev_list_ioctl(prop_dictionary_t dm_dict)
234 prop_array_t dev_list;
240 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
242 dm_dbg_print_flags(flags);
244 dev_list = dm_dev_prop_list();
246 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list);
247 prop_object_release(dev_list);
252 * Rename selected devices old name is in struct dm_ioctl.
253 * newname is taken from dictionary
255 * <key>cmd_data</key>
257 * <string>...</string>
261 dm_dev_rename_ioctl(prop_dictionary_t dm_dict)
264 prop_array_t cmd_array;
267 const char *name, *uuid, *n_name;
268 uint32_t flags, minor;
274 /* Get needed values from dictionary. */
275 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
276 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
277 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
278 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
280 dm_dbg_print_flags(flags);
282 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
284 prop_array_get_cstring_nocopy(cmd_array, 0, &n_name);
286 if (strlen(n_name) + 1 > DM_NAME_LEN)
289 if ((dmv = dm_dev_rem(name, uuid, minor)) == NULL) {
290 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
293 /* change device name */
295 * XXX How to deal with this change, name only used in
296 * dm_dev_routines, should I add dm_dev_change_name which will run
297 * under the dm_dev_list mutex ?
299 strlcpy(dmv->name, n_name, DM_NAME_LEN);
301 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
302 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
303 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
309 * XXX: the rename is not yet implemented. The main complication
310 * here is devfs. We'd probably need a new function, rename_dev()
311 * that would trigger a node rename in devfs.
313 kprintf("dm_dev_rename_ioctl called, but not implemented!\n");
321 dm_dev_remove_ioctl(prop_dictionary_t dm_dict)
324 const char *name, *uuid;
325 uint32_t flags, minor, is_open;
331 /* Get needed values from dictionary. */
332 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
333 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
334 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
335 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
337 dm_dbg_print_flags(flags);
339 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
340 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
344 is_open = dmv->is_open;
352 * This will call dm_dev_rem_dev routine which will actually remove
355 return dm_dev_remove(dmv);
359 * Try to remove all devices
362 dm_dev_remove_all_ioctl(prop_dictionary_t dm_dict)
366 /* Get needed values from dictionary. */
367 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
369 dm_dbg_print_flags(flags);
371 /* Gently remove all devices, if possible */
372 return dm_dev_remove_all(1);
376 * Return actual state of device to libdevmapper.
379 dm_dev_status_ioctl(prop_dictionary_t dm_dict)
382 const char *name, *uuid;
383 uint32_t flags, j, minor;
390 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
391 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
392 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
393 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
395 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
396 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
399 dm_dbg_print_flags(dmv->flags);
401 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
402 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
403 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
405 if (dmv->flags & DM_SUSPEND_FLAG)
406 DM_ADD_FLAG(flags, DM_SUSPEND_FLAG);
409 * Add status flags for tables I have to check both active and
412 if ((j = dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE))) {
413 DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
415 DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
417 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_TARGET_COUNT, j);
419 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE))
420 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
422 DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
429 * Set only flag to suggest that device is suspended. This call is
430 * not supported in NetBSD.
434 dm_dev_suspend_ioctl(prop_dictionary_t dm_dict)
437 const char *name, *uuid;
438 uint32_t flags, minor;
444 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
445 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
446 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
447 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
449 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
450 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
453 atomic_set_int(&dmv->flags, DM_SUSPEND_FLAG);
455 dm_dbg_print_flags(dmv->flags);
457 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
458 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags);
459 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
463 /* Add flags to dictionary flag after dmv -> dict copy */
464 DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
469 * Simulate Linux behaviour better and switch tables here and not in
470 * dm_table_load_ioctl.
473 dm_dev_resume_ioctl(prop_dictionary_t dm_dict)
476 const char *name, *uuid;
477 uint32_t flags, minor;
484 * char *xml; xml = prop_dictionary_externalize(dm_dict);
485 * printf("%s\n",xml);
488 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
489 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
490 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
491 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
493 /* Remove device from global device list */
494 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
495 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
498 atomic_clear_int(&dmv->flags, (DM_SUSPEND_FLAG | DM_INACTIVE_PRESENT_FLAG));
499 atomic_set_int(&dmv->flags, DM_ACTIVE_PRESENT_FLAG);
501 dm_table_switch_tables(&dmv->table_head);
503 DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
505 dmsetdiskinfo(dmv->diskp, &dmv->table_head);
507 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
508 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags);
509 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
513 /* Destroy inactive table after resume. */
514 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
519 * Table management routines
520 * lvm2tools doens't send name/uuid to kernel with table
521 * for lookup I have to use minor number.
525 * Remove inactive table from device. Routines which work's with inactive tables
526 * doesn't need to synchronise with dmstrategy. They can synchronise themselves with mutex?.
530 dm_table_clear_ioctl(prop_dictionary_t dm_dict)
533 const char *name, *uuid;
534 uint32_t flags, minor;
542 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
543 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
544 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
545 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
547 aprint_debug("Clearing inactive table from device: %s--%s\n",
550 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
551 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
554 /* Select unused table */
555 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
557 atomic_clear_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG);
564 * Get list of physical devices for active table.
565 * Get dev_t from pdev vnode and insert it into cmd_array.
567 * XXX. This function is called from lvm2tools to get information
568 * about physical devices, too e.g. during vgcreate.
571 dm_table_deps_ioctl(prop_dictionary_t dm_dict)
575 dm_table_entry_t *table_en;
577 prop_array_t cmd_array;
578 const char *name, *uuid;
579 uint32_t flags, minor;
588 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
589 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
590 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
591 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
593 /* create array for dev_t's */
594 cmd_array = prop_array_create();
596 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
597 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
600 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
601 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_NAME, dmv->name);
602 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
604 aprint_debug("Getting table deps for device: %s\n", dmv->name);
607 * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query
610 if (flags & DM_QUERY_INACTIVE_TABLE_FLAG)
611 table_type = DM_TABLE_INACTIVE;
613 table_type = DM_TABLE_ACTIVE;
615 tbl = dm_table_get_entry(&dmv->table_head, table_type);
617 SLIST_FOREACH(table_en, tbl, next)
618 table_en->target->deps(table_en, cmd_array);
620 dm_table_release(&dmv->table_head, table_type);
623 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array);
624 prop_object_release(cmd_array);
629 * Load new table/tables to device.
630 * Call apropriate target init routine open all physical pdev's and
631 * link them to device. For other targets mirror, strip, snapshot
632 * etc. also add dependency devices to upcalls list.
634 * Load table to inactive slot table are switched in dm_device_resume_ioctl.
635 * This simulates Linux behaviour better there should not be any difference.
639 dm_table_load_ioctl(prop_dictionary_t dm_dict)
642 dm_table_entry_t *table_en, *last_table;
646 prop_object_iterator_t iter;
647 prop_array_t cmd_array;
648 prop_dictionary_t target_dict;
650 const char *name, *uuid, *type;
652 uint32_t flags, ret, minor;
665 * char *xml; xml = prop_dictionary_externalize(dm_dict);
666 * printf("%s\n",xml);
669 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
670 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
671 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
672 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
674 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
675 iter = prop_array_iterator(cmd_array);
676 dm_dbg_print_flags(flags);
678 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
679 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
682 aprint_debug("Loading table to device: %s--%d\n", name,
683 dmv->table_head.cur_active_table);
686 * I have to check if this table slot is not used by another table list.
687 * if it is used I should free them.
689 if (dmv->flags & DM_INACTIVE_PRESENT_FLAG)
690 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
692 dm_dbg_print_flags(dmv->flags);
693 tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_INACTIVE);
695 aprint_debug("dmv->name = %s\n", dmv->name);
697 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
699 while ((target_dict = prop_object_iterator_next(iter)) != NULL) {
700 prop_dictionary_get_cstring_nocopy(target_dict,
701 DM_TABLE_TYPE, &type);
703 * If we want to deny table with 2 or more different
704 * target we should do it here
706 if (((target = dm_target_lookup(type)) == NULL) &&
707 ((target = dm_target_autoload(type)) == NULL)) {
708 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
712 if ((table_en = kmalloc(sizeof(dm_table_entry_t),
713 M_DM, M_WAITOK)) == NULL) {
714 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
716 dm_target_unbusy(target);
719 prop_dictionary_get_uint64(target_dict, DM_TABLE_START,
721 prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH,
724 aprint_debug("dm_ioctl.c... table_en->start = %ju, "
725 "table_en->length = %ju\n",
726 (uintmax_t)table_en->start,
727 (uintmax_t)table_en->length);
729 table_en->target = target;
730 table_en->dm_dev = dmv;
731 table_en->target_config = NULL;
734 * There is a parameter string after dm_target_spec
735 * structure which points to /dev/wd0a 284 part of
736 * table. String str points to this text. This can be
737 * null and therefore it should be checked before we try to
740 prop_dictionary_get_cstring(target_dict,
741 DM_TABLE_PARAMS, &str);
743 if (SLIST_EMPTY(tbl))
744 /* insert this table to head */
745 SLIST_INSERT_HEAD(tbl, table_en, next);
747 SLIST_INSERT_AFTER(last_table, table_en, next);
750 * Params string is different for every target,
751 * therfore I have to pass it to target init
752 * routine and parse parameters there.
754 aprint_debug("DM: str passed in is: \"%s\"\n", str);
755 if ((ret = target->init(dmv, &table_en->target_config,
758 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
759 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
765 last_table = table_en;
768 prop_object_iterator_release(iter);
770 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
771 atomic_set_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG);
773 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
777 dmsetdiskinfo(dmv->diskp, &dmv->table_head);
782 * Get description of all tables loaded to device from kernel
783 * and send it to libdevmapper.
785 * Output dictionary for every table:
787 * <key>cmd_data</key>
791 * <string>...</string>
794 * <integer>...</integer>
797 * <integer>...</integer>
800 * <string>...</string>
806 dm_table_status_ioctl(prop_dictionary_t dm_dict)
810 dm_table_entry_t *table_en;
812 prop_array_t cmd_array;
813 prop_dictionary_t target_dict;
817 const char *name, *uuid;
828 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
829 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
830 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
831 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
833 cmd_array = prop_array_create();
835 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
836 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
840 * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query
843 if (flags & DM_QUERY_INACTIVE_TABLE_FLAG)
844 table_type = DM_TABLE_INACTIVE;
846 table_type = DM_TABLE_ACTIVE;
848 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE))
849 DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
851 DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
853 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE))
854 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
856 DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
860 if (dmv->flags & DM_SUSPEND_FLAG)
861 DM_ADD_FLAG(flags, DM_SUSPEND_FLAG);
863 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
865 aprint_debug("Status of device tables: %s--%d\n",
866 name, dmv->table_head.cur_active_table);
868 tbl = dm_table_get_entry(&dmv->table_head, table_type);
870 SLIST_FOREACH(table_en, tbl, next) {
871 target_dict = prop_dictionary_create();
872 aprint_debug("%016" PRIu64 ", length %016" PRIu64
873 ", target %s\n", table_en->start, table_en->length,
874 table_en->target->name);
876 prop_dictionary_set_uint64(target_dict, DM_TABLE_START,
878 prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH,
881 prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE,
882 table_en->target->name);
884 /* dm_table_get_cur_actv.table ?? */
885 prop_dictionary_set_int32(target_dict, DM_TABLE_STAT,
886 dmv->table_head.cur_active_table);
888 if (flags & DM_STATUS_TABLE_FLAG) {
889 params = table_en->target->status
890 (table_en->target_config);
892 if (params != NULL) {
893 prop_dictionary_set_cstring(target_dict,
894 DM_TABLE_PARAMS, params);
899 prop_array_add(cmd_array, target_dict);
900 prop_object_release(target_dict);
903 dm_table_release(&dmv->table_head, table_type);
906 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags);
907 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array);
908 prop_object_release(cmd_array);
914 dm_message_ioctl(prop_dictionary_t dm_dict)
917 dm_table_entry_t *table_en;
919 const char *name, *uuid;
920 uint32_t flags, minor;
921 uint64_t table_start, table_end, sector;
929 /* Get needed values from dictionary. */
930 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
931 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
932 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
933 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
934 prop_dictionary_get_uint64(dm_dict, DM_MESSAGE_SECTOR, §or);
936 dm_dbg_print_flags(flags);
938 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
939 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
943 /* Get message string */
944 prop_dictionary_get_cstring(dm_dict, DM_MESSAGE_STR, &msg);
946 tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE);
951 if (!SLIST_EMPTY(tbl)) {
952 table_en = SLIST_FIRST(tbl);
956 SLIST_FOREACH(table_en, tbl, next) {
957 table_start = table_en->start;
958 table_end = table_start + (table_en->length);
960 if ((sector >= table_start) && (sector < table_end)) {
968 if (table_en->target->message != NULL)
969 ret = table_en->target->message(table_en, msg);
972 dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE);
982 * For every call I have to set kernel driver version.
983 * Because I can have commands supported only in other
984 * newer/later version. This routine is called for every
988 dm_check_version(prop_dictionary_t dm_dict)
994 ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION);
996 for (i = 0; i < 3; i++)
997 prop_array_get_uint32(ver, i, &dm_version[i]);
999 if (DM_VERSION_MAJOR != dm_version[0] || DM_VERSION_MINOR < dm_version[1]) {
1000 aprint_debug("libdevmapper/kernel version mismatch "
1001 "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n",
1002 DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL,
1003 dm_version[0], dm_version[1], dm_version[2]);
1007 prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR);
1008 prop_array_set_uint32(ver, 1, DM_VERSION_MINOR);
1009 prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL);
1011 prop_dictionary_set(dm_dict, DM_IOCTL_VERSION, ver);