1 /* $NetBSD: dm_ioctl.c,v 1.21 2010/02/25 20:48:58 jakllsch 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 depends 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 #include <sys/device.h> 84 #include <sys/malloc.h> 85 #include <sys/vnode.h> 86 #include <dev/disk/dm/dm.h> 87 88 #include "netbsd-dm.h" 89 90 #define DM_REMOVE_FLAG(flag, name) do { \ 91 prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \ 92 flag &= ~name; \ 93 prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \ 94 } while (/*CONSTCOND*/0) 95 96 #define DM_ADD_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 static int dm_dbg_print_flags(int); 103 104 /* 105 * Print flags sent to the kernel from libevmapper. 106 */ 107 static int 108 dm_dbg_print_flags(int flags) 109 { 110 aprint_debug("dbg_print --- %d\n", flags); 111 112 if (flags & DM_READONLY_FLAG) 113 aprint_debug("dbg_flags: DM_READONLY_FLAG set In/Out\n"); 114 115 if (flags & DM_SUSPEND_FLAG) 116 aprint_debug("dbg_flags: DM_SUSPEND_FLAG set In/Out \n"); 117 118 if (flags & DM_PERSISTENT_DEV_FLAG) 119 aprint_debug("db_flags: DM_PERSISTENT_DEV_FLAG set In\n"); 120 121 if (flags & DM_STATUS_TABLE_FLAG) 122 aprint_debug("dbg_flags: DM_STATUS_TABLE_FLAG set In\n"); 123 124 if (flags & DM_ACTIVE_PRESENT_FLAG) 125 aprint_debug("dbg_flags: DM_ACTIVE_PRESENT_FLAG set Out\n"); 126 127 if (flags & DM_INACTIVE_PRESENT_FLAG) 128 aprint_debug("dbg_flags: DM_INACTIVE_PRESENT_FLAG set Out\n"); 129 130 if (flags & DM_BUFFER_FULL_FLAG) 131 aprint_debug("dbg_flags: DM_BUFFER_FULL_FLAG set Out\n"); 132 133 if (flags & DM_SKIP_BDGET_FLAG) 134 aprint_debug("dbg_flags: DM_SKIP_BDGET_FLAG set In\n"); 135 136 if (flags & DM_SKIP_LOCKFS_FLAG) 137 aprint_debug("dbg_flags: DM_SKIP_LOCKFS_FLAG set In\n"); 138 139 if (flags & DM_NOFLUSH_FLAG) 140 aprint_debug("dbg_flags: DM_NOFLUSH_FLAG set In\n"); 141 142 return 0; 143 } 144 /* 145 * Get version ioctl call I do it as default therefore this 146 * function is unused now. 147 */ 148 int 149 dm_get_version_ioctl(prop_dictionary_t dm_dict) 150 { 151 return 0; 152 } 153 /* 154 * Get list of all available targets from global 155 * target list and sent them back to libdevmapper. 156 */ 157 int 158 dm_list_versions_ioctl(prop_dictionary_t dm_dict) 159 { 160 prop_array_t target_list; 161 uint32_t flags; 162 163 flags = 0; 164 165 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 166 167 dm_dbg_print_flags(flags); 168 target_list = dm_target_prop_list(); 169 170 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, target_list); 171 prop_object_release(target_list); 172 173 return 0; 174 } 175 /* 176 * Create in-kernel entry for device. Device attributes such as name, uuid are 177 * taken from proplib dictionary. 178 * 179 */ 180 int 181 dm_dev_create_ioctl(prop_dictionary_t dm_dict) 182 { 183 dm_dev_t *dmv; 184 const char *name, *uuid; 185 int r, flags; 186 187 r = 0; 188 flags = 0; 189 name = NULL; 190 uuid = NULL; 191 192 /* Get needed values from dictionary. */ 193 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 194 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 195 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 196 197 dm_dbg_print_flags(flags); 198 199 /* Lookup name and uuid if device already exist quit. */ 200 if ((dmv = dm_dev_lookup(name, uuid, -1)) != NULL) { 201 DM_ADD_FLAG(flags, DM_EXISTS_FLAG); /* Device already exists */ 202 dm_dev_unbusy(dmv); 203 return EEXIST; 204 } 205 206 r = dm_dev_create(&dmv, name, uuid, flags); 207 208 if (r == 0) { 209 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 210 DM_ADD_FLAG(flags, DM_EXISTS_FLAG); 211 DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); 212 } 213 214 return r; 215 } 216 /* 217 * Get list of created device-mapper devices fromglobal list and 218 * send it to kernel. 219 * 220 * Output dictionary: 221 * 222 * <key>cmd_data</key> 223 * <array> 224 * <dict> 225 * <key>name<key> 226 * <string>...</string> 227 * 228 * <key>dev</key> 229 * <integer>...</integer> 230 * </dict> 231 * </array> 232 * 233 */ 234 int 235 dm_dev_list_ioctl(prop_dictionary_t dm_dict) 236 { 237 prop_array_t dev_list; 238 239 uint32_t flags; 240 241 flags = 0; 242 243 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 244 245 dm_dbg_print_flags(flags); 246 247 dev_list = dm_dev_prop_list(); 248 249 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list); 250 prop_object_release(dev_list); 251 252 return 0; 253 } 254 /* 255 * Rename selected devices old name is in struct dm_ioctl. 256 * newname is taken from dictionary 257 * 258 * <key>cmd_data</key> 259 * <array> 260 * <string>...</string> 261 * </array> 262 */ 263 int 264 dm_dev_rename_ioctl(prop_dictionary_t dm_dict) 265 { 266 #if 0 267 prop_array_t cmd_array; 268 dm_dev_t *dmv; 269 270 const char *name, *uuid, *n_name; 271 uint32_t flags, minor; 272 273 name = NULL; 274 uuid = NULL; 275 minor = 0; 276 277 /* Get needed values from dictionary. */ 278 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 279 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 280 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 281 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 282 283 dm_dbg_print_flags(flags); 284 285 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA); 286 287 prop_array_get_cstring_nocopy(cmd_array, 0, &n_name); 288 289 if (strlen(n_name) + 1 > DM_NAME_LEN) 290 return EINVAL; 291 292 if ((dmv = dm_dev_rem(NULL, name, uuid, minor)) == NULL) { 293 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 294 return ENOENT; 295 } 296 /* change device name */ 297 /* 298 * XXX How to deal with this change, name only used in 299 * dm_dev_routines, should I add dm_dev_change_name which will run 300 * under the dm_dev_list mutex ? 301 */ 302 strlcpy(dmv->name, n_name, DM_NAME_LEN); 303 304 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); 305 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 306 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); 307 308 dm_dev_insert(dmv); 309 #endif 310 311 /* 312 * XXX: the rename is not yet implemented. The main complication 313 * here is devfs. We'd probably need a new function, rename_dev() 314 * that would trigger a node rename in devfs. 315 */ 316 kprintf("dm_dev_rename_ioctl called, but not implemented!\n"); 317 return 0; 318 } 319 320 /* 321 * Remove device 322 */ 323 int 324 dm_dev_remove_ioctl(prop_dictionary_t dm_dict) 325 { 326 dm_dev_t *dmv; 327 const char *name, *uuid; 328 uint32_t flags, minor; 329 330 flags = 0; 331 name = NULL; 332 uuid = NULL; 333 334 /* Get needed values from dictionary. */ 335 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 336 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 337 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 338 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 339 340 dm_dbg_print_flags(flags); 341 342 /* 343 * This seems as hack to me, probably use routine dm_dev_get_devt to 344 * atomicaly get devt from device. 345 */ 346 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 347 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 348 return ENOENT; 349 } 350 351 dm_dev_unbusy(dmv); 352 353 if (dmv->is_open) 354 return EBUSY; 355 356 /* 357 * This will call dm_detach routine which will actually remove 358 * device. 359 */ 360 return dm_dev_remove(dmv); 361 } 362 363 /* 364 * Try to remove all devices 365 */ 366 int 367 dm_dev_remove_all_ioctl(prop_dictionary_t dm_dict) 368 { 369 uint32_t flags = 0; 370 371 /* Get needed values from dictionary. */ 372 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 373 374 dm_dbg_print_flags(flags); 375 376 /* Gently remove all devices, if possible */ 377 return dm_dev_remove_all(1); 378 } 379 380 /* 381 * Return actual state of device to libdevmapper. 382 */ 383 int 384 dm_dev_status_ioctl(prop_dictionary_t dm_dict) 385 { 386 dm_dev_t *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 dm_dbg_print_flags(dmv->flags); 405 406 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); 407 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 408 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); 409 410 if (dmv->flags & DM_SUSPEND_FLAG) 411 DM_ADD_FLAG(flags, DM_SUSPEND_FLAG); 412 413 /* 414 * Add status flags for tables I have to check both active and 415 * inactive tables. 416 */ 417 if ((j = dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE))) { 418 DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); 419 } else 420 DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); 421 422 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_TARGET_COUNT, j); 423 424 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE)) 425 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); 426 else 427 DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); 428 429 dm_dev_unbusy(dmv); 430 431 return 0; 432 } 433 /* 434 * Set only flag to suggest that device is suspended. This call is 435 * not supported in NetBSD. 436 * 437 */ 438 int 439 dm_dev_suspend_ioctl(prop_dictionary_t dm_dict) 440 { 441 dm_dev_t *dmv; 442 const char *name, *uuid; 443 uint32_t flags, minor; 444 445 name = NULL; 446 uuid = NULL; 447 flags = 0; 448 449 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 450 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 451 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 452 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 453 454 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 455 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 456 return ENOENT; 457 } 458 atomic_set_int(&dmv->flags, DM_SUSPEND_FLAG); 459 460 dm_dbg_print_flags(dmv->flags); 461 462 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); 463 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags); 464 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 465 466 dm_dev_unbusy(dmv); 467 468 /* Add flags to dictionary flag after dmv -> dict copy */ 469 DM_ADD_FLAG(flags, DM_EXISTS_FLAG); 470 471 return 0; 472 } 473 /* 474 * Simulate Linux behaviour better and switch tables here and not in 475 * dm_table_load_ioctl. 476 */ 477 int 478 dm_dev_resume_ioctl(prop_dictionary_t dm_dict) 479 { 480 dm_dev_t *dmv; 481 const char *name, *uuid; 482 uint32_t flags, minor; 483 484 name = NULL; 485 uuid = NULL; 486 flags = 0; 487 488 /* 489 * char *xml; xml = prop_dictionary_externalize(dm_dict); 490 * printf("%s\n",xml); 491 */ 492 493 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 494 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 495 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 496 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 497 498 /* Remove device from global device list */ 499 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 500 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 501 return ENOENT; 502 } 503 atomic_clear_int(&dmv->flags, (DM_SUSPEND_FLAG | DM_INACTIVE_PRESENT_FLAG)); 504 atomic_set_int(&dmv->flags, DM_ACTIVE_PRESENT_FLAG); 505 506 dm_table_switch_tables(&dmv->table_head); 507 508 DM_ADD_FLAG(flags, DM_EXISTS_FLAG); 509 510 dmsetdiskinfo(dmv->diskp, &dmv->table_head); 511 512 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); 513 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags); 514 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 515 516 dm_dev_unbusy(dmv); 517 518 /* Destroy inactive table after resume. */ 519 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 520 521 return 0; 522 } 523 /* 524 * Table management routines 525 * lvm2tools doens't send name/uuid to kernel with table 526 * for lookup I have to use minor number. 527 */ 528 529 /* 530 * Remove inactive table from device. Routines which work's with inactive tables 531 * doesn't need to synchronise with dmstrategy. They can synchronise themselves with mutex?. 532 * 533 */ 534 int 535 dm_table_clear_ioctl(prop_dictionary_t dm_dict) 536 { 537 dm_dev_t *dmv; 538 const char *name, *uuid; 539 uint32_t flags, minor; 540 541 dmv = NULL; 542 name = NULL; 543 uuid = NULL; 544 flags = 0; 545 minor = 0; 546 547 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 548 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 549 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 550 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 551 552 aprint_debug("Clearing inactive table from device: %s--%s\n", 553 name, uuid); 554 555 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 556 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 557 return ENOENT; 558 } 559 /* Select unused table */ 560 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 561 562 atomic_clear_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG); 563 564 dm_dev_unbusy(dmv); 565 566 return 0; 567 } 568 /* 569 * Get list of physical devices for active table. 570 * Get dev_t from pdev vnode and insert it into cmd_array. 571 * 572 * XXX. This function is called from lvm2tools to get information 573 * about physical devices, too e.g. during vgcreate. 574 */ 575 int 576 dm_table_deps_ioctl(prop_dictionary_t dm_dict) 577 { 578 dm_dev_t *dmv; 579 dm_table_t *tbl; 580 dm_table_entry_t *table_en; 581 582 prop_array_t cmd_array; 583 const char *name, *uuid; 584 uint32_t flags, minor; 585 586 int table_type; 587 size_t i; 588 589 name = NULL; 590 uuid = NULL; 591 dmv = NULL; 592 flags = 0; 593 594 i = 0; 595 596 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 597 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 598 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 599 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 600 601 /* create array for dev_t's */ 602 cmd_array = prop_array_create(); 603 604 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 605 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 606 return ENOENT; 607 } 608 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 609 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_NAME, dmv->name); 610 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); 611 612 aprint_debug("Getting table deps for device: %s\n", dmv->name); 613 614 /* 615 * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query 616 * INACTIVE TABLE 617 */ 618 if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) 619 table_type = DM_TABLE_INACTIVE; 620 else 621 table_type = DM_TABLE_ACTIVE; 622 623 tbl = dm_table_get_entry(&dmv->table_head, table_type); 624 625 SLIST_FOREACH(table_en, tbl, next) 626 table_en->target->deps(table_en, cmd_array); 627 628 dm_table_release(&dmv->table_head, table_type); 629 dm_dev_unbusy(dmv); 630 631 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array); 632 prop_object_release(cmd_array); 633 634 return 0; 635 } 636 /* 637 * Load new table/tables to device. 638 * Call apropriate target init routine open all physical pdev's and 639 * link them to device. For other targets mirror, strip, snapshot 640 * etc. also add dependency devices to upcalls list. 641 * 642 * Load table to inactive slot table are switched in dm_device_resume_ioctl. 643 * This simulates Linux behaviour better there should not be any difference. 644 * 645 */ 646 int 647 dm_table_load_ioctl(prop_dictionary_t dm_dict) 648 { 649 dm_dev_t *dmv; 650 dm_table_entry_t *table_en, *last_table; 651 dm_table_t *tbl; 652 dm_target_t *target; 653 654 prop_object_iterator_t iter; 655 prop_array_t cmd_array; 656 prop_dictionary_t target_dict; 657 658 const char *name, *uuid, *type; 659 660 uint32_t flags, ret, minor; 661 662 char *str; 663 664 ret = 0; 665 flags = 0; 666 name = NULL; 667 uuid = NULL; 668 dmv = NULL; 669 last_table = NULL; 670 str = NULL; 671 672 /* 673 * char *xml; xml = prop_dictionary_externalize(dm_dict); 674 * printf("%s\n",xml); 675 */ 676 677 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 678 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 679 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 680 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 681 682 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA); 683 iter = prop_array_iterator(cmd_array); 684 dm_dbg_print_flags(flags); 685 686 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 687 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 688 return ENOENT; 689 } 690 aprint_debug("Loading table to device: %s--%d\n", name, 691 dmv->table_head.cur_active_table); 692 693 /* 694 * I have to check if this table slot is not used by another table list. 695 * if it is used I should free them. 696 */ 697 if (dmv->flags & DM_INACTIVE_PRESENT_FLAG) 698 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 699 700 dm_dbg_print_flags(dmv->flags); 701 tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_INACTIVE); 702 703 aprint_debug("dmv->name = %s\n", dmv->name); 704 705 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 706 707 while ((target_dict = prop_object_iterator_next(iter)) != NULL) { 708 prop_dictionary_get_cstring_nocopy(target_dict, 709 DM_TABLE_TYPE, &type); 710 /* 711 * If we want to deny table with 2 or more different 712 * target we should do it here 713 */ 714 if (((target = dm_target_lookup(type)) == NULL) && 715 ((target = dm_target_autoload(type)) == NULL)) { 716 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); 717 dm_dev_unbusy(dmv); 718 return ENOENT; 719 } 720 if ((table_en = kmalloc(sizeof(dm_table_entry_t), 721 M_DM, M_WAITOK)) == NULL) { 722 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); 723 dm_dev_unbusy(dmv); 724 dm_target_unbusy(target); 725 return ENOMEM; 726 } 727 prop_dictionary_get_uint64(target_dict, DM_TABLE_START, 728 &table_en->start); 729 prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH, 730 &table_en->length); 731 732 aprint_debug("dm_ioctl.c... table_en->start = %ju, " 733 "table_en->length = %ju\n", 734 (uintmax_t)table_en->start, 735 (uintmax_t)table_en->length); 736 737 table_en->target = target; 738 table_en->dm_dev = dmv; 739 table_en->target_config = NULL; 740 741 /* 742 * There is a parameter string after dm_target_spec 743 * structure which points to /dev/wd0a 284 part of 744 * table. String str points to this text. This can be 745 * null and therefore it should be checked before we try to 746 * use it. 747 */ 748 prop_dictionary_get_cstring(target_dict, 749 DM_TABLE_PARAMS, (char **) &str); 750 751 if (SLIST_EMPTY(tbl)) 752 /* insert this table to head */ 753 SLIST_INSERT_HEAD(tbl, table_en, next); 754 else 755 SLIST_INSERT_AFTER(last_table, table_en, next); 756 757 /* 758 * Params string is different for every target, 759 * therfore I have to pass it to target init 760 * routine and parse parameters there. 761 */ 762 aprint_debug("DM: str passed in is: %s", str); 763 if ((ret = target->init(dmv, &table_en->target_config, 764 str)) != 0) { 765 766 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); 767 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 768 kfree(str, M_TEMP); 769 770 dm_dev_unbusy(dmv); 771 dm_target_unbusy(target); 772 return ret; 773 } 774 last_table = table_en; 775 kfree(str, M_TEMP); 776 } 777 prop_object_iterator_release(iter); 778 779 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); 780 atomic_set_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG); 781 782 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); 783 784 dm_dev_unbusy(dmv); 785 #if 0 786 dmsetdiskinfo(dmv->diskp, &dmv->table_head); 787 #endif 788 return 0; 789 } 790 /* 791 * Get description of all tables loaded to device from kernel 792 * and send it to libdevmapper. 793 * 794 * Output dictionary for every table: 795 * 796 * <key>cmd_data</key> 797 * <array> 798 * <dict> 799 * <key>type<key> 800 * <string>...</string> 801 * 802 * <key>start</key> 803 * <integer>...</integer> 804 * 805 * <key>length</key> 806 * <integer>...</integer> 807 * 808 * <key>params</key> 809 * <string>...</string> 810 * </dict> 811 * </array> 812 * 813 */ 814 int 815 dm_table_status_ioctl(prop_dictionary_t dm_dict) 816 { 817 dm_dev_t *dmv; 818 dm_table_t *tbl; 819 dm_table_entry_t *table_en; 820 821 prop_array_t cmd_array; 822 prop_dictionary_t target_dict; 823 824 uint32_t rec_size, minor; 825 826 const char *name, *uuid; 827 char *params; 828 int flags; 829 int table_type; 830 831 dmv = NULL; 832 uuid = NULL; 833 name = NULL; 834 params = NULL; 835 flags = 0; 836 rec_size = 0; 837 838 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 839 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 840 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 841 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 842 843 cmd_array = prop_array_create(); 844 845 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 846 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 847 return ENOENT; 848 } 849 /* 850 * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query 851 * INACTIVE TABLE 852 */ 853 if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) 854 table_type = DM_TABLE_INACTIVE; 855 else 856 table_type = DM_TABLE_ACTIVE; 857 858 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE)) 859 DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); 860 else { 861 DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); 862 863 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE)) 864 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); 865 else { 866 DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); 867 } 868 } 869 870 if (dmv->flags & DM_SUSPEND_FLAG) 871 DM_ADD_FLAG(flags, DM_SUSPEND_FLAG); 872 873 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 874 875 aprint_debug("Status of device tables: %s--%d\n", 876 name, dmv->table_head.cur_active_table); 877 878 tbl = dm_table_get_entry(&dmv->table_head, table_type); 879 880 SLIST_FOREACH(table_en, tbl, next) { 881 target_dict = prop_dictionary_create(); 882 aprint_debug("%016" PRIu64 ", length %016" PRIu64 883 ", target %s\n", table_en->start, table_en->length, 884 table_en->target->name); 885 886 prop_dictionary_set_uint64(target_dict, DM_TABLE_START, 887 table_en->start); 888 prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH, 889 table_en->length); 890 891 prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE, 892 table_en->target->name); 893 894 /* dm_table_get_cur_actv.table ?? */ 895 prop_dictionary_set_int32(target_dict, DM_TABLE_STAT, 896 dmv->table_head.cur_active_table); 897 898 if (flags & DM_STATUS_TABLE_FLAG) { 899 params = table_en->target->status 900 (table_en->target_config); 901 902 if (params != NULL) { 903 prop_dictionary_set_cstring(target_dict, 904 DM_TABLE_PARAMS, params); 905 906 kfree(params, M_DM); 907 } 908 } 909 prop_array_add(cmd_array, target_dict); 910 prop_object_release(target_dict); 911 } 912 913 dm_table_release(&dmv->table_head, table_type); 914 dm_dev_unbusy(dmv); 915 916 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags); 917 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array); 918 prop_object_release(cmd_array); 919 920 return 0; 921 } 922 923 924 /* 925 * For every call I have to set kernel driver version. 926 * Because I can have commands supported only in other 927 * newer/later version. This routine is called for every 928 * ioctl command. 929 */ 930 int 931 dm_check_version(prop_dictionary_t dm_dict) 932 { 933 size_t i; 934 int dm_version[3]; 935 prop_array_t ver; 936 937 ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION); 938 939 for (i = 0; i < 3; i++) 940 prop_array_get_uint32(ver, i, &dm_version[i]); 941 942 if (DM_VERSION_MAJOR != dm_version[0] || DM_VERSION_MINOR < dm_version[1]) { 943 aprint_debug("libdevmapper/kernel version mismatch " 944 "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n", 945 DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, 946 dm_version[0], dm_version[1], dm_version[2]); 947 948 return EIO; 949 } 950 prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR); 951 prop_array_set_uint32(ver, 1, DM_VERSION_MINOR); 952 prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL); 953 954 prop_dictionary_set(dm_dict, DM_IOCTL_VERSION, ver); 955 956 return 0; 957 } 958