Home | History | Annotate | Line # | Download | only in dm
dm_ioctl.c revision 1.1.2.2
      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_verbose("dbg_print --- %d\n",flags);
     71 
     72 	if (flags & DM_READONLY_FLAG)
     73 		aprint_verbose("dbg_flags: DM_READONLY_FLAG set In/Out\n");
     74 
     75 	if (flags & DM_SUSPEND_FLAG)
     76 		aprint_verbose("dbg_flags: DM_SUSPEND_FLAG set In/Out \n");
     77 
     78 	if (flags & DM_PERSISTENT_DEV_FLAG)
     79 		aprint_verbose("dbg_flags: DM_PERSISTENT_DEV_FLAG set In\n");
     80 
     81 	if (flags & DM_STATUS_TABLE_FLAG)
     82 		aprint_verbose("dbg_flags: DM_STATUS_TABLE_FLAG set In\n");
     83 
     84 	if (flags & DM_ACTIVE_PRESENT_FLAG)
     85 		aprint_verbose("dbg_flags: DM_ACTIVE_PRESENT_FLAG set Out\n");
     86 
     87 	if (flags & DM_INACTIVE_PRESENT_FLAG)
     88 		aprint_verbose("dbg_flags: DM_INACTIVE_PRESENT_FLAG set Out\n");
     89 
     90 	if (flags & DM_BUFFER_FULL_FLAG)
     91 		aprint_verbose("dbg_flags: DM_BUFFER_FULL_FLAG set Out\n");
     92 
     93 	if (flags & DM_SKIP_BDGET_FLAG)
     94 		aprint_verbose("dbg_flags: DM_SKIP_BDGET_FLAG set In\n");
     95 
     96 	if (flags & DM_SKIP_LOCKFS_FLAG)
     97 		aprint_verbose("dbg_flags: DM_SKIP_LOCKFS_FLAG set In\n");
     98 
     99 	if (flags & DM_NOFLUSH_FLAG)
    100 		aprint_verbose("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 	r = 0;
    134 
    135 	aprint_verbose("dm_list_versions_ioctl called\n");
    136 
    137 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    138 
    139 	dm_dbg_print_flags(flags);
    140 
    141 	target_list = dm_target_prop_list();
    142 
    143 	prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, target_list);
    144 
    145 	return r;
    146 }
    147 
    148 /*
    149  * Create in-kernel entry for device. Device attributes such as name, uuid are
    150  * taken from proplib dictionary.
    151  */
    152 int
    153 dm_dev_create_ioctl(prop_dictionary_t dm_dict)
    154 {
    155 	struct dm_dev *dmv;
    156 	const char *name, *uuid;
    157 	int r,flags;
    158 
    159 	r = 0;
    160 	flags = 0;
    161 	name = NULL;
    162 	uuid = NULL;
    163 
    164 	/* Get needed values from dictionary. */
    165 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    166 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    167 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    168 
    169 	dm_dbg_print_flags(flags);
    170 
    171 	/* Lookup name and uuid if device already exist quit. */
    172 	if ((dm_dev_lookup_name(name) != NULL) &&
    173 	    (dm_dev_lookup_uuid(uuid) != NULL)) {
    174 		DM_ADD_FLAG(flags, DM_EXISTS_FLAG); /* Device already exists */
    175 		return EEXIST;
    176 	}
    177 
    178 
    179 	if ((dmv = dm_dev_alloc()) == NULL)
    180 		return ENOMEM;
    181 /*	printf("%d---%d\n",sizeof(dmv->uuid),DM_UUID_LEN);
    182 	printf("%s\n",uuid);
    183 	if (uuid)
    184 	memcpy(dmv->uuid,uuid,DM_UUID_LEN);*/
    185 	printf("%s\n",name);
    186 	if (name)
    187 		strlcpy(dmv->name, name, DM_NAME_LEN);
    188 
    189 	dmv->flags = flags;
    190 
    191 	dmv->minor = ++(dm_sc->sc_minor_num);
    192 
    193 	dmv->ref_cnt = 0;
    194 	dmv->event_nr = 0;
    195 	dmv->cur_active_table = 0;
    196 
    197 	/* Initialize tables. */
    198 	SLIST_INIT(&dmv->tables[0]);
    199 	SLIST_INIT(&dmv->tables[1]);
    200 
    201 	/* init device list of physical devices. */
    202 	SLIST_INIT(&dmv->pdevs);
    203 	/*
    204 	 * Locking strategy here is this: this is per device mutex lock
    205 	 * and it should be taken when we work with device. Almost all
    206 	 * ioctl callbacks for tables and devices must acquire this lock.
    207      	 */
    208 
    209 	prop_dictionary_set_uint64(dm_dict, DM_IOCTL_DEV, dmv->minor);
    210 
    211 	mutex_init(&dmv->dev_mtx, MUTEX_DEFAULT, IPL_NONE);
    212 
    213 	/* Test readonly flag change anything only if it is not set*/
    214 	if (flags & DM_READONLY_FLAG)
    215 		dm_dev_free(dmv);
    216 	else
    217 		r = dm_dev_insert(dmv);
    218 
    219 	return r;
    220 }
    221 
    222 /*
    223  * Get list of created device-mapper devices fromglobal list and
    224  * send it to kernel.
    225  *
    226  * Output dictionary:
    227  *
    228  * <key>cmd_data</key>
    229  *  <array>
    230  *   <dict>
    231  *    <key>name<key>
    232  *    <string>...</string>
    233  *
    234  *    <key>dev</key>
    235  *    <integer>...</integer>
    236  *   </dict>
    237  *  </array>
    238  *
    239  */
    240 int
    241 dm_dev_list_ioctl(prop_dictionary_t dm_dict)
    242 {
    243 	prop_array_t dev_list;
    244 
    245 	int r;
    246 	uint32_t flags;
    247 
    248 	r = 0;
    249 
    250 	aprint_verbose("dm_dev_list called\n");
    251 
    252 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    253 
    254 	dm_dbg_print_flags(flags);
    255 
    256 	dev_list = dm_dev_prop_list();
    257 
    258 	prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list);
    259 
    260 	return 0;
    261 }
    262 
    263 /*
    264  * Rename selected devices old name is in struct dm_ioctl.
    265  * newname is taken from dictionary
    266  *
    267  * <key>cmd_data</key>
    268  *  <array>
    269  *   <string>...</string>
    270  *  </array>
    271  */
    272 int
    273 dm_dev_rename_ioctl(prop_dictionary_t dm_dict)
    274 {
    275 	prop_array_t cmd_array;
    276 	struct dm_dev *dmv;
    277 
    278 	const char *name,*uuid,*n_name;
    279 	uint32_t flags;
    280 
    281 	name = NULL;
    282 	uuid = NULL;
    283 
    284 	/* Get needed values from dictionary. */
    285 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    286 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    287 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    288 	cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
    289 
    290 	prop_array_get_cstring_nocopy(cmd_array, 0, &n_name);
    291 
    292 	if (strlen(n_name) + 1 > DM_NAME_LEN)
    293 		return EINVAL;
    294 
    295 	if (((dmv = dm_dev_lookup_uuid(uuid)) == NULL) ||
    296 	    (dmv = dm_dev_lookup_name(name)) == NULL) {
    297 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    298 		return ENOENT;
    299 	}
    300 
    301 	/* Test readonly flag change anything only if it is not set*/
    302 	if (!(flags & DM_READONLY_FLAG))
    303 		strlcpy(dmv->name, n_name, DM_NAME_LEN);
    304 
    305 	return 0;
    306 }
    307 
    308 /*
    309  * Remove device from global list I have to remove active
    310  * and inactive tables first and decrement reference_counters
    311  * for used pdevs.
    312  */
    313 int
    314 dm_dev_remove_ioctl(prop_dictionary_t dm_dict)
    315 {
    316 	struct dm_dev *dmv;
    317 
    318 	const char *name, *uuid;
    319 	uint32_t flags;
    320 
    321 	name = NULL;
    322 	uuid = NULL;
    323 
    324 	/* Get needed values from dictionary. */
    325 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    326 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    327 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    328 
    329 	dm_dbg_print_flags(flags);
    330 
    331 	if (((dmv = dm_dev_lookup_uuid(uuid)) == NULL) &&
    332 	    (dmv = dm_dev_lookup_name(name)) == NULL) {
    333 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    334 		return ENOENT;
    335 	}
    336 
    337 	if (!(flags & DM_READONLY_FLAG)) {
    338 		if (dmv->ref_cnt == 0){
    339 			/* Destroy active table first.  */
    340 			dm_table_destroy(&dmv->tables[dmv->cur_active_table]);
    341 
    342 			/* Destroy unactive table if exits, too. */
    343 			if (!SLIST_EMPTY(&dmv->tables[1 - dmv->cur_active_table]))
    344 				dm_table_destroy(&dmv->tables[1 - dmv->cur_active_table]);
    345 
    346 			/* Decrement reference counters for all pdevs from this
    347 			   device if they are unused close vnode and remove them
    348 			   from global pdev list, too. */
    349 			dm_pdev_decr(&dmv->pdevs);
    350 
    351 			/* Test readonly flag change anything only if it is not set*/
    352 
    353 			dm_dev_rem(name); /* XXX. try to use uuid, too */
    354 		}
    355 
    356 	}
    357 	return 0;
    358 }
    359 
    360 /*
    361  * Return actual state of device to libdevmapper.
    362  */
    363 int
    364 dm_dev_status_ioctl(prop_dictionary_t dm_dict)
    365 {
    366 	struct dm_dev *dmv;
    367 	const char *name, *uuid;
    368 	uint32_t flags;
    369 
    370 	name = NULL;
    371 	uuid = NULL;
    372 
    373 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    374 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    375 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    376 
    377 	if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
    378 	    ((dmv = dm_dev_lookup_uuid(uuid)) == NULL)) {
    379 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    380 		return 0;
    381 	}
    382 
    383 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->ref_cnt);
    384 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags);
    385 
    386 	prop_dictionary_set_uint64(dm_dict, DM_IOCTL_DEV, dmv->minor);
    387 
    388 	return 0;
    389 }
    390 
    391 /*
    392  * Unsupported on NetBSD.
    393  */
    394 int
    395 dm_dev_suspend_ioctl(prop_dictionary_t dm_dict)
    396 {
    397 	return 0;
    398 }
    399 
    400 /*
    401  * Unsupported on NetBSD.
    402  */
    403 int
    404 dm_dev_resume_ioctl(prop_dictionary_t dm_dict)
    405 {
    406 //	DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
    407 
    408 	return 0;
    409 }
    410 
    411 /*
    412  * Table management routines
    413  * lvm2tools doens't send name/uuid to kernel with table for lookup I have to use minor number.
    414  */
    415 
    416 
    417 /*
    418  * Remove active table from device.
    419  */
    420 int
    421 dm_table_clear_ioctl(prop_dictionary_t dm_dict)
    422 {
    423 	struct dm_dev *dmv;
    424 	struct dm_table  *tbl;
    425 
    426 	const char *name, *uuid;
    427 	int flags;
    428 
    429 	dmv  = NULL;
    430 	name = NULL;
    431 	uuid = NULL;
    432 
    433 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    434 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    435 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    436 
    437 	aprint_verbose("Clearing inactive table from device: %s--%s\n",
    438 	    name, uuid);
    439 
    440 	if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
    441 	    ((dmv = dm_dev_lookup_uuid(uuid)) == NULL)) {
    442 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    443 		return ENOENT;
    444 	}
    445 
    446 	/* Select unused table */
    447 	tbl = &dmv->tables[1-dmv->cur_active_table];
    448 
    449 	/* Test readonly flag change anything only if it is not set*/
    450 	if (!(flags & DM_READONLY_FLAG))
    451 			dm_table_destroy(tbl);
    452 
    453 	return 0;
    454 }
    455 
    456 /*
    457  * Get list of physical devices for active table.
    458  * Get dev_t from pdev vnode and insert it into cmd_array.
    459  *
    460  * XXX. This function is called from lvm2tools to get information
    461  *      about physical devices, too e.g. during vgcreate.
    462  */
    463 int
    464 dm_table_deps_ioctl(prop_dictionary_t dm_dict)
    465 {
    466 	int error;
    467 	struct dm_dev *dmv;
    468 	struct dm_pdev *dmp;
    469 	struct vattr va;
    470 
    471 	prop_array_t cmd_array;
    472 
    473 	const char *name, *uuid;
    474 	int flags;
    475 	uint64_t dev;
    476 
    477 	size_t i;
    478 
    479 	name = NULL;
    480 	uuid = NULL;
    481 	dmv  = NULL;
    482 
    483 	i=0;
    484 
    485 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    486 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    487 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    488 	prop_dictionary_get_uint64(dm_dict, DM_IOCTL_DEV, &dev);
    489 
    490 	cmd_array = prop_dictionary_get(dm_dict,DM_IOCTL_CMD_DATA);
    491 
    492 	if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
    493 	    ((dmv = dm_dev_lookup_uuid(uuid)) == NULL) &&
    494 	    ((dmv = dm_dev_lookup_minor(minor(dev))) == NULL)) {
    495 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    496 		return ENOENT;
    497 	}
    498 
    499 	aprint_verbose("Getting table deps for device: %s\n",name);
    500 
    501 	SLIST_FOREACH(dmp, &dmv->pdevs, next_pdev){
    502 
    503 		if ((error = VOP_GETATTR(dmp->pdev_vnode, &va, curlwp->l_cred))
    504 		    != 0)
    505 			return (error);
    506 
    507 		prop_array_set_uint64(cmd_array, i, (uint64_t)va.va_rdev);
    508 
    509 		i++;
    510 	}
    511 
    512 	return 0;
    513 }
    514 
    515 /*
    516  * Load new table/tables to device.
    517  * Call apropriate target init routine open all physical pdev's and
    518  * link them to device. For other targets mirror, strip, snapshot
    519  * etc. also add dependency devices to upcalls list.
    520  *
    521  * XXX. It would be usefull to refactorize this routine to be shorter ?
    522  */
    523 int
    524 dm_table_load_ioctl(prop_dictionary_t dm_dict)
    525 {
    526 	struct dm_dev *dmv;
    527 	struct dm_pdev *dmp;
    528 	struct dm_table_entry *table_en, *last_table;
    529 	struct dm_table  *tbl;
    530 	struct dm_target *target;
    531 
    532 	prop_object_iterator_t iter;
    533 	prop_array_t cmd_array;
    534 	prop_dictionary_t target_dict;
    535 
    536 	const char *name, *uuid, *type, *str_ptr;
    537 
    538 	uint32_t flags;
    539 
    540 	uint64_t dev;
    541 
    542 	char *dev_name,*str;
    543 
    544 	flags = 0;
    545 	name = NULL;
    546 	uuid = NULL;
    547 	dmv = NULL;
    548 	dmp = NULL;
    549 	last_table = NULL;
    550 	str_ptr = NULL;
    551 
    552 	char *xml;
    553 	xml = prop_dictionary_externalize(dm_dict);
    554 	printf("%s\n",xml);
    555 
    556 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    557 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    558 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    559 	prop_dictionary_get_uint64(dm_dict, DM_IOCTL_DEV, &dev);
    560 
    561 	cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
    562 	iter = prop_array_iterator(cmd_array);
    563 
    564 	dm_dbg_print_flags(flags);
    565 
    566 	aprint_verbose("Loading table to device: %s--%s\n",name,uuid);
    567 
    568 	if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
    569 	    ((dmv = dm_dev_lookup_uuid(uuid)) == NULL) &&
    570 	    ((dmv = dm_dev_lookup_minor(minor(dev))) == NULL)) {
    571 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    572 		return ENOENT;
    573 	}
    574 
    575 	/* Select unused table */
    576 	tbl = &dmv->tables[1-dmv->cur_active_table];
    577 
    578 	/*
    579 	 * I have to check if this table slot is not used by another table list.
    580 	 * if it is used I should free them.
    581 	 */
    582 
    583 	dm_table_destroy(tbl);
    584 
    585 	while((target_dict = prop_object_iterator_next(iter)) != NULL){
    586 
    587 		prop_dictionary_get_cstring_nocopy(target_dict,
    588 		    DM_TABLE_TYPE, &type);
    589 
    590 		/*
    591 		 * If we want to deny table with 2 or more different
    592 		 * target we should do it here
    593 		 */
    594 		if ((target = dm_target_lookup_name(type)) == NULL)
    595 			return ENOENT;
    596 
    597 		if ((table_en=kmem_alloc(sizeof(struct dm_table_entry),
    598 			    KM_NOSLEEP)) == NULL)
    599 			return ENOMEM;
    600 
    601 		prop_dictionary_get_uint64(target_dict, DM_TABLE_START,
    602 		    &table_en->start);
    603 		prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH,
    604 		    &table_en->length);
    605 
    606 		table_en->target=target;
    607 		table_en->dm_dev=dmv;
    608 
    609 		/*
    610 		 * There is a parameter string after dm_target_spec
    611 		 * structure which  points to /dev/wd0a 284 part of
    612 		 * table. String str points to this text.
    613 		 */
    614 
    615 		prop_dictionary_get_cstring_nocopy(target_dict,
    616 		    DM_TABLE_PARAMS, (const char**)&str);
    617 
    618 		if (strlen(str) != 0) {
    619 
    620 			str_ptr = str; /* save pointer to start of string */
    621 
    622 			aprint_verbose("trg_str: %s\n", str);
    623 
    624 		        dev_name = strsep(&str," ");
    625 
    626 			aprint_verbose("namei: %s, str: %s\n", dev_name, str);
    627 
    628 			if (!(flags & DM_READONLY_FLAG)){
    629 
    630 				if ((dmp = dm_pdev_insert(dev_name)) == NULL){
    631 					kmem_free(table_en,
    632 					    sizeof(struct dm_table_entry));
    633 					return ENOENT;
    634 				}
    635 
    636 				/* insert pdev to device list  */
    637 				SLIST_INSERT_HEAD(&dmv->pdevs, dmp, next_pdev);
    638 			}
    639 		}
    640 
    641 		/* Test readonly flag change anything only if it is not set*/
    642 		if (!(flags & DM_READONLY_FLAG)){
    643 
    644 			if (SLIST_EMPTY(tbl))
    645 				/* insert this table to head */
    646 				SLIST_INSERT_HEAD(tbl, table_en, next);
    647 			else
    648 				SLIST_INSERT_AFTER(last_table, table_en, next);
    649 
    650 			prop_dictionary_get_cstring(target_dict,
    651 			    DM_TABLE_PARAMS, (char **)&table_en->params);
    652 
    653 			/*
    654 			 * XXX I have to calculate argc
    655 			 */
    656 			if (target->init != NULL)
    657 				target->init(dmv, &table_en->target_config,
    658 				    2, &str_ptr);
    659 
    660 			last_table = table_en;
    661 
    662 		} else {
    663 			kmem_free(table_en, sizeof(struct dm_table_entry));
    664 			dm_pdev_destroy(dmp);
    665 		}
    666 
    667 	}
    668 
    669 	dmv->cur_active_table = 1 - dmv->cur_active_table;
    670 
    671 	prop_object_release(cmd_array);
    672 
    673 	DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
    674 
    675 	return 0;
    676 }
    677 
    678 /*
    679  * Get description of all tables loaded to device from kernel
    680  * and send it to libdevmapper.
    681  *
    682  * Output dictionary for every table:
    683  *
    684  * <key>cmd_data</key>
    685  * <array>
    686  *   <dict>
    687  *    <key>type<key>
    688  *    <string>...</string>
    689  *
    690  *    <key>start</key>
    691  *    <integer>...</integer>
    692  *
    693  *    <key>length</key>
    694  *    <integer>...</integer>
    695  *
    696  *    <key>params</key>
    697  *    <string>...</string>
    698  *   </dict>
    699  * </array>
    700  *
    701  */
    702 int
    703 dm_table_status_ioctl(prop_dictionary_t dm_dict)
    704 {
    705 	struct dm_dev *dmv;
    706 	struct dm_table  *tbl;
    707 	struct dm_table_entry *table_en;
    708 
    709 	prop_array_t cmd_array;
    710 	prop_dictionary_t target_dict;
    711 
    712 	uint32_t rec_size;
    713 	uint64_t dev;
    714 
    715 	const char *name, *uuid;
    716 	int flags,i;
    717 
    718 	dmv = NULL;
    719 	uuid = NULL;
    720 	name = NULL;
    721 
    722 	flags = 0;
    723 	rec_size = 0;
    724 	i=0;
    725 
    726 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    727 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    728 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    729 	prop_dictionary_get_uint64(dm_dict, DM_IOCTL_DEV, &dev);
    730 
    731 	cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
    732 
    733 	if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
    734 	    ((dmv = dm_dev_lookup_uuid(uuid)) == NULL) &&
    735 	    ((dmv = dm_dev_lookup_minor(minor(dev)))) == NULL) {
    736 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    737 		return ENOENT;
    738 	}
    739 
    740 	aprint_verbose("Status of device tables: %s--%d\n",
    741 	    name, dmv->cur_active_table);
    742 
    743 	tbl = &dmv->tables[dmv->cur_active_table];
    744 
    745 	SLIST_FOREACH(table_en,tbl,next)
    746 	{
    747 		target_dict = prop_dictionary_create();
    748 		aprint_verbose("%016" PRIu64 ", length %016" PRIu64
    749 		    ", target %s\n", table_en->start, table_en->length,
    750 		    table_en->target->name);
    751 
    752 		prop_dictionary_set_uint64(target_dict, DM_TABLE_START,
    753 		    table_en->start);
    754 		prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH,
    755 		    table_en->length);
    756 
    757 		prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE,
    758 		    table_en->target->name);
    759 		prop_dictionary_set_cstring(target_dict, DM_TABLE_PARAMS,
    760 		    table_en->params);
    761 
    762 		prop_dictionary_set_int32(target_dict, DM_TABLE_STAT,
    763 		    dmv->cur_active_table);
    764 
    765 		prop_array_set(cmd_array, i, target_dict);
    766 
    767 		prop_object_release(target_dict);
    768 
    769 		DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
    770 
    771 		i++;
    772 	}
    773 
    774 	return 0;
    775 }
    776 
    777 
    778 /*
    779  * For every call I have to set kernel driver version.
    780  * Because I can have commands supported only in other
    781  * newer/later version. This routine is called for every
    782  * ioctl command.
    783  */
    784 int
    785 dm_check_version(prop_dictionary_t dm_dict)
    786 {
    787 	size_t i;
    788 	int dm_version[3];
    789 	prop_array_t ver;
    790 	int r;
    791 
    792 	r = 0;
    793 
    794 	ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION);
    795 
    796 	for(i=0; i < 3; i++)
    797 		prop_array_get_uint32(ver, i, &dm_version[i]);
    798 
    799 
    800 	if (DM_VERSION_MAJOR != dm_version[0] ||
    801 	    DM_VERSION_MINOR < dm_version[1])
    802 	{
    803 		aprint_verbose("libdevmapper/kernel version mismatch "
    804 		    "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n",
    805 		    DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL,
    806 		    dm_version[0], dm_version[1], dm_version[2]);
    807 
    808 		r = EIO;
    809 		goto out;
    810 	}
    811 
    812 	prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR);
    813 	prop_array_set_uint32(ver, 1, DM_VERSION_MINOR);
    814 	prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL);
    815 
    816 out:
    817 	return r;
    818 }
    819