1 /* 2 * CDDL HEADER START 3 * 4 * This file and its contents are supplied under the terms of the 5 * Common Development and Distribution License ("CDDL"), version 1.0. 6 * You may only use this file in accordance with the terms of version 7 * 1.0 of the CDDL. 8 * 9 * A full copy of the text of the CDDL should have accompanied this 10 * source. A copy of the CDDL is also available via the Internet at 11 * http://www.illumos.org/license/CDDL. 12 * 13 * CDDL HEADER END 14 */ 15 16 /* 17 * Copyright (c) 2018 by Delphix. All rights reserved. 18 * Copyright 2020 Joyent, Inc. 19 */ 20 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <strings.h> 27 #include <libzfs_core.h> 28 #include <unistd.h> 29 30 #include <sys/nvpair.h> 31 #include <sys/zfs_ioctl.h> 32 33 /* 34 * Test the nvpair inputs for the non-legacy zfs ioctl commands. 35 */ 36 37 boolean_t unexpected_failures; 38 int zfs_fd; 39 const char *active_test; 40 41 /* 42 * Tracks which zfs_ioc_t commands were tested 43 */ 44 boolean_t ioc_tested[256]; 45 46 /* 47 * Legacy ioctls that are skipped (for now) 48 */ 49 static unsigned ioc_skip[] = { 50 ZFS_IOC_POOL_CREATE, 51 ZFS_IOC_POOL_DESTROY, 52 ZFS_IOC_POOL_IMPORT, 53 ZFS_IOC_POOL_EXPORT, 54 ZFS_IOC_POOL_CONFIGS, 55 ZFS_IOC_POOL_STATS, 56 ZFS_IOC_POOL_TRYIMPORT, 57 ZFS_IOC_POOL_SCAN, 58 ZFS_IOC_POOL_FREEZE, 59 ZFS_IOC_POOL_UPGRADE, 60 ZFS_IOC_POOL_GET_HISTORY, 61 62 ZFS_IOC_VDEV_ADD, 63 ZFS_IOC_VDEV_REMOVE, 64 ZFS_IOC_VDEV_SET_STATE, 65 ZFS_IOC_VDEV_ATTACH, 66 ZFS_IOC_VDEV_DETACH, 67 ZFS_IOC_VDEV_SETPATH, 68 ZFS_IOC_VDEV_SETFRU, 69 70 ZFS_IOC_OBJSET_STATS, 71 ZFS_IOC_OBJSET_ZPLPROPS, 72 ZFS_IOC_DATASET_LIST_NEXT, 73 ZFS_IOC_SNAPSHOT_LIST_NEXT, 74 ZFS_IOC_SET_PROP, 75 ZFS_IOC_DESTROY, 76 ZFS_IOC_RENAME, 77 ZFS_IOC_RECV, 78 ZFS_IOC_SEND, 79 ZFS_IOC_INJECT_FAULT, 80 ZFS_IOC_CLEAR_FAULT, 81 ZFS_IOC_INJECT_LIST_NEXT, 82 ZFS_IOC_ERROR_LOG, 83 ZFS_IOC_CLEAR, 84 ZFS_IOC_PROMOTE, 85 ZFS_IOC_DSOBJ_TO_DSNAME, 86 ZFS_IOC_OBJ_TO_PATH, 87 ZFS_IOC_POOL_SET_PROPS, 88 ZFS_IOC_POOL_GET_PROPS, 89 ZFS_IOC_SET_FSACL, 90 ZFS_IOC_GET_FSACL, 91 ZFS_IOC_SHARE, 92 ZFS_IOC_INHERIT_PROP, 93 ZFS_IOC_SMB_ACL, 94 ZFS_IOC_USERSPACE_ONE, 95 ZFS_IOC_USERSPACE_MANY, 96 ZFS_IOC_USERSPACE_UPGRADE, 97 ZFS_IOC_OBJSET_RECVD_PROPS, 98 ZFS_IOC_VDEV_SPLIT, 99 ZFS_IOC_NEXT_OBJ, 100 ZFS_IOC_DIFF, 101 ZFS_IOC_TMP_SNAPSHOT, 102 ZFS_IOC_OBJ_TO_STATS, 103 ZFS_IOC_SPACE_WRITTEN, 104 ZFS_IOC_POOL_REGUID, 105 ZFS_IOC_SEND_PROGRESS, 106 107 #ifndef __sun 108 ZFS_IOC_EVENTS_NEXT, 109 ZFS_IOC_EVENTS_CLEAR, 110 ZFS_IOC_EVENTS_SEEK, 111 #else 112 /* This is still a legacy ioctl in illumos */ 113 ZFS_IOC_POOL_REOPEN, 114 #endif 115 }; 116 117 118 #define IOC_INPUT_TEST(ioc, name, req, opt, err) \ 119 IOC_INPUT_TEST_IMPL(ioc, name, req, opt, err, B_FALSE) 120 121 #define IOC_INPUT_TEST_WILD(ioc, name, req, opt, err) \ 122 IOC_INPUT_TEST_IMPL(ioc, name, req, opt, err, B_TRUE) 123 124 #define IOC_INPUT_TEST_IMPL(ioc, name, req, opt, err, wild) \ 125 do { \ 126 active_test = __func__ + 5; \ 127 ioc_tested[ioc - ZFS_IOC_FIRST] = B_TRUE; \ 128 (void) lzc_ioctl_test(ioc, name, req, opt, err, wild); \ 129 } while (0) 130 131 /* 132 * run a zfs ioctl command, verify expected results and log failures 133 */ 134 static void 135 lzc_ioctl_run(zfs_ioc_t ioc, const char *name, nvlist_t *innvl, int expected) 136 { 137 zfs_cmd_t zc = {"\0"}; 138 char *packed = NULL; 139 const char *variant; 140 size_t size = 0; 141 int error = 0; 142 143 switch (expected) { 144 case ZFS_ERR_IOC_ARG_UNAVAIL: 145 variant = "unsupported input"; 146 break; 147 case ZFS_ERR_IOC_ARG_REQUIRED: 148 variant = "missing input"; 149 break; 150 case ZFS_ERR_IOC_ARG_BADTYPE: 151 variant = "invalid input type"; 152 break; 153 default: 154 variant = "valid input"; 155 break; 156 } 157 158 packed = fnvlist_pack(innvl, &size); 159 (void) strncpy(zc.zc_name, name, sizeof (zc.zc_name)); 160 zc.zc_name[sizeof (zc.zc_name) - 1] = '\0'; 161 zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed; 162 zc.zc_nvlist_src_size = size; 163 zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024); 164 zc.zc_nvlist_dst = (uint64_t)(uintptr_t)malloc(zc.zc_nvlist_dst_size); 165 166 if (ioctl(zfs_fd, ioc, &zc) != 0) 167 error = errno; 168 169 if (error != expected) { 170 unexpected_failures = B_TRUE; 171 (void) fprintf(stderr, "%s: Unexpected result with %s, " 172 "error %d (expecting %d)\n", 173 active_test, variant, error, expected); 174 } 175 176 fnvlist_pack_free(packed, size); 177 free((void *)(uintptr_t)zc.zc_nvlist_dst); 178 } 179 180 /* 181 * Test each ioc for the following ioctl input errors: 182 * ZFS_ERR_IOC_ARG_UNAVAIL an input argument is not supported by kernel 183 * ZFS_ERR_IOC_ARG_REQUIRED a required input argument is missing 184 * ZFS_ERR_IOC_ARG_BADTYPE an input argument has an invalid type 185 */ 186 static int 187 lzc_ioctl_test(zfs_ioc_t ioc, const char *name, nvlist_t *required, 188 nvlist_t *optional, int expected_error, boolean_t wildcard) 189 { 190 nvlist_t *input = fnvlist_alloc(); 191 nvlist_t *future = fnvlist_alloc(); 192 int error = 0; 193 194 if (required != NULL) { 195 for (nvpair_t *pair = nvlist_next_nvpair(required, NULL); 196 pair != NULL; pair = nvlist_next_nvpair(required, pair)) { 197 fnvlist_add_nvpair(input, pair); 198 } 199 } 200 if (optional != NULL) { 201 for (nvpair_t *pair = nvlist_next_nvpair(optional, NULL); 202 pair != NULL; pair = nvlist_next_nvpair(optional, pair)) { 203 fnvlist_add_nvpair(input, pair); 204 } 205 } 206 207 /* 208 * Generic input run with 'optional' nvlist pair 209 */ 210 if (!wildcard) 211 fnvlist_add_nvlist(input, "optional", future); 212 lzc_ioctl_run(ioc, name, input, expected_error); 213 if (!wildcard) 214 fnvlist_remove(input, "optional"); 215 216 /* 217 * Bogus input value 218 */ 219 if (!wildcard) { 220 fnvlist_add_string(input, "bogus_input", "bogus"); 221 lzc_ioctl_run(ioc, name, input, ZFS_ERR_IOC_ARG_UNAVAIL); 222 fnvlist_remove(input, "bogus_input"); 223 } 224 225 /* 226 * Missing required inputs 227 */ 228 if (required != NULL) { 229 nvlist_t *empty = fnvlist_alloc(); 230 lzc_ioctl_run(ioc, name, empty, ZFS_ERR_IOC_ARG_REQUIRED); 231 nvlist_free(empty); 232 } 233 234 /* 235 * Wrong nvpair type 236 */ 237 if (required != NULL || optional != NULL) { 238 /* 239 * switch the type of one of the input pairs 240 */ 241 for (nvpair_t *pair = nvlist_next_nvpair(input, NULL); 242 pair != NULL; pair = nvlist_next_nvpair(input, pair)) { 243 char pname[MAXNAMELEN]; 244 data_type_t ptype; 245 246 (void) strncpy(pname, nvpair_name(pair), 247 sizeof (pname)); 248 pname[sizeof (pname) - 1] = '\0'; 249 ptype = nvpair_type(pair); 250 fnvlist_remove_nvpair(input, pair); 251 252 switch (ptype) { 253 case DATA_TYPE_STRING: 254 fnvlist_add_uint64(input, pname, 42); 255 break; 256 default: 257 fnvlist_add_string(input, pname, "bogus"); 258 break; 259 } 260 } 261 lzc_ioctl_run(ioc, name, input, ZFS_ERR_IOC_ARG_BADTYPE); 262 } 263 264 nvlist_free(future); 265 nvlist_free(input); 266 267 return (error); 268 } 269 270 static void 271 test_pool_sync(const char *pool) 272 { 273 nvlist_t *required = fnvlist_alloc(); 274 275 fnvlist_add_boolean_value(required, "force", B_TRUE); 276 277 IOC_INPUT_TEST(ZFS_IOC_POOL_SYNC, pool, required, NULL, 0); 278 279 nvlist_free(required); 280 } 281 282 #ifndef sun 283 static void 284 test_pool_reopen(const char *pool) 285 { 286 nvlist_t *required = fnvlist_alloc(); 287 288 fnvlist_add_boolean_value(required, "scrub_restart", B_FALSE); 289 290 IOC_INPUT_TEST(ZFS_IOC_POOL_REOPEN, pool, required, NULL, 0); 291 292 nvlist_free(required); 293 } 294 #endif 295 296 static void 297 test_pool_checkpoint(const char *pool) 298 { 299 IOC_INPUT_TEST(ZFS_IOC_POOL_CHECKPOINT, pool, NULL, NULL, 0); 300 } 301 302 static void 303 test_pool_discard_checkpoint(const char *pool) 304 { 305 int err = lzc_pool_checkpoint(pool); 306 if (err == 0 || err == ZFS_ERR_CHECKPOINT_EXISTS) 307 IOC_INPUT_TEST(ZFS_IOC_POOL_DISCARD_CHECKPOINT, pool, NULL, 308 NULL, 0); 309 } 310 311 static void 312 test_log_history(const char *pool) 313 { 314 nvlist_t *required = fnvlist_alloc(); 315 316 fnvlist_add_string(required, "message", "input check"); 317 318 IOC_INPUT_TEST(ZFS_IOC_LOG_HISTORY, pool, required, NULL, 0); 319 320 nvlist_free(required); 321 } 322 323 static void 324 test_create(const char *pool) 325 { 326 char dataset[MAXNAMELEN + 32]; 327 328 (void) snprintf(dataset, sizeof (dataset), "%s/create-fs", pool); 329 330 nvlist_t *required = fnvlist_alloc(); 331 nvlist_t *optional = fnvlist_alloc(); 332 nvlist_t *props = fnvlist_alloc(); 333 334 fnvlist_add_int32(required, "type", DMU_OST_ZFS); 335 fnvlist_add_uint64(props, "recordsize", 8192); 336 fnvlist_add_nvlist(optional, "props", props); 337 338 IOC_INPUT_TEST(ZFS_IOC_CREATE, dataset, required, optional, 0); 339 340 nvlist_free(required); 341 nvlist_free(optional); 342 } 343 344 static void 345 test_snapshot(const char *pool, const char *snapshot) 346 { 347 nvlist_t *required = fnvlist_alloc(); 348 nvlist_t *optional = fnvlist_alloc(); 349 nvlist_t *snaps = fnvlist_alloc(); 350 nvlist_t *props = fnvlist_alloc(); 351 352 fnvlist_add_boolean(snaps, snapshot); 353 fnvlist_add_nvlist(required, "snaps", snaps); 354 355 fnvlist_add_string(props, "org.openzfs:launch", "September 17th, 2013"); 356 fnvlist_add_nvlist(optional, "props", props); 357 358 IOC_INPUT_TEST(ZFS_IOC_SNAPSHOT, pool, required, optional, 0); 359 360 nvlist_free(props); 361 nvlist_free(snaps); 362 nvlist_free(optional); 363 nvlist_free(required); 364 } 365 366 static void 367 test_space_snaps(const char *snapshot) 368 { 369 nvlist_t *required = fnvlist_alloc(); 370 fnvlist_add_string(required, "firstsnap", snapshot); 371 372 IOC_INPUT_TEST(ZFS_IOC_SPACE_SNAPS, snapshot, required, NULL, 0); 373 374 nvlist_free(required); 375 } 376 377 static void 378 test_destroy_snaps(const char *pool, const char *snapshot) 379 { 380 nvlist_t *required = fnvlist_alloc(); 381 nvlist_t *snaps = fnvlist_alloc(); 382 383 fnvlist_add_boolean(snaps, snapshot); 384 fnvlist_add_nvlist(required, "snaps", snaps); 385 386 IOC_INPUT_TEST(ZFS_IOC_DESTROY_SNAPS, pool, required, NULL, 0); 387 388 nvlist_free(snaps); 389 nvlist_free(required); 390 } 391 392 393 static void 394 test_bookmark(const char *pool, const char *snapshot, const char *bookmark) 395 { 396 nvlist_t *required = fnvlist_alloc(); 397 398 fnvlist_add_string(required, bookmark, snapshot); 399 400 IOC_INPUT_TEST_WILD(ZFS_IOC_BOOKMARK, pool, required, NULL, 0); 401 402 nvlist_free(required); 403 } 404 405 static void 406 test_get_bookmarks(const char *dataset) 407 { 408 nvlist_t *optional = fnvlist_alloc(); 409 410 fnvlist_add_boolean(optional, "guid"); 411 fnvlist_add_boolean(optional, "createtxg"); 412 fnvlist_add_boolean(optional, "creation"); 413 414 IOC_INPUT_TEST_WILD(ZFS_IOC_GET_BOOKMARKS, dataset, NULL, optional, 0); 415 416 nvlist_free(optional); 417 } 418 419 static void 420 test_destroy_bookmarks(const char *pool, const char *bookmark) 421 { 422 nvlist_t *required = fnvlist_alloc(); 423 424 fnvlist_add_boolean(required, bookmark); 425 426 IOC_INPUT_TEST_WILD(ZFS_IOC_DESTROY_BOOKMARKS, pool, required, NULL, 0); 427 428 nvlist_free(required); 429 } 430 431 static void 432 test_clone(const char *snapshot, const char *clone) 433 { 434 nvlist_t *required = fnvlist_alloc(); 435 nvlist_t *optional = fnvlist_alloc(); 436 nvlist_t *props = fnvlist_alloc(); 437 438 fnvlist_add_string(required, "origin", snapshot); 439 440 IOC_INPUT_TEST(ZFS_IOC_CLONE, clone, required, NULL, 0); 441 442 nvlist_free(props); 443 nvlist_free(optional); 444 nvlist_free(required); 445 } 446 447 static void 448 test_rollback(const char *dataset, const char *snapshot) 449 { 450 nvlist_t *optional = fnvlist_alloc(); 451 452 fnvlist_add_string(optional, "target", snapshot); 453 454 IOC_INPUT_TEST(ZFS_IOC_ROLLBACK, dataset, NULL, optional, B_FALSE); 455 456 nvlist_free(optional); 457 } 458 459 static void 460 test_hold(const char *pool, const char *snapshot) 461 { 462 nvlist_t *required = fnvlist_alloc(); 463 nvlist_t *optional = fnvlist_alloc(); 464 nvlist_t *holds = fnvlist_alloc(); 465 466 fnvlist_add_string(holds, snapshot, "libzfs_check_hold"); 467 fnvlist_add_nvlist(required, "holds", holds); 468 fnvlist_add_int32(optional, "cleanup_fd", zfs_fd); 469 470 IOC_INPUT_TEST(ZFS_IOC_HOLD, pool, required, optional, 0); 471 472 nvlist_free(holds); 473 nvlist_free(optional); 474 nvlist_free(required); 475 } 476 477 static void 478 test_get_holds(const char *snapshot) 479 { 480 IOC_INPUT_TEST(ZFS_IOC_GET_HOLDS, snapshot, NULL, NULL, 0); 481 } 482 483 static void 484 test_release(const char *pool, const char *snapshot) 485 { 486 nvlist_t *required = fnvlist_alloc(); 487 nvlist_t *release = fnvlist_alloc(); 488 489 fnvlist_add_boolean(release, "libzfs_check_hold"); 490 fnvlist_add_nvlist(required, snapshot, release); 491 492 IOC_INPUT_TEST_WILD(ZFS_IOC_RELEASE, pool, required, NULL, 0); 493 494 nvlist_free(release); 495 nvlist_free(required); 496 } 497 498 499 static void 500 test_send_new(const char *snapshot, int fd) 501 { 502 nvlist_t *required = fnvlist_alloc(); 503 nvlist_t *optional = fnvlist_alloc(); 504 505 fnvlist_add_int32(required, "fd", fd); 506 507 fnvlist_add_boolean(optional, "largeblockok"); 508 fnvlist_add_boolean(optional, "embedok"); 509 fnvlist_add_boolean(optional, "compressok"); 510 fnvlist_add_boolean(optional, "rawok"); 511 512 /* 513 * TODO - Resumable send is harder to set up. So we currently 514 * ignore testing for that variant. 515 */ 516 #if 0 517 fnvlist_add_string(optional, "fromsnap", from); 518 fnvlist_add_uint64(optional, "resume_object", resumeobj); 519 fnvlist_add_uint64(optional, "resume_offset", offset); 520 #endif 521 IOC_INPUT_TEST(ZFS_IOC_SEND_NEW, snapshot, required, optional, 0); 522 523 nvlist_free(optional); 524 nvlist_free(required); 525 } 526 527 #ifndef __sun 528 static void 529 test_recv_new(const char *dataset, int fd) 530 { 531 dmu_replay_record_t drr = { 0 }; 532 nvlist_t *required = fnvlist_alloc(); 533 nvlist_t *optional = fnvlist_alloc(); 534 nvlist_t *props = fnvlist_alloc(); 535 char snapshot[MAXNAMELEN + 32]; 536 ssize_t count; 537 538 int cleanup_fd = open(ZFS_DEV, O_RDWR); 539 540 (void) snprintf(snapshot, sizeof (snapshot), "%s@replicant", dataset); 541 542 count = pread(fd, &drr, sizeof (drr), 0); 543 if (count != sizeof (drr)) { 544 (void) fprintf(stderr, "could not read stream: %s\n", 545 strerror(errno)); 546 } 547 548 fnvlist_add_string(required, "snapname", snapshot); 549 fnvlist_add_byte_array(required, "begin_record", (uchar_t *)&drr, 550 sizeof (drr)); 551 fnvlist_add_int32(required, "input_fd", fd); 552 553 fnvlist_add_string(props, "org.openzfs:launch", "September 17th, 2013"); 554 fnvlist_add_nvlist(optional, "localprops", props); 555 fnvlist_add_boolean(optional, "force"); 556 fnvlist_add_int32(optional, "cleanup_fd", cleanup_fd); 557 558 /* 559 * TODO - Resumable receive is harder to set up. So we currently 560 * ignore testing for one. 561 */ 562 #if 0 563 fnvlist_add_nvlist(optional, "props", recvdprops); 564 fnvlist_add_string(optional, "origin", origin); 565 fnvlist_add_boolean(optional, "resumable"); 566 fnvlist_add_uint64(optional, "action_handle", *action_handle); 567 #endif 568 IOC_INPUT_TEST(ZFS_IOC_RECV_NEW, dataset, required, optional, EBADE); 569 570 nvlist_free(props); 571 nvlist_free(optional); 572 nvlist_free(required); 573 574 (void) close(cleanup_fd); 575 } 576 #endif 577 578 static void 579 test_send_space(const char *snapshot1, const char *snapshot2) 580 { 581 nvlist_t *optional = fnvlist_alloc(); 582 583 fnvlist_add_string(optional, "from", snapshot1); 584 fnvlist_add_boolean(optional, "largeblockok"); 585 fnvlist_add_boolean(optional, "embedok"); 586 fnvlist_add_boolean(optional, "compressok"); 587 fnvlist_add_boolean(optional, "rawok"); 588 589 IOC_INPUT_TEST(ZFS_IOC_SEND_SPACE, snapshot2, NULL, optional, 0); 590 591 nvlist_free(optional); 592 } 593 594 static void 595 test_remap(const char *dataset) 596 { 597 IOC_INPUT_TEST(ZFS_IOC_REMAP, dataset, NULL, NULL, 0); 598 } 599 600 static void 601 test_channel_program(const char *pool) 602 { 603 const char *program = 604 "arg = ...\n" 605 "argv = arg[\"argv\"]\n" 606 "return argv[1]"; 607 char *const argv[1] = { "Hello World!" }; 608 nvlist_t *required = fnvlist_alloc(); 609 nvlist_t *optional = fnvlist_alloc(); 610 nvlist_t *args = fnvlist_alloc(); 611 612 fnvlist_add_string(required, "program", program); 613 fnvlist_add_string_array(args, "argv", argv, 1); 614 fnvlist_add_nvlist(required, "arg", args); 615 616 fnvlist_add_boolean_value(optional, "sync", B_TRUE); 617 fnvlist_add_uint64(optional, "instrlimit", 1000 * 1000); 618 fnvlist_add_uint64(optional, "memlimit", 8192 * 1024); 619 620 IOC_INPUT_TEST(ZFS_IOC_CHANNEL_PROGRAM, pool, required, optional, 0); 621 622 nvlist_free(args); 623 nvlist_free(optional); 624 nvlist_free(required); 625 } 626 627 #define WRAPPING_KEY_LEN 32 628 629 static void 630 test_load_key(const char *dataset) 631 { 632 nvlist_t *required = fnvlist_alloc(); 633 nvlist_t *optional = fnvlist_alloc(); 634 nvlist_t *hidden = fnvlist_alloc(); 635 uint8_t keydata[WRAPPING_KEY_LEN] = {0}; 636 637 fnvlist_add_uint8_array(hidden, "wkeydata", keydata, sizeof (keydata)); 638 fnvlist_add_nvlist(required, "hidden_args", hidden); 639 fnvlist_add_boolean(optional, "noop"); 640 641 IOC_INPUT_TEST(ZFS_IOC_LOAD_KEY, dataset, required, optional, EINVAL); 642 nvlist_free(hidden); 643 nvlist_free(optional); 644 nvlist_free(required); 645 } 646 647 static void 648 test_change_key(const char *dataset) 649 { 650 IOC_INPUT_TEST(ZFS_IOC_CHANGE_KEY, dataset, NULL, NULL, EINVAL); 651 } 652 653 static void 654 test_unload_key(const char *dataset) 655 { 656 IOC_INPUT_TEST(ZFS_IOC_UNLOAD_KEY, dataset, NULL, NULL, EACCES); 657 } 658 659 static void 660 test_vdev_initialize(const char *pool) 661 { 662 nvlist_t *required = fnvlist_alloc(); 663 nvlist_t *vdev_guids = fnvlist_alloc(); 664 665 fnvlist_add_uint64(vdev_guids, "path", 0xdeadbeefdeadbeef); 666 fnvlist_add_uint64(required, ZPOOL_INITIALIZE_COMMAND, 667 POOL_INITIALIZE_START); 668 fnvlist_add_nvlist(required, ZPOOL_INITIALIZE_VDEVS, vdev_guids); 669 670 IOC_INPUT_TEST(ZFS_IOC_POOL_INITIALIZE, pool, required, NULL, EINVAL); 671 nvlist_free(vdev_guids); 672 nvlist_free(required); 673 } 674 675 static void 676 test_vdev_trim(const char *pool) 677 { 678 nvlist_t *required = fnvlist_alloc(); 679 nvlist_t *optional = fnvlist_alloc(); 680 nvlist_t *vdev_guids = fnvlist_alloc(); 681 682 fnvlist_add_uint64(vdev_guids, "path", 0xdeadbeefdeadbeef); 683 fnvlist_add_uint64(required, ZPOOL_TRIM_COMMAND, POOL_TRIM_START); 684 fnvlist_add_nvlist(required, ZPOOL_TRIM_VDEVS, vdev_guids); 685 fnvlist_add_uint64(optional, ZPOOL_TRIM_RATE, 1ULL << 30); 686 fnvlist_add_boolean_value(optional, ZPOOL_TRIM_SECURE, B_TRUE); 687 688 IOC_INPUT_TEST(ZFS_IOC_POOL_TRIM, pool, required, optional, EINVAL); 689 nvlist_free(vdev_guids); 690 nvlist_free(optional); 691 nvlist_free(required); 692 } 693 694 static int 695 zfs_destroy(const char *dataset) 696 { 697 zfs_cmd_t zc = {"\0"}; 698 int err; 699 700 (void) strncpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 701 zc.zc_name[sizeof (zc.zc_name) - 1] = '\0'; 702 zc.zc_objset_type = DMU_OST_ZFS; 703 err = ioctl(zfs_fd, ZFS_IOC_DESTROY, &zc); 704 705 return (err == 0 ? 0 : errno); 706 } 707 708 static void 709 zfs_ioc_input_tests(const char *pool) 710 { 711 char filepath[] = "/tmp/ioc_test_file_XXXXXX"; 712 char dataset[ZFS_MAX_DATASET_NAME_LEN]; 713 char snapbase[ZFS_MAX_DATASET_NAME_LEN + 32]; 714 char snapshot[ZFS_MAX_DATASET_NAME_LEN + 32]; 715 char bookmark[ZFS_MAX_DATASET_NAME_LEN + 32]; 716 char backup[ZFS_MAX_DATASET_NAME_LEN]; 717 char clone[ZFS_MAX_DATASET_NAME_LEN]; 718 int tmpfd, err; 719 720 /* 721 * Setup names and create a working dataset 722 */ 723 (void) snprintf(dataset, sizeof (dataset), "%s/test-fs", pool); 724 (void) snprintf(snapbase, sizeof (snapbase), "%s@snapbase", dataset); 725 (void) snprintf(snapshot, sizeof (snapshot), "%s@snapshot", dataset); 726 (void) snprintf(bookmark, sizeof (bookmark), "%s#bookmark", dataset); 727 (void) snprintf(clone, sizeof (clone), "%s/test-fs-clone", pool); 728 (void) snprintf(backup, sizeof (backup), "%s/backup", pool); 729 730 err = lzc_create(dataset, DMU_OST_ZFS, NULL, NULL, 0); 731 if (err) { 732 (void) fprintf(stderr, "could not create '%s': %s\n", 733 dataset, strerror(errno)); 734 exit(2); 735 } 736 737 tmpfd = mkstemp(filepath); 738 if (tmpfd < 0) { 739 (void) fprintf(stderr, "could not create '%s': %s\n", 740 filepath, strerror(errno)); 741 exit(2); 742 } 743 744 /* 745 * run a test for each ioctl 746 * Note that some test build on previous test operations 747 */ 748 test_pool_sync(pool); 749 #ifndef __sun 750 test_pool_reopen(pool); 751 #endif 752 test_pool_checkpoint(pool); 753 test_pool_discard_checkpoint(pool); 754 test_log_history(pool); 755 756 test_create(dataset); 757 test_snapshot(pool, snapbase); 758 test_snapshot(pool, snapshot); 759 760 test_space_snaps(snapshot); 761 test_send_space(snapbase, snapshot); 762 test_send_new(snapshot, tmpfd); 763 #ifndef __sun 764 test_recv_new(backup, tmpfd); 765 #endif 766 767 test_bookmark(pool, snapshot, bookmark); 768 test_get_bookmarks(dataset); 769 test_destroy_bookmarks(pool, bookmark); 770 771 test_hold(pool, snapshot); 772 test_get_holds(snapshot); 773 test_release(pool, snapshot); 774 775 test_clone(snapshot, clone); 776 (void) zfs_destroy(clone); 777 778 test_rollback(dataset, snapshot); 779 test_destroy_snaps(pool, snapshot); 780 test_destroy_snaps(pool, snapbase); 781 782 test_remap(dataset); 783 test_channel_program(pool); 784 785 test_load_key(dataset); 786 test_change_key(dataset); 787 test_unload_key(dataset); 788 789 test_vdev_initialize(pool); 790 test_vdev_trim(pool); 791 792 /* 793 * cleanup 794 */ 795 zfs_cmd_t zc = {"\0"}; 796 797 nvlist_t *snaps = fnvlist_alloc(); 798 fnvlist_add_boolean(snaps, snapshot); 799 (void) lzc_destroy_snaps(snaps, B_FALSE, NULL); 800 nvlist_free(snaps); 801 802 (void) zfs_destroy(dataset); 803 (void) zfs_destroy(backup); 804 805 (void) close(tmpfd); 806 (void) unlink(filepath); 807 808 /* 809 * All the unused slots should yield ZFS_ERR_IOC_CMD_UNAVAIL 810 */ 811 for (int i = 0; i < ARRAY_SIZE(ioc_skip); i++) { 812 if (ioc_tested[ioc_skip[i] - ZFS_IOC_FIRST]) 813 (void) fprintf(stderr, "cmd %d tested, not skipped!\n", 814 (int)(ioc_skip[i] - ZFS_IOC_FIRST)); 815 816 ioc_tested[ioc_skip[i] - ZFS_IOC_FIRST] = B_TRUE; 817 } 818 819 (void) strncpy(zc.zc_name, pool, sizeof (zc.zc_name)); 820 zc.zc_name[sizeof (zc.zc_name) - 1] = '\0'; 821 822 for (unsigned ioc = ZFS_IOC_FIRST; ioc < ZFS_IOC_LAST; ioc++) { 823 unsigned cmd = ioc - ZFS_IOC_FIRST; 824 825 if (ioc_tested[cmd]) 826 continue; 827 828 if (ioctl(zfs_fd, ioc, &zc) != 0 && 829 errno != ZFS_ERR_IOC_CMD_UNAVAIL) { 830 (void) fprintf(stderr, "cmd %d is missing a test case " 831 "(%d)\n", cmd, errno); 832 } 833 } 834 } 835 836 enum zfs_ioc_ref { 837 ZFS_IOC_BASE = ('Z' << 8), 838 LINUX_IOC_BASE = ('Z' << 8) + 0x80, 839 FREEBSD_IOC_BASE = ('Z' << 8) + 0xC0, 840 }; 841 842 /* 843 * Canonical reference check of /dev/zfs ioctl numbers. 844 * These cannot change and new ioctl numbers must be appended. 845 */ 846 boolean_t 847 validate_ioc_values(void) 848 { 849 return ( 850 ZFS_IOC_BASE + 0 == ZFS_IOC_POOL_CREATE && 851 ZFS_IOC_BASE + 1 == ZFS_IOC_POOL_DESTROY && 852 ZFS_IOC_BASE + 2 == ZFS_IOC_POOL_IMPORT && 853 ZFS_IOC_BASE + 3 == ZFS_IOC_POOL_EXPORT && 854 ZFS_IOC_BASE + 4 == ZFS_IOC_POOL_CONFIGS && 855 ZFS_IOC_BASE + 5 == ZFS_IOC_POOL_STATS && 856 ZFS_IOC_BASE + 6 == ZFS_IOC_POOL_TRYIMPORT && 857 ZFS_IOC_BASE + 7 == ZFS_IOC_POOL_SCAN && 858 ZFS_IOC_BASE + 8 == ZFS_IOC_POOL_FREEZE && 859 ZFS_IOC_BASE + 9 == ZFS_IOC_POOL_UPGRADE && 860 ZFS_IOC_BASE + 10 == ZFS_IOC_POOL_GET_HISTORY && 861 ZFS_IOC_BASE + 11 == ZFS_IOC_VDEV_ADD && 862 ZFS_IOC_BASE + 12 == ZFS_IOC_VDEV_REMOVE && 863 ZFS_IOC_BASE + 13 == ZFS_IOC_VDEV_SET_STATE && 864 ZFS_IOC_BASE + 14 == ZFS_IOC_VDEV_ATTACH && 865 ZFS_IOC_BASE + 15 == ZFS_IOC_VDEV_DETACH && 866 ZFS_IOC_BASE + 16 == ZFS_IOC_VDEV_SETPATH && 867 ZFS_IOC_BASE + 17 == ZFS_IOC_VDEV_SETFRU && 868 ZFS_IOC_BASE + 18 == ZFS_IOC_OBJSET_STATS && 869 ZFS_IOC_BASE + 19 == ZFS_IOC_OBJSET_ZPLPROPS && 870 ZFS_IOC_BASE + 20 == ZFS_IOC_DATASET_LIST_NEXT && 871 ZFS_IOC_BASE + 21 == ZFS_IOC_SNAPSHOT_LIST_NEXT && 872 ZFS_IOC_BASE + 22 == ZFS_IOC_SET_PROP && 873 ZFS_IOC_BASE + 23 == ZFS_IOC_CREATE && 874 ZFS_IOC_BASE + 24 == ZFS_IOC_DESTROY && 875 ZFS_IOC_BASE + 25 == ZFS_IOC_ROLLBACK && 876 ZFS_IOC_BASE + 26 == ZFS_IOC_RENAME && 877 ZFS_IOC_BASE + 27 == ZFS_IOC_RECV && 878 ZFS_IOC_BASE + 28 == ZFS_IOC_SEND && 879 ZFS_IOC_BASE + 29 == ZFS_IOC_INJECT_FAULT && 880 ZFS_IOC_BASE + 30 == ZFS_IOC_CLEAR_FAULT && 881 ZFS_IOC_BASE + 31 == ZFS_IOC_INJECT_LIST_NEXT && 882 ZFS_IOC_BASE + 32 == ZFS_IOC_ERROR_LOG && 883 ZFS_IOC_BASE + 33 == ZFS_IOC_CLEAR && 884 ZFS_IOC_BASE + 34 == ZFS_IOC_PROMOTE && 885 ZFS_IOC_BASE + 35 == ZFS_IOC_SNAPSHOT && 886 ZFS_IOC_BASE + 36 == ZFS_IOC_DSOBJ_TO_DSNAME && 887 ZFS_IOC_BASE + 37 == ZFS_IOC_OBJ_TO_PATH && 888 ZFS_IOC_BASE + 38 == ZFS_IOC_POOL_SET_PROPS && 889 ZFS_IOC_BASE + 39 == ZFS_IOC_POOL_GET_PROPS && 890 ZFS_IOC_BASE + 40 == ZFS_IOC_SET_FSACL && 891 ZFS_IOC_BASE + 41 == ZFS_IOC_GET_FSACL && 892 ZFS_IOC_BASE + 42 == ZFS_IOC_SHARE && 893 ZFS_IOC_BASE + 43 == ZFS_IOC_INHERIT_PROP && 894 ZFS_IOC_BASE + 44 == ZFS_IOC_SMB_ACL && 895 ZFS_IOC_BASE + 45 == ZFS_IOC_USERSPACE_ONE && 896 ZFS_IOC_BASE + 46 == ZFS_IOC_USERSPACE_MANY && 897 ZFS_IOC_BASE + 47 == ZFS_IOC_USERSPACE_UPGRADE && 898 ZFS_IOC_BASE + 48 == ZFS_IOC_HOLD && 899 ZFS_IOC_BASE + 49 == ZFS_IOC_RELEASE && 900 ZFS_IOC_BASE + 50 == ZFS_IOC_GET_HOLDS && 901 ZFS_IOC_BASE + 51 == ZFS_IOC_OBJSET_RECVD_PROPS && 902 ZFS_IOC_BASE + 52 == ZFS_IOC_VDEV_SPLIT && 903 ZFS_IOC_BASE + 53 == ZFS_IOC_NEXT_OBJ && 904 ZFS_IOC_BASE + 54 == ZFS_IOC_DIFF && 905 ZFS_IOC_BASE + 55 == ZFS_IOC_TMP_SNAPSHOT && 906 ZFS_IOC_BASE + 56 == ZFS_IOC_OBJ_TO_STATS && 907 ZFS_IOC_BASE + 57 == ZFS_IOC_SPACE_WRITTEN && 908 ZFS_IOC_BASE + 58 == ZFS_IOC_SPACE_SNAPS && 909 ZFS_IOC_BASE + 59 == ZFS_IOC_DESTROY_SNAPS && 910 ZFS_IOC_BASE + 60 == ZFS_IOC_POOL_REGUID && 911 ZFS_IOC_BASE + 61 == ZFS_IOC_POOL_REOPEN && 912 ZFS_IOC_BASE + 62 == ZFS_IOC_SEND_PROGRESS && 913 ZFS_IOC_BASE + 63 == ZFS_IOC_LOG_HISTORY && 914 ZFS_IOC_BASE + 64 == ZFS_IOC_SEND_NEW && 915 ZFS_IOC_BASE + 65 == ZFS_IOC_SEND_SPACE && 916 ZFS_IOC_BASE + 66 == ZFS_IOC_CLONE && 917 ZFS_IOC_BASE + 67 == ZFS_IOC_BOOKMARK && 918 ZFS_IOC_BASE + 68 == ZFS_IOC_GET_BOOKMARKS && 919 ZFS_IOC_BASE + 69 == ZFS_IOC_DESTROY_BOOKMARKS && 920 #ifndef __sun 921 ZFS_IOC_BASE + 71 == ZFS_IOC_RECV_NEW && 922 #endif 923 ZFS_IOC_BASE + 70 == ZFS_IOC_POOL_SYNC && 924 ZFS_IOC_BASE + 71 == ZFS_IOC_CHANNEL_PROGRAM && 925 ZFS_IOC_BASE + 72 == ZFS_IOC_LOAD_KEY && 926 ZFS_IOC_BASE + 73 == ZFS_IOC_UNLOAD_KEY && 927 ZFS_IOC_BASE + 74 == ZFS_IOC_CHANGE_KEY && 928 ZFS_IOC_BASE + 75 == ZFS_IOC_REMAP && 929 ZFS_IOC_BASE + 76 == ZFS_IOC_POOL_CHECKPOINT && 930 931 #ifndef __sun 932 ZFS_IOC_BASE + 78 == ZFS_IOC_POOL_DISCARD_CHECKPOINT && 933 LINUX_IOC_BASE + 1 == ZFS_IOC_EVENTS_NEXT && 934 LINUX_IOC_BASE + 2 == ZFS_IOC_EVENTS_CLEAR && 935 LINUX_IOC_BASE + 3 == ZFS_IOC_EVENTS_SEEK); 936 #else 937 ZFS_IOC_BASE + 77 == ZFS_IOC_POOL_DISCARD_CHECKPOINT && 938 ZFS_IOC_BASE + 78 == ZFS_IOC_POOL_INITIALIZE && 939 ZFS_IOC_BASE + 79 == ZFS_IOC_POOL_TRIM && 940 ZFS_IOC_BASE + 80 == ZFS_IOC_REDACT && 941 ZFS_IOC_BASE + 81 == ZFS_IOC_GET_BOOKMARK_PROPS); 942 #endif 943 } 944 945 int 946 main(int argc, const char *argv[]) 947 { 948 if (argc != 2) { 949 (void) fprintf(stderr, "usage: %s <pool>\n", argv[0]); 950 exit(2); 951 } 952 953 if (!validate_ioc_values()) { 954 (void) fprintf(stderr, "WARNING: zfs_ioc_t has binary " 955 "incompatible command values\n"); 956 exit(3); 957 } 958 959 (void) libzfs_core_init(); 960 zfs_fd = open(ZFS_DEV, O_RDWR|O_EXCL); 961 if (zfs_fd < 0) { 962 (void) fprintf(stderr, "open: %s\n", strerror(errno)); 963 libzfs_core_fini(); 964 exit(2); 965 } 966 967 zfs_ioc_input_tests(argv[1]); 968 969 (void) close(zfs_fd); 970 libzfs_core_fini(); 971 972 return (unexpected_failures); 973 } 974