1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright (c) 2011, 2015 by Delphix. All rights reserved. 25 * Copyright (c) 2013 Steven Hartland. All rights reserved. 26 */ 27 28 /* 29 * zhack is a debugging tool that can write changes to ZFS pool using libzpool 30 * for testing purposes. Altering pools with zhack is unsupported and may 31 * result in corrupted pools. 32 */ 33 34 #include <zfs_prop.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <ctype.h> 38 #include <sys/stat.h> 39 #include <sys/zfs_context.h> 40 #include <sys/spa.h> 41 #include <sys/spa_impl.h> 42 #include <sys/dmu.h> 43 #include <sys/zap.h> 44 #include <sys/zfs_znode.h> 45 #include <sys/dsl_synctask.h> 46 #include <sys/vdev.h> 47 #include <sys/vdev_impl.h> 48 #include <sys/fs/zfs.h> 49 #include <sys/dmu_objset.h> 50 #include <sys/dsl_pool.h> 51 #include <sys/zio_checksum.h> 52 #include <sys/zio_compress.h> 53 #include <sys/zfeature.h> 54 #include <sys/dmu_tx.h> 55 #include <zfeature_common.h> 56 #include <libzutil.h> 57 58 static importargs_t g_importargs; 59 static char *g_pool; 60 static boolean_t g_readonly; 61 62 typedef enum { 63 ZHACK_REPAIR_OP_UNKNOWN = 0, 64 ZHACK_REPAIR_OP_CKSUM = (1 << 0), 65 ZHACK_REPAIR_OP_UNDETACH = (1 << 1) 66 } zhack_repair_op_t; 67 68 static __attribute__((noreturn)) void 69 usage(void) 70 { 71 (void) fprintf(stderr, 72 "Usage: zhack [-c cachefile] [-d dir] <subcommand> <args> ...\n" 73 "where <subcommand> <args> is one of the following:\n" 74 "\n"); 75 76 (void) fprintf(stderr, 77 " feature stat <pool>\n" 78 " print information about enabled features\n" 79 " feature enable [-r] [-d desc] <pool> <feature>\n" 80 " add a new enabled feature to the pool\n" 81 " -d <desc> sets the feature's description\n" 82 " -r set read-only compatible flag for feature\n" 83 " feature ref [-md] <pool> <feature>\n" 84 " change the refcount on the given feature\n" 85 " -d decrease instead of increase the refcount\n" 86 " -m add the feature to the label if increasing refcount\n" 87 "\n" 88 " <feature> : should be a feature guid\n" 89 "\n" 90 " label repair <device>\n" 91 " repair labels of a specified device according to options\n" 92 " which may be combined to do their functions in one call\n" 93 " -c repair corrupted label checksums\n" 94 " -u restore the label on a detached device\n" 95 "\n" 96 " <device> : path to vdev\n"); 97 exit(1); 98 } 99 100 101 static __attribute__((format(printf, 3, 4))) __attribute__((noreturn)) void 102 fatal(spa_t *spa, const void *tag, const char *fmt, ...) 103 { 104 va_list ap; 105 106 if (spa != NULL) { 107 spa_close(spa, tag); 108 (void) spa_export(g_pool, NULL, B_TRUE, B_FALSE); 109 } 110 111 va_start(ap, fmt); 112 (void) fputs("zhack: ", stderr); 113 (void) vfprintf(stderr, fmt, ap); 114 va_end(ap); 115 (void) fputc('\n', stderr); 116 117 exit(1); 118 } 119 120 static int 121 space_delta_cb(dmu_object_type_t bonustype, const void *data, 122 zfs_file_info_t *zoi) 123 { 124 (void) data, (void) zoi; 125 126 /* 127 * Is it a valid type of object to track? 128 */ 129 if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA) 130 return (ENOENT); 131 (void) fprintf(stderr, "modifying object that needs user accounting"); 132 abort(); 133 } 134 135 /* 136 * Target is the dataset whose pool we want to open. 137 */ 138 static void 139 zhack_import(char *target, boolean_t readonly) 140 { 141 nvlist_t *config; 142 nvlist_t *props; 143 int error; 144 145 kernel_init(readonly ? SPA_MODE_READ : 146 (SPA_MODE_READ | SPA_MODE_WRITE)); 147 148 dmu_objset_register_type(DMU_OST_ZFS, space_delta_cb); 149 150 g_readonly = readonly; 151 g_importargs.can_be_active = readonly; 152 g_pool = strdup(target); 153 154 libpc_handle_t lpch = { 155 .lpc_lib_handle = NULL, 156 .lpc_ops = &libzpool_config_ops, 157 .lpc_printerr = B_TRUE 158 }; 159 error = zpool_find_config(&lpch, target, &config, &g_importargs); 160 if (error) 161 fatal(NULL, FTAG, "cannot import '%s'", target); 162 163 props = NULL; 164 if (readonly) { 165 VERIFY0(nvlist_alloc(&props, NV_UNIQUE_NAME, 0)); 166 VERIFY0(nvlist_add_uint64(props, 167 zpool_prop_to_name(ZPOOL_PROP_READONLY), 1)); 168 } 169 170 zfeature_checks_disable = B_TRUE; 171 error = spa_import(target, config, props, 172 (readonly ? ZFS_IMPORT_SKIP_MMP : ZFS_IMPORT_NORMAL)); 173 fnvlist_free(config); 174 zfeature_checks_disable = B_FALSE; 175 if (error == EEXIST) 176 error = 0; 177 178 if (error) 179 fatal(NULL, FTAG, "can't import '%s': %s", target, 180 strerror(error)); 181 } 182 183 static void 184 zhack_spa_open(char *target, boolean_t readonly, const void *tag, spa_t **spa) 185 { 186 int err; 187 188 zhack_import(target, readonly); 189 190 zfeature_checks_disable = B_TRUE; 191 err = spa_open(target, spa, tag); 192 zfeature_checks_disable = B_FALSE; 193 194 if (err != 0) 195 fatal(*spa, FTAG, "cannot open '%s': %s", target, 196 strerror(err)); 197 if (spa_version(*spa) < SPA_VERSION_FEATURES) { 198 fatal(*spa, FTAG, "'%s' has version %d, features not enabled", 199 target, (int)spa_version(*spa)); 200 } 201 } 202 203 static void 204 dump_obj(objset_t *os, uint64_t obj, const char *name) 205 { 206 zap_cursor_t zc; 207 zap_attribute_t *za = zap_attribute_long_alloc(); 208 209 (void) printf("%s_obj:\n", name); 210 211 for (zap_cursor_init(&zc, os, obj); 212 zap_cursor_retrieve(&zc, za) == 0; 213 zap_cursor_advance(&zc)) { 214 if (za->za_integer_length == 8) { 215 ASSERT(za->za_num_integers == 1); 216 (void) printf("\t%s = %llu\n", 217 za->za_name, (u_longlong_t)za->za_first_integer); 218 } else { 219 ASSERT(za->za_integer_length == 1); 220 char val[1024]; 221 VERIFY0(zap_lookup(os, obj, za->za_name, 222 1, sizeof (val), val)); 223 (void) printf("\t%s = %s\n", za->za_name, val); 224 } 225 } 226 zap_cursor_fini(&zc); 227 zap_attribute_free(za); 228 } 229 230 static void 231 dump_mos(spa_t *spa) 232 { 233 nvlist_t *nv = spa->spa_label_features; 234 nvpair_t *pair; 235 236 (void) printf("label config:\n"); 237 for (pair = nvlist_next_nvpair(nv, NULL); 238 pair != NULL; 239 pair = nvlist_next_nvpair(nv, pair)) { 240 (void) printf("\t%s\n", nvpair_name(pair)); 241 } 242 } 243 244 static void 245 zhack_do_feature_stat(int argc, char **argv) 246 { 247 spa_t *spa; 248 objset_t *os; 249 char *target; 250 251 argc--; 252 argv++; 253 254 if (argc < 1) { 255 (void) fprintf(stderr, "error: missing pool name\n"); 256 usage(); 257 } 258 target = argv[0]; 259 260 zhack_spa_open(target, B_TRUE, FTAG, &spa); 261 os = spa->spa_meta_objset; 262 263 dump_obj(os, spa->spa_feat_for_read_obj, "for_read"); 264 dump_obj(os, spa->spa_feat_for_write_obj, "for_write"); 265 dump_obj(os, spa->spa_feat_desc_obj, "descriptions"); 266 if (spa_feature_is_active(spa, SPA_FEATURE_ENABLED_TXG)) { 267 dump_obj(os, spa->spa_feat_enabled_txg_obj, "enabled_txg"); 268 } 269 dump_mos(spa); 270 271 spa_close(spa, FTAG); 272 } 273 274 static void 275 zhack_feature_enable_sync(void *arg, dmu_tx_t *tx) 276 { 277 spa_t *spa = dmu_tx_pool(tx)->dp_spa; 278 zfeature_info_t *feature = arg; 279 280 feature_enable_sync(spa, feature, tx); 281 282 spa_history_log_internal(spa, "zhack enable feature", tx, 283 "name=%s flags=%u", 284 feature->fi_guid, feature->fi_flags); 285 } 286 287 static void 288 zhack_do_feature_enable(int argc, char **argv) 289 { 290 int c; 291 char *desc, *target; 292 spa_t *spa; 293 objset_t *mos; 294 zfeature_info_t feature; 295 const spa_feature_t nodeps[] = { SPA_FEATURE_NONE }; 296 297 /* 298 * Features are not added to the pool's label until their refcounts 299 * are incremented, so fi_mos can just be left as false for now. 300 */ 301 desc = NULL; 302 feature.fi_uname = "zhack"; 303 feature.fi_flags = 0; 304 feature.fi_depends = nodeps; 305 feature.fi_feature = SPA_FEATURE_NONE; 306 307 optind = 1; 308 while ((c = getopt(argc, argv, "+rd:")) != -1) { 309 switch (c) { 310 case 'r': 311 feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT; 312 break; 313 case 'd': 314 if (desc != NULL) 315 free(desc); 316 desc = strdup(optarg); 317 break; 318 default: 319 usage(); 320 break; 321 } 322 } 323 324 if (desc == NULL) 325 desc = strdup("zhack injected"); 326 feature.fi_desc = desc; 327 328 argc -= optind; 329 argv += optind; 330 331 if (argc < 2) { 332 (void) fprintf(stderr, "error: missing feature or pool name\n"); 333 usage(); 334 } 335 target = argv[0]; 336 feature.fi_guid = argv[1]; 337 338 if (!zfeature_is_valid_guid(feature.fi_guid)) 339 fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid); 340 341 zhack_spa_open(target, B_FALSE, FTAG, &spa); 342 mos = spa->spa_meta_objset; 343 344 if (zfeature_is_supported(feature.fi_guid)) 345 fatal(spa, FTAG, "'%s' is a real feature, will not enable", 346 feature.fi_guid); 347 if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid)) 348 fatal(spa, FTAG, "feature already enabled: %s", 349 feature.fi_guid); 350 351 VERIFY0(dsl_sync_task(spa_name(spa), NULL, 352 zhack_feature_enable_sync, &feature, 5, ZFS_SPACE_CHECK_NORMAL)); 353 354 spa_close(spa, FTAG); 355 356 free(desc); 357 } 358 359 static void 360 feature_incr_sync(void *arg, dmu_tx_t *tx) 361 { 362 spa_t *spa = dmu_tx_pool(tx)->dp_spa; 363 zfeature_info_t *feature = arg; 364 uint64_t refcount; 365 366 mutex_enter(&spa->spa_feat_stats_lock); 367 VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount)); 368 feature_sync(spa, feature, refcount + 1, tx); 369 spa_history_log_internal(spa, "zhack feature incr", tx, 370 "name=%s", feature->fi_guid); 371 mutex_exit(&spa->spa_feat_stats_lock); 372 } 373 374 static void 375 feature_decr_sync(void *arg, dmu_tx_t *tx) 376 { 377 spa_t *spa = dmu_tx_pool(tx)->dp_spa; 378 zfeature_info_t *feature = arg; 379 uint64_t refcount; 380 381 mutex_enter(&spa->spa_feat_stats_lock); 382 VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount)); 383 feature_sync(spa, feature, refcount - 1, tx); 384 spa_history_log_internal(spa, "zhack feature decr", tx, 385 "name=%s", feature->fi_guid); 386 mutex_exit(&spa->spa_feat_stats_lock); 387 } 388 389 static void 390 zhack_do_feature_ref(int argc, char **argv) 391 { 392 int c; 393 char *target; 394 boolean_t decr = B_FALSE; 395 spa_t *spa; 396 objset_t *mos; 397 zfeature_info_t feature; 398 const spa_feature_t nodeps[] = { SPA_FEATURE_NONE }; 399 400 /* 401 * fi_desc does not matter here because it was written to disk 402 * when the feature was enabled, but we need to properly set the 403 * feature for read or write based on the information we read off 404 * disk later. 405 */ 406 feature.fi_uname = "zhack"; 407 feature.fi_flags = 0; 408 feature.fi_desc = NULL; 409 feature.fi_depends = nodeps; 410 feature.fi_feature = SPA_FEATURE_NONE; 411 412 optind = 1; 413 while ((c = getopt(argc, argv, "+md")) != -1) { 414 switch (c) { 415 case 'm': 416 feature.fi_flags |= ZFEATURE_FLAG_MOS; 417 break; 418 case 'd': 419 decr = B_TRUE; 420 break; 421 default: 422 usage(); 423 break; 424 } 425 } 426 argc -= optind; 427 argv += optind; 428 429 if (argc < 2) { 430 (void) fprintf(stderr, "error: missing feature or pool name\n"); 431 usage(); 432 } 433 target = argv[0]; 434 feature.fi_guid = argv[1]; 435 436 if (!zfeature_is_valid_guid(feature.fi_guid)) 437 fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid); 438 439 zhack_spa_open(target, B_FALSE, FTAG, &spa); 440 mos = spa->spa_meta_objset; 441 442 if (zfeature_is_supported(feature.fi_guid)) { 443 fatal(spa, FTAG, 444 "'%s' is a real feature, will not change refcount", 445 feature.fi_guid); 446 } 447 448 if (0 == zap_contains(mos, spa->spa_feat_for_read_obj, 449 feature.fi_guid)) { 450 feature.fi_flags &= ~ZFEATURE_FLAG_READONLY_COMPAT; 451 } else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj, 452 feature.fi_guid)) { 453 feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT; 454 } else { 455 fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid); 456 } 457 458 if (decr) { 459 uint64_t count; 460 if (feature_get_refcount_from_disk(spa, &feature, 461 &count) == 0 && count == 0) { 462 fatal(spa, FTAG, "feature refcount already 0: %s", 463 feature.fi_guid); 464 } 465 } 466 467 VERIFY0(dsl_sync_task(spa_name(spa), NULL, 468 decr ? feature_decr_sync : feature_incr_sync, &feature, 469 5, ZFS_SPACE_CHECK_NORMAL)); 470 471 spa_close(spa, FTAG); 472 } 473 474 static int 475 zhack_do_feature(int argc, char **argv) 476 { 477 char *subcommand; 478 479 argc--; 480 argv++; 481 if (argc == 0) { 482 (void) fprintf(stderr, 483 "error: no feature operation specified\n"); 484 usage(); 485 } 486 487 subcommand = argv[0]; 488 if (strcmp(subcommand, "stat") == 0) { 489 zhack_do_feature_stat(argc, argv); 490 } else if (strcmp(subcommand, "enable") == 0) { 491 zhack_do_feature_enable(argc, argv); 492 } else if (strcmp(subcommand, "ref") == 0) { 493 zhack_do_feature_ref(argc, argv); 494 } else { 495 (void) fprintf(stderr, "error: unknown subcommand: %s\n", 496 subcommand); 497 usage(); 498 } 499 500 return (0); 501 } 502 503 #define ASHIFT_UBERBLOCK_SHIFT(ashift) \ 504 MIN(MAX(ashift, UBERBLOCK_SHIFT), \ 505 MAX_UBERBLOCK_SHIFT) 506 #define ASHIFT_UBERBLOCK_SIZE(ashift) \ 507 (1ULL << ASHIFT_UBERBLOCK_SHIFT(ashift)) 508 509 #define REPAIR_LABEL_STATUS_CKSUM (1 << 0) 510 #define REPAIR_LABEL_STATUS_UB (1 << 1) 511 512 static int 513 zhack_repair_read_label(const int fd, vdev_label_t *vl, 514 const uint64_t label_offset, const int l) 515 { 516 const int err = pread64(fd, vl, sizeof (vdev_label_t), label_offset); 517 518 if (err == -1) { 519 (void) fprintf(stderr, 520 "error: cannot read label %d: %s\n", 521 l, strerror(errno)); 522 return (err); 523 } else if (err != sizeof (vdev_label_t)) { 524 (void) fprintf(stderr, 525 "error: bad label %d read size\n", l); 526 return (err); 527 } 528 529 return (0); 530 } 531 532 static void 533 zhack_repair_calc_cksum(const int byteswap, void *data, const uint64_t offset, 534 const uint64_t abdsize, zio_eck_t *eck, zio_cksum_t *cksum) 535 { 536 zio_cksum_t verifier; 537 zio_cksum_t current_cksum; 538 zio_checksum_info_t *ci; 539 abd_t *abd; 540 541 ZIO_SET_CHECKSUM(&verifier, offset, 0, 0, 0); 542 543 if (byteswap) 544 byteswap_uint64_array(&verifier, sizeof (zio_cksum_t)); 545 546 current_cksum = eck->zec_cksum; 547 eck->zec_cksum = verifier; 548 549 ci = &zio_checksum_table[ZIO_CHECKSUM_LABEL]; 550 abd = abd_get_from_buf(data, abdsize); 551 ci->ci_func[byteswap](abd, abdsize, NULL, cksum); 552 abd_free(abd); 553 554 eck->zec_cksum = current_cksum; 555 } 556 557 static int 558 zhack_repair_check_label(uberblock_t *ub, const int l, const char **cfg_keys, 559 const size_t cfg_keys_len, nvlist_t *cfg, nvlist_t *vdev_tree_cfg, 560 uint64_t *ashift) 561 { 562 int err; 563 564 if (ub->ub_txg != 0) { 565 (void) fprintf(stderr, 566 "error: label %d: UB TXG of 0 expected, but got %" 567 PRIu64 "\n", 568 l, ub->ub_txg); 569 (void) fprintf(stderr, "It would appear the device was not " 570 "properly removed.\n"); 571 return (1); 572 } 573 574 for (int i = 0; i < cfg_keys_len; i++) { 575 uint64_t val; 576 err = nvlist_lookup_uint64(cfg, cfg_keys[i], &val); 577 if (err) { 578 (void) fprintf(stderr, 579 "error: label %d, %d: " 580 "cannot find nvlist key %s\n", 581 l, i, cfg_keys[i]); 582 return (err); 583 } 584 } 585 586 err = nvlist_lookup_nvlist(cfg, 587 ZPOOL_CONFIG_VDEV_TREE, &vdev_tree_cfg); 588 if (err) { 589 (void) fprintf(stderr, 590 "error: label %d: cannot find nvlist key %s\n", 591 l, ZPOOL_CONFIG_VDEV_TREE); 592 return (err); 593 } 594 595 err = nvlist_lookup_uint64(vdev_tree_cfg, 596 ZPOOL_CONFIG_ASHIFT, ashift); 597 if (err) { 598 (void) fprintf(stderr, 599 "error: label %d: cannot find nvlist key %s\n", 600 l, ZPOOL_CONFIG_ASHIFT); 601 return (err); 602 } 603 604 if (*ashift == 0) { 605 (void) fprintf(stderr, 606 "error: label %d: nvlist key %s is zero\n", 607 l, ZPOOL_CONFIG_ASHIFT); 608 return (err); 609 } 610 611 return (0); 612 } 613 614 static int 615 zhack_repair_undetach(uberblock_t *ub, nvlist_t *cfg, const int l) 616 { 617 /* 618 * Uberblock root block pointer has valid birth TXG. 619 * Copying it to the label NVlist 620 */ 621 if (BP_GET_LOGICAL_BIRTH(&ub->ub_rootbp) != 0) { 622 const uint64_t txg = BP_GET_LOGICAL_BIRTH(&ub->ub_rootbp); 623 ub->ub_txg = txg; 624 625 if (nvlist_remove_all(cfg, ZPOOL_CONFIG_CREATE_TXG) != 0) { 626 (void) fprintf(stderr, 627 "error: label %d: " 628 "Failed to remove pool creation TXG\n", 629 l); 630 return (1); 631 } 632 633 if (nvlist_remove_all(cfg, ZPOOL_CONFIG_POOL_TXG) != 0) { 634 (void) fprintf(stderr, 635 "error: label %d: Failed to remove pool TXG to " 636 "be replaced.\n", 637 l); 638 return (1); 639 } 640 641 if (nvlist_add_uint64(cfg, ZPOOL_CONFIG_POOL_TXG, txg) != 0) { 642 (void) fprintf(stderr, 643 "error: label %d: " 644 "Failed to add pool TXG of %" PRIu64 "\n", 645 l, txg); 646 return (1); 647 } 648 } 649 650 return (0); 651 } 652 653 static boolean_t 654 zhack_repair_write_label(const int l, const int fd, const int byteswap, 655 void *data, zio_eck_t *eck, const uint64_t offset, const uint64_t abdsize) 656 { 657 zio_cksum_t actual_cksum; 658 zhack_repair_calc_cksum(byteswap, data, offset, abdsize, eck, 659 &actual_cksum); 660 zio_cksum_t expected_cksum = eck->zec_cksum; 661 ssize_t err; 662 663 if (ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum)) 664 return (B_FALSE); 665 666 eck->zec_cksum = actual_cksum; 667 668 err = pwrite64(fd, data, abdsize, offset); 669 if (err == -1) { 670 (void) fprintf(stderr, "error: cannot write label %d: %s\n", 671 l, strerror(errno)); 672 return (B_FALSE); 673 } else if (err != abdsize) { 674 (void) fprintf(stderr, "error: bad write size label %d\n", l); 675 return (B_FALSE); 676 } else { 677 (void) fprintf(stderr, 678 "label %d: wrote %" PRIu64 " bytes at offset %" PRIu64 "\n", 679 l, abdsize, offset); 680 } 681 682 return (B_TRUE); 683 } 684 685 static void 686 zhack_repair_write_uberblock(vdev_label_t *vl, const int l, 687 const uint64_t ashift, const int fd, const int byteswap, 688 const uint64_t label_offset, uint32_t *labels_repaired) 689 { 690 void *ub_data = 691 (char *)vl + offsetof(vdev_label_t, vl_uberblock); 692 zio_eck_t *ub_eck = 693 (zio_eck_t *) 694 ((char *)(ub_data) + (ASHIFT_UBERBLOCK_SIZE(ashift))) - 1; 695 696 if (ub_eck->zec_magic != 0) { 697 (void) fprintf(stderr, 698 "error: label %d: " 699 "Expected Uberblock checksum magic number to " 700 "be 0, but got %" PRIu64 "\n", 701 l, ub_eck->zec_magic); 702 (void) fprintf(stderr, "It would appear there's already " 703 "a checksum for the uberblock.\n"); 704 return; 705 } 706 707 708 ub_eck->zec_magic = byteswap ? BSWAP_64(ZEC_MAGIC) : ZEC_MAGIC; 709 710 if (zhack_repair_write_label(l, fd, byteswap, 711 ub_data, ub_eck, 712 label_offset + offsetof(vdev_label_t, vl_uberblock), 713 ASHIFT_UBERBLOCK_SIZE(ashift))) 714 labels_repaired[l] |= REPAIR_LABEL_STATUS_UB; 715 } 716 717 static void 718 zhack_repair_print_cksum(FILE *stream, const zio_cksum_t *cksum) 719 { 720 (void) fprintf(stream, 721 "%016llx:%016llx:%016llx:%016llx", 722 (u_longlong_t)cksum->zc_word[0], 723 (u_longlong_t)cksum->zc_word[1], 724 (u_longlong_t)cksum->zc_word[2], 725 (u_longlong_t)cksum->zc_word[3]); 726 } 727 728 static int 729 zhack_repair_test_cksum(const int byteswap, void *vdev_data, 730 zio_eck_t *vdev_eck, const uint64_t vdev_phys_offset, const int l) 731 { 732 const zio_cksum_t expected_cksum = vdev_eck->zec_cksum; 733 zio_cksum_t actual_cksum; 734 zhack_repair_calc_cksum(byteswap, vdev_data, vdev_phys_offset, 735 VDEV_PHYS_SIZE, vdev_eck, &actual_cksum); 736 const uint64_t expected_magic = byteswap ? 737 BSWAP_64(ZEC_MAGIC) : ZEC_MAGIC; 738 const uint64_t actual_magic = vdev_eck->zec_magic; 739 int err = 0; 740 if (actual_magic != expected_magic) { 741 (void) fprintf(stderr, "error: label %d: " 742 "Expected " 743 "the nvlist checksum magic number to not be %" 744 PRIu64 " not %" PRIu64 "\n", 745 l, expected_magic, actual_magic); 746 err = ECKSUM; 747 } 748 if (!ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum)) { 749 (void) fprintf(stderr, "error: label %d: " 750 "Expected the nvlist checksum to be ", l); 751 (void) zhack_repair_print_cksum(stderr, 752 &expected_cksum); 753 (void) fprintf(stderr, " not "); 754 zhack_repair_print_cksum(stderr, &actual_cksum); 755 (void) fprintf(stderr, "\n"); 756 err = ECKSUM; 757 } 758 return (err); 759 } 760 761 static void 762 zhack_repair_one_label(const zhack_repair_op_t op, const int fd, 763 vdev_label_t *vl, const uint64_t label_offset, const int l, 764 uint32_t *labels_repaired) 765 { 766 ssize_t err; 767 uberblock_t *ub = (uberblock_t *)vl->vl_uberblock; 768 void *vdev_data = 769 (char *)vl + offsetof(vdev_label_t, vl_vdev_phys); 770 zio_eck_t *vdev_eck = 771 (zio_eck_t *)((char *)(vdev_data) + VDEV_PHYS_SIZE) - 1; 772 const uint64_t vdev_phys_offset = 773 label_offset + offsetof(vdev_label_t, vl_vdev_phys); 774 const char *cfg_keys[] = { ZPOOL_CONFIG_VERSION, 775 ZPOOL_CONFIG_POOL_STATE, ZPOOL_CONFIG_GUID }; 776 nvlist_t *cfg; 777 nvlist_t *vdev_tree_cfg = NULL; 778 uint64_t ashift; 779 int byteswap; 780 781 err = zhack_repair_read_label(fd, vl, label_offset, l); 782 if (err) 783 return; 784 785 if (vdev_eck->zec_magic == 0) { 786 (void) fprintf(stderr, "error: label %d: " 787 "Expected the nvlist checksum magic number to not be zero" 788 "\n", 789 l); 790 (void) fprintf(stderr, "There should already be a checksum " 791 "for the label.\n"); 792 return; 793 } 794 795 byteswap = 796 (vdev_eck->zec_magic == BSWAP_64((uint64_t)ZEC_MAGIC)); 797 798 if (byteswap) { 799 byteswap_uint64_array(&vdev_eck->zec_cksum, 800 sizeof (zio_cksum_t)); 801 vdev_eck->zec_magic = BSWAP_64(vdev_eck->zec_magic); 802 } 803 804 if ((op & ZHACK_REPAIR_OP_CKSUM) == 0 && 805 zhack_repair_test_cksum(byteswap, vdev_data, vdev_eck, 806 vdev_phys_offset, l) != 0) { 807 (void) fprintf(stderr, "It would appear checksums are " 808 "corrupted. Try zhack repair label -c <device>\n"); 809 return; 810 } 811 812 err = nvlist_unpack(vl->vl_vdev_phys.vp_nvlist, 813 VDEV_PHYS_SIZE - sizeof (zio_eck_t), &cfg, 0); 814 if (err) { 815 (void) fprintf(stderr, 816 "error: cannot unpack nvlist label %d\n", l); 817 return; 818 } 819 820 err = zhack_repair_check_label(ub, 821 l, cfg_keys, ARRAY_SIZE(cfg_keys), cfg, vdev_tree_cfg, &ashift); 822 if (err) 823 return; 824 825 if ((op & ZHACK_REPAIR_OP_UNDETACH) != 0) { 826 char *buf; 827 size_t buflen; 828 829 err = zhack_repair_undetach(ub, cfg, l); 830 if (err) 831 return; 832 833 buf = vl->vl_vdev_phys.vp_nvlist; 834 buflen = VDEV_PHYS_SIZE - sizeof (zio_eck_t); 835 if (nvlist_pack(cfg, &buf, &buflen, NV_ENCODE_XDR, 0) != 0) { 836 (void) fprintf(stderr, 837 "error: label %d: Failed to pack nvlist\n", l); 838 return; 839 } 840 841 zhack_repair_write_uberblock(vl, 842 l, ashift, fd, byteswap, label_offset, labels_repaired); 843 } 844 845 if (zhack_repair_write_label(l, fd, byteswap, vdev_data, vdev_eck, 846 vdev_phys_offset, VDEV_PHYS_SIZE)) 847 labels_repaired[l] |= REPAIR_LABEL_STATUS_CKSUM; 848 849 fsync(fd); 850 } 851 852 static const char * 853 zhack_repair_label_status(const uint32_t label_status, 854 const uint32_t to_check) 855 { 856 return ((label_status & to_check) != 0 ? "repaired" : "skipped"); 857 } 858 859 static int 860 zhack_label_repair(const zhack_repair_op_t op, const int argc, char **argv) 861 { 862 uint32_t labels_repaired[VDEV_LABELS] = {0}; 863 vdev_label_t labels[VDEV_LABELS] = {{{0}}}; 864 struct stat64 st; 865 int fd; 866 off_t filesize; 867 uint32_t repaired = 0; 868 869 abd_init(); 870 871 if (argc < 1) { 872 (void) fprintf(stderr, "error: missing device\n"); 873 usage(); 874 } 875 876 if ((fd = open(argv[0], O_RDWR)) == -1) 877 fatal(NULL, FTAG, "cannot open '%s': %s", argv[0], 878 strerror(errno)); 879 880 if (fstat64_blk(fd, &st) != 0) 881 fatal(NULL, FTAG, "cannot stat '%s': %s", argv[0], 882 strerror(errno)); 883 884 filesize = st.st_size; 885 (void) fprintf(stderr, "Calculated filesize to be %jd\n", 886 (intmax_t)filesize); 887 888 if (filesize % sizeof (vdev_label_t) != 0) 889 filesize = 890 (filesize / sizeof (vdev_label_t)) * sizeof (vdev_label_t); 891 892 for (int l = 0; l < VDEV_LABELS; l++) { 893 zhack_repair_one_label(op, fd, &labels[l], 894 vdev_label_offset(filesize, l, 0), l, labels_repaired); 895 } 896 897 close(fd); 898 899 abd_fini(); 900 901 for (int l = 0; l < VDEV_LABELS; l++) { 902 const uint32_t lr = labels_repaired[l]; 903 (void) printf("label %d: ", l); 904 (void) printf("uberblock: %s ", 905 zhack_repair_label_status(lr, REPAIR_LABEL_STATUS_UB)); 906 (void) printf("checksum: %s\n", 907 zhack_repair_label_status(lr, REPAIR_LABEL_STATUS_CKSUM)); 908 repaired |= lr; 909 } 910 911 if (repaired > 0) 912 return (0); 913 914 return (1); 915 } 916 917 static int 918 zhack_do_label_repair(int argc, char **argv) 919 { 920 zhack_repair_op_t op = ZHACK_REPAIR_OP_UNKNOWN; 921 int c; 922 923 optind = 1; 924 while ((c = getopt(argc, argv, "+cu")) != -1) { 925 switch (c) { 926 case 'c': 927 op |= ZHACK_REPAIR_OP_CKSUM; 928 break; 929 case 'u': 930 op |= ZHACK_REPAIR_OP_UNDETACH; 931 break; 932 default: 933 usage(); 934 break; 935 } 936 } 937 938 argc -= optind; 939 argv += optind; 940 941 if (op == ZHACK_REPAIR_OP_UNKNOWN) 942 op = ZHACK_REPAIR_OP_CKSUM; 943 944 return (zhack_label_repair(op, argc, argv)); 945 } 946 947 static int 948 zhack_do_label(int argc, char **argv) 949 { 950 char *subcommand; 951 int err; 952 953 argc--; 954 argv++; 955 if (argc == 0) { 956 (void) fprintf(stderr, 957 "error: no label operation specified\n"); 958 usage(); 959 } 960 961 subcommand = argv[0]; 962 if (strcmp(subcommand, "repair") == 0) { 963 err = zhack_do_label_repair(argc, argv); 964 } else { 965 (void) fprintf(stderr, "error: unknown subcommand: %s\n", 966 subcommand); 967 usage(); 968 } 969 970 return (err); 971 } 972 973 #define MAX_NUM_PATHS 1024 974 975 int 976 main(int argc, char **argv) 977 { 978 char *path[MAX_NUM_PATHS]; 979 const char *subcommand; 980 int rv = 0; 981 int c; 982 983 g_importargs.path = path; 984 985 dprintf_setup(&argc, argv); 986 zfs_prop_init(); 987 988 while ((c = getopt(argc, argv, "+c:d:")) != -1) { 989 switch (c) { 990 case 'c': 991 g_importargs.cachefile = optarg; 992 break; 993 case 'd': 994 assert(g_importargs.paths < MAX_NUM_PATHS); 995 g_importargs.path[g_importargs.paths++] = optarg; 996 break; 997 default: 998 usage(); 999 break; 1000 } 1001 } 1002 1003 argc -= optind; 1004 argv += optind; 1005 optind = 1; 1006 1007 if (argc == 0) { 1008 (void) fprintf(stderr, "error: no command specified\n"); 1009 usage(); 1010 } 1011 1012 subcommand = argv[0]; 1013 1014 if (strcmp(subcommand, "feature") == 0) { 1015 rv = zhack_do_feature(argc, argv); 1016 } else if (strcmp(subcommand, "label") == 0) { 1017 return (zhack_do_label(argc, argv)); 1018 } else { 1019 (void) fprintf(stderr, "error: unknown subcommand: %s\n", 1020 subcommand); 1021 usage(); 1022 } 1023 1024 if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_FALSE) != 0) { 1025 fatal(NULL, FTAG, "pool export failed; " 1026 "changes may not be committed to disk\n"); 1027 } 1028 1029 kernel_fini(); 1030 1031 return (rv); 1032 } 1033