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 TAILQS 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/device.h> 83 #include <sys/malloc.h> 84 #include <cpu/atomic.h> 85 #include <dev/disk/dm/dm.h> 86 #include <dev/disk/dm/netbsd-dm.h> 87 88 static int 89 dm_table_deps(dm_table_entry_t *, prop_array_t); 90 static int 91 dm_table_init(dm_target_t *, dm_table_entry_t *, char *); 92 static int 93 dm_table_status(dm_table_entry_t *, prop_dictionary_t, uint32_t); 94 95 static __inline 96 void dm_add_flag(prop_dictionary_t dp, uint32_t *fp, const uint32_t val) 97 { 98 KKASSERT(dp != NULL); 99 prop_dictionary_get_uint32(dp, DM_IOCTL_FLAGS, fp); 100 (*fp) |= val; 101 prop_dictionary_set_uint32(dp, DM_IOCTL_FLAGS, *fp); 102 KKASSERT((*fp) & val); 103 } 104 105 static __inline 106 void dm_remove_flag(prop_dictionary_t dp, uint32_t *fp, const uint32_t val) 107 { 108 KKASSERT(dp != NULL); 109 prop_dictionary_get_uint32(dp, DM_IOCTL_FLAGS, fp); 110 (*fp) &= ~val; 111 prop_dictionary_set_uint32(dp, DM_IOCTL_FLAGS, *fp); 112 KKASSERT(!((*fp) & val)); 113 } 114 115 /* 116 * Print flags sent to the kernel from libdevmapper. 117 */ 118 static int 119 dm_dbg_print_flags(uint32_t flags) 120 { 121 if (dm_debug_level == 0) 122 return 1; 123 124 kprintf("%s --- flags=%08X\n", __func__, flags); 125 126 if (flags & DM_READONLY_FLAG) 127 kprintf(" DM_READONLY_FLAG\n"); 128 if (flags & DM_SUSPEND_FLAG) 129 kprintf(" DM_SUSPEND_FLAG\n"); 130 if (flags & DM_EXISTS_FLAG) 131 kprintf(" DM_EXISTS_FLAG\n"); 132 if (flags & DM_PERSISTENT_DEV_FLAG) 133 kprintf(" DM_PERSISTENT_DEV_FLAG\n"); 134 if (flags & DM_STATUS_TABLE_FLAG) 135 kprintf(" DM_STATUS_TABLE_FLAG\n"); 136 if (flags & DM_ACTIVE_PRESENT_FLAG) 137 kprintf(" DM_ACTIVE_PRESENT_FLAG\n"); 138 if (flags & DM_INACTIVE_PRESENT_FLAG) 139 kprintf(" DM_INACTIVE_PRESENT_FLAG\n"); 140 if (flags & DM_BUFFER_FULL_FLAG) 141 kprintf(" DM_BUFFER_FULL_FLAG\n"); 142 if (flags & DM_SKIP_BDGET_FLAG) 143 kprintf(" DM_SKIP_BDGET_FLAG\n"); 144 if (flags & DM_SKIP_LOCKFS_FLAG) 145 kprintf(" DM_SKIP_LOCKFS_FLAG\n"); 146 if (flags & DM_NOFLUSH_FLAG) 147 kprintf(" DM_NOFLUSH_FLAG\n"); 148 if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) 149 kprintf(" DM_QUERY_INACTIVE_TABLE_FLAG\n"); 150 if (flags & DM_UUID_FLAG) 151 kprintf(" DM_UUID_FLAG\n"); 152 if (flags & DM_SECURE_DATA_FLAG) 153 kprintf(" DM_SECURE_DATA_FLAG\n"); 154 155 return 0; 156 } 157 158 /* 159 * Get list of all available targets from global 160 * target list and sent them back to libdevmapper. 161 */ 162 int 163 dm_list_versions_ioctl(prop_dictionary_t dm_dict) 164 { 165 prop_array_t target_list; 166 uint32_t flags; 167 168 flags = 0; 169 170 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 171 172 dm_dbg_print_flags(flags); 173 target_list = dm_target_prop_list(); 174 175 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, target_list); 176 prop_object_release(target_list); 177 178 return 0; 179 } 180 181 /* 182 * Create in-kernel entry for device. Device attributes such as name, uuid are 183 * taken from proplib dictionary. 184 */ 185 int 186 dm_dev_create_ioctl(prop_dictionary_t dm_dict) 187 { 188 dm_dev_t *dmv; 189 const char *name, *uuid; 190 int r; 191 uint32_t flags; 192 193 r = 0; 194 flags = 0; 195 name = NULL; 196 uuid = NULL; 197 198 /* Get needed values from dictionary. */ 199 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 200 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 201 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 202 203 dm_dbg_print_flags(flags); 204 205 /* Lookup name and uuid if device already exist quit. */ 206 if ((dmv = dm_dev_lookup(name, uuid, -1)) != NULL) { 207 dm_add_flag(dm_dict, &flags, DM_EXISTS_FLAG); /* Device already exists */ 208 dm_dev_unbusy(dmv); 209 return EEXIST; 210 } 211 212 r = dm_dev_create(&dmv, name, uuid, flags); 213 if (r == 0) { 214 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 215 dm_add_flag(dm_dict, &flags, DM_EXISTS_FLAG); 216 dm_remove_flag(dm_dict, &flags, DM_INACTIVE_PRESENT_FLAG); 217 } 218 219 return r; 220 } 221 222 /* 223 * Get list of created device-mapper devices from global 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 int 240 dm_dev_list_ioctl(prop_dictionary_t dm_dict) 241 { 242 prop_array_t dev_list; 243 244 uint32_t flags; 245 246 flags = 0; 247 248 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 249 250 dm_dbg_print_flags(flags); 251 252 dev_list = dm_dev_prop_list(); 253 254 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list); 255 prop_object_release(dev_list); 256 257 return 0; 258 } 259 260 /* 261 * Rename selected devices old name is in struct dm_ioctl. 262 * new name is taken from dictionary. 263 * 264 * <key>cmd_data</key> 265 * <array> 266 * <string>...</string> 267 * </array> 268 */ 269 int 270 dm_dev_rename_ioctl(prop_dictionary_t dm_dict) 271 { 272 #if 0 273 prop_array_t cmd_array; 274 dm_dev_t *dmv; 275 276 const char *name, *uuid, *n_name; 277 uint32_t flags, minor; 278 279 name = NULL; 280 uuid = NULL; 281 minor = 0; 282 283 /* Get needed values from dictionary. */ 284 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 285 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 286 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 287 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 288 289 dm_dbg_print_flags(flags); 290 291 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA); 292 293 prop_array_get_cstring_nocopy(cmd_array, 0, &n_name); 294 295 if (strlen(n_name) + 1 > DM_NAME_LEN) 296 return EINVAL; 297 298 if ((dmv = dm_dev_lookup_evict(name, uuid, minor)) == NULL) { 299 dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); 300 return ENOENT; 301 } 302 /* change device name */ 303 /* 304 * XXX How to deal with this change, name only used in 305 * dm_dev_routines, should I add dm_dev_change_name which will run 306 * under the dm_dev_list mutex ? 307 */ 308 strlcpy(dmv->name, n_name, DM_NAME_LEN); 309 310 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); 311 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 312 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); 313 314 dm_dev_insert(dmv); 315 #endif 316 317 /* 318 * XXX: the rename is not yet implemented. The main complication 319 * here is devfs. We'd probably need a new function, rename_dev() 320 * that would trigger a node rename in devfs. 321 */ 322 kprintf("dm_dev_rename_ioctl called, but not implemented!\n"); 323 return ENOSYS; 324 } 325 326 /* 327 * Remove device 328 */ 329 int 330 dm_dev_remove_ioctl(prop_dictionary_t dm_dict) 331 { 332 dm_dev_t *dmv; 333 const char *name, *uuid; 334 uint32_t flags, minor, is_open; 335 336 flags = 0; 337 name = NULL; 338 uuid = NULL; 339 340 /* Get needed values from dictionary. */ 341 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 342 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 343 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 344 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 345 346 dm_dbg_print_flags(flags); 347 348 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 349 dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); 350 return ENOENT; 351 } 352 353 is_open = dmv->is_open; 354 355 dm_dev_unbusy(dmv); 356 357 if (is_open) 358 return EBUSY; 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(dm_dict, &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(dm_dict, &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(dm_dict, &flags, DM_ACTIVE_PRESENT_FLAG); 419 else 420 dm_remove_flag(dm_dict, &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(dm_dict, &flags, DM_INACTIVE_PRESENT_FLAG); 426 else 427 dm_remove_flag(dm_dict, &flags, DM_INACTIVE_PRESENT_FLAG); 428 429 dm_dev_unbusy(dmv); 430 431 return 0; 432 } 433 434 /* 435 * Set only flag to suggest that device is suspended. This call is 436 * not supported in NetBSD. 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(dm_dict, &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(dm_dict, &flags, DM_EXISTS_FLAG); 470 471 return 0; 472 } 473 474 /* 475 * Simulate Linux behaviour better and switch tables here and not in 476 * dm_table_load_ioctl. 477 */ 478 int 479 dm_dev_resume_ioctl(prop_dictionary_t dm_dict) 480 { 481 dm_dev_t *dmv; 482 const char *name, *uuid; 483 uint32_t flags, minor; 484 485 name = NULL; 486 uuid = NULL; 487 flags = 0; 488 489 /* 490 * char *xml; xml = prop_dictionary_externalize(dm_dict); 491 * kprintf("%s\n",xml); 492 */ 493 494 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 495 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 496 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 497 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 498 499 /* Remove device from global device list */ 500 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 501 dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); 502 return ENOENT; 503 } 504 atomic_clear_int(&dmv->flags, (DM_SUSPEND_FLAG | DM_INACTIVE_PRESENT_FLAG)); 505 atomic_set_int(&dmv->flags, DM_ACTIVE_PRESENT_FLAG); 506 507 dm_table_switch_tables(&dmv->table_head); 508 509 dm_add_flag(dm_dict, &flags, DM_EXISTS_FLAG); 510 511 dmsetdiskinfo(dmv->diskp, &dmv->table_head); 512 513 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); 514 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags); 515 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 516 517 dm_dev_unbusy(dmv); 518 519 /* Destroy inactive table after resume. */ 520 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 521 522 return 0; 523 } 524 525 /* 526 * Table management routines 527 * lvm2tools doens't send name/uuid to kernel with table 528 * for lookup I have to use minor number. 529 */ 530 531 /* 532 * Remove inactive table from device. Routines which work's with inactive tables 533 * doesn't need to synchronise with dmstrategy. They can synchronise themselves with mutex?. 534 */ 535 int 536 dm_table_clear_ioctl(prop_dictionary_t dm_dict) 537 { 538 dm_dev_t *dmv; 539 const char *name, *uuid; 540 uint32_t flags, minor; 541 542 dmv = NULL; 543 name = NULL; 544 uuid = NULL; 545 flags = 0; 546 minor = 0; 547 548 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 549 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 550 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 551 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 552 553 dmdebug("Clearing inactive table from device: %s--%s\n", 554 name, uuid); 555 556 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 557 dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); 558 return ENOENT; 559 } 560 /* Select unused table */ 561 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 562 563 atomic_clear_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG); 564 565 dm_dev_unbusy(dmv); 566 567 return 0; 568 } 569 570 /* 571 * Get list of physical devices for active table. 572 * Get dev_t from pdev vnode and insert it into cmd_array. 573 * 574 * XXX. This function is called from lvm2tools to get information 575 * about physical devices, too e.g. during vgcreate. 576 */ 577 int 578 dm_table_deps_ioctl(prop_dictionary_t dm_dict) 579 { 580 dm_dev_t *dmv; 581 dm_table_t *tbl; 582 dm_table_entry_t *table_en; 583 584 prop_array_t cmd_array; 585 const char *name, *uuid; 586 uint32_t flags, minor; 587 588 int table_type; 589 590 name = NULL; 591 uuid = NULL; 592 dmv = NULL; 593 flags = 0; 594 595 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 596 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 597 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 598 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 599 600 /* create array for dev_t's */ 601 cmd_array = prop_array_create(); 602 603 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 604 dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); 605 return ENOENT; 606 } 607 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 608 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_NAME, dmv->name); 609 prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); 610 611 dmdebug("Getting table deps for device: %s\n", dmv->name); 612 613 /* 614 * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query 615 * INACTIVE TABLE 616 */ 617 if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) 618 table_type = DM_TABLE_INACTIVE; 619 else 620 table_type = DM_TABLE_ACTIVE; 621 622 tbl = dm_table_get_entry(&dmv->table_head, table_type); 623 624 TAILQ_FOREACH(table_en, tbl, next) 625 dm_table_deps(table_en, cmd_array); 626 627 dm_table_release(&dmv->table_head, table_type); 628 dm_dev_unbusy(dmv); 629 630 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array); 631 prop_object_release(cmd_array); 632 633 return 0; 634 } 635 636 static int 637 dm_table_deps(dm_table_entry_t *table_en, prop_array_t array) 638 { 639 dm_mapping_t *map; 640 int i, size; 641 uint64_t ret, tmp; 642 643 size = prop_array_count(array); 644 645 TAILQ_FOREACH(map, &table_en->pdev_maps, next) { 646 ret = map->data.pdev->udev; 647 for (i = 0; i < size; i++) { 648 if (prop_array_get_uint64(array, i, &tmp) == true) 649 if (ret == tmp) 650 break; /* exists */ 651 } 652 /* 653 * Ignore if the device has already been added by 654 * other tables. 655 */ 656 if (i == size) 657 prop_array_add_uint64(array, ret); 658 } 659 660 return 0; 661 } 662 663 /* 664 * Load new table/tables to device. 665 * Call apropriate target init routine open all physical pdev's and 666 * link them to device. For other targets mirror, strip, snapshot etc. 667 * 668 * Load table to inactive slot table are switched in dm_device_resume_ioctl. 669 * This simulates Linux behaviour better there should not be any difference. 670 */ 671 int 672 dm_table_load_ioctl(prop_dictionary_t dm_dict) 673 { 674 dm_dev_t *dmv; 675 dm_table_entry_t *table_en; 676 dm_table_t *tbl; 677 dm_target_t *target; 678 679 prop_object_iterator_t iter; 680 prop_array_t cmd_array; 681 prop_dictionary_t target_dict; 682 683 const char *name, *uuid, *type; 684 685 uint32_t flags, ret, minor; 686 687 char *str; 688 689 ret = 0; 690 flags = 0; 691 name = NULL; 692 uuid = NULL; 693 dmv = NULL; 694 str = NULL; 695 696 /* 697 * char *xml; xml = prop_dictionary_externalize(dm_dict); 698 * kprintf("%s\n",xml); 699 */ 700 701 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 702 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 703 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 704 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 705 706 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA); 707 iter = prop_array_iterator(cmd_array); 708 dm_dbg_print_flags(flags); 709 710 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 711 dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); 712 return ENOENT; 713 } 714 dmdebug("Loading table to device: %s--%d\n", name, 715 dmv->table_head.cur_active_table); 716 717 /* 718 * I have to check if this table slot is not used by another table list. 719 * if it is used I should free them. 720 */ 721 if (dmv->flags & DM_INACTIVE_PRESENT_FLAG) 722 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 723 724 dm_dbg_print_flags(dmv->flags); 725 tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_INACTIVE); 726 727 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 728 729 while ((target_dict = prop_object_iterator_next(iter)) != NULL) { 730 prop_dictionary_get_cstring_nocopy(target_dict, 731 DM_TABLE_TYPE, &type); 732 /* 733 * If we want to deny table with 2 or more different 734 * target we should do it here 735 */ 736 if (((target = dm_target_lookup(type)) == NULL) && 737 ((target = dm_target_autoload(type)) == NULL)) { 738 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); 739 dm_dev_unbusy(dmv); 740 return ENOENT; 741 } 742 if ((table_en = kmalloc(sizeof(dm_table_entry_t), 743 M_DM, M_WAITOK)) == NULL) { 744 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); 745 dm_dev_unbusy(dmv); 746 dm_target_unbusy(target); 747 return ENOMEM; 748 } 749 prop_dictionary_get_uint64(target_dict, DM_TABLE_START, 750 &table_en->start); 751 prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH, 752 &table_en->length); 753 754 dmdebug("table_en->start = %ju, table_en->length = %ju\n", 755 (uintmax_t)table_en->start, 756 (uintmax_t)table_en->length); 757 758 table_en->target = target; 759 table_en->dev = dmv; 760 table_en->target_config = NULL; 761 TAILQ_INIT(&table_en->pdev_maps); 762 763 /* 764 * There is a parameter string after dm_target_spec 765 * structure which points to /dev/wd0a 284 part of 766 * table. String str points to this text. This can be 767 * null and therefore it should be checked before we try to 768 * use it. 769 */ 770 prop_dictionary_get_cstring(target_dict, 771 DM_TABLE_PARAMS, &str); 772 773 TAILQ_INSERT_TAIL(tbl, table_en, next); 774 775 /* 776 * Params string is different for every target, 777 * therfore I have to pass it to target init 778 * routine and parse parameters there. 779 */ 780 dmdebug("String passed in is: \"%s\"\n", str); 781 782 if ((ret = dm_table_init(target, table_en, str)) != 0) { 783 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); 784 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 785 kfree(str, M_TEMP); 786 787 dm_dev_unbusy(dmv); 788 return ret; 789 } 790 kfree(str, M_TEMP); 791 } 792 prop_object_iterator_release(iter); 793 794 dm_add_flag(dm_dict, &flags, DM_INACTIVE_PRESENT_FLAG); 795 atomic_set_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG); 796 797 dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); 798 799 dm_dev_unbusy(dmv); 800 #if 0 801 dmsetdiskinfo(dmv->diskp, &dmv->table_head); 802 #endif 803 return 0; 804 } 805 806 static int 807 dm_table_init(dm_target_t *target, dm_table_entry_t *table_en, char *params) 808 { 809 int i, n, argc; 810 int ret = 0; 811 char **ap, **argv; 812 813 if (params == NULL) 814 return EINVAL; 815 816 n = target->max_argc; 817 if (n) { 818 dmdebug("Max argc %d for %s target\n", n, target->name); 819 } else { 820 n = 20; /* large enough slots for most targets */ 821 } 822 823 argv = kmalloc(sizeof(*argv) * n, M_DM, M_WAITOK | M_ZERO); 824 825 for (ap = argv; 826 ap < &argv[n] && (*ap = strsep(¶ms, " \t")) != NULL;) { 827 if (**ap != '\0') 828 ap++; 829 } 830 argc = ap - argv; 831 832 if (dm_debug_level) { 833 for (i = 0; i < argc; i++) 834 kprintf("DM: argv[%d] = \"%s\"\n", i, argv[i]); 835 } 836 837 if (target->init) 838 ret = target->init(table_en, argc, argv); 839 840 kfree(argv, M_DM); 841 842 return ret; 843 } 844 845 /* 846 * Get description of all tables loaded to device from kernel 847 * and send it to libdevmapper. 848 * 849 * Output dictionary for every table: 850 * 851 * <key>cmd_data</key> 852 * <array> 853 * <dict> 854 * <key>type<key> 855 * <string>...</string> 856 * 857 * <key>start</key> 858 * <integer>...</integer> 859 * 860 * <key>length</key> 861 * <integer>...</integer> 862 * 863 * <key>params</key> 864 * <string>...</string> 865 * </dict> 866 * </array> 867 */ 868 int 869 dm_table_status_ioctl(prop_dictionary_t dm_dict) 870 { 871 dm_dev_t *dmv; 872 dm_table_t *tbl; 873 dm_table_entry_t *table_en; 874 875 prop_array_t cmd_array; 876 prop_dictionary_t target_dict; 877 878 uint32_t minor; 879 880 const char *name, *uuid; 881 uint32_t flags; 882 int table_type; 883 884 dmv = NULL; 885 uuid = NULL; 886 name = NULL; 887 flags = 0; 888 889 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 890 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 891 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 892 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 893 894 cmd_array = prop_array_create(); 895 896 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 897 dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); 898 return ENOENT; 899 } 900 /* 901 * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query 902 * INACTIVE TABLE 903 */ 904 if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) 905 table_type = DM_TABLE_INACTIVE; 906 else 907 table_type = DM_TABLE_ACTIVE; 908 909 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE)) 910 dm_add_flag(dm_dict, &flags, DM_ACTIVE_PRESENT_FLAG); 911 else { 912 dm_remove_flag(dm_dict, &flags, DM_ACTIVE_PRESENT_FLAG); 913 914 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE)) 915 dm_add_flag(dm_dict, &flags, DM_INACTIVE_PRESENT_FLAG); 916 else 917 dm_remove_flag(dm_dict, &flags, DM_INACTIVE_PRESENT_FLAG); 918 } 919 920 if (dmv->flags & DM_SUSPEND_FLAG) 921 dm_add_flag(dm_dict, &flags, DM_SUSPEND_FLAG); 922 923 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); 924 925 dmdebug("Status of device tables: %s--%d\n", 926 name, dmv->table_head.cur_active_table); 927 928 tbl = dm_table_get_entry(&dmv->table_head, table_type); 929 930 TAILQ_FOREACH(table_en, tbl, next) { 931 target_dict = prop_dictionary_create(); 932 dmdebug("%016" PRIu64 ", length %016" PRIu64 933 ", target %s\n", table_en->start, table_en->length, 934 table_en->target->name); 935 936 prop_dictionary_set_uint64(target_dict, DM_TABLE_START, 937 table_en->start); 938 prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH, 939 table_en->length); 940 941 prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE, 942 table_en->target->name); 943 944 /* dm_table_get_cur_actv.table ?? */ 945 prop_dictionary_set_int32(target_dict, DM_TABLE_STAT, 946 dmv->table_head.cur_active_table); 947 948 dm_table_status(table_en, target_dict, flags); 949 950 prop_array_add(cmd_array, target_dict); 951 prop_object_release(target_dict); 952 } 953 954 dm_table_release(&dmv->table_head, table_type); 955 dm_dev_unbusy(dmv); 956 957 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags); 958 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array); 959 prop_object_release(cmd_array); 960 961 return 0; 962 } 963 964 static int 965 dm_table_status(dm_table_entry_t *table_en, 966 prop_dictionary_t target_dict, uint32_t flags) 967 { 968 void *cfg; 969 char *params; 970 int is_table; 971 972 cfg = table_en->target_config; 973 params = NULL; 974 975 is_table = (flags & DM_STATUS_TABLE_FLAG) ? 1 : 0; 976 977 if (is_table && table_en->target->table) { 978 params = table_en->target->table(cfg); 979 } else if (!is_table && table_en->target->info) { 980 params = table_en->target->info(cfg); 981 } else { 982 prop_dictionary_set_cstring(target_dict, DM_TABLE_PARAMS, ""); 983 return ENOTSUP; 984 } 985 986 if (params == NULL) { 987 prop_dictionary_set_cstring(target_dict, DM_TABLE_PARAMS, ""); 988 return ENOMEM; 989 } 990 991 prop_dictionary_set_cstring(target_dict, DM_TABLE_PARAMS, params); 992 kfree(params, M_DM); 993 return 0; 994 } 995 996 int 997 dm_message_ioctl(prop_dictionary_t dm_dict) 998 { 999 dm_table_t *tbl; 1000 dm_table_entry_t *table_en; 1001 dm_dev_t *dmv; 1002 const char *name, *uuid; 1003 uint32_t flags, minor; 1004 uint64_t table_start, table_end, sector; 1005 char *msg; 1006 int ret, found = 0; 1007 1008 flags = 0; 1009 name = NULL; 1010 uuid = NULL; 1011 1012 /* Get needed values from dictionary. */ 1013 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); 1014 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); 1015 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); 1016 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); 1017 prop_dictionary_get_uint64(dm_dict, DM_MESSAGE_SECTOR, §or); 1018 1019 dm_dbg_print_flags(flags); 1020 1021 if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { 1022 dm_remove_flag(dm_dict, &flags, DM_EXISTS_FLAG); 1023 return ENOENT; 1024 } 1025 1026 /* Get message string */ 1027 prop_dictionary_get_cstring(dm_dict, DM_MESSAGE_STR, &msg); 1028 1029 tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE); 1030 1031 ret = EINVAL; 1032 1033 if (sector == 0) { 1034 if (!TAILQ_EMPTY(tbl)) { 1035 table_en = TAILQ_FIRST(tbl); 1036 found = 1; 1037 } 1038 } else { 1039 TAILQ_FOREACH(table_en, tbl, next) { 1040 table_start = table_en->start; 1041 table_end = table_start + table_en->length; 1042 1043 if ((sector >= table_start) && (sector < table_end)) { 1044 found = 1; 1045 break; 1046 } 1047 } 1048 } 1049 1050 if (found) { 1051 if (table_en->target->message != NULL) 1052 ret = table_en->target->message(table_en, msg); 1053 } 1054 1055 dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE); 1056 1057 kfree(msg, M_TEMP); 1058 dm_dev_unbusy(dmv); 1059 1060 return ret; 1061 } 1062 1063 /* 1064 * For every call I have to set kernel driver version. 1065 * Because I can have commands supported only in other 1066 * newer/later version. This routine is called for every 1067 * ioctl command. 1068 */ 1069 int 1070 dm_check_version(prop_dictionary_t dm_dict) 1071 { 1072 size_t i; 1073 int dm_version[3]; 1074 prop_array_t ver; 1075 1076 ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION); 1077 1078 for (i = 0; i < 3; i++) 1079 prop_array_get_uint32(ver, i, &dm_version[i]); 1080 1081 if (DM_VERSION_MAJOR != dm_version[0] || DM_VERSION_MINOR < dm_version[1]) { 1082 dmdebug("libdevmapper/kernel version mismatch " 1083 "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n", 1084 DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, 1085 dm_version[0], dm_version[1], dm_version[2]); 1086 1087 return EIO; 1088 } 1089 prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR); 1090 prop_array_set_uint32(ver, 1, DM_VERSION_MINOR); 1091 prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL); 1092 1093 prop_dictionary_set(dm_dict, DM_IOCTL_VERSION, ver); 1094 1095 return 0; 1096 } 1097