1 /* $NetBSD: dm_ioctl.c,v 1.4 2008/12/21 00:53:27 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 uint32_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_32_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