Home | History | Annotate | Line # | Download | only in dm
dm_ioctl.c revision 1.5
      1 /*        $NetBSD: dm_ioctl.c,v 1.5 2009/01/11 11:54:52 haad Exp $      */
      2 
      3 /*
      4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Adam Hamsik.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Locking is used to synchronise between ioctl calls and between dm_table's
     34  * users.
     35  *
     36  * ioctl locking:
     37  * Simple reference counting, to count users of device will be used routines
     38  * dm_dev_busy/dm_dev_unbusy are used for that.
     39  * dm_dev_lookup/dm_dev_rem call dm_dev_busy before return(caller is therefore
     40  * holder of reference_counter last).
     41  *
     42  * ioctl routines which change/remove dm_dev parameters must wait on
     43  * dm_dev::dev_cv and when last user will call dm_dev_unbusy they will wake
     44  * up them.
     45  *
     46  * table_head locking:
     47  * To access table entries dm_table_* routines must be used.
     48  *
     49  * dm_table_get_entry will increment table users reference
     50  * counter. It will return active or inactive table depedns
     51  * on uint8_t argument.
     52  *
     53  * dm_table_release must be called for every table_entry from
     54  * dm_table_get_entry. Between these to calls tables can'tbe switched
     55  * or destroyed.
     56  *
     57  * dm_table_head_init initialize talbe_entries SLISTS and io_cv.
     58  *
     59  * dm_table_head_destroy destroy cv.
     60  *
     61  * There are two types of users for dm_table_head first type will
     62  * only read list and try to do anything with it e.g. dmstrategy,
     63  * dm_table_size etc. There is another user for table_head which wants
     64  * to change table lists e.g. dm_dev_resume_ioctl, dm_dev_remove_ioctl,
     65  * dm_table_clear_ioctl.
     66  *
     67  * NOTE: It is not allowed to call dm_table_destroy, dm_table_switch_tables
     68  *       with hold table reference counter. Table reference counter is hold
     69  *       after calling dm_table_get_entry routine. After calling this
     70  *       function user must call dm_table_release before any writer table
     71  *       operation.
     72  *
     73  * Example: dm_table_get_entry
     74  *          dm_table_destroy/dm_table_switch_tables
     75  * This exaple will lead to deadlock situation because after dm_table_get_entry
     76  * table reference counter is != 0 and dm_table_destroy have to wait on cv until
     77  * reference counter is 0.
     78  *
     79  */
     80 
     81 #include <sys/types.h>
     82 #include <sys/param.h>
     83 
     84 #include <sys/disklabel.h>
     85 #include <sys/kmem.h>
     86 #include <sys/malloc.h>
     87 #include <sys/vnode.h>
     88 
     89 #include <machine/int_fmtio.h>
     90 
     91 #include "netbsd-dm.h"
     92 #include "dm.h"
     93 
     94 static uint64_t      sc_minor_num;
     95 
     96 #define DM_REMOVE_FLAG(flag, name) do {					\
     97 		prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \
     98 		flag &= ~name;						\
     99 		prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \
    100 	} while (/*CONSTCOND*/0)
    101 
    102 #define DM_ADD_FLAG(flag, name) do {					\
    103 		prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \
    104 		flag |= name;						\
    105 		prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \
    106 	} while (/*CONSTCOND*/0)
    107 
    108 static int dm_dbg_print_flags(int);
    109 
    110 /*
    111  * Print flags sent to the kernel from libevmapper.
    112  */
    113 static int
    114 dm_dbg_print_flags(int flags)
    115 {
    116 	aprint_debug("dbg_print --- %d\n",flags);
    117 
    118 	if (flags & DM_READONLY_FLAG)
    119 		aprint_debug("dbg_flags: DM_READONLY_FLAG set In/Out\n");
    120 
    121 	if (flags & DM_SUSPEND_FLAG)
    122 		aprint_debug("dbg_flags: DM_SUSPEND_FLAG set In/Out \n");
    123 
    124 	if (flags & DM_PERSISTENT_DEV_FLAG)
    125 		aprint_debug("db_flags: DM_PERSISTENT_DEV_FLAG set In\n");
    126 
    127 	if (flags & DM_STATUS_TABLE_FLAG)
    128 		aprint_debug("dbg_flags: DM_STATUS_TABLE_FLAG set In\n");
    129 
    130 	if (flags & DM_ACTIVE_PRESENT_FLAG)
    131 		aprint_debug("dbg_flags: DM_ACTIVE_PRESENT_FLAG set Out\n");
    132 
    133 	if (flags & DM_INACTIVE_PRESENT_FLAG)
    134 		aprint_debug("dbg_flags: DM_INACTIVE_PRESENT_FLAG set Out\n");
    135 
    136 	if (flags & DM_BUFFER_FULL_FLAG)
    137 		aprint_debug("dbg_flags: DM_BUFFER_FULL_FLAG set Out\n");
    138 
    139 	if (flags & DM_SKIP_BDGET_FLAG)
    140 		aprint_debug("dbg_flags: DM_SKIP_BDGET_FLAG set In\n");
    141 
    142 	if (flags & DM_SKIP_LOCKFS_FLAG)
    143 		aprint_debug("dbg_flags: DM_SKIP_LOCKFS_FLAG set In\n");
    144 
    145 	if (flags & DM_NOFLUSH_FLAG)
    146 		aprint_debug("dbg_flags: DM_NOFLUSH_FLAG set In\n");
    147 
    148 	return 0;
    149 }
    150 
    151 /*
    152  * Get version ioctl call I do it as default therefore this
    153  * function is unused now.
    154  */
    155 int
    156 dm_get_version_ioctl(prop_dictionary_t dm_dict)
    157 {
    158 	return 0;
    159 }
    160 
    161 /*
    162  * Get list of all available targets from global
    163  * target list and sent them back to libdevmapper.
    164  */
    165 int
    166 dm_list_versions_ioctl(prop_dictionary_t dm_dict)
    167 {
    168 	prop_array_t target_list;
    169 	uint32_t flags;
    170 
    171 	flags = 0;
    172 
    173 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    174 
    175 	dm_dbg_print_flags(flags);
    176 
    177 	target_list = dm_target_prop_list();
    178 
    179 	prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, target_list);
    180 
    181 	prop_object_release(target_list);
    182 
    183 	return 0;
    184 }
    185 
    186 /*
    187  * Create in-kernel entry for device. Device attributes such as name, uuid are
    188  * taken from proplib dictionary.
    189  *
    190  */
    191 int
    192 dm_dev_create_ioctl(prop_dictionary_t dm_dict)
    193 {
    194 	dm_dev_t *dmv;
    195 	const char *name, *uuid;
    196 	int r, flags;
    197 
    198 	r = 0;
    199 	flags = 0;
    200 	name = NULL;
    201 	uuid = NULL;
    202 
    203 	/* Get needed values from dictionary. */
    204 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    205 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    206 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    207 
    208 	dm_dbg_print_flags(flags);
    209 
    210 	/* Lookup name and uuid if device already exist quit. */
    211 	if ((dmv = dm_dev_lookup(name, uuid, -1)) != NULL) {
    212 		DM_ADD_FLAG(flags, DM_EXISTS_FLAG); /* Device already exists */
    213 		dm_dev_unbusy(dmv);
    214 		return EEXIST;
    215 	}
    216 
    217 	if ((dmv = dm_dev_alloc()) == NULL)
    218 		return ENOMEM;
    219 
    220 	if (uuid)
    221 		strncpy(dmv->uuid, uuid, DM_UUID_LEN);
    222 	else
    223 		dmv->uuid[0] = '\0';
    224 
    225 	if (name)
    226 		strlcpy(dmv->name, name, DM_NAME_LEN);
    227 
    228 	dmv->minor = atomic_inc_64_nv(&sc_minor_num);
    229 
    230 	dmv->flags = 0; /* device flags are set when needed */
    231 	dmv->ref_cnt = 0;
    232 	dmv->event_nr = 0;
    233 	dmv->dev_type = 0;
    234 
    235 	mutex_init(&dmv->dev_mtx, MUTEX_DEFAULT, IPL_NONE);
    236 	cv_init(&dmv->dev_cv, "dm_dev");
    237 
    238 	dm_table_head_init(&dmv->table_head);
    239 
    240 	if (flags & DM_READONLY_FLAG)
    241 		dmv->flags |= DM_READONLY_FLAG;
    242 
    243 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    244 
    245 	if ((r = dm_dev_insert(dmv)) != 0){
    246 		dm_dev_free(dmv);
    247 	}
    248 
    249 	DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
    250 	DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
    251 
    252 	return r;
    253 }
    254 
    255 /*
    256  * Get list of created device-mapper devices fromglobal list and
    257  * send it to kernel.
    258  *
    259  * Output dictionary:
    260  *
    261  * <key>cmd_data</key>
    262  *  <array>
    263  *   <dict>
    264  *    <key>name<key>
    265  *    <string>...</string>
    266  *
    267  *    <key>dev</key>
    268  *    <integer>...</integer>
    269  *   </dict>
    270  *  </array>
    271  *
    272  */
    273 int
    274 dm_dev_list_ioctl(prop_dictionary_t dm_dict)
    275 {
    276 	prop_array_t dev_list;
    277 
    278 	uint32_t flags;
    279 
    280 	flags = 0;
    281 
    282 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    283 
    284 	dm_dbg_print_flags(flags);
    285 
    286 	dev_list = dm_dev_prop_list();
    287 
    288 	prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list);
    289 	prop_object_release(dev_list);
    290 
    291 	return 0;
    292 }
    293 
    294 /*
    295  * Rename selected devices old name is in struct dm_ioctl.
    296  * newname is taken from dictionary
    297  *
    298  * <key>cmd_data</key>
    299  *  <array>
    300  *   <string>...</string>
    301  *  </array>
    302  */
    303 int
    304 dm_dev_rename_ioctl(prop_dictionary_t dm_dict)
    305 {
    306 	prop_array_t cmd_array;
    307 	dm_dev_t *dmv;
    308 
    309 	const char *name, *uuid, *n_name;
    310 	uint32_t flags, minor;
    311 
    312 	name = NULL;
    313 	uuid = NULL;
    314 	minor = 0;
    315 
    316 	/* Get needed values from dictionary. */
    317 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    318 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    319 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    320 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    321 
    322 	dm_dbg_print_flags(flags);
    323 
    324 	cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
    325 
    326 	prop_array_get_cstring_nocopy(cmd_array, 0, &n_name);
    327 
    328 	if (strlen(n_name) + 1 > DM_NAME_LEN)
    329 		return EINVAL;
    330 
    331 	if ((dmv = dm_dev_rem(name, uuid, minor)) == NULL) {
    332 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    333 		return ENOENT;
    334 	}
    335 
    336 	/* change device name */
    337 	/* XXX How to deal with this change, name only used in
    338 	 * dm_dev_routines, should I add dm_dev_change_name which will run under the
    339 	 * dm_dev_list mutex ?
    340 	 */
    341 	strlcpy(dmv->name, n_name, DM_NAME_LEN);
    342 
    343 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
    344 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    345 	prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
    346 
    347 	dm_dev_insert(dmv);
    348 
    349 	return 0;
    350 }
    351 
    352 /*
    353  * Remove device from global list I have to remove active
    354  * and inactive tables first.
    355  */
    356 int
    357 dm_dev_remove_ioctl(prop_dictionary_t dm_dict)
    358 {
    359 	dm_dev_t *dmv;
    360 	const char *name, *uuid;
    361 	uint32_t flags, minor;
    362 
    363 	flags = 0;
    364 	name = NULL;
    365 	uuid = NULL;
    366 
    367 	/* Get needed values from dictionary. */
    368 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    369 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    370 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    371 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    372 
    373 	dm_dbg_print_flags(flags);
    374 
    375 	/* Remove device from global device list */
    376 	if ((dmv = dm_dev_rem(name, uuid, minor)) == NULL){
    377 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    378 		return ENOENT;
    379 	}
    380 
    381 	/* Destroy active table first.  */
    382 	dm_table_destroy(&dmv->table_head, DM_TABLE_ACTIVE);
    383 
    384 	/* Destroy inactive table if exits, too. */
    385 	dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
    386 
    387 	dm_table_head_destroy(&dmv->table_head);
    388 
    389 	mutex_destroy(&dmv->dev_mtx);
    390 	cv_destroy(&dmv->dev_cv);
    391 
    392 	/* Destroy device */
    393 	(void)dm_dev_free(dmv);
    394 
    395 	return 0;
    396 }
    397 
    398 /*
    399  * Return actual state of device to libdevmapper.
    400  */
    401 int
    402 dm_dev_status_ioctl(prop_dictionary_t dm_dict)
    403 {
    404 	dm_dev_t *dmv;
    405 	const char *name, *uuid;
    406 	uint32_t flags, j, minor;
    407 
    408 	name = NULL;
    409 	uuid = NULL;
    410 	flags = 0;
    411 	j = 0;
    412 
    413 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    414 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    415 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    416 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    417 
    418 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
    419 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    420 		return ENOENT;
    421 	}
    422 
    423 	dm_dbg_print_flags(dmv->flags);
    424 
    425 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
    426 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    427 	prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
    428 
    429 	if (dmv->flags & DM_SUSPEND_FLAG)
    430 		DM_ADD_FLAG(flags, DM_SUSPEND_FLAG);
    431 
    432 	/* Add status flags for tables I have to check both
    433 	   active and inactive tables. */
    434 	if ((j = dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE))) {
    435 		DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
    436 	} else
    437 		DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
    438 
    439 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_TARGET_COUNT, j);
    440 
    441 	if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE))
    442 		DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
    443 	else
    444 		DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
    445 
    446 	dm_dev_unbusy(dmv);
    447 
    448 	return 0;
    449 }
    450 
    451 /*
    452  * Set only flag to suggest that device is suspended. This call is
    453  * not supported in NetBSD.
    454  *
    455  */
    456 int
    457 dm_dev_suspend_ioctl(prop_dictionary_t dm_dict)
    458 {
    459 	dm_dev_t *dmv;
    460 	const char *name, *uuid;
    461 	uint32_t flags, minor;
    462 
    463 	name = NULL;
    464 	uuid = NULL;
    465 	flags = 0;
    466 
    467 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    468 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    469 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    470 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    471 
    472 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL){
    473 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    474 		return ENOENT;
    475 	}
    476 
    477 	atomic_or_32(&dmv->flags, DM_SUSPEND_FLAG);
    478 
    479 	dm_dbg_print_flags(dmv->flags);
    480 
    481 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
    482 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags);
    483 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    484 
    485 	dm_dev_unbusy(dmv);
    486 
    487 	/* Add flags to dictionary flag after dmv -> dict copy */
    488 	DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
    489 
    490 	return 0;
    491 }
    492 
    493 /*
    494  * Simulate Linux behaviour better and switch tables here and not in
    495  * dm_table_load_ioctl.
    496  */
    497 int
    498 dm_dev_resume_ioctl(prop_dictionary_t dm_dict)
    499 {
    500 	dm_dev_t *dmv;
    501 	const char *name, *uuid;
    502 	uint32_t flags, minor;
    503 
    504 	name = NULL;
    505 	uuid = NULL;
    506 	flags = 0;
    507 
    508 /*	char *xml;
    509 	xml = prop_dictionary_externalize(dm_dict);
    510 	printf("%s\n",xml);*/
    511 
    512 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    513 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    514 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    515 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    516 
    517 	/* Remove device from global device list */
    518 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL){
    519 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    520 		return ENOENT;
    521 	}
    522 
    523 	atomic_and_32(&dmv->flags, ~(DM_SUSPEND_FLAG | DM_INACTIVE_PRESENT_FLAG));
    524 	atomic_or_32(&dmv->flags, DM_ACTIVE_PRESENT_FLAG);
    525 
    526 	dm_table_switch_tables(&dmv->table_head);
    527 
    528 	DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
    529 
    530 	dmgetdisklabel(dmv->dk_label, &dmv->table_head);
    531 
    532 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
    533 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags);
    534 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    535 
    536 	dm_dev_unbusy(dmv);
    537 
    538 	/* Destroy inactive table after resume. */
    539 	dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
    540 
    541 	return 0;
    542 }
    543 
    544 /*
    545  * Table management routines
    546  * lvm2tools doens't send name/uuid to kernel with table
    547  * for lookup I have to use minor number.
    548  */
    549 
    550 /*
    551  * Remove inactive table from device. Routines which work's with inactive tables
    552  * doesn't need to synchronise with dmstrategy. They can synchronise themselves with mutex?.
    553  *
    554  */
    555 int
    556 dm_table_clear_ioctl(prop_dictionary_t dm_dict)
    557 {
    558 	dm_dev_t *dmv;
    559 	const char *name, *uuid;
    560 	uint32_t flags, minor;
    561 
    562 	dmv  = NULL;
    563 	name = NULL;
    564 	uuid = NULL;
    565 	flags = 0;
    566 	minor = 0;
    567 
    568 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    569 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    570 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    571 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    572 
    573 	aprint_debug("Clearing inactive table from device: %s--%s\n",
    574 	    name, uuid);
    575 
    576 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL){
    577 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    578 		return ENOENT;
    579 	}
    580 
    581 	/* Select unused table */
    582 	dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
    583 
    584 	atomic_and_32(&dmv->flags, ~DM_INACTIVE_PRESENT_FLAG);
    585 
    586 	dm_dev_unbusy(dmv);
    587 
    588 	return 0;
    589 }
    590 
    591 /*
    592  * Get list of physical devices for active table.
    593  * Get dev_t from pdev vnode and insert it into cmd_array.
    594  *
    595  * XXX. This function is called from lvm2tools to get information
    596  *      about physical devices, too e.g. during vgcreate.
    597  */
    598 int
    599 dm_table_deps_ioctl(prop_dictionary_t dm_dict)
    600 {
    601 	dm_dev_t *dmv;
    602 	dm_table_t *tbl;
    603 	dm_table_entry_t *table_en;
    604 
    605 	prop_array_t cmd_array;
    606 	const char *name, *uuid;
    607 	uint32_t flags, minor;
    608 
    609 	size_t i;
    610 
    611 	name = NULL;
    612 	uuid = NULL;
    613 	dmv  = NULL;
    614 	flags = 0;
    615 
    616 	i = 0;
    617 
    618 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    619 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    620 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    621 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    622 
    623 	/* create array for dev_t's */
    624 	cmd_array = prop_array_create();
    625 
    626 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL){
    627 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    628 		return ENOENT;
    629 	}
    630 
    631 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    632 	prop_dictionary_set_cstring(dm_dict, DM_IOCTL_NAME, dmv->name);
    633 	prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
    634 
    635 	aprint_debug("Getting table deps for device: %s\n", dmv->name);
    636 
    637 	tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE);
    638 
    639 	SLIST_FOREACH(table_en, tbl, next)
    640        		table_en->target->deps(table_en, cmd_array);
    641 
    642 	dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE);
    643 	dm_dev_unbusy(dmv);
    644 
    645 	prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array);
    646 	prop_object_release(cmd_array);
    647 
    648 	return 0;
    649 }
    650 
    651 /*
    652  * Load new table/tables to device.
    653  * Call apropriate target init routine open all physical pdev's and
    654  * link them to device. For other targets mirror, strip, snapshot
    655  * etc. also add dependency devices to upcalls list.
    656  *
    657  * Load table to inactive slot table are switched in dm_device_resume_ioctl.
    658  * This simulates Linux behaviour better there should not be any difference.
    659  *
    660  */
    661 int
    662 dm_table_load_ioctl(prop_dictionary_t dm_dict)
    663 {
    664 	dm_dev_t *dmv;
    665 	dm_table_entry_t *table_en, *last_table;
    666 	dm_table_t  *tbl;
    667 	dm_target_t *target;
    668 
    669 	prop_object_iterator_t iter;
    670 	prop_array_t cmd_array;
    671 	prop_dictionary_t target_dict;
    672 
    673 	const char *name, *uuid, *type;
    674 
    675 	uint32_t flags, ret, minor;
    676 
    677 	char *str;
    678 
    679 	ret = 0;
    680 	flags = 0;
    681 	name = NULL;
    682 	uuid = NULL;
    683 	dmv = NULL;
    684 	last_table = NULL;
    685 	str = NULL;
    686 
    687 /*	char *xml;
    688 	xml = prop_dictionary_externalize(dm_dict);
    689 	printf("%s\n",xml);*/
    690 
    691 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    692 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    693 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    694 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    695 
    696 	cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
    697 	iter = prop_array_iterator(cmd_array);
    698 	dm_dbg_print_flags(flags);
    699 
    700 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL){
    701 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    702 		return ENOENT;
    703 	}
    704 
    705 	aprint_debug("Loading table to device: %s--%d\n",name,dmv->table_head.cur_active_table);
    706 
    707 	/*
    708 	 * I have to check if this table slot is not used by another table list.
    709 	 * if it is used I should free them.
    710 	 */
    711 	if (dmv->flags & DM_INACTIVE_PRESENT_FLAG)
    712 		dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
    713 
    714 	dm_dbg_print_flags(dmv->flags);
    715 	tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_INACTIVE);
    716 
    717 	aprint_debug("dmv->name = %s\n", dmv->name);
    718 
    719 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    720 
    721 	while((target_dict = prop_object_iterator_next(iter)) != NULL){
    722 
    723 		prop_dictionary_get_cstring_nocopy(target_dict,
    724 		    DM_TABLE_TYPE, &type);
    725 
    726 		/*
    727 		 * If we want to deny table with 2 or more different
    728 		 * target we should do it here
    729 		 */
    730 		if ((target = dm_target_lookup(type)) == NULL)
    731 			return ENOENT;
    732 
    733 		if ((table_en = kmem_alloc(sizeof(dm_table_entry_t),
    734 			    KM_NOSLEEP)) == NULL)
    735 			return ENOMEM;
    736 
    737 		prop_dictionary_get_uint64(target_dict, DM_TABLE_START,
    738 		    &table_en->start);
    739 		prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH,
    740 		    &table_en->length);
    741 
    742 		table_en->target = target;
    743 		table_en->dm_dev = dmv;
    744 		table_en->target_config = NULL;
    745 
    746 		/*
    747 		 * There is a parameter string after dm_target_spec
    748 		 * structure which  points to /dev/wd0a 284 part of
    749 		 * table. String str points to this text. This can be
    750 		 * null and therefore it should be checked before we try to
    751 		 * use it.
    752 		 */
    753 		prop_dictionary_get_cstring(target_dict,
    754 		    DM_TABLE_PARAMS, (char**)&str);
    755 
    756 		if (SLIST_EMPTY(tbl))
    757 			/* insert this table to head */
    758 			SLIST_INSERT_HEAD(tbl, table_en, next);
    759 		else
    760 			SLIST_INSERT_AFTER(last_table, table_en, next);
    761 
    762 		/*
    763 		 * Params string is different for every target,
    764 		 * therfore I have to pass it to target init
    765 		 * routine and parse parameters there.
    766 		 */
    767 
    768 		if ((ret = target->init(dmv, &table_en->target_config,
    769 			    str)) != 0) {
    770 
    771 			dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
    772 			dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
    773 			free(str, M_TEMP);
    774 
    775 			dm_dev_unbusy(dmv);
    776 			return ret;
    777 		}
    778 
    779 		last_table = table_en;
    780 
    781 		free(str, M_TEMP);
    782 	}
    783 	prop_object_iterator_release(iter);
    784 
    785 	DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
    786 	atomic_or_32(&dmv->flags, DM_INACTIVE_PRESENT_FLAG);
    787 
    788 	dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
    789 	dm_dev_unbusy(dmv);
    790 	return 0;
    791 }
    792 
    793 /*
    794  * Get description of all tables loaded to device from kernel
    795  * and send it to libdevmapper.
    796  *
    797  * Output dictionary for every table:
    798  *
    799  * <key>cmd_data</key>
    800  * <array>
    801  *   <dict>
    802  *    <key>type<key>
    803  *    <string>...</string>
    804  *
    805  *    <key>start</key>
    806  *    <integer>...</integer>
    807  *
    808  *    <key>length</key>
    809  *    <integer>...</integer>
    810  *
    811  *    <key>params</key>
    812  *    <string>...</string>
    813  *   </dict>
    814  * </array>
    815  *
    816  */
    817 int
    818 dm_table_status_ioctl(prop_dictionary_t dm_dict)
    819 {
    820 	dm_dev_t *dmv;
    821 	dm_table_t *tbl;
    822 	dm_table_entry_t *table_en;
    823 
    824 	prop_array_t cmd_array;
    825 	prop_dictionary_t target_dict;
    826 
    827 	uint32_t rec_size, minor;
    828 
    829 	const char *name, *uuid;
    830 	char *params;
    831 	int flags;
    832 
    833 	dmv = NULL;
    834 	uuid = NULL;
    835 	name = NULL;
    836 	params = NULL;
    837 	flags = 0;
    838 	rec_size = 0;
    839 
    840 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    841 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    842 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    843 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    844 
    845 	cmd_array = prop_array_create();
    846 
    847 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL){
    848 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    849 		return ENOENT;
    850 	}
    851 
    852 	if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE))
    853 		DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
    854 	else {
    855 		DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
    856 
    857 		if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE))
    858 			DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
    859 		else {
    860 			DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
    861 		}
    862 	}
    863 
    864 	if (dmv->flags & DM_SUSPEND_FLAG)
    865 		DM_ADD_FLAG(flags, DM_SUSPEND_FLAG);
    866 
    867 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    868 
    869 	/* I should use mutex here and not rwlock there can be IO operation
    870 	   during this ioctl on device. */
    871 
    872 	aprint_debug("Status of device tables: %s--%d\n",
    873 	    name, dmv->table_head.cur_active_table);
    874 
    875 	tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE);
    876 
    877 	SLIST_FOREACH(table_en, tbl, next)
    878 	{
    879 		target_dict = prop_dictionary_create();
    880 		aprint_debug("%016" PRIu64 ", length %016" PRIu64
    881 		    ", target %s\n", table_en->start, table_en->length,
    882 		    table_en->target->name);
    883 
    884 		prop_dictionary_set_uint64(target_dict, DM_TABLE_START,
    885 		    table_en->start);
    886 		prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH,
    887 		    table_en->length);
    888 
    889 		prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE,
    890 		    table_en->target->name);
    891 
    892 		/* dm_table_get_cur_actv.table ?? */
    893 		prop_dictionary_set_int32(target_dict, DM_TABLE_STAT,
    894 		    dmv->table_head.cur_active_table);
    895 
    896 		if (flags |= DM_STATUS_TABLE_FLAG) {
    897 			params = table_en->target->status
    898 			    (table_en->target_config);
    899 
    900 			if(params != NULL){
    901 				prop_dictionary_set_cstring(target_dict,
    902 				    DM_TABLE_PARAMS, params);
    903 
    904 				kmem_free(params, strlen(params) + 1);
    905 			}
    906 		}
    907 
    908 		prop_array_add(cmd_array, target_dict);
    909 		prop_object_release(target_dict);
    910 	}
    911 
    912 	dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE);
    913 	dm_dev_unbusy(dmv);
    914 
    915 	prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array);
    916 	prop_object_release(cmd_array);
    917 
    918 	return 0;
    919 }
    920 
    921 
    922 /*
    923  * For every call I have to set kernel driver version.
    924  * Because I can have commands supported only in other
    925  * newer/later version. This routine is called for every
    926  * ioctl command.
    927  */
    928 int
    929 dm_check_version(prop_dictionary_t dm_dict)
    930 {
    931 	size_t i;
    932 	int dm_version[3];
    933 	prop_array_t ver;
    934 
    935 	ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION);
    936 
    937 	for(i=0; i < 3; i++)
    938 		prop_array_get_uint32(ver, i, &dm_version[i]);
    939 
    940 	if (DM_VERSION_MAJOR != dm_version[0] || DM_VERSION_MINOR < dm_version[1]){
    941 		aprint_debug("libdevmapper/kernel version mismatch "
    942 		    "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n",
    943 		    DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL,
    944 		    dm_version[0], dm_version[1], dm_version[2]);
    945 
    946 		return EIO;
    947 	}
    948 
    949 	prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR);
    950 	prop_array_set_uint32(ver, 1, DM_VERSION_MINOR);
    951 	prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL);
    952 
    953 	return 0;
    954 }
    955