1716fd348SMartin Matuska /* 2716fd348SMartin Matuska * CDDL HEADER START 3716fd348SMartin Matuska * 4716fd348SMartin Matuska * The contents of this file are subject to the terms of the 5716fd348SMartin Matuska * Common Development and Distribution License (the "License"). 6716fd348SMartin Matuska * You may not use this file except in compliance with the License. 7716fd348SMartin Matuska * 8716fd348SMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 10716fd348SMartin Matuska * See the License for the specific language governing permissions 11716fd348SMartin Matuska * and limitations under the License. 12716fd348SMartin Matuska * 13716fd348SMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each 14716fd348SMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15716fd348SMartin Matuska * If applicable, add the following below this CDDL HEADER, with the 16716fd348SMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying 17716fd348SMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner] 18716fd348SMartin Matuska * 19716fd348SMartin Matuska * CDDL HEADER END 20716fd348SMartin Matuska */ 21716fd348SMartin Matuska 22716fd348SMartin Matuska /* 23716fd348SMartin Matuska * Copyright (c) 2011, 2015 by Delphix. All rights reserved. 24716fd348SMartin Matuska * Copyright (c) 2013 Steven Hartland. All rights reserved. 25716fd348SMartin Matuska */ 26716fd348SMartin Matuska 27716fd348SMartin Matuska /* 28716fd348SMartin Matuska * zhack is a debugging tool that can write changes to ZFS pool using libzpool 29716fd348SMartin Matuska * for testing purposes. Altering pools with zhack is unsupported and may 30716fd348SMartin Matuska * result in corrupted pools. 31716fd348SMartin Matuska */ 32716fd348SMartin Matuska 33*15f0b8c3SMartin Matuska #include <zfs_prop.h> 34716fd348SMartin Matuska #include <stdio.h> 35716fd348SMartin Matuska #include <stdlib.h> 36716fd348SMartin Matuska #include <ctype.h> 37716fd348SMartin Matuska #include <sys/stat.h> 38716fd348SMartin Matuska #include <sys/zfs_context.h> 39716fd348SMartin Matuska #include <sys/spa.h> 40716fd348SMartin Matuska #include <sys/spa_impl.h> 41716fd348SMartin Matuska #include <sys/dmu.h> 42716fd348SMartin Matuska #include <sys/zap.h> 43716fd348SMartin Matuska #include <sys/zfs_znode.h> 44716fd348SMartin Matuska #include <sys/dsl_synctask.h> 45716fd348SMartin Matuska #include <sys/vdev.h> 46716fd348SMartin Matuska #include <sys/vdev_impl.h> 47716fd348SMartin Matuska #include <sys/fs/zfs.h> 48716fd348SMartin Matuska #include <sys/dmu_objset.h> 49716fd348SMartin Matuska #include <sys/dsl_pool.h> 50716fd348SMartin Matuska #include <sys/zio_checksum.h> 51716fd348SMartin Matuska #include <sys/zio_compress.h> 52716fd348SMartin Matuska #include <sys/zfeature.h> 53716fd348SMartin Matuska #include <sys/dmu_tx.h> 54716fd348SMartin Matuska #include <zfeature_common.h> 55716fd348SMartin Matuska #include <libzutil.h> 56716fd348SMartin Matuska 57716fd348SMartin Matuska static importargs_t g_importargs; 58716fd348SMartin Matuska static char *g_pool; 59716fd348SMartin Matuska static boolean_t g_readonly; 60716fd348SMartin Matuska 61716fd348SMartin Matuska static __attribute__((noreturn)) void 62716fd348SMartin Matuska usage(void) 63716fd348SMartin Matuska { 64716fd348SMartin Matuska (void) fprintf(stderr, 65716fd348SMartin Matuska "Usage: zhack [-c cachefile] [-d dir] <subcommand> <args> ...\n" 66716fd348SMartin Matuska "where <subcommand> <args> is one of the following:\n" 67716fd348SMartin Matuska "\n"); 68716fd348SMartin Matuska 69716fd348SMartin Matuska (void) fprintf(stderr, 70716fd348SMartin Matuska " feature stat <pool>\n" 71716fd348SMartin Matuska " print information about enabled features\n" 72716fd348SMartin Matuska " feature enable [-r] [-d desc] <pool> <feature>\n" 73716fd348SMartin Matuska " add a new enabled feature to the pool\n" 74716fd348SMartin Matuska " -d <desc> sets the feature's description\n" 75716fd348SMartin Matuska " -r set read-only compatible flag for feature\n" 76716fd348SMartin Matuska " feature ref [-md] <pool> <feature>\n" 77716fd348SMartin Matuska " change the refcount on the given feature\n" 78716fd348SMartin Matuska " -d decrease instead of increase the refcount\n" 79716fd348SMartin Matuska " -m add the feature to the label if increasing refcount\n" 80716fd348SMartin Matuska "\n" 81716fd348SMartin Matuska " <feature> : should be a feature guid\n" 82716fd348SMartin Matuska "\n" 83716fd348SMartin Matuska " label repair <device>\n" 84716fd348SMartin Matuska " repair corrupted label checksums\n" 85716fd348SMartin Matuska "\n" 86716fd348SMartin Matuska " <device> : path to vdev\n"); 87716fd348SMartin Matuska exit(1); 88716fd348SMartin Matuska } 89716fd348SMartin Matuska 90716fd348SMartin Matuska 91716fd348SMartin Matuska static __attribute__((format(printf, 3, 4))) __attribute__((noreturn)) void 92a0b956f5SMartin Matuska fatal(spa_t *spa, const void *tag, const char *fmt, ...) 93716fd348SMartin Matuska { 94716fd348SMartin Matuska va_list ap; 95716fd348SMartin Matuska 96716fd348SMartin Matuska if (spa != NULL) { 97716fd348SMartin Matuska spa_close(spa, tag); 98716fd348SMartin Matuska (void) spa_export(g_pool, NULL, B_TRUE, B_FALSE); 99716fd348SMartin Matuska } 100716fd348SMartin Matuska 101716fd348SMartin Matuska va_start(ap, fmt); 102716fd348SMartin Matuska (void) fputs("zhack: ", stderr); 103716fd348SMartin Matuska (void) vfprintf(stderr, fmt, ap); 104716fd348SMartin Matuska va_end(ap); 105716fd348SMartin Matuska (void) fputc('\n', stderr); 106716fd348SMartin Matuska 107716fd348SMartin Matuska exit(1); 108716fd348SMartin Matuska } 109716fd348SMartin Matuska 110716fd348SMartin Matuska static int 111716fd348SMartin Matuska space_delta_cb(dmu_object_type_t bonustype, const void *data, 112716fd348SMartin Matuska zfs_file_info_t *zoi) 113716fd348SMartin Matuska { 114716fd348SMartin Matuska (void) data, (void) zoi; 115716fd348SMartin Matuska 116716fd348SMartin Matuska /* 117716fd348SMartin Matuska * Is it a valid type of object to track? 118716fd348SMartin Matuska */ 119716fd348SMartin Matuska if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA) 120716fd348SMartin Matuska return (ENOENT); 121716fd348SMartin Matuska (void) fprintf(stderr, "modifying object that needs user accounting"); 122716fd348SMartin Matuska abort(); 123716fd348SMartin Matuska } 124716fd348SMartin Matuska 125716fd348SMartin Matuska /* 126716fd348SMartin Matuska * Target is the dataset whose pool we want to open. 127716fd348SMartin Matuska */ 128716fd348SMartin Matuska static void 129716fd348SMartin Matuska zhack_import(char *target, boolean_t readonly) 130716fd348SMartin Matuska { 131716fd348SMartin Matuska nvlist_t *config; 132716fd348SMartin Matuska nvlist_t *props; 133716fd348SMartin Matuska int error; 134716fd348SMartin Matuska 135716fd348SMartin Matuska kernel_init(readonly ? SPA_MODE_READ : 136716fd348SMartin Matuska (SPA_MODE_READ | SPA_MODE_WRITE)); 137716fd348SMartin Matuska 138716fd348SMartin Matuska dmu_objset_register_type(DMU_OST_ZFS, space_delta_cb); 139716fd348SMartin Matuska 140716fd348SMartin Matuska g_readonly = readonly; 141716fd348SMartin Matuska g_importargs.can_be_active = readonly; 142716fd348SMartin Matuska g_pool = strdup(target); 143716fd348SMartin Matuska 144dbd5678dSMartin Matuska libpc_handle_t lpch = { 145dbd5678dSMartin Matuska .lpc_lib_handle = NULL, 146dbd5678dSMartin Matuska .lpc_ops = &libzpool_config_ops, 147dbd5678dSMartin Matuska .lpc_printerr = B_TRUE 148dbd5678dSMartin Matuska }; 149dbd5678dSMartin Matuska error = zpool_find_config(&lpch, target, &config, &g_importargs); 150716fd348SMartin Matuska if (error) 151716fd348SMartin Matuska fatal(NULL, FTAG, "cannot import '%s'", target); 152716fd348SMartin Matuska 153716fd348SMartin Matuska props = NULL; 154716fd348SMartin Matuska if (readonly) { 155716fd348SMartin Matuska VERIFY(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0); 156716fd348SMartin Matuska VERIFY(nvlist_add_uint64(props, 157716fd348SMartin Matuska zpool_prop_to_name(ZPOOL_PROP_READONLY), 1) == 0); 158716fd348SMartin Matuska } 159716fd348SMartin Matuska 160716fd348SMartin Matuska zfeature_checks_disable = B_TRUE; 161716fd348SMartin Matuska error = spa_import(target, config, props, 162716fd348SMartin Matuska (readonly ? ZFS_IMPORT_SKIP_MMP : ZFS_IMPORT_NORMAL)); 163716fd348SMartin Matuska fnvlist_free(config); 164716fd348SMartin Matuska zfeature_checks_disable = B_FALSE; 165716fd348SMartin Matuska if (error == EEXIST) 166716fd348SMartin Matuska error = 0; 167716fd348SMartin Matuska 168716fd348SMartin Matuska if (error) 169716fd348SMartin Matuska fatal(NULL, FTAG, "can't import '%s': %s", target, 170716fd348SMartin Matuska strerror(error)); 171716fd348SMartin Matuska } 172716fd348SMartin Matuska 173716fd348SMartin Matuska static void 174a0b956f5SMartin Matuska zhack_spa_open(char *target, boolean_t readonly, const void *tag, spa_t **spa) 175716fd348SMartin Matuska { 176716fd348SMartin Matuska int err; 177716fd348SMartin Matuska 178716fd348SMartin Matuska zhack_import(target, readonly); 179716fd348SMartin Matuska 180716fd348SMartin Matuska zfeature_checks_disable = B_TRUE; 181716fd348SMartin Matuska err = spa_open(target, spa, tag); 182716fd348SMartin Matuska zfeature_checks_disable = B_FALSE; 183716fd348SMartin Matuska 184716fd348SMartin Matuska if (err != 0) 185716fd348SMartin Matuska fatal(*spa, FTAG, "cannot open '%s': %s", target, 186716fd348SMartin Matuska strerror(err)); 187716fd348SMartin Matuska if (spa_version(*spa) < SPA_VERSION_FEATURES) { 188716fd348SMartin Matuska fatal(*spa, FTAG, "'%s' has version %d, features not enabled", 189716fd348SMartin Matuska target, (int)spa_version(*spa)); 190716fd348SMartin Matuska } 191716fd348SMartin Matuska } 192716fd348SMartin Matuska 193716fd348SMartin Matuska static void 194716fd348SMartin Matuska dump_obj(objset_t *os, uint64_t obj, const char *name) 195716fd348SMartin Matuska { 196716fd348SMartin Matuska zap_cursor_t zc; 197716fd348SMartin Matuska zap_attribute_t za; 198716fd348SMartin Matuska 199716fd348SMartin Matuska (void) printf("%s_obj:\n", name); 200716fd348SMartin Matuska 201716fd348SMartin Matuska for (zap_cursor_init(&zc, os, obj); 202716fd348SMartin Matuska zap_cursor_retrieve(&zc, &za) == 0; 203716fd348SMartin Matuska zap_cursor_advance(&zc)) { 204716fd348SMartin Matuska if (za.za_integer_length == 8) { 205716fd348SMartin Matuska ASSERT(za.za_num_integers == 1); 206716fd348SMartin Matuska (void) printf("\t%s = %llu\n", 207716fd348SMartin Matuska za.za_name, (u_longlong_t)za.za_first_integer); 208716fd348SMartin Matuska } else { 209716fd348SMartin Matuska ASSERT(za.za_integer_length == 1); 210716fd348SMartin Matuska char val[1024]; 211716fd348SMartin Matuska VERIFY(zap_lookup(os, obj, za.za_name, 212716fd348SMartin Matuska 1, sizeof (val), val) == 0); 213716fd348SMartin Matuska (void) printf("\t%s = %s\n", za.za_name, val); 214716fd348SMartin Matuska } 215716fd348SMartin Matuska } 216716fd348SMartin Matuska zap_cursor_fini(&zc); 217716fd348SMartin Matuska } 218716fd348SMartin Matuska 219716fd348SMartin Matuska static void 220716fd348SMartin Matuska dump_mos(spa_t *spa) 221716fd348SMartin Matuska { 222716fd348SMartin Matuska nvlist_t *nv = spa->spa_label_features; 223716fd348SMartin Matuska nvpair_t *pair; 224716fd348SMartin Matuska 225716fd348SMartin Matuska (void) printf("label config:\n"); 226716fd348SMartin Matuska for (pair = nvlist_next_nvpair(nv, NULL); 227716fd348SMartin Matuska pair != NULL; 228716fd348SMartin Matuska pair = nvlist_next_nvpair(nv, pair)) { 229716fd348SMartin Matuska (void) printf("\t%s\n", nvpair_name(pair)); 230716fd348SMartin Matuska } 231716fd348SMartin Matuska } 232716fd348SMartin Matuska 233716fd348SMartin Matuska static void 234716fd348SMartin Matuska zhack_do_feature_stat(int argc, char **argv) 235716fd348SMartin Matuska { 236716fd348SMartin Matuska spa_t *spa; 237716fd348SMartin Matuska objset_t *os; 238716fd348SMartin Matuska char *target; 239716fd348SMartin Matuska 240716fd348SMartin Matuska argc--; 241716fd348SMartin Matuska argv++; 242716fd348SMartin Matuska 243716fd348SMartin Matuska if (argc < 1) { 244716fd348SMartin Matuska (void) fprintf(stderr, "error: missing pool name\n"); 245716fd348SMartin Matuska usage(); 246716fd348SMartin Matuska } 247716fd348SMartin Matuska target = argv[0]; 248716fd348SMartin Matuska 249716fd348SMartin Matuska zhack_spa_open(target, B_TRUE, FTAG, &spa); 250716fd348SMartin Matuska os = spa->spa_meta_objset; 251716fd348SMartin Matuska 252716fd348SMartin Matuska dump_obj(os, spa->spa_feat_for_read_obj, "for_read"); 253716fd348SMartin Matuska dump_obj(os, spa->spa_feat_for_write_obj, "for_write"); 254716fd348SMartin Matuska dump_obj(os, spa->spa_feat_desc_obj, "descriptions"); 255716fd348SMartin Matuska if (spa_feature_is_active(spa, SPA_FEATURE_ENABLED_TXG)) { 256716fd348SMartin Matuska dump_obj(os, spa->spa_feat_enabled_txg_obj, "enabled_txg"); 257716fd348SMartin Matuska } 258716fd348SMartin Matuska dump_mos(spa); 259716fd348SMartin Matuska 260716fd348SMartin Matuska spa_close(spa, FTAG); 261716fd348SMartin Matuska } 262716fd348SMartin Matuska 263716fd348SMartin Matuska static void 264716fd348SMartin Matuska zhack_feature_enable_sync(void *arg, dmu_tx_t *tx) 265716fd348SMartin Matuska { 266716fd348SMartin Matuska spa_t *spa = dmu_tx_pool(tx)->dp_spa; 267716fd348SMartin Matuska zfeature_info_t *feature = arg; 268716fd348SMartin Matuska 269716fd348SMartin Matuska feature_enable_sync(spa, feature, tx); 270716fd348SMartin Matuska 271716fd348SMartin Matuska spa_history_log_internal(spa, "zhack enable feature", tx, 272716fd348SMartin Matuska "name=%s flags=%u", 273716fd348SMartin Matuska feature->fi_guid, feature->fi_flags); 274716fd348SMartin Matuska } 275716fd348SMartin Matuska 276716fd348SMartin Matuska static void 277716fd348SMartin Matuska zhack_do_feature_enable(int argc, char **argv) 278716fd348SMartin Matuska { 279716fd348SMartin Matuska int c; 280716fd348SMartin Matuska char *desc, *target; 281716fd348SMartin Matuska spa_t *spa; 282716fd348SMartin Matuska objset_t *mos; 283716fd348SMartin Matuska zfeature_info_t feature; 284716fd348SMartin Matuska const spa_feature_t nodeps[] = { SPA_FEATURE_NONE }; 285716fd348SMartin Matuska 286716fd348SMartin Matuska /* 287716fd348SMartin Matuska * Features are not added to the pool's label until their refcounts 288716fd348SMartin Matuska * are incremented, so fi_mos can just be left as false for now. 289716fd348SMartin Matuska */ 290716fd348SMartin Matuska desc = NULL; 291716fd348SMartin Matuska feature.fi_uname = "zhack"; 292716fd348SMartin Matuska feature.fi_flags = 0; 293716fd348SMartin Matuska feature.fi_depends = nodeps; 294716fd348SMartin Matuska feature.fi_feature = SPA_FEATURE_NONE; 295716fd348SMartin Matuska 296716fd348SMartin Matuska optind = 1; 297716fd348SMartin Matuska while ((c = getopt(argc, argv, "+rd:")) != -1) { 298716fd348SMartin Matuska switch (c) { 299716fd348SMartin Matuska case 'r': 300716fd348SMartin Matuska feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT; 301716fd348SMartin Matuska break; 302716fd348SMartin Matuska case 'd': 303be181ee2SMartin Matuska if (desc != NULL) 304be181ee2SMartin Matuska free(desc); 305716fd348SMartin Matuska desc = strdup(optarg); 306716fd348SMartin Matuska break; 307716fd348SMartin Matuska default: 308716fd348SMartin Matuska usage(); 309716fd348SMartin Matuska break; 310716fd348SMartin Matuska } 311716fd348SMartin Matuska } 312716fd348SMartin Matuska 313716fd348SMartin Matuska if (desc == NULL) 314716fd348SMartin Matuska desc = strdup("zhack injected"); 315716fd348SMartin Matuska feature.fi_desc = desc; 316716fd348SMartin Matuska 317716fd348SMartin Matuska argc -= optind; 318716fd348SMartin Matuska argv += optind; 319716fd348SMartin Matuska 320716fd348SMartin Matuska if (argc < 2) { 321716fd348SMartin Matuska (void) fprintf(stderr, "error: missing feature or pool name\n"); 322716fd348SMartin Matuska usage(); 323716fd348SMartin Matuska } 324716fd348SMartin Matuska target = argv[0]; 325716fd348SMartin Matuska feature.fi_guid = argv[1]; 326716fd348SMartin Matuska 327716fd348SMartin Matuska if (!zfeature_is_valid_guid(feature.fi_guid)) 328716fd348SMartin Matuska fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid); 329716fd348SMartin Matuska 330716fd348SMartin Matuska zhack_spa_open(target, B_FALSE, FTAG, &spa); 331716fd348SMartin Matuska mos = spa->spa_meta_objset; 332716fd348SMartin Matuska 333716fd348SMartin Matuska if (zfeature_is_supported(feature.fi_guid)) 334716fd348SMartin Matuska fatal(spa, FTAG, "'%s' is a real feature, will not enable", 335716fd348SMartin Matuska feature.fi_guid); 336716fd348SMartin Matuska if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid)) 337716fd348SMartin Matuska fatal(spa, FTAG, "feature already enabled: %s", 338716fd348SMartin Matuska feature.fi_guid); 339716fd348SMartin Matuska 340716fd348SMartin Matuska VERIFY0(dsl_sync_task(spa_name(spa), NULL, 341716fd348SMartin Matuska zhack_feature_enable_sync, &feature, 5, ZFS_SPACE_CHECK_NORMAL)); 342716fd348SMartin Matuska 343716fd348SMartin Matuska spa_close(spa, FTAG); 344716fd348SMartin Matuska 345716fd348SMartin Matuska free(desc); 346716fd348SMartin Matuska } 347716fd348SMartin Matuska 348716fd348SMartin Matuska static void 349716fd348SMartin Matuska feature_incr_sync(void *arg, dmu_tx_t *tx) 350716fd348SMartin Matuska { 351716fd348SMartin Matuska spa_t *spa = dmu_tx_pool(tx)->dp_spa; 352716fd348SMartin Matuska zfeature_info_t *feature = arg; 353716fd348SMartin Matuska uint64_t refcount; 354716fd348SMartin Matuska 355716fd348SMartin Matuska VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount)); 356716fd348SMartin Matuska feature_sync(spa, feature, refcount + 1, tx); 357716fd348SMartin Matuska spa_history_log_internal(spa, "zhack feature incr", tx, 358716fd348SMartin Matuska "name=%s", feature->fi_guid); 359716fd348SMartin Matuska } 360716fd348SMartin Matuska 361716fd348SMartin Matuska static void 362716fd348SMartin Matuska feature_decr_sync(void *arg, dmu_tx_t *tx) 363716fd348SMartin Matuska { 364716fd348SMartin Matuska spa_t *spa = dmu_tx_pool(tx)->dp_spa; 365716fd348SMartin Matuska zfeature_info_t *feature = arg; 366716fd348SMartin Matuska uint64_t refcount; 367716fd348SMartin Matuska 368716fd348SMartin Matuska VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount)); 369716fd348SMartin Matuska feature_sync(spa, feature, refcount - 1, tx); 370716fd348SMartin Matuska spa_history_log_internal(spa, "zhack feature decr", tx, 371716fd348SMartin Matuska "name=%s", feature->fi_guid); 372716fd348SMartin Matuska } 373716fd348SMartin Matuska 374716fd348SMartin Matuska static void 375716fd348SMartin Matuska zhack_do_feature_ref(int argc, char **argv) 376716fd348SMartin Matuska { 377716fd348SMartin Matuska int c; 378716fd348SMartin Matuska char *target; 379716fd348SMartin Matuska boolean_t decr = B_FALSE; 380716fd348SMartin Matuska spa_t *spa; 381716fd348SMartin Matuska objset_t *mos; 382716fd348SMartin Matuska zfeature_info_t feature; 383716fd348SMartin Matuska const spa_feature_t nodeps[] = { SPA_FEATURE_NONE }; 384716fd348SMartin Matuska 385716fd348SMartin Matuska /* 386716fd348SMartin Matuska * fi_desc does not matter here because it was written to disk 387716fd348SMartin Matuska * when the feature was enabled, but we need to properly set the 388716fd348SMartin Matuska * feature for read or write based on the information we read off 389716fd348SMartin Matuska * disk later. 390716fd348SMartin Matuska */ 391716fd348SMartin Matuska feature.fi_uname = "zhack"; 392716fd348SMartin Matuska feature.fi_flags = 0; 393716fd348SMartin Matuska feature.fi_desc = NULL; 394716fd348SMartin Matuska feature.fi_depends = nodeps; 395716fd348SMartin Matuska feature.fi_feature = SPA_FEATURE_NONE; 396716fd348SMartin Matuska 397716fd348SMartin Matuska optind = 1; 398716fd348SMartin Matuska while ((c = getopt(argc, argv, "+md")) != -1) { 399716fd348SMartin Matuska switch (c) { 400716fd348SMartin Matuska case 'm': 401716fd348SMartin Matuska feature.fi_flags |= ZFEATURE_FLAG_MOS; 402716fd348SMartin Matuska break; 403716fd348SMartin Matuska case 'd': 404716fd348SMartin Matuska decr = B_TRUE; 405716fd348SMartin Matuska break; 406716fd348SMartin Matuska default: 407716fd348SMartin Matuska usage(); 408716fd348SMartin Matuska break; 409716fd348SMartin Matuska } 410716fd348SMartin Matuska } 411716fd348SMartin Matuska argc -= optind; 412716fd348SMartin Matuska argv += optind; 413716fd348SMartin Matuska 414716fd348SMartin Matuska if (argc < 2) { 415716fd348SMartin Matuska (void) fprintf(stderr, "error: missing feature or pool name\n"); 416716fd348SMartin Matuska usage(); 417716fd348SMartin Matuska } 418716fd348SMartin Matuska target = argv[0]; 419716fd348SMartin Matuska feature.fi_guid = argv[1]; 420716fd348SMartin Matuska 421716fd348SMartin Matuska if (!zfeature_is_valid_guid(feature.fi_guid)) 422716fd348SMartin Matuska fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid); 423716fd348SMartin Matuska 424716fd348SMartin Matuska zhack_spa_open(target, B_FALSE, FTAG, &spa); 425716fd348SMartin Matuska mos = spa->spa_meta_objset; 426716fd348SMartin Matuska 427716fd348SMartin Matuska if (zfeature_is_supported(feature.fi_guid)) { 428716fd348SMartin Matuska fatal(spa, FTAG, 429716fd348SMartin Matuska "'%s' is a real feature, will not change refcount", 430716fd348SMartin Matuska feature.fi_guid); 431716fd348SMartin Matuska } 432716fd348SMartin Matuska 433716fd348SMartin Matuska if (0 == zap_contains(mos, spa->spa_feat_for_read_obj, 434716fd348SMartin Matuska feature.fi_guid)) { 435716fd348SMartin Matuska feature.fi_flags &= ~ZFEATURE_FLAG_READONLY_COMPAT; 436716fd348SMartin Matuska } else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj, 437716fd348SMartin Matuska feature.fi_guid)) { 438716fd348SMartin Matuska feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT; 439716fd348SMartin Matuska } else { 440716fd348SMartin Matuska fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid); 441716fd348SMartin Matuska } 442716fd348SMartin Matuska 443716fd348SMartin Matuska if (decr) { 444716fd348SMartin Matuska uint64_t count; 445716fd348SMartin Matuska if (feature_get_refcount_from_disk(spa, &feature, 446716fd348SMartin Matuska &count) == 0 && count == 0) { 447716fd348SMartin Matuska fatal(spa, FTAG, "feature refcount already 0: %s", 448716fd348SMartin Matuska feature.fi_guid); 449716fd348SMartin Matuska } 450716fd348SMartin Matuska } 451716fd348SMartin Matuska 452716fd348SMartin Matuska VERIFY0(dsl_sync_task(spa_name(spa), NULL, 453716fd348SMartin Matuska decr ? feature_decr_sync : feature_incr_sync, &feature, 454716fd348SMartin Matuska 5, ZFS_SPACE_CHECK_NORMAL)); 455716fd348SMartin Matuska 456716fd348SMartin Matuska spa_close(spa, FTAG); 457716fd348SMartin Matuska } 458716fd348SMartin Matuska 459716fd348SMartin Matuska static int 460716fd348SMartin Matuska zhack_do_feature(int argc, char **argv) 461716fd348SMartin Matuska { 462716fd348SMartin Matuska char *subcommand; 463716fd348SMartin Matuska 464716fd348SMartin Matuska argc--; 465716fd348SMartin Matuska argv++; 466716fd348SMartin Matuska if (argc == 0) { 467716fd348SMartin Matuska (void) fprintf(stderr, 468716fd348SMartin Matuska "error: no feature operation specified\n"); 469716fd348SMartin Matuska usage(); 470716fd348SMartin Matuska } 471716fd348SMartin Matuska 472716fd348SMartin Matuska subcommand = argv[0]; 473716fd348SMartin Matuska if (strcmp(subcommand, "stat") == 0) { 474716fd348SMartin Matuska zhack_do_feature_stat(argc, argv); 475716fd348SMartin Matuska } else if (strcmp(subcommand, "enable") == 0) { 476716fd348SMartin Matuska zhack_do_feature_enable(argc, argv); 477716fd348SMartin Matuska } else if (strcmp(subcommand, "ref") == 0) { 478716fd348SMartin Matuska zhack_do_feature_ref(argc, argv); 479716fd348SMartin Matuska } else { 480716fd348SMartin Matuska (void) fprintf(stderr, "error: unknown subcommand: %s\n", 481716fd348SMartin Matuska subcommand); 482716fd348SMartin Matuska usage(); 483716fd348SMartin Matuska } 484716fd348SMartin Matuska 485716fd348SMartin Matuska return (0); 486716fd348SMartin Matuska } 487716fd348SMartin Matuska 488716fd348SMartin Matuska static int 489716fd348SMartin Matuska zhack_repair_label_cksum(int argc, char **argv) 490716fd348SMartin Matuska { 491716fd348SMartin Matuska zio_checksum_info_t *ci = &zio_checksum_table[ZIO_CHECKSUM_LABEL]; 492716fd348SMartin Matuska const char *cfg_keys[] = { ZPOOL_CONFIG_VERSION, 493716fd348SMartin Matuska ZPOOL_CONFIG_POOL_STATE, ZPOOL_CONFIG_GUID }; 494716fd348SMartin Matuska boolean_t labels_repaired[VDEV_LABELS] = {0}; 495716fd348SMartin Matuska boolean_t repaired = B_FALSE; 496716fd348SMartin Matuska vdev_label_t labels[VDEV_LABELS] = {{{0}}}; 497716fd348SMartin Matuska struct stat st; 498716fd348SMartin Matuska int fd; 499716fd348SMartin Matuska 500716fd348SMartin Matuska abd_init(); 501716fd348SMartin Matuska 502716fd348SMartin Matuska argc -= 1; 503716fd348SMartin Matuska argv += 1; 504716fd348SMartin Matuska 505716fd348SMartin Matuska if (argc < 1) { 506716fd348SMartin Matuska (void) fprintf(stderr, "error: missing device\n"); 507716fd348SMartin Matuska usage(); 508716fd348SMartin Matuska } 509716fd348SMartin Matuska 510716fd348SMartin Matuska if ((fd = open(argv[0], O_RDWR)) == -1) 511716fd348SMartin Matuska fatal(NULL, FTAG, "cannot open '%s': %s", argv[0], 512716fd348SMartin Matuska strerror(errno)); 513716fd348SMartin Matuska 514716fd348SMartin Matuska if (stat(argv[0], &st) != 0) 515716fd348SMartin Matuska fatal(NULL, FTAG, "cannot stat '%s': %s", argv[0], 516716fd348SMartin Matuska strerror(errno)); 517716fd348SMartin Matuska 518716fd348SMartin Matuska for (int l = 0; l < VDEV_LABELS; l++) { 519716fd348SMartin Matuska uint64_t label_offset, offset; 520716fd348SMartin Matuska zio_cksum_t expected_cksum; 521716fd348SMartin Matuska zio_cksum_t actual_cksum; 522716fd348SMartin Matuska zio_cksum_t verifier; 523716fd348SMartin Matuska zio_eck_t *eck; 524716fd348SMartin Matuska nvlist_t *cfg; 525716fd348SMartin Matuska int byteswap; 526716fd348SMartin Matuska uint64_t val; 527716fd348SMartin Matuska ssize_t err; 528716fd348SMartin Matuska 529716fd348SMartin Matuska vdev_label_t *vl = &labels[l]; 530716fd348SMartin Matuska 531716fd348SMartin Matuska label_offset = vdev_label_offset(st.st_size, l, 0); 532716fd348SMartin Matuska err = pread64(fd, vl, sizeof (vdev_label_t), label_offset); 533716fd348SMartin Matuska if (err == -1) { 534716fd348SMartin Matuska (void) fprintf(stderr, "error: cannot read " 535716fd348SMartin Matuska "label %d: %s\n", l, strerror(errno)); 536716fd348SMartin Matuska continue; 537716fd348SMartin Matuska } else if (err != sizeof (vdev_label_t)) { 538716fd348SMartin Matuska (void) fprintf(stderr, "error: bad label %d read size " 539716fd348SMartin Matuska "\n", l); 540716fd348SMartin Matuska continue; 541716fd348SMartin Matuska } 542716fd348SMartin Matuska 543716fd348SMartin Matuska err = nvlist_unpack(vl->vl_vdev_phys.vp_nvlist, 544716fd348SMartin Matuska VDEV_PHYS_SIZE - sizeof (zio_eck_t), &cfg, 0); 545716fd348SMartin Matuska if (err) { 546716fd348SMartin Matuska (void) fprintf(stderr, "error: cannot unpack nvlist " 547716fd348SMartin Matuska "label %d\n", l); 548716fd348SMartin Matuska continue; 549716fd348SMartin Matuska } 550716fd348SMartin Matuska 551716fd348SMartin Matuska for (int i = 0; i < ARRAY_SIZE(cfg_keys); i++) { 552716fd348SMartin Matuska err = nvlist_lookup_uint64(cfg, cfg_keys[i], &val); 553716fd348SMartin Matuska if (err) { 554716fd348SMartin Matuska (void) fprintf(stderr, "error: label %d: " 555716fd348SMartin Matuska "cannot find nvlist key %s\n", 556716fd348SMartin Matuska l, cfg_keys[i]); 557716fd348SMartin Matuska continue; 558716fd348SMartin Matuska } 559716fd348SMartin Matuska } 560716fd348SMartin Matuska 561716fd348SMartin Matuska void *data = (char *)vl + offsetof(vdev_label_t, vl_vdev_phys); 562716fd348SMartin Matuska eck = (zio_eck_t *)((char *)(data) + VDEV_PHYS_SIZE) - 1; 563716fd348SMartin Matuska 564716fd348SMartin Matuska offset = label_offset + offsetof(vdev_label_t, vl_vdev_phys); 565716fd348SMartin Matuska ZIO_SET_CHECKSUM(&verifier, offset, 0, 0, 0); 566716fd348SMartin Matuska 567716fd348SMartin Matuska byteswap = (eck->zec_magic == BSWAP_64(ZEC_MAGIC)); 568716fd348SMartin Matuska if (byteswap) 569716fd348SMartin Matuska byteswap_uint64_array(&verifier, sizeof (zio_cksum_t)); 570716fd348SMartin Matuska 571716fd348SMartin Matuska expected_cksum = eck->zec_cksum; 572716fd348SMartin Matuska eck->zec_cksum = verifier; 573716fd348SMartin Matuska 574716fd348SMartin Matuska abd_t *abd = abd_get_from_buf(data, VDEV_PHYS_SIZE); 575716fd348SMartin Matuska ci->ci_func[byteswap](abd, VDEV_PHYS_SIZE, NULL, &actual_cksum); 576716fd348SMartin Matuska abd_free(abd); 577716fd348SMartin Matuska 578716fd348SMartin Matuska if (byteswap) 579716fd348SMartin Matuska byteswap_uint64_array(&expected_cksum, 580716fd348SMartin Matuska sizeof (zio_cksum_t)); 581716fd348SMartin Matuska 582716fd348SMartin Matuska if (ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum)) 583716fd348SMartin Matuska continue; 584716fd348SMartin Matuska 585716fd348SMartin Matuska eck->zec_cksum = actual_cksum; 586716fd348SMartin Matuska 587716fd348SMartin Matuska err = pwrite64(fd, data, VDEV_PHYS_SIZE, offset); 588716fd348SMartin Matuska if (err == -1) { 589716fd348SMartin Matuska (void) fprintf(stderr, "error: cannot write " 590716fd348SMartin Matuska "label %d: %s\n", l, strerror(errno)); 591716fd348SMartin Matuska continue; 592716fd348SMartin Matuska } else if (err != VDEV_PHYS_SIZE) { 593716fd348SMartin Matuska (void) fprintf(stderr, "error: bad write size " 594716fd348SMartin Matuska "label %d\n", l); 595716fd348SMartin Matuska continue; 596716fd348SMartin Matuska } 597716fd348SMartin Matuska 598716fd348SMartin Matuska fsync(fd); 599716fd348SMartin Matuska 600716fd348SMartin Matuska labels_repaired[l] = B_TRUE; 601716fd348SMartin Matuska } 602716fd348SMartin Matuska 603716fd348SMartin Matuska close(fd); 604716fd348SMartin Matuska 605716fd348SMartin Matuska abd_fini(); 606716fd348SMartin Matuska 607716fd348SMartin Matuska for (int l = 0; l < VDEV_LABELS; l++) { 608716fd348SMartin Matuska (void) printf("label %d: %s\n", l, 609716fd348SMartin Matuska labels_repaired[l] ? "repaired" : "skipped"); 610716fd348SMartin Matuska repaired |= labels_repaired[l]; 611716fd348SMartin Matuska } 612716fd348SMartin Matuska 613716fd348SMartin Matuska if (repaired) 614716fd348SMartin Matuska return (0); 615716fd348SMartin Matuska 616716fd348SMartin Matuska return (1); 617716fd348SMartin Matuska } 618716fd348SMartin Matuska 619716fd348SMartin Matuska static int 620716fd348SMartin Matuska zhack_do_label(int argc, char **argv) 621716fd348SMartin Matuska { 622716fd348SMartin Matuska char *subcommand; 623716fd348SMartin Matuska int err; 624716fd348SMartin Matuska 625716fd348SMartin Matuska argc--; 626716fd348SMartin Matuska argv++; 627716fd348SMartin Matuska if (argc == 0) { 628716fd348SMartin Matuska (void) fprintf(stderr, 629716fd348SMartin Matuska "error: no label operation specified\n"); 630716fd348SMartin Matuska usage(); 631716fd348SMartin Matuska } 632716fd348SMartin Matuska 633716fd348SMartin Matuska subcommand = argv[0]; 634716fd348SMartin Matuska if (strcmp(subcommand, "repair") == 0) { 635716fd348SMartin Matuska err = zhack_repair_label_cksum(argc, argv); 636716fd348SMartin Matuska } else { 637716fd348SMartin Matuska (void) fprintf(stderr, "error: unknown subcommand: %s\n", 638716fd348SMartin Matuska subcommand); 639716fd348SMartin Matuska usage(); 640716fd348SMartin Matuska } 641716fd348SMartin Matuska 642716fd348SMartin Matuska return (err); 643716fd348SMartin Matuska } 644716fd348SMartin Matuska 645716fd348SMartin Matuska #define MAX_NUM_PATHS 1024 646716fd348SMartin Matuska 647716fd348SMartin Matuska int 648716fd348SMartin Matuska main(int argc, char **argv) 649716fd348SMartin Matuska { 650716fd348SMartin Matuska char *path[MAX_NUM_PATHS]; 651716fd348SMartin Matuska const char *subcommand; 652716fd348SMartin Matuska int rv = 0; 653716fd348SMartin Matuska int c; 654716fd348SMartin Matuska 655716fd348SMartin Matuska g_importargs.path = path; 656716fd348SMartin Matuska 657716fd348SMartin Matuska dprintf_setup(&argc, argv); 658716fd348SMartin Matuska zfs_prop_init(); 659716fd348SMartin Matuska 660716fd348SMartin Matuska while ((c = getopt(argc, argv, "+c:d:")) != -1) { 661716fd348SMartin Matuska switch (c) { 662716fd348SMartin Matuska case 'c': 663716fd348SMartin Matuska g_importargs.cachefile = optarg; 664716fd348SMartin Matuska break; 665716fd348SMartin Matuska case 'd': 666716fd348SMartin Matuska assert(g_importargs.paths < MAX_NUM_PATHS); 667716fd348SMartin Matuska g_importargs.path[g_importargs.paths++] = optarg; 668716fd348SMartin Matuska break; 669716fd348SMartin Matuska default: 670716fd348SMartin Matuska usage(); 671716fd348SMartin Matuska break; 672716fd348SMartin Matuska } 673716fd348SMartin Matuska } 674716fd348SMartin Matuska 675716fd348SMartin Matuska argc -= optind; 676716fd348SMartin Matuska argv += optind; 677716fd348SMartin Matuska optind = 1; 678716fd348SMartin Matuska 679716fd348SMartin Matuska if (argc == 0) { 680716fd348SMartin Matuska (void) fprintf(stderr, "error: no command specified\n"); 681716fd348SMartin Matuska usage(); 682716fd348SMartin Matuska } 683716fd348SMartin Matuska 684716fd348SMartin Matuska subcommand = argv[0]; 685716fd348SMartin Matuska 686716fd348SMartin Matuska if (strcmp(subcommand, "feature") == 0) { 687716fd348SMartin Matuska rv = zhack_do_feature(argc, argv); 688716fd348SMartin Matuska } else if (strcmp(subcommand, "label") == 0) { 689716fd348SMartin Matuska return (zhack_do_label(argc, argv)); 690716fd348SMartin Matuska } else { 691716fd348SMartin Matuska (void) fprintf(stderr, "error: unknown subcommand: %s\n", 692716fd348SMartin Matuska subcommand); 693716fd348SMartin Matuska usage(); 694716fd348SMartin Matuska } 695716fd348SMartin Matuska 696716fd348SMartin Matuska if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_FALSE) != 0) { 697716fd348SMartin Matuska fatal(NULL, FTAG, "pool export failed; " 698716fd348SMartin Matuska "changes may not be committed to disk\n"); 699716fd348SMartin Matuska } 700716fd348SMartin Matuska 701716fd348SMartin Matuska kernel_fini(); 702716fd348SMartin Matuska 703716fd348SMartin Matuska return (rv); 704716fd348SMartin Matuska } 705