1 /* $NetBSD: dm_ioctl.c,v 1.21 2010/02/25 20:48:58 jakllsch Exp $ */ 2 3 /* 4 * Copyright (c) 2010-2011 Alex Hornung <alex@alexhornung.com> 5 * Copyright (c) 2008 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Adam Hamsik. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Locking is used to synchronise between ioctl calls and between dm_table's 35 * users. 36 * 37 * ioctl locking: 38 * Simple reference counting, to count users of device will be used routines 39 * dm_dev_busy/dm_dev_unbusy are used for that. 40 * dm_dev_lookup/dm_dev_rem call dm_dev_busy before return(caller is therefore 41 * holder of reference_counter last). 42 * 43 * ioctl routines which change/remove dm_dev parameters must wait on 44 * dm_dev::dev_cv and when last user will call dm_dev_unbusy they will wake 45 * up them. 46 * 47 * table_head locking: 48 * To access table entries dm_table_* routines must be used. 49 * 50 * dm_table_get_entry will increment table users reference 51 * counter. It will return active or inactive table depends 52 * on uint8_t argument. 53 * 54 * dm_table_release must be called for every table_entry from 55 * dm_table_get_entry. Between these to calls tables can'tbe switched 56 * or destroyed. 57 * 58 * dm_table_head_init initialize talbe_entries SLISTS and io_cv. 59 * 60 * dm_table_head_destroy destroy cv. 61 * 62 * There are two types of users for dm_table_head first type will 63 * only read list and try to do anything with it e.g. dmstrategy, 64 * dm_table_size etc. There is another user for table_head which wants 65 * to change table lists e.g. dm_dev_resume_ioctl, dm_dev_remove_ioctl, 66 * dm_table_clear_ioctl. 67 * 68 * NOTE: It is not allowed to call dm_table_destroy, dm_table_switch_tables 69 * with hold table reference counter. Table reference counter is hold 70 * after calling dm_table_get_entry routine. After calling this 71 * function user must call dm_table_release before any writer table 72 * operation. 73 * 74 * Example: dm_table_get_entry 75 * dm_table_destroy/dm_table_switch_tables 76 * This exaple will lead to deadlock situation because after dm_table_get_entry 77 * table reference counter is != 0 and dm_table_destroy have to wait on cv until 78 * reference counter is 0. 79 * 80 */ 81 82 #include <sys/types.h> 83 #include <sys/param.h> 84 #include <sys/device.h> 85 #include <sys/malloc.h> 86 #include <sys/vnode.h> 87 #include <dev/disk/dm/dm.h> 88 89 #include "netbsd-dm.h" 90 91 #define DM_REMOVE_FLAG(flag, name) do { \ 92 prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \ 93 flag &= ~name; \ 94 prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \ 95 } while (/*CONSTCOND*/0) 96 97 #define DM_ADD_FLAG(flag, name) do { \ 98 prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \ 99 flag |= name; \ 100 prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \ 101 } while (/*CONSTCOND*/0) 102 103 static int dm_dbg_print_flags(int); 104 105 /* 106 * Print flags sent to the kernel from libevmapper. 107 */ 108 static int 109 dm_dbg_print_flags(int flags) 110 { 111 aprint_debug("dbg_print --- %d\n", flags); 112 113 if (flags & DM_READONLY_FLAG) 114 aprint_debug("dbg_flags: DM_READONLY_FLAG set In/Out\n"); 115 116 if (flags & DM_SUSPEND_FLAG) 117 aprint_debug("dbg_flags: DM_SUSPEND_FLAG set In/Out \n"); 118 119 if (flags & DM_PERSISTENT_DEV_FLAG) 120 aprint_debug("db_flags: DM_PERSISTENT_DEV_FLAG set In\n"); 121 122 if (flags & DM_STATUS_TABLE_FLAG) 123 aprint_debug("dbg_flags: DM_STATUS_TABLE_FLAG set In\n"); 124 125 if (flags & DM_ACTIVE_PRESENT_FLAG) 126 aprint_debug("dbg_flags: DM_ACTIVE_PRESENT_FLAG set Out\n"); 127 128 if (flags & DM_INACTIVE_PRESENT_FLAG) 129 aprint_debug("dbg_flags: DM_INACTIVE_PRESENT_FLAG set Out\n"); 130 131 if (flags & DM_BUFFER_FULL_FLAG) 132 aprint_debug("dbg_flags: DM_BUFFER_FULL_FLAG set Out\n"); 133 134 if (flags & DM_SKIP_BDGET_FLAG) 135 aprint_debug("dbg_flags: DM_SKIP_BDGET_FLAG set In\n"); 136 137 if (flags & DM_SKIP_LOCKFS_FLAG) 138 aprint_debug("dbg_flags: DM_SKIP_LOCKFS_FLAG set In\n"); 139 140 if (flags & DM_NOFLUSH_FLAG) 141 aprint_debug("dbg_flags: DM_NOFLUSH_FLAG set In\n"); 142 143 return 0; 144 } 145 /* 146 * Get version ioctl call I do it as default therefore this 147 * function is unused now. 148 */ 149 int 150 dm_get_version_ioctl(prop_dictionary_t dm_dict) 151 { 152 return 0; 153 } 154 /* 155 * Get list of all available targets from global 156 * target list and sent them back to libdevmapper. 157 */ 158 int 159 dm_list_versions_ioctl(prop_dictionary_t dm_dict) 160 { 161 prop_array_t target_list; 162 uint32_t flags; 163 164 flags = 0; 165 166 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 167 168 dm_dbg_print_flags(flags); 169 target_list = dm_target_prop_list(); 170 171 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, target_list); 172 prop_object_release(target_list); 173 174 return 0; 175 } 176 /* 177 * Create in-kernel entry for device. Device attributes such as name, uuid are 178 * taken from proplib dictionary. 179 * 180 */ 181 int 182 dm_dev_create_ioctl(prop_dictionary_t dm_dict) 183 { 184 dm_dev_t *dmv; 185 const char *name, *uuid; 186 int r, flags; 187 188 r = 0; 189 flags = 0; 190 name = NULL; 191 uuid = NULL; 192 193 /* Get needed values from dictionary. */ 194 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 195 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 196 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 197 198 dm_dbg_print_flags(flags); 199 200 /* Lookup name and uuid if device already exist quit. */ 201 if ((dmv = dm_dev_lookup(name, uuid, -1)) != NULL) { 202 DM_ADD_FLAG(flags, DM_EXISTS_FLAG); /* Device already exists */ 203 dm_dev_unbusy(dmv); 204 return EEXIST; 205 } 206 207 r = dm_dev_create(&dmv, name, uuid, flags); 208 209 if (r == 0) { 210 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 211 DM_ADD_FLAG(flags, DM_EXISTS_FLAG); 212 DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); 213 } 214 215 return r; 216 } 217 /* 218 * Get list of created device-mapper devices fromglobal list and 219 * send it to kernel. 220 * 221 * Output dictionary: 222 * 223 * <key>cmd_data</key> 224 * <array> 225 * <dict> 226 * <key>name<key> 227 * <string>...</string> 228 * 229 * <key>dev</key> 230 * <integer>...</integer> 231 * </dict> 232 * </array> 233 * 234 */ 235 int 236 dm_dev_list_ioctl(prop_dictionary_t dm_dict) 237 { 238 prop_array_t dev_list; 239 240 uint32_t flags; 241 242 flags = 0; 243 244 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 245 246 dm_dbg_print_flags(flags); 247 248 dev_list = dm_dev_prop_list(); 249 250 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list); 251 prop_object_release(dev_list); 252 253 return 0; 254 } 255 /* 256 * Rename selected devices old name is in struct dm_ioctl. 257 * newname is taken from dictionary 258 * 259 * <key>cmd_data</key> 260 * <array> 261 * <string>...</string> 262 * </array> 263 */ 264 int 265 dm_dev_rename_ioctl(prop_dictionary_t dm_dict) 266 { 267 #if 0 268 prop_array_t cmd_array; 269 dm_dev_t *dmv; 270 271 const char *name, *uuid, *n_name; 272 uint32_t flags, minor; 273 274 name = NULL; 275 uuid = NULL; 276 minor = 0; 277 278 /* Get needed values from dictionary. */ 279 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 280 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 281 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 282 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 283 284 dm_dbg_print_flags(flags); 285 286 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA); 287 288 prop_array_get_cstring_nocopy(cmd_array, 0, &n_name); 289 290 if (strlen(n_name) + 1 > DM_NAME_LEN) 291 return EINVAL; 292 293 if ((dmv = dm_dev_rem(NULL, name, uuid, minor)) == NULL) { 294 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 295 return ENOENT; 296 } 297 /* change device name */ 298 /* 299 * XXX How to deal with this change, name only used in 300 * dm_dev_routines, should I add dm_dev_change_name which will run 301 * under the dm_dev_list mutex ? 302 */ 303 strlcpy(dmv->name, n_name, DM_NAME_LEN); 304 305 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); 306 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 307 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); 308 309 dm_dev_insert(dmv); 310 #endif 311 312 /* 313 * XXX: the rename is not yet implemented. The main complication 314 * here is devfs. We'd probably need a new function, rename_dev() 315 * that would trigger a node rename in devfs. 316 */ 317 kprintf("dm_dev_rename_ioctl called, but not implemented!\n"); 318 return 0; 319 } 320 321 /* 322 * Remove device 323 */ 324 int 325 dm_dev_remove_ioctl(prop_dictionary_t dm_dict) 326 { 327 dm_dev_t *dmv; 328 const char *name, *uuid; 329 uint32_t flags, minor, is_open; 330 331 flags = 0; 332 name = NULL; 333 uuid = NULL; 334 335 /* Get needed values from dictionary. */ 336 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 337 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 338 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 339 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 340 341 dm_dbg_print_flags(flags); 342 343 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 344 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 345 return ENOENT; 346 } 347 348 is_open = dmv->is_open; 349 350 dm_dev_unbusy(dmv); 351 352 if (is_open) 353 return EBUSY; 354 355 /* 356 * This will call dm_detach routine which will actually remove 357 * device. 358 */ 359 return dm_dev_remove(dmv); 360 } 361 362 /* 363 * Try to remove all devices 364 */ 365 int 366 dm_dev_remove_all_ioctl(prop_dictionary_t dm_dict) 367 { 368 uint32_t flags = 0; 369 370 /* Get needed values from dictionary. */ 371 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 372 373 dm_dbg_print_flags(flags); 374 375 /* Gently remove all devices, if possible */ 376 return dm_dev_remove_all(1); 377 } 378 379 /* 380 * Return actual state of device to libdevmapper. 381 */ 382 int 383 dm_dev_status_ioctl(prop_dictionary_t dm_dict) 384 { 385 dm_dev_t *dmv; 386 const char *name, *uuid; 387 uint32_t flags, j, minor; 388 389 name = NULL; 390 uuid = NULL; 391 flags = 0; 392 j = 0; 393 394 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 395 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 396 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 397 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 398 399 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 400 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 401 return ENOENT; 402 } 403 dm_dbg_print_flags(dmv->flags); 404 405 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); 406 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 407 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); 408 409 if (dmv->flags & DM_SUSPEND_FLAG) 410 DM_ADD_FLAG(flags, DM_SUSPEND_FLAG); 411 412 /* 413 * Add status flags for tables I have to check both active and 414 * inactive tables. 415 */ 416 if ((j = dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE))) { 417 DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); 418 } else 419 DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); 420 421 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_TARGET_COUNT, j); 422 423 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE)) 424 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); 425 else 426 DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); 427 428 dm_dev_unbusy(dmv); 429 430 return 0; 431 } 432 /* 433 * Set only flag to suggest that device is suspended. This call is 434 * not supported in NetBSD. 435 * 436 */ 437 int 438 dm_dev_suspend_ioctl(prop_dictionary_t dm_dict) 439 { 440 dm_dev_t *dmv; 441 const char *name, *uuid; 442 uint32_t flags, minor; 443 444 name = NULL; 445 uuid = NULL; 446 flags = 0; 447 448 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 449 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 450 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 451 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 452 453 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 454 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 455 return ENOENT; 456 } 457 atomic_set_int(&dmv->flags, DM_SUSPEND_FLAG); 458 459 dm_dbg_print_flags(dmv->flags); 460 461 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); 462 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags); 463 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 464 465 dm_dev_unbusy(dmv); 466 467 /* Add flags to dictionary flag after dmv -> dict copy */ 468 DM_ADD_FLAG(flags, DM_EXISTS_FLAG); 469 470 return 0; 471 } 472 /* 473 * Simulate Linux behaviour better and switch tables here and not in 474 * dm_table_load_ioctl. 475 */ 476 int 477 dm_dev_resume_ioctl(prop_dictionary_t dm_dict) 478 { 479 dm_dev_t *dmv; 480 const char *name, *uuid; 481 uint32_t flags, minor; 482 483 name = NULL; 484 uuid = NULL; 485 flags = 0; 486 487 /* 488 * char *xml; xml = prop_dictionary_externalize(dm_dict); 489 * printf("%s\n",xml); 490 */ 491 492 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 493 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 494 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 495 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 496 497 /* Remove device from global device list */ 498 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 499 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 500 return ENOENT; 501 } 502 atomic_clear_int(&dmv->flags, (DM_SUSPEND_FLAG | DM_INACTIVE_PRESENT_FLAG)); 503 atomic_set_int(&dmv->flags, DM_ACTIVE_PRESENT_FLAG); 504 505 dm_table_switch_tables(&dmv->table_head); 506 507 DM_ADD_FLAG(flags, DM_EXISTS_FLAG); 508 509 dmsetdiskinfo(dmv->diskp, &dmv->table_head); 510 511 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); 512 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags); 513 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 514 515 dm_dev_unbusy(dmv); 516 517 /* Destroy inactive table after resume. */ 518 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 519 520 return 0; 521 } 522 /* 523 * Table management routines 524 * lvm2tools doens't send name/uuid to kernel with table 525 * for lookup I have to use minor number. 526 */ 527 528 /* 529 * Remove inactive table from device. Routines which work's with inactive tables 530 * doesn't need to synchronise with dmstrategy. They can synchronise themselves with mutex?. 531 * 532 */ 533 int 534 dm_table_clear_ioctl(prop_dictionary_t dm_dict) 535 { 536 dm_dev_t *dmv; 537 const char *name, *uuid; 538 uint32_t flags, minor; 539 540 dmv = NULL; 541 name = NULL; 542 uuid = NULL; 543 flags = 0; 544 minor = 0; 545 546 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 547 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 548 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 549 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 550 551 aprint_debug("Clearing inactive table from device: %s--%s\n", 552 name, uuid); 553 554 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 555 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 556 return ENOENT; 557 } 558 /* Select unused table */ 559 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 560 561 atomic_clear_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG); 562 563 dm_dev_unbusy(dmv); 564 565 return 0; 566 } 567 /* 568 * Get list of physical devices for active table. 569 * Get dev_t from pdev vnode and insert it into cmd_array. 570 * 571 * XXX. This function is called from lvm2tools to get information 572 * about physical devices, too e.g. during vgcreate. 573 */ 574 int 575 dm_table_deps_ioctl(prop_dictionary_t dm_dict) 576 { 577 dm_dev_t *dmv; 578 dm_table_t *tbl; 579 dm_table_entry_t *table_en; 580 581 prop_array_t cmd_array; 582 const char *name, *uuid; 583 uint32_t flags, minor; 584 585 int table_type; 586 587 name = NULL; 588 uuid = NULL; 589 dmv = NULL; 590 flags = 0; 591 592 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 593 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 594 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 595 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 596 597 /* create array for dev_t's */ 598 cmd_array = prop_array_create(); 599 600 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 601 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 602 return ENOENT; 603 } 604 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 605 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_NAME, dmv->name); 606 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); 607 608 aprint_debug("Getting table deps for device: %s\n", dmv->name); 609 610 /* 611 * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query 612 * INACTIVE TABLE 613 */ 614 if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) 615 table_type = DM_TABLE_INACTIVE; 616 else 617 table_type = DM_TABLE_ACTIVE; 618 619 tbl = dm_table_get_entry(&dmv->table_head, table_type); 620 621 SLIST_FOREACH(table_en, tbl, next) 622 table_en->target->deps(table_en, cmd_array); 623 624 dm_table_release(&dmv->table_head, table_type); 625 dm_dev_unbusy(dmv); 626 627 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array); 628 prop_object_release(cmd_array); 629 630 return 0; 631 } 632 /* 633 * Load new table/tables to device. 634 * Call apropriate target init routine open all physical pdev's and 635 * link them to device. For other targets mirror, strip, snapshot 636 * etc. also add dependency devices to upcalls list. 637 * 638 * Load table to inactive slot table are switched in dm_device_resume_ioctl. 639 * This simulates Linux behaviour better there should not be any difference. 640 * 641 */ 642 int 643 dm_table_load_ioctl(prop_dictionary_t dm_dict) 644 { 645 dm_dev_t *dmv; 646 dm_table_entry_t *table_en, *last_table; 647 dm_table_t *tbl; 648 dm_target_t *target; 649 650 prop_object_iterator_t iter; 651 prop_array_t cmd_array; 652 prop_dictionary_t target_dict; 653 654 const char *name, *uuid, *type; 655 656 uint32_t flags, ret, minor; 657 658 char *str; 659 660 ret = 0; 661 flags = 0; 662 name = NULL; 663 uuid = NULL; 664 dmv = NULL; 665 last_table = NULL; 666 str = NULL; 667 668 /* 669 * char *xml; xml = prop_dictionary_externalize(dm_dict); 670 * printf("%s\n",xml); 671 */ 672 673 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 674 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 675 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 676 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 677 678 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA); 679 iter = prop_array_iterator(cmd_array); 680 dm_dbg_print_flags(flags); 681 682 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 683 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 684 return ENOENT; 685 } 686 aprint_debug("Loading table to device: %s--%d\n", name, 687 dmv->table_head.cur_active_table); 688 689 /* 690 * I have to check if this table slot is not used by another table list. 691 * if it is used I should free them. 692 */ 693 if (dmv->flags & DM_INACTIVE_PRESENT_FLAG) 694 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 695 696 dm_dbg_print_flags(dmv->flags); 697 tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_INACTIVE); 698 699 aprint_debug("dmv->name = %s\n", dmv->name); 700 701 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 702 703 while ((target_dict = prop_object_iterator_next(iter)) != NULL) { 704 prop_dictionary_get_cstring_nocopy(target_dict, 705 DM_TABLE_TYPE, &type); 706 /* 707 * If we want to deny table with 2 or more different 708 * target we should do it here 709 */ 710 if (((target = dm_target_lookup(type)) == NULL) && 711 ((target = dm_target_autoload(type)) == NULL)) { 712 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); 713 dm_dev_unbusy(dmv); 714 return ENOENT; 715 } 716 if ((table_en = kmalloc(sizeof(dm_table_entry_t), 717 M_DM, M_WAITOK)) == NULL) { 718 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); 719 dm_dev_unbusy(dmv); 720 dm_target_unbusy(target); 721 return ENOMEM; 722 } 723 prop_dictionary_get_uint64(target_dict, DM_TABLE_START, 724 &table_en->start); 725 prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH, 726 &table_en->length); 727 728 aprint_debug("dm_ioctl.c... table_en->start = %ju, " 729 "table_en->length = %ju\n", 730 (uintmax_t)table_en->start, 731 (uintmax_t)table_en->length); 732 733 table_en->target = target; 734 table_en->dm_dev = dmv; 735 table_en->target_config = NULL; 736 737 /* 738 * There is a parameter string after dm_target_spec 739 * structure which points to /dev/wd0a 284 part of 740 * table. String str points to this text. This can be 741 * null and therefore it should be checked before we try to 742 * use it. 743 */ 744 prop_dictionary_get_cstring(target_dict, 745 DM_TABLE_PARAMS, &str); 746 747 if (SLIST_EMPTY(tbl)) 748 /* insert this table to head */ 749 SLIST_INSERT_HEAD(tbl, table_en, next); 750 else 751 SLIST_INSERT_AFTER(last_table, table_en, next); 752 753 /* 754 * Params string is different for every target, 755 * therfore I have to pass it to target init 756 * routine and parse parameters there. 757 */ 758 aprint_debug("DM: str passed in is: %s", str); 759 if ((ret = target->init(dmv, &table_en->target_config, 760 str)) != 0) { 761 762 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); 763 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 764 kfree(str, M_TEMP); 765 766 dm_dev_unbusy(dmv); 767 dm_target_unbusy(target); 768 return ret; 769 } 770 last_table = table_en; 771 kfree(str, M_TEMP); 772 } 773 prop_object_iterator_release(iter); 774 775 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); 776 atomic_set_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG); 777 778 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); 779 780 dm_dev_unbusy(dmv); 781 #if 0 782 dmsetdiskinfo(dmv->diskp, &dmv->table_head); 783 #endif 784 return 0; 785 } 786 /* 787 * Get description of all tables loaded to device from kernel 788 * and send it to libdevmapper. 789 * 790 * Output dictionary for every table: 791 * 792 * <key>cmd_data</key> 793 * <array> 794 * <dict> 795 * <key>type<key> 796 * <string>...</string> 797 * 798 * <key>start</key> 799 * <integer>...</integer> 800 * 801 * <key>length</key> 802 * <integer>...</integer> 803 * 804 * <key>params</key> 805 * <string>...</string> 806 * </dict> 807 * </array> 808 * 809 */ 810 int 811 dm_table_status_ioctl(prop_dictionary_t dm_dict) 812 { 813 dm_dev_t *dmv; 814 dm_table_t *tbl; 815 dm_table_entry_t *table_en; 816 817 prop_array_t cmd_array; 818 prop_dictionary_t target_dict; 819 820 uint32_t minor; 821 822 const char *name, *uuid; 823 char *params; 824 int flags; 825 int table_type; 826 827 dmv = NULL; 828 uuid = NULL; 829 name = NULL; 830 params = NULL; 831 flags = 0; 832 833 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 834 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 835 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 836 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 837 838 cmd_array = prop_array_create(); 839 840 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 841 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 842 return ENOENT; 843 } 844 /* 845 * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query 846 * INACTIVE TABLE 847 */ 848 if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) 849 table_type = DM_TABLE_INACTIVE; 850 else 851 table_type = DM_TABLE_ACTIVE; 852 853 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE)) 854 DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); 855 else { 856 DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); 857 858 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE)) 859 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); 860 else { 861 DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); 862 } 863 } 864 865 if (dmv->flags & DM_SUSPEND_FLAG) 866 DM_ADD_FLAG(flags, DM_SUSPEND_FLAG); 867 868 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 869 870 aprint_debug("Status of device tables: %s--%d\n", 871 name, dmv->table_head.cur_active_table); 872 873 tbl = dm_table_get_entry(&dmv->table_head, table_type); 874 875 SLIST_FOREACH(table_en, tbl, next) { 876 target_dict = prop_dictionary_create(); 877 aprint_debug("%016" PRIu64 ", length %016" PRIu64 878 ", target %s\n", table_en->start, table_en->length, 879 table_en->target->name); 880 881 prop_dictionary_set_uint64(target_dict, DM_TABLE_START, 882 table_en->start); 883 prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH, 884 table_en->length); 885 886 prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE, 887 table_en->target->name); 888 889 /* dm_table_get_cur_actv.table ?? */ 890 prop_dictionary_set_int32(target_dict, DM_TABLE_STAT, 891 dmv->table_head.cur_active_table); 892 893 if (flags & DM_STATUS_TABLE_FLAG) { 894 params = table_en->target->status 895 (table_en->target_config); 896 897 if (params != NULL) { 898 prop_dictionary_set_cstring(target_dict, 899 DM_TABLE_PARAMS, params); 900 901 kfree(params, M_DM); 902 } 903 } 904 prop_array_add(cmd_array, target_dict); 905 prop_object_release(target_dict); 906 } 907 908 dm_table_release(&dmv->table_head, table_type); 909 dm_dev_unbusy(dmv); 910 911 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags); 912 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array); 913 prop_object_release(cmd_array); 914 915 return 0; 916 } 917 918 int 919 dm_message_ioctl(prop_dictionary_t dm_dict) 920 { 921 dm_table_t *tbl; 922 dm_table_entry_t *table_en; 923 dm_dev_t *dmv; 924 const char *name, *uuid; 925 uint32_t flags, minor; 926 uint64_t table_start, table_end, sector; 927 char *msg; 928 int ret, found = 0; 929 930 flags = 0; 931 name = NULL; 932 uuid = NULL; 933 934 /* Get needed values from dictionary. */ 935 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 936 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 937 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 938 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 939 prop_dictionary_get_uint64(dm_dict, DM_MESSAGE_SECTOR, §or); 940 941 dm_dbg_print_flags(flags); 942 943 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 944 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); 945 return ENOENT; 946 } 947 948 /* Get message string */ 949 prop_dictionary_get_cstring(dm_dict, DM_MESSAGE_STR, &msg); 950 951 tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE); 952 953 ret = EINVAL; 954 955 if (sector == 0) { 956 if (!SLIST_EMPTY(tbl)) { 957 table_en = SLIST_FIRST(tbl); 958 found = 1; 959 } 960 } else { 961 SLIST_FOREACH(table_en, tbl, next) { 962 table_start = table_en->start; 963 table_end = table_start + (table_en->length); 964 965 if ((sector >= table_start) && (sector < table_end)) { 966 found = 1; 967 break; 968 } 969 } 970 } 971 972 if (found) { 973 if (table_en->target->message != NULL) 974 ret = table_en->target->message(table_en, msg); 975 } 976 977 dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE); 978 979 980 kfree(msg, M_TEMP); 981 dm_dev_unbusy(dmv); 982 983 return ret; 984 } 985 986 /* 987 * For every call I have to set kernel driver version. 988 * Because I can have commands supported only in other 989 * newer/later version. This routine is called for every 990 * ioctl command. 991 */ 992 int 993 dm_check_version(prop_dictionary_t dm_dict) 994 { 995 size_t i; 996 int dm_version[3]; 997 prop_array_t ver; 998 999 ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION); 1000 1001 for (i = 0; i < 3; i++) 1002 prop_array_get_uint32(ver, i, &dm_version[i]); 1003 1004 if (DM_VERSION_MAJOR != dm_version[0] || DM_VERSION_MINOR < dm_version[1]) { 1005 aprint_debug("libdevmapper/kernel version mismatch " 1006 "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n", 1007 DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, 1008 dm_version[0], dm_version[1], dm_version[2]); 1009 1010 return EIO; 1011 } 1012 prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR); 1013 prop_array_set_uint32(ver, 1, DM_VERSION_MINOR); 1014 prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL); 1015 1016 prop_dictionary_set(dm_dict, DM_IOCTL_VERSION, ver); 1017 1018 return 0; 1019 } 1020