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