Home | History | Annotate | Line # | Download | only in dm
dm_ioctl.c revision 1.1.2.18
      1 /*        $NetBSD: dm_ioctl.c,v 1.1.2.18 2008/09/26 22:57:13 haad Exp $      */
      2 
      3 /*
      4  * Copyright (c) 1996, 1997, 1998, 1999, 2002 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 #include <sys/types.h>
     33 #include <sys/param.h>
     34 
     35 #include <sys/atomic.h>
     36 #include <sys/disklabel.h>
     37 #include <sys/kmem.h>
     38 #include <sys/vnode.h>
     39 
     40 #include <machine/int_fmtio.h>
     41 
     42 #include "netbsd-dm.h"
     43 #include "dm.h"
     44 
     45 extern struct dm_softc *dm_sc;
     46 
     47 #define DM_REMOVE_FLAG(flag, name) do {					\
     48 		prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \
     49 		flag &= ~name;						\
     50 		prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \
     51 	} while (/*CONSTCOND*/0)
     52 
     53 #define DM_ADD_FLAG(flag, name) do {					\
     54 		prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \
     55 		flag |= name;						\
     56 		prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \
     57 	} while (/*CONSTCOND*/0)
     58 
     59 static int dm_dbg_print_flags(int);
     60 
     61 /*
     62  * Print flags sent to the kernel from libevmapper.
     63  */
     64 static int
     65 dm_dbg_print_flags(int flags)
     66 {
     67 	aprint_normal("dbg_print --- %d\n",flags);
     68 
     69 	if (flags & DM_READONLY_FLAG)
     70 		aprint_normal("dbg_flags: DM_READONLY_FLAG set In/Out\n");
     71 
     72 	if (flags & DM_SUSPEND_FLAG)
     73 		aprint_normal("dbg_flags: DM_SUSPEND_FLAG set In/Out \n");
     74 
     75 	if (flags & DM_PERSISTENT_DEV_FLAG)
     76 		aprint_normal("db_flags: DM_PERSISTENT_DEV_FLAG set In\n");
     77 
     78 	if (flags & DM_STATUS_TABLE_FLAG)
     79 		aprint_normal("dbg_flags: DM_STATUS_TABLE_FLAG set In\n");
     80 
     81 	if (flags & DM_ACTIVE_PRESENT_FLAG)
     82 		aprint_normal("dbg_flags: DM_ACTIVE_PRESENT_FLAG set Out\n");
     83 
     84 	if (flags & DM_INACTIVE_PRESENT_FLAG)
     85 		aprint_normal("dbg_flags: DM_INACTIVE_PRESENT_FLAG set Out\n");
     86 
     87 	if (flags & DM_BUFFER_FULL_FLAG)
     88 		aprint_normal("dbg_flags: DM_BUFFER_FULL_FLAG set Out\n");
     89 
     90 	if (flags & DM_SKIP_BDGET_FLAG)
     91 		aprint_normal("dbg_flags: DM_SKIP_BDGET_FLAG set In\n");
     92 
     93 	if (flags & DM_SKIP_LOCKFS_FLAG)
     94 		aprint_normal("dbg_flags: DM_SKIP_LOCKFS_FLAG set In\n");
     95 
     96 	if (flags & DM_NOFLUSH_FLAG)
     97 		aprint_normal("dbg_flags: DM_NOFLUSH_FLAG set In\n");
     98 
     99 	return 0;
    100 }
    101 
    102 /*
    103  * Get version ioctl call I do it as default therefore this
    104  * function is unused now.
    105  */
    106 int
    107 dm_get_version_ioctl(prop_dictionary_t dm_dict)
    108 {
    109 	return 0;
    110 }
    111 
    112 /*
    113  * Get list of all available targets from global
    114  * target list and sent them back to libdevmapper.
    115  */
    116 int
    117 dm_list_versions_ioctl(prop_dictionary_t dm_dict)
    118 {
    119 	prop_array_t target_list;
    120 	uint32_t flags;
    121 
    122 	flags = 0;
    123 
    124 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    125 
    126 	dm_dbg_print_flags(flags);
    127 
    128 	target_list = dm_target_prop_list();
    129 
    130 	prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, target_list);
    131 
    132 	return 0;
    133 }
    134 
    135 /*
    136  * Create in-kernel entry for device. Device attributes such as name, uuid are
    137  * taken from proplib dictionary.
    138  *
    139  */
    140 int
    141 dm_dev_create_ioctl(prop_dictionary_t dm_dict)
    142 {
    143 	struct dm_dev *dmv;
    144 	const char *name, *uuid;
    145 	int r, flags;
    146 
    147 	r = 0;
    148 	flags = 0;
    149 	name = NULL;
    150 	uuid = NULL;
    151 
    152 	/* Get needed values from dictionary. */
    153 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    154 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    155 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    156 
    157 	dm_dbg_print_flags(flags);
    158 
    159 	/* Lookup name and uuid if device already exist quit. */
    160 	if ((dmv = dm_dev_lookup(name, uuid, -1)) != NULL) {
    161 		DM_ADD_FLAG(flags, DM_EXISTS_FLAG); /* Device already exists */
    162 		return EEXIST;
    163 	}
    164 
    165 	if ((dmv = dm_dev_alloc()) == NULL)
    166 		return ENOMEM;
    167 
    168 	if (uuid)
    169 		strncpy(dmv->uuid, uuid, DM_UUID_LEN);
    170 	else
    171 		dmv->uuid[0] = '\0';
    172 
    173 	if (name)
    174 		strlcpy(dmv->name, name, DM_NAME_LEN);
    175 
    176 	dmv->minor = ++(dm_sc->sc_minor_num);
    177 
    178 	dmv->flags = 0; /* device flags are set when needed */
    179 	dmv->ref_cnt = 0;
    180 	dmv->event_nr = 0;
    181 	dmv->cur_active_table = 0;
    182 	dmv->dev_type = 0;
    183 
    184 	/* Initialize tables. */
    185 	SLIST_INIT(&dmv->tables[0]);
    186 	SLIST_INIT(&dmv->tables[1]);
    187 
    188 	if (flags & DM_READONLY_FLAG)
    189 		dmv->flags |= DM_READONLY_FLAG;
    190 
    191 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    192 
    193 	/*
    194 	 * Locking strategy here is this: this is per device rw lock
    195 	 * and it should be write locked when we work with device.
    196 	 * Almost all ioctl callbacks for tables and devices must
    197 	 * acquire this lock. This rw_lock is locked for reading in
    198 	 * dmstrategy routine and therefore device can't be changed
    199 	 * before all running IO operations are done.
    200 	 *
    201 	 * XXX: I'm not sure what will happend when we start to use
    202 	 * upcall devices (mirror, snapshot targets), because then
    203 	 * dmstrategy routine of device X can wait for end of ioctl
    204 	 * call on other device.
    205 	 *
    206 	 */
    207 
    208 	rw_init(&dmv->dev_rwlock);
    209 
    210 
    211 	if ((r = dm_dev_insert(dmv)) != 0){
    212 		rw_destroy(&dmv->dev_rwlock);
    213 		dm_dev_free(dmv);
    214 	}
    215 
    216 	DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
    217 	DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
    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  * Locking: dev_mutex, dev_rwlock ??
    241  */
    242 int
    243 dm_dev_list_ioctl(prop_dictionary_t dm_dict)
    244 {
    245 	prop_array_t dev_list;
    246 
    247 	uint32_t flags;
    248 
    249 	flags = 0;
    250 
    251 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    252 
    253 	dm_dbg_print_flags(flags);
    254 
    255 	dev_list = dm_dev_prop_list();
    256 
    257 	prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list);
    258 
    259 	return 0;
    260 }
    261 
    262 /*
    263  * Rename selected devices old name is in struct dm_ioctl.
    264  * newname is taken from dictionary
    265  *
    266  * <key>cmd_data</key>
    267  *  <array>
    268  *   <string>...</string>
    269  *  </array>
    270  *
    271  * Locking: dev_mutex, dev_rwlock ??
    272  */
    273 int
    274 dm_dev_rename_ioctl(prop_dictionary_t dm_dict)
    275 {
    276 	prop_array_t cmd_array;
    277 	struct dm_dev *dmv;
    278 
    279 	const char *name, *uuid, *n_name;
    280 	uint32_t flags, minor;
    281 
    282 	name = NULL;
    283 	uuid = NULL;
    284 	minor = 0;
    285 
    286 	/* Get needed values from dictionary. */
    287 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    288 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    289 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    290 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    291 
    292 	dm_dbg_print_flags(flags);
    293 
    294 	cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
    295 
    296 	prop_array_get_cstring_nocopy(cmd_array, 0, &n_name);
    297 
    298 	if (strlen(n_name) + 1 > DM_NAME_LEN)
    299 		return EINVAL;
    300 
    301 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
    302 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    303 		return ENOENT;
    304 	}
    305 
    306 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->ref_cnt);
    307 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    308 	prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
    309 
    310 	/* change device name */
    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.
    319  *
    320  * Locking: dev_rwlock
    321  */
    322 int
    323 dm_dev_remove_ioctl(prop_dictionary_t dm_dict)
    324 {
    325 	struct dm_dev *dmv;
    326 	const char *name, *uuid;
    327 	uint32_t flags, minor;
    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 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    338 
    339 	dm_dbg_print_flags(flags);
    340 
    341 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL){
    342 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    343 		return ENOENT;
    344 	}
    345 
    346 	/*
    347 	 * Write lock rw lock firs and then remove all stuff.
    348 	 */
    349 	rw_enter(&dmv->dev_rwlock, RW_WRITER);
    350 
    351 	atomic_or_32(&dmv->dev_type, DM_DELETING_DEV);
    352 
    353 	/*
    354  	 * Remove device from global list so no new IO can
    355 	 * be started on it. Do it as first task after rw_enter.
    356 	 */
    357 	(void)dm_dev_rem(dmv);
    358 
    359 	rw_exit(&dmv->dev_rwlock);
    360 
    361 	/* Destroy active table first.  */
    362 	if (!SLIST_EMPTY(&dmv->tables[dmv->cur_active_table]))
    363 		dm_table_destroy(&dmv->tables[dmv->cur_active_table]);
    364 
    365 	/* Destroy inactive table if exits, too. */
    366 	if (!SLIST_EMPTY(&dmv->tables[1 - dmv->cur_active_table]))
    367 		dm_table_destroy(&dmv->tables[1 - dmv->cur_active_table]);
    368 
    369 	rw_destroy(&dmv->dev_rwlock);
    370 
    371 	/* Destroy device */
    372 	(void)dm_dev_free(dmv);
    373 
    374 	return 0;
    375 }
    376 
    377 /*
    378  * Return actual state of device to libdevmapper.
    379  *
    380  */
    381 int
    382 dm_dev_status_ioctl(prop_dictionary_t dm_dict)
    383 {
    384 	struct dm_table_entry *table_en;
    385 	struct dm_table  *tbl;
    386 	struct dm_dev *dmv;
    387 	const char *name, *uuid;
    388 	uint32_t flags, j, minor;
    389 
    390 	name = NULL;
    391 	uuid = NULL;
    392 	flags = 0;
    393 	j = 0;
    394 
    395 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    396 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    397 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    398 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    399 
    400 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
    401 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    402 		return ENOENT;
    403 	}
    404 
    405 	dm_dbg_print_flags(dmv->flags);
    406 
    407 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->ref_cnt);
    408 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    409 	prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
    410 
    411 	if (dmv->flags & DM_SUSPEND_FLAG)
    412 		DM_ADD_FLAG(flags, DM_SUSPEND_FLAG);
    413 
    414 	/* Add status flags for tables I have to check both
    415 	   active and inactive tables. */
    416 
    417 	tbl = &dmv->tables[dmv->cur_active_table];
    418 
    419 	if (!SLIST_EMPTY(tbl)) {
    420 		DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
    421 
    422 		SLIST_FOREACH(table_en, tbl, next)
    423 			j++;
    424 
    425 	} else
    426 		DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
    427 
    428 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_TARGET_COUNT, j);
    429 
    430 	tbl = &dmv->tables[1 - dmv->cur_active_table];
    431 
    432 	if (!SLIST_EMPTY(tbl))
    433 		DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
    434 	else
    435 		DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
    436 
    437 	return 0;
    438 }
    439 
    440 /*
    441  * Set only flag to suggest that device is suspended. This call is
    442  * not supported in NetBSD.
    443  *
    444  * Locking: null
    445  */
    446 int
    447 dm_dev_suspend_ioctl(prop_dictionary_t dm_dict)
    448 {
    449 	struct dm_dev *dmv;
    450 	const char *name, *uuid;
    451 	uint32_t flags, minor;
    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 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    461 
    462 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL){
    463 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    464 		return ENOENT;
    465 	}
    466 
    467 	dmv->flags |= DM_SUSPEND_FLAG | DM_INACTIVE_PRESENT_FLAG;
    468 
    469 	dm_dbg_print_flags(dmv->flags);
    470 
    471 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->ref_cnt);
    472 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags);
    473 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    474 
    475 	/* Add flags to dictionary flag after dmv -> dict copy */
    476 	DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
    477 
    478 	return 0;
    479 }
    480 
    481 /*
    482  * Simulate Linux behaviour better and switch tables here and not in
    483  * dm_table_load_ioctl.
    484  *
    485  * Locking: dev_mutex ??, dev_rwlock
    486  */
    487 int
    488 dm_dev_resume_ioctl(prop_dictionary_t dm_dict)
    489 {
    490 	struct dm_dev *dmv;
    491 	const char *name, *uuid;
    492 
    493 	uint32_t flags, minor;
    494 	dev_t dev;
    495 
    496 
    497 	name = NULL;
    498 	uuid = NULL;
    499 	flags = 0;
    500 
    501 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    502 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    503 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    504 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    505 
    506 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL){
    507 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    508 		return ENOENT;
    509 	}
    510 
    511 	rw_enter(&dmv->dev_rwlock, RW_WRITER);
    512 
    513 	dmv->flags &= ~(DM_SUSPEND_FLAG | DM_INACTIVE_PRESENT_FLAG);
    514 	dmv->flags |= DM_ACTIVE_PRESENT_FLAG;
    515 
    516 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->ref_cnt);
    517 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags);
    518 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    519 
    520 	DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
    521 
    522 	dmv->cur_active_table = 1 - dmv->cur_active_table;
    523 
    524 	rw_exit(&dmv->dev_rwlock);
    525 
    526 	/* XXX locking this should be guarded too. */
    527 	dev = makedev(0, dmv->minor);
    528 
    529 	dmgetdisklabel(dmv->dk_label, dev);
    530 
    531 	/* Destroy inactive table after resume. */
    532 	dm_table_destroy(&dmv->tables[1 - dmv->cur_active_table]);
    533 
    534 	return 0;
    535 }
    536 
    537 /*
    538  * Table management routines
    539  * lvm2tools doens't send name/uuid to kernel with table
    540  * for lookup I have to use minor number.
    541  */
    542 
    543 
    544 /*
    545  * Remove inactive table from device. Routines which work's with inactive tables
    546  * doesn't need to held write rw_lock. They can synchronise themselves with mutex?.
    547  *
    548  * Locking: dev_mutex
    549  */
    550 int
    551 dm_table_clear_ioctl(prop_dictionary_t dm_dict)
    552 {
    553 	struct dm_dev *dmv;
    554 	struct dm_table  *tbl;
    555 
    556 	const char *name, *uuid;
    557 	uint32_t flags, minor;
    558 
    559 	dmv  = NULL;
    560 	name = NULL;
    561 	uuid = NULL;
    562 	flags = 0;
    563 	minor = 0;
    564 
    565 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    566 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    567 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    568 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    569 
    570 	aprint_verbose("Clearing inactive table from device: %s--%s\n",
    571 	    name, uuid);
    572 
    573 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL){
    574 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    575 		return ENOENT;
    576 	}
    577 
    578 	/* Select unused table */
    579 	tbl = &dmv->tables[1 - dmv->cur_active_table];
    580 
    581 	dm_table_destroy(tbl);
    582 
    583 	dmv->flags &= ~DM_INACTIVE_PRESENT_FLAG;
    584 
    585 	return 0;
    586 }
    587 
    588 /*
    589  * Get list of physical devices for active table.
    590  * Get dev_t from pdev vnode and insert it into cmd_array.
    591  *
    592  * XXX. This function is called from lvm2tools to get information
    593  *      about physical devices, too e.g. during vgcreate.
    594  *
    595  * Locking: dev_mutex ??, dev_rwlock
    596  */
    597 int
    598 dm_table_deps_ioctl(prop_dictionary_t dm_dict)
    599 {
    600 	struct dm_dev *dmv;
    601 	struct dm_table_entry *table_en;
    602 
    603 	prop_array_t cmd_array;
    604 
    605 	const char *name, *uuid;
    606 	uint32_t flags, minor;
    607 
    608 	size_t i;
    609 
    610 	name = NULL;
    611 	uuid = NULL;
    612 	dmv  = NULL;
    613 	flags = 0;
    614 
    615 	i = 0;
    616 
    617 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    618 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    619 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    620 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    621 
    622 	/* create array for dev_t's */
    623 	cmd_array = prop_array_create();
    624 
    625 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL){
    626 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    627 		return ENOENT;
    628 	}
    629 
    630 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    631 	prop_dictionary_set_cstring(dm_dict, DM_IOCTL_NAME, dmv->name);
    632 	prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
    633 
    634 	aprint_verbose("Getting table deps for device: %s\n", dmv->name);
    635 
    636 	/* XXX DO I really need to write lock it here */
    637 	rw_enter(&dmv->dev_rwlock, RW_WRITER);
    638 
    639 	SLIST_FOREACH(table_en, &dmv->tables[dmv->cur_active_table], next)
    640 		table_en->target->deps(table_en, cmd_array);
    641 
    642 	rw_exit(&dmv->dev_rwlock);
    643 
    644 	prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array);
    645 
    646 	return 0;
    647 }
    648 
    649 /*
    650  * Load new table/tables to device.
    651  * Call apropriate target init routine open all physical pdev's and
    652  * link them to device. For other targets mirror, strip, snapshot
    653  * etc. also add dependency devices to upcalls list.
    654  *
    655  * Load table to inactive slot table are switched in dm_device_resume_ioctl.
    656  * This simulates Linux behaviour better there should not be any difference.
    657  *
    658  */
    659 int
    660 dm_table_load_ioctl(prop_dictionary_t dm_dict)
    661 {
    662 	struct dm_dev *dmv;
    663 	struct dm_table_entry *table_en, *last_table;
    664 	struct dm_table  *tbl;
    665 	struct dm_target *target;
    666 
    667 	prop_object_iterator_t iter;
    668 	prop_array_t cmd_array;
    669 	prop_dictionary_t target_dict;
    670 
    671 	const char *name, *uuid, *type;
    672 
    673 	uint32_t flags, ret, minor;
    674 
    675 	char *str;
    676 
    677 	ret = 0;
    678 	flags = 0;
    679 	name = NULL;
    680 	uuid = NULL;
    681 	dmv = NULL;
    682 	last_table = NULL;
    683 	str = NULL;
    684 
    685 
    686 /*	char *xml;
    687 	xml = prop_dictionary_externalize(dm_dict);
    688 	printf("%s\n",xml);*/
    689 
    690 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    691 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    692 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    693 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    694 
    695 	cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
    696 	iter = prop_array_iterator(cmd_array);
    697 
    698 	dm_dbg_print_flags(flags);
    699 
    700 	aprint_normal("Loading table to device: %s--%s\n",name,uuid);
    701 
    702 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL){
    703 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    704 		return ENOENT;
    705 	}
    706 
    707 	printf("dmv->name = %s\n", dmv->name);
    708 
    709 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    710 
    711 	/* Select unused table */
    712 	tbl = &dmv->tables[1-dmv->cur_active_table];
    713 
    714 	/*
    715 	 * I have to check if this table slot is not used by another table list.
    716 	 * if it is used I should free them.
    717 	 */
    718 	if (dmv->flags & DM_INACTIVE_PRESENT_FLAG)
    719 		dm_table_destroy(tbl);
    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_name(type)) == NULL)
    731 			return ENOENT;
    732 
    733 		if ((table_en=kmem_alloc(sizeof(struct dm_table_entry),
    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 		if ((ret = target->init(dmv, &table_en->target_config,
    768 			    str)) != 0) {
    769 
    770 			dm_table_destroy(tbl);
    771 
    772 			return ret;
    773 		}
    774 
    775 		last_table = table_en;
    776 
    777 		if (str != NULL)
    778 			prop_object_release(str);
    779 	}
    780 
    781 	prop_object_release(cmd_array);
    782 
    783 	DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
    784 	dmv->flags |= DM_INACTIVE_PRESENT_FLAG;
    785 
    786 	return 0;
    787 }
    788 
    789 /*
    790  * Get description of all tables loaded to device from kernel
    791  * and send it to libdevmapper.
    792  *
    793  * Output dictionary for every table:
    794  *
    795  * <key>cmd_data</key>
    796  * <array>
    797  *   <dict>
    798  *    <key>type<key>
    799  *    <string>...</string>
    800  *
    801  *    <key>start</key>
    802  *    <integer>...</integer>
    803  *
    804  *    <key>length</key>
    805  *    <integer>...</integer>
    806  *
    807  *    <key>params</key>
    808  *    <string>...</string>
    809  *   </dict>
    810  * </array>
    811  *
    812  */
    813 int
    814 dm_table_status_ioctl(prop_dictionary_t dm_dict)
    815 {
    816 	struct dm_dev *dmv;
    817 	struct dm_table  *tbl;
    818 	struct dm_table_entry *table_en;
    819 
    820 	prop_array_t cmd_array;
    821 	prop_dictionary_t target_dict;
    822 
    823 	uint32_t rec_size, minor;
    824 
    825 	const char *name, *uuid;
    826 	char *params;
    827 	int flags;
    828 
    829 	dmv = NULL;
    830 	uuid = NULL;
    831 	name = NULL;
    832 	params = NULL;
    833 	flags = 0;
    834 	rec_size = 0;
    835 
    836 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
    837 	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
    838 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
    839 	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
    840 
    841 	if ((cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA)) == NULL)
    842 		cmd_array = prop_array_create();
    843 
    844 	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL){
    845 		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
    846 		return ENOENT;
    847 	}
    848 
    849 	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
    850 
    851 	/* I should use mutex here and not rwlock there can be IO operation
    852 	   during this ioctl on device. */
    853 
    854 	aprint_normal("Status of device tables: %s--%d\n",
    855 	    name, dmv->cur_active_table);
    856 
    857 	if (dmv->flags | DM_SUSPEND_FLAG)
    858 		DM_ADD_FLAG(flags, DM_SUSPEND_FLAG);
    859 
    860 	tbl = &dmv->tables[dmv->cur_active_table];
    861 
    862 	if (!SLIST_EMPTY(tbl))
    863 		DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
    864 	else {
    865 		DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
    866 
    867 		tbl = &dmv->tables[1 - dmv->cur_active_table];
    868 
    869 		if (!SLIST_EMPTY(tbl))
    870 			DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
    871 		else {
    872 			DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
    873 		}
    874 	}
    875 
    876 	SLIST_FOREACH(table_en,tbl,next)
    877 	{
    878 		target_dict = prop_dictionary_create();
    879 		aprint_verbose("%016" PRIu64 ", length %016" PRIu64
    880 		    ", target %s\n", table_en->start, table_en->length,
    881 		    table_en->target->name);
    882 
    883 		prop_dictionary_set_uint64(target_dict, DM_TABLE_START,
    884 		    table_en->start);
    885 		prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH,
    886 		    table_en->length);
    887 
    888 		prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE,
    889 		    table_en->target->name);
    890 
    891 		prop_dictionary_set_int32(target_dict, DM_TABLE_STAT,
    892 		    dmv->cur_active_table);
    893 
    894 		if (flags |= DM_STATUS_TABLE_FLAG) {
    895 			params = table_en->target->status
    896 			    (table_en->target_config);
    897 
    898 			if(params != NULL){
    899 				prop_dictionary_set_cstring(target_dict,
    900 				    DM_TABLE_PARAMS, params);
    901 
    902 				kmem_free(params, strlen(params) + 1);
    903 			}
    904 		}
    905 		prop_array_add(cmd_array, target_dict);
    906 		prop_object_release(target_dict);
    907 	}
    908 
    909 	prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array);
    910 
    911 	return 0;
    912 }
    913 
    914 
    915 /*
    916  * For every call I have to set kernel driver version.
    917  * Because I can have commands supported only in other
    918  * newer/later version. This routine is called for every
    919  * ioctl command.
    920  */
    921 int
    922 dm_check_version(prop_dictionary_t dm_dict)
    923 {
    924 	size_t i;
    925 	int dm_version[3];
    926 	prop_array_t ver;
    927 
    928 	ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION);
    929 
    930 	for(i=0; i < 3; i++)
    931 		prop_array_get_uint32(ver, i, &dm_version[i]);
    932 
    933 
    934 	if (DM_VERSION_MAJOR != dm_version[0] || DM_VERSION_MINOR < dm_version[1]){
    935 		aprint_verbose("libdevmapper/kernel version mismatch "
    936 		    "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n",
    937 		    DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL,
    938 		    dm_version[0], dm_version[1], dm_version[2]);
    939 
    940 		return EIO;
    941 	}
    942 
    943 	prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR);
    944 	prop_array_set_uint32(ver, 1, DM_VERSION_MINOR);
    945 	prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL);
    946 
    947 	return 0;
    948 }
    949