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/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 dm_table_deps(dm_table_entry_t *, prop_array_t);
105 dm_table_init(dm_target_t *, dm_table_entry_t *, char *);
108 * Print flags sent to the kernel from libevmapper.
111 dm_dbg_print_flags(int flags)
113 aprint_debug("dbg_print --- %d\n", flags);
115 if (flags & DM_READONLY_FLAG)
116 aprint_debug("dbg_flags: DM_READONLY_FLAG set In/Out\n");
118 if (flags & DM_SUSPEND_FLAG)
119 aprint_debug("dbg_flags: DM_SUSPEND_FLAG set In/Out\n");
121 if (flags & DM_PERSISTENT_DEV_FLAG)
122 aprint_debug("dbg_flags: DM_PERSISTENT_DEV_FLAG set In\n");
124 if (flags & DM_STATUS_TABLE_FLAG)
125 aprint_debug("dbg_flags: DM_STATUS_TABLE_FLAG set In\n");
127 if (flags & DM_ACTIVE_PRESENT_FLAG)
128 aprint_debug("dbg_flags: DM_ACTIVE_PRESENT_FLAG set Out\n");
130 if (flags & DM_INACTIVE_PRESENT_FLAG)
131 aprint_debug("dbg_flags: DM_INACTIVE_PRESENT_FLAG set Out\n");
133 if (flags & DM_BUFFER_FULL_FLAG)
134 aprint_debug("dbg_flags: DM_BUFFER_FULL_FLAG set Out\n");
136 if (flags & DM_SKIP_BDGET_FLAG)
137 aprint_debug("dbg_flags: DM_SKIP_BDGET_FLAG set In\n");
139 if (flags & DM_SKIP_LOCKFS_FLAG)
140 aprint_debug("dbg_flags: DM_SKIP_LOCKFS_FLAG set In\n");
142 if (flags & DM_NOFLUSH_FLAG)
143 aprint_debug("dbg_flags: DM_NOFLUSH_FLAG set In\n");
148 * Get list of all available targets from global
149 * target list and sent them back to libdevmapper.
152 dm_list_versions_ioctl(prop_dictionary_t dm_dict)
154 prop_array_t target_list;
159 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
161 dm_dbg_print_flags(flags);
162 target_list = dm_target_prop_list();
164 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, target_list);
165 prop_object_release(target_list);
170 * Create in-kernel entry for device. Device attributes such as name, uuid are
171 * taken from proplib dictionary.
175 dm_dev_create_ioctl(prop_dictionary_t dm_dict)
178 const char *name, *uuid;
186 /* Get needed values from dictionary. */
187 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
188 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
189 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
191 dm_dbg_print_flags(flags);
193 /* Lookup name and uuid if device already exist quit. */
194 if ((dmv = dm_dev_lookup(name, uuid, -1)) != NULL) {
195 DM_ADD_FLAG(flags, DM_EXISTS_FLAG); /* Device already exists */
200 r = dm_dev_create(&dmv, name, uuid, flags);
202 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
203 DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
204 DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
210 * Get list of created device-mapper devices fromglobal list and
215 * <key>cmd_data</key>
219 * <string>...</string>
222 * <integer>...</integer>
228 dm_dev_list_ioctl(prop_dictionary_t dm_dict)
230 prop_array_t dev_list;
236 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
238 dm_dbg_print_flags(flags);
240 dev_list = dm_dev_prop_list();
242 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list);
243 prop_object_release(dev_list);
248 * Rename selected devices old name is in struct dm_ioctl.
249 * newname is taken from dictionary
251 * <key>cmd_data</key>
253 * <string>...</string>
257 dm_dev_rename_ioctl(prop_dictionary_t dm_dict)
260 prop_array_t cmd_array;
263 const char *name, *uuid, *n_name;
264 uint32_t flags, minor;
270 /* Get needed values from dictionary. */
271 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
272 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
273 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
274 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
276 dm_dbg_print_flags(flags);
278 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
280 prop_array_get_cstring_nocopy(cmd_array, 0, &n_name);
282 if (strlen(n_name) + 1 > DM_NAME_LEN)
285 if ((dmv = dm_dev_rem(name, uuid, minor)) == NULL) {
286 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
289 /* change device name */
291 * XXX How to deal with this change, name only used in
292 * dm_dev_routines, should I add dm_dev_change_name which will run
293 * under the dm_dev_list mutex ?
295 strlcpy(dmv->name, n_name, DM_NAME_LEN);
297 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
298 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
299 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
305 * XXX: the rename is not yet implemented. The main complication
306 * here is devfs. We'd probably need a new function, rename_dev()
307 * that would trigger a node rename in devfs.
309 kprintf("dm_dev_rename_ioctl called, but not implemented!\n");
317 dm_dev_remove_ioctl(prop_dictionary_t dm_dict)
320 const char *name, *uuid;
321 uint32_t flags, minor, is_open;
327 /* Get needed values from dictionary. */
328 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
329 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
330 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
331 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
333 dm_dbg_print_flags(flags);
335 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
336 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
340 is_open = dmv->is_open;
348 * This will call dm_dev_rem_dev routine which will actually remove
351 return dm_dev_remove(dmv);
355 * Try to remove all devices
358 dm_dev_remove_all_ioctl(prop_dictionary_t dm_dict)
362 /* Get needed values from dictionary. */
363 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
365 dm_dbg_print_flags(flags);
367 /* Gently remove all devices, if possible */
368 return dm_dev_remove_all(1);
372 * Return actual state of device to libdevmapper.
375 dm_dev_status_ioctl(prop_dictionary_t dm_dict)
378 const char *name, *uuid;
379 uint32_t flags, j, minor;
386 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
387 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
388 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
389 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
391 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
392 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
395 dm_dbg_print_flags(dmv->flags);
397 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
398 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
399 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
401 if (dmv->flags & DM_SUSPEND_FLAG)
402 DM_ADD_FLAG(flags, DM_SUSPEND_FLAG);
405 * Add status flags for tables I have to check both active and
408 if ((j = dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE))) {
409 DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
411 DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
413 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_TARGET_COUNT, j);
415 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE))
416 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
418 DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
425 * Set only flag to suggest that device is suspended. This call is
426 * not supported in NetBSD.
430 dm_dev_suspend_ioctl(prop_dictionary_t dm_dict)
433 const char *name, *uuid;
434 uint32_t flags, minor;
440 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
441 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
442 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
443 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
445 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
446 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
449 atomic_set_int(&dmv->flags, DM_SUSPEND_FLAG);
451 dm_dbg_print_flags(dmv->flags);
453 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
454 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags);
455 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
459 /* Add flags to dictionary flag after dmv -> dict copy */
460 DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
465 * Simulate Linux behaviour better and switch tables here and not in
466 * dm_table_load_ioctl.
469 dm_dev_resume_ioctl(prop_dictionary_t dm_dict)
472 const char *name, *uuid;
473 uint32_t flags, minor;
480 * char *xml; xml = prop_dictionary_externalize(dm_dict);
481 * kprintf("%s\n",xml);
484 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
485 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
486 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
487 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
489 /* Remove device from global device list */
490 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
491 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
494 atomic_clear_int(&dmv->flags, (DM_SUSPEND_FLAG | DM_INACTIVE_PRESENT_FLAG));
495 atomic_set_int(&dmv->flags, DM_ACTIVE_PRESENT_FLAG);
497 dm_table_switch_tables(&dmv->table_head);
499 DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
501 dmsetdiskinfo(dmv->diskp, &dmv->table_head);
503 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
504 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags);
505 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
509 /* Destroy inactive table after resume. */
510 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
515 * Table management routines
516 * lvm2tools doens't send name/uuid to kernel with table
517 * for lookup I have to use minor number.
521 * Remove inactive table from device. Routines which work's with inactive tables
522 * doesn't need to synchronise with dmstrategy. They can synchronise themselves with mutex?.
526 dm_table_clear_ioctl(prop_dictionary_t dm_dict)
529 const char *name, *uuid;
530 uint32_t flags, minor;
538 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
539 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
540 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
541 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
543 aprint_debug("Clearing inactive table from device: %s--%s\n",
546 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
547 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
550 /* Select unused table */
551 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
553 atomic_clear_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG);
560 * Get list of physical devices for active table.
561 * Get dev_t from pdev vnode and insert it into cmd_array.
563 * XXX. This function is called from lvm2tools to get information
564 * about physical devices, too e.g. during vgcreate.
567 dm_table_deps_ioctl(prop_dictionary_t dm_dict)
571 dm_table_entry_t *table_en;
573 prop_array_t cmd_array;
574 const char *name, *uuid;
575 uint32_t flags, minor;
584 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
585 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
586 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
587 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
589 /* create array for dev_t's */
590 cmd_array = prop_array_create();
592 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
593 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
596 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
597 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_NAME, dmv->name);
598 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
600 aprint_debug("Getting table deps for device: %s\n", dmv->name);
603 * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query
606 if (flags & DM_QUERY_INACTIVE_TABLE_FLAG)
607 table_type = DM_TABLE_INACTIVE;
609 table_type = DM_TABLE_ACTIVE;
611 tbl = dm_table_get_entry(&dmv->table_head, table_type);
613 TAILQ_FOREACH(table_en, tbl, next)
614 dm_table_deps(table_en, cmd_array);
616 dm_table_release(&dmv->table_head, table_type);
619 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array);
620 prop_object_release(cmd_array);
626 dm_table_deps(dm_table_entry_t *table_en, prop_array_t array)
632 size = prop_array_count(array);
634 TAILQ_FOREACH(map, &table_en->pdev_maps, next) {
635 ret = map->data.pdev->udev;
636 for (i = 0; i < size; i++) {
637 if (prop_array_get_uint64(array, i, &tmp) == true)
642 * Ignore if the device has already been added by
646 prop_array_add_uint64(array, ret);
653 * Load new table/tables to device.
654 * Call apropriate target init routine open all physical pdev's and
655 * link them to device. For other targets mirror, strip, snapshot
656 * etc. also add dependency devices to upcalls list.
658 * Load table to inactive slot table are switched in dm_device_resume_ioctl.
659 * This simulates Linux behaviour better there should not be any difference.
663 dm_table_load_ioctl(prop_dictionary_t dm_dict)
666 dm_table_entry_t *table_en;
670 prop_object_iterator_t iter;
671 prop_array_t cmd_array;
672 prop_dictionary_t target_dict;
674 const char *name, *uuid, *type;
676 uint32_t flags, ret, minor;
688 * char *xml; xml = prop_dictionary_externalize(dm_dict);
689 * kprintf("%s\n",xml);
692 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
693 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
694 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
695 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
697 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
698 iter = prop_array_iterator(cmd_array);
699 dm_dbg_print_flags(flags);
701 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
702 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
705 aprint_debug("Loading table to device: %s--%d\n", name,
706 dmv->table_head.cur_active_table);
709 * I have to check if this table slot is not used by another table list.
710 * if it is used I should free them.
712 if (dmv->flags & DM_INACTIVE_PRESENT_FLAG)
713 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
715 dm_dbg_print_flags(dmv->flags);
716 tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_INACTIVE);
718 aprint_debug("dmv->name = %s\n", dmv->name);
720 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
722 while ((target_dict = prop_object_iterator_next(iter)) != NULL) {
723 prop_dictionary_get_cstring_nocopy(target_dict,
724 DM_TABLE_TYPE, &type);
726 * If we want to deny table with 2 or more different
727 * target we should do it here
729 if (((target = dm_target_lookup(type)) == NULL) &&
730 ((target = dm_target_autoload(type)) == NULL)) {
731 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
735 if ((table_en = kmalloc(sizeof(dm_table_entry_t),
736 M_DM, M_WAITOK)) == NULL) {
737 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
739 dm_target_unbusy(target);
742 prop_dictionary_get_uint64(target_dict, DM_TABLE_START,
744 prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH,
747 aprint_debug("dm_ioctl.c... table_en->start = %ju, "
748 "table_en->length = %ju\n",
749 (uintmax_t)table_en->start,
750 (uintmax_t)table_en->length);
752 table_en->target = target;
754 table_en->target_config = NULL;
755 TAILQ_INIT(&table_en->pdev_maps);
758 * There is a parameter string after dm_target_spec
759 * structure which points to /dev/wd0a 284 part of
760 * table. String str points to this text. This can be
761 * null and therefore it should be checked before we try to
764 prop_dictionary_get_cstring(target_dict,
765 DM_TABLE_PARAMS, &str);
767 TAILQ_INSERT_TAIL(tbl, table_en, next);
770 * Params string is different for every target,
771 * therfore I have to pass it to target init
772 * routine and parse parameters there.
774 aprint_debug("DM: str passed in is: \"%s\"\n", str);
776 if ((ret = dm_table_init(target, table_en, str)) != 0) {
777 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
778 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
786 prop_object_iterator_release(iter);
788 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
789 atomic_set_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG);
791 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
795 dmsetdiskinfo(dmv->diskp, &dmv->table_head);
801 dm_table_init(dm_target_t *target, dm_table_entry_t *table_en, char *params)
809 n = target->max_argc;
811 aprint_debug("Max argc %d for %s target\n", n, target->name);
813 n = 20; /* large enough slots for most targets */
816 argv = kmalloc(sizeof(*argv) * n, M_DM, M_WAITOK | M_ZERO);
819 ap < &argv[n] && (*ap = strsep(¶ms, " \t")) != NULL;) {
825 if (dm_debug_level) {
826 for (i = 0; i < argc; i++)
827 kprintf("DM: argv[%d] = \"%s\"\n", i, argv[i]);
830 KKASSERT(target->init);
831 ret = target->init(table_en, argc, argv);
839 * Get description of all tables loaded to device from kernel
840 * and send it to libdevmapper.
842 * Output dictionary for every table:
844 * <key>cmd_data</key>
848 * <string>...</string>
851 * <integer>...</integer>
854 * <integer>...</integer>
857 * <string>...</string>
863 dm_table_status_ioctl(prop_dictionary_t dm_dict)
867 dm_table_entry_t *table_en;
869 prop_array_t cmd_array;
870 prop_dictionary_t target_dict;
874 const char *name, *uuid;
885 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
886 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
887 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
888 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
890 cmd_array = prop_array_create();
892 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
893 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
897 * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query
900 if (flags & DM_QUERY_INACTIVE_TABLE_FLAG)
901 table_type = DM_TABLE_INACTIVE;
903 table_type = DM_TABLE_ACTIVE;
905 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE))
906 DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
908 DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
910 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE))
911 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
913 DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
917 if (dmv->flags & DM_SUSPEND_FLAG)
918 DM_ADD_FLAG(flags, DM_SUSPEND_FLAG);
920 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
922 aprint_debug("Status of device tables: %s--%d\n",
923 name, dmv->table_head.cur_active_table);
925 tbl = dm_table_get_entry(&dmv->table_head, table_type);
927 TAILQ_FOREACH(table_en, tbl, next) {
928 target_dict = prop_dictionary_create();
929 aprint_debug("%016" PRIu64 ", length %016" PRIu64
930 ", target %s\n", table_en->start, table_en->length,
931 table_en->target->name);
933 prop_dictionary_set_uint64(target_dict, DM_TABLE_START,
935 prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH,
938 prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE,
939 table_en->target->name);
941 /* dm_table_get_cur_actv.table ?? */
942 prop_dictionary_set_int32(target_dict, DM_TABLE_STAT,
943 dmv->table_head.cur_active_table);
945 if (flags & DM_STATUS_TABLE_FLAG) {
946 params = table_en->target->table
947 (table_en->target_config);
948 } else if (table_en->target->info) {
949 params = table_en->target->info
950 (table_en->target_config);
955 if (params != NULL) {
956 prop_dictionary_set_cstring(target_dict,
957 DM_TABLE_PARAMS, params);
960 prop_dictionary_set_cstring(target_dict,
961 DM_TABLE_PARAMS, "");
964 prop_array_add(cmd_array, target_dict);
965 prop_object_release(target_dict);
968 dm_table_release(&dmv->table_head, table_type);
971 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags);
972 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array);
973 prop_object_release(cmd_array);
979 dm_message_ioctl(prop_dictionary_t dm_dict)
982 dm_table_entry_t *table_en;
984 const char *name, *uuid;
985 uint32_t flags, minor;
986 uint64_t table_start, table_end, sector;
994 /* Get needed values from dictionary. */
995 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
996 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
997 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
998 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
999 prop_dictionary_get_uint64(dm_dict, DM_MESSAGE_SECTOR, §or);
1001 dm_dbg_print_flags(flags);
1003 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
1004 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
1008 /* Get message string */
1009 prop_dictionary_get_cstring(dm_dict, DM_MESSAGE_STR, &msg);
1011 tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE);
1016 if (!TAILQ_EMPTY(tbl)) {
1017 table_en = TAILQ_FIRST(tbl);
1021 TAILQ_FOREACH(table_en, tbl, next) {
1022 table_start = table_en->start;
1023 table_end = table_start + table_en->length;
1025 if ((sector >= table_start) && (sector < table_end)) {
1033 if (table_en->target->message != NULL)
1034 ret = table_en->target->message(table_en, msg);
1037 dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE);
1047 * For every call I have to set kernel driver version.
1048 * Because I can have commands supported only in other
1049 * newer/later version. This routine is called for every
1053 dm_check_version(prop_dictionary_t dm_dict)
1059 ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION);
1061 for (i = 0; i < 3; i++)
1062 prop_array_get_uint32(ver, i, &dm_version[i]);
1064 if (DM_VERSION_MAJOR != dm_version[0] || DM_VERSION_MINOR < dm_version[1]) {
1065 aprint_debug("libdevmapper/kernel version mismatch "
1066 "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n",
1067 DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL,
1068 dm_version[0], dm_version[1], dm_version[2]);
1072 prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR);
1073 prop_array_set_uint32(ver, 1, DM_VERSION_MINOR);
1074 prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL);
1076 prop_dictionary_set(dm_dict, DM_IOCTL_VERSION, ver);