xref: /freebsd/sys/contrib/openzfs/cmd/zhack.c (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * This file and its contents are supplied under the terms of the
4  * Common Development and Distribution License ("CDDL"), version 1.0.
5  * You may only use this file in accordance with the terms of version
6  * 1.0 of the CDDL.
7  *
8  * A full copy of the text of the CDDL should have accompanied this
9  * source.  A copy of the CDDL is also available via the Internet at
10  * https://opensource.org/license/CDDL-1.0.
11  */
12 
13 /*
14  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
15  * Copyright (c) 2013 Steven Hartland. All rights reserved.
16  */
17 
18 /*
19  * zhack is a debugging tool that can write changes to ZFS pool using libzpool
20  * for testing purposes. Altering pools with zhack is unsupported and may
21  * result in corrupted pools.
22  */
23 
24 #include <zfs_prop.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <sys/stat.h>
29 #include <sys/zfs_context.h>
30 #include <sys/spa.h>
31 #include <sys/spa_impl.h>
32 #include <sys/dmu.h>
33 #include <sys/zap.h>
34 #include <sys/zfs_znode.h>
35 #include <sys/dsl_synctask.h>
36 #include <sys/vdev.h>
37 #include <sys/vdev_impl.h>
38 #include <sys/mmp.h>
39 #include <sys/fs/zfs.h>
40 #include <sys/dmu_objset.h>
41 #include <sys/dsl_pool.h>
42 #include <sys/zio_checksum.h>
43 #include <sys/zio_compress.h>
44 #include <sys/zfeature.h>
45 #include <sys/dmu_tx.h>
46 #include <sys/backtrace.h>
47 #include <zfeature_common.h>
48 #include <libzutil.h>
49 #include <sys/metaslab_impl.h>
50 #include <libzpool.h>
51 
52 static importargs_t g_importargs;
53 static char *g_pool;
54 static boolean_t g_readonly;
55 static boolean_t g_dump_dbgmsg;
56 
57 typedef enum {
58 	ZHACK_REPAIR_OP_UNKNOWN  = 0,
59 	ZHACK_REPAIR_OP_CKSUM    = (1 << 0),
60 	ZHACK_REPAIR_OP_UNDETACH = (1 << 1)
61 } zhack_repair_op_t;
62 
63 static __attribute__((noreturn)) void
usage(void)64 usage(void)
65 {
66 	(void) fprintf(stderr,
67 	    "Usage: zhack [-o tunable] [-c cachefile] [-d dir] [-G] "
68 	    "<subcommand> <args> ...\n"
69 	    "       where <subcommand> <args> is one of the following:\n"
70 	    "\n");
71 
72 	(void) fprintf(stderr,
73 	    "    global options:\n"
74 	    "    -c <cachefile>   reads config from the given cachefile\n"
75 	    "    -d <dir>         directory with vdevs for import\n"
76 	    "    -o var=value...  set global variable to an unsigned "
77 	    "32-bit integer\n"
78 	    "    -G               dump zfs_dbgmsg buffer before exiting\n"
79 	    "\n"
80 	    "    action idle <pool> [-f] [-t seconds]\n"
81 	    "        import the pool for a set time then export it\n"
82 	    "        -t <seconds> sets the time the pool is imported\n"
83 	    "\n"
84 	    "    feature stat <pool>\n"
85 	    "        print information about enabled features\n"
86 	    "    feature enable [-r] [-d desc] <pool> <feature>\n"
87 	    "        add a new enabled feature to the pool\n"
88 	    "        -d <desc> sets the feature's description\n"
89 	    "        -r set read-only compatible flag for feature\n"
90 	    "    feature ref [-md] <pool> <feature>\n"
91 	    "        change the refcount on the given feature\n"
92 	    "        -d decrease instead of increase the refcount\n"
93 	    "        -m add the feature to the label if increasing refcount\n"
94 	    "\n"
95 	    "    <feature> : should be a feature guid\n"
96 	    "\n"
97 	    "    label repair <device>\n"
98 	    "        repair labels of a specified device according to options\n"
99 	    "        which may be combined to do their functions in one call\n"
100 	    "        -c repair corrupted label checksums\n"
101 	    "        -u restore the label on a detached device\n"
102 	    "\n"
103 	    "    <device> : path to vdev\n"
104 	    "\n"
105 	    "    mmp reclaim <pool>\n"
106 	    "        import a pool whose MMP claim cannot reach every mirror\n"
107 	    "        leg the config still expects, then mark the unreachable\n"
108 	    "        leaves offline so ordinary imports succeed.  Manual\n"
109 	    "        recovery: fence the peer first, this cannot see a\n"
110 	    "        live host whose legs are all invisible from here\n"
111 	    "\n"
112 	    "    metaslab leak <pool>\n"
113 	    "        apply allocation map from zdb to specified pool\n");
114 	exit(1);
115 }
116 
117 static void
dump_debug_buffer(void)118 dump_debug_buffer(void)
119 {
120 	ssize_t ret __attribute__((unused));
121 
122 	if (!g_dump_dbgmsg)
123 		return;
124 
125 	/*
126 	 * We use write() instead of printf() so that this function
127 	 * is safe to call from a signal handler.
128 	 */
129 	ret = write(STDERR_FILENO, "\n", 1);
130 	zfs_dbgmsg_print(STDERR_FILENO, "zhack");
131 }
132 
sig_handler(int signo)133 static void sig_handler(int signo)
134 {
135 	struct sigaction action;
136 
137 	libspl_backtrace(STDERR_FILENO);
138 	dump_debug_buffer();
139 
140 	/*
141 	 * Restore default action and re-raise signal so SIGSEGV and
142 	 * SIGABRT can trigger a core dump.
143 	 */
144 	action.sa_handler = SIG_DFL;
145 	sigemptyset(&action.sa_mask);
146 	action.sa_flags = 0;
147 	(void) sigaction(signo, &action, NULL);
148 	raise(signo);
149 }
150 
151 static __attribute__((format(printf, 3, 4))) __attribute__((noreturn)) void
fatal(spa_t * spa,const void * tag,const char * fmt,...)152 fatal(spa_t *spa, const void *tag, const char *fmt, ...)
153 {
154 	va_list ap;
155 
156 	if (spa != NULL) {
157 		spa_close(spa, tag);
158 		(void) spa_export(g_pool, NULL, B_TRUE, B_FALSE);
159 	}
160 
161 	va_start(ap, fmt);
162 	(void) fputs("zhack: ", stderr);
163 	(void) vfprintf(stderr, fmt, ap);
164 	va_end(ap);
165 	(void) fputc('\n', stderr);
166 
167 	dump_debug_buffer();
168 
169 	exit(1);
170 }
171 
172 static int
space_delta_cb(dmu_object_type_t bonustype,const void * data,zfs_file_info_t * zoi)173 space_delta_cb(dmu_object_type_t bonustype, const void *data,
174     zfs_file_info_t *zoi)
175 {
176 	(void) data, (void) zoi;
177 
178 	/*
179 	 * Is it a valid type of object to track?
180 	 */
181 	if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA)
182 		return (ENOENT);
183 	(void) fprintf(stderr, "modifying object that needs user accounting");
184 	abort();
185 }
186 
187 /*
188  * Target is the dataset whose pool we want to open.
189  */
190 static void
zhack_import(char * target,boolean_t readonly)191 zhack_import(char *target, boolean_t readonly)
192 {
193 	nvlist_t *config;
194 	nvlist_t *props;
195 	int error;
196 
197 	kernel_init(readonly ? SPA_MODE_READ :
198 	    (SPA_MODE_READ | SPA_MODE_WRITE));
199 
200 	dmu_objset_register_type(DMU_OST_ZFS, space_delta_cb);
201 
202 	g_readonly = readonly;
203 	g_importargs.can_be_active = readonly;
204 	g_pool = strdup(target);
205 
206 	libpc_handle_t lpch = {
207 		.lpc_lib_handle = NULL,
208 		.lpc_ops = &libzpool_config_ops,
209 		.lpc_printerr = B_TRUE
210 	};
211 	error = zpool_find_config(&lpch, target, &config, &g_importargs);
212 	if (error)
213 		fatal(NULL, FTAG, "cannot import '%s'", target);
214 
215 	props = NULL;
216 	if (readonly) {
217 		VERIFY0(nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
218 		VERIFY0(nvlist_add_uint64(props,
219 		    zpool_prop_to_name(ZPOOL_PROP_READONLY), 1));
220 	}
221 
222 	zfeature_checks_disable = B_TRUE;
223 	error = spa_import(target, config, props,
224 	    (readonly ? ZFS_IMPORT_SKIP_MMP : ZFS_IMPORT_NORMAL));
225 	fnvlist_free(config);
226 	zfeature_checks_disable = B_FALSE;
227 	if (error == EEXIST)
228 		error = 0;
229 
230 	if (error)
231 		fatal(NULL, FTAG, "can't import '%s': %s", target,
232 		    strerror(error));
233 }
234 
235 static void
zhack_spa_open(char * target,boolean_t readonly,const void * tag,spa_t ** spa)236 zhack_spa_open(char *target, boolean_t readonly, const void *tag, spa_t **spa)
237 {
238 	int err;
239 
240 	zhack_import(target, readonly);
241 
242 	zfeature_checks_disable = B_TRUE;
243 	err = spa_open(target, spa, tag);
244 	zfeature_checks_disable = B_FALSE;
245 
246 	if (err != 0)
247 		fatal(*spa, FTAG, "cannot open '%s': %s", target,
248 		    strerror(err));
249 	if (spa_version(*spa) < SPA_VERSION_FEATURES) {
250 		fatal(*spa, FTAG, "'%s' has version %d, features not enabled",
251 		    target, (int)spa_version(*spa));
252 	}
253 }
254 
255 static void
dump_obj(objset_t * os,uint64_t obj,const char * name)256 dump_obj(objset_t *os, uint64_t obj, const char *name)
257 {
258 	zap_cursor_t zc;
259 	zap_attribute_t *za = zap_attribute_long_alloc();
260 
261 	(void) printf("%s_obj:\n", name);
262 
263 	for (zap_cursor_init(&zc, os, obj);
264 	    zap_cursor_retrieve(&zc, za) == 0;
265 	    zap_cursor_advance(&zc)) {
266 		if (za->za_integer_length == 8) {
267 			ASSERT(za->za_num_integers == 1);
268 			(void) printf("\t%s = %llu\n",
269 			    za->za_name, (u_longlong_t)za->za_first_integer);
270 		} else {
271 			ASSERT(za->za_integer_length == 1);
272 			char val[1024];
273 			VERIFY0(zap_lookup(os, obj, za->za_name,
274 			    1, sizeof (val), val));
275 			(void) printf("\t%s = %s\n", za->za_name, val);
276 		}
277 	}
278 	zap_cursor_fini(&zc);
279 	zap_attribute_free(za);
280 }
281 
282 static void
dump_mos(spa_t * spa)283 dump_mos(spa_t *spa)
284 {
285 	nvlist_t *nv = spa->spa_label_features;
286 	nvpair_t *pair;
287 
288 	(void) printf("label config:\n");
289 	for (pair = nvlist_next_nvpair(nv, NULL);
290 	    pair != NULL;
291 	    pair = nvlist_next_nvpair(nv, pair)) {
292 		(void) printf("\t%s\n", nvpair_name(pair));
293 	}
294 }
295 
296 static void
zhack_do_feature_stat(int argc,char ** argv)297 zhack_do_feature_stat(int argc, char **argv)
298 {
299 	spa_t *spa;
300 	objset_t *os;
301 	char *target;
302 
303 	argc--;
304 	argv++;
305 
306 	if (argc < 1) {
307 		(void) fprintf(stderr, "error: missing pool name\n");
308 		usage();
309 	}
310 	target = argv[0];
311 
312 	zhack_spa_open(target, B_TRUE, FTAG, &spa);
313 	os = spa->spa_meta_objset;
314 
315 	dump_obj(os, spa->spa_feat_for_read_obj, "for_read");
316 	dump_obj(os, spa->spa_feat_for_write_obj, "for_write");
317 	dump_obj(os, spa->spa_feat_desc_obj, "descriptions");
318 	if (spa_feature_is_active(spa, SPA_FEATURE_ENABLED_TXG)) {
319 		dump_obj(os, spa->spa_feat_enabled_txg_obj, "enabled_txg");
320 	}
321 	dump_mos(spa);
322 
323 	spa_close(spa, FTAG);
324 }
325 
326 static void
zhack_feature_enable_sync(void * arg,dmu_tx_t * tx)327 zhack_feature_enable_sync(void *arg, dmu_tx_t *tx)
328 {
329 	spa_t *spa = dmu_tx_pool(tx)->dp_spa;
330 	zfeature_info_t *feature = arg;
331 
332 	feature_enable_sync(spa, feature, tx);
333 
334 	spa_history_log_internal(spa, "zhack enable feature", tx,
335 	    "name=%s flags=%u",
336 	    feature->fi_guid, feature->fi_flags);
337 }
338 
339 static void
zhack_do_feature_enable(int argc,char ** argv)340 zhack_do_feature_enable(int argc, char **argv)
341 {
342 	int c;
343 	char *desc, *target;
344 	spa_t *spa;
345 	objset_t *mos;
346 	zfeature_info_t feature;
347 	const spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
348 
349 	/*
350 	 * Features are not added to the pool's label until their refcounts
351 	 * are incremented, so fi_mos can just be left as false for now.
352 	 */
353 	desc = NULL;
354 	feature.fi_uname = "zhack";
355 	feature.fi_flags = 0;
356 	feature.fi_depends = nodeps;
357 	feature.fi_feature = SPA_FEATURE_NONE;
358 
359 	optind = 1;
360 	while ((c = getopt(argc, argv, "+rd:")) != -1) {
361 		switch (c) {
362 		case 'r':
363 			feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
364 			break;
365 		case 'd':
366 			if (desc != NULL)
367 				free(desc);
368 			desc = strdup(optarg);
369 			break;
370 		default:
371 			usage();
372 			break;
373 		}
374 	}
375 
376 	if (desc == NULL)
377 		desc = strdup("zhack injected");
378 	feature.fi_desc = desc;
379 
380 	argc -= optind;
381 	argv += optind;
382 
383 	if (argc < 2) {
384 		(void) fprintf(stderr, "error: missing feature or pool name\n");
385 		usage();
386 	}
387 	target = argv[0];
388 	feature.fi_guid = argv[1];
389 
390 	if (!zfeature_is_valid_guid(feature.fi_guid))
391 		fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);
392 
393 	zhack_spa_open(target, B_FALSE, FTAG, &spa);
394 	mos = spa->spa_meta_objset;
395 
396 	if (zfeature_is_supported(feature.fi_guid))
397 		fatal(spa, FTAG, "'%s' is a real feature, will not enable",
398 		    feature.fi_guid);
399 	if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
400 		fatal(spa, FTAG, "feature already enabled: %s",
401 		    feature.fi_guid);
402 
403 	VERIFY0(dsl_sync_task(spa_name(spa), NULL,
404 	    zhack_feature_enable_sync, &feature, 5, ZFS_SPACE_CHECK_NORMAL));
405 
406 	spa_close(spa, FTAG);
407 
408 	free(desc);
409 }
410 
411 static void
feature_incr_sync(void * arg,dmu_tx_t * tx)412 feature_incr_sync(void *arg, dmu_tx_t *tx)
413 {
414 	spa_t *spa = dmu_tx_pool(tx)->dp_spa;
415 	zfeature_info_t *feature = arg;
416 	uint64_t refcount;
417 
418 	mutex_enter(&spa->spa_feat_stats_lock);
419 	VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
420 	feature_sync(spa, feature, refcount + 1, tx);
421 	spa_history_log_internal(spa, "zhack feature incr", tx,
422 	    "name=%s", feature->fi_guid);
423 	mutex_exit(&spa->spa_feat_stats_lock);
424 }
425 
426 static void
feature_decr_sync(void * arg,dmu_tx_t * tx)427 feature_decr_sync(void *arg, dmu_tx_t *tx)
428 {
429 	spa_t *spa = dmu_tx_pool(tx)->dp_spa;
430 	zfeature_info_t *feature = arg;
431 	uint64_t refcount;
432 
433 	mutex_enter(&spa->spa_feat_stats_lock);
434 	VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
435 	feature_sync(spa, feature, refcount - 1, tx);
436 	spa_history_log_internal(spa, "zhack feature decr", tx,
437 	    "name=%s", feature->fi_guid);
438 	mutex_exit(&spa->spa_feat_stats_lock);
439 }
440 
441 static void
zhack_do_feature_ref(int argc,char ** argv)442 zhack_do_feature_ref(int argc, char **argv)
443 {
444 	int c;
445 	char *target;
446 	boolean_t decr = B_FALSE;
447 	spa_t *spa;
448 	objset_t *mos;
449 	zfeature_info_t feature;
450 	const spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
451 
452 	/*
453 	 * fi_desc does not matter here because it was written to disk
454 	 * when the feature was enabled, but we need to properly set the
455 	 * feature for read or write based on the information we read off
456 	 * disk later.
457 	 */
458 	feature.fi_uname = "zhack";
459 	feature.fi_flags = 0;
460 	feature.fi_desc = NULL;
461 	feature.fi_depends = nodeps;
462 	feature.fi_feature = SPA_FEATURE_NONE;
463 
464 	optind = 1;
465 	while ((c = getopt(argc, argv, "+md")) != -1) {
466 		switch (c) {
467 		case 'm':
468 			feature.fi_flags |= ZFEATURE_FLAG_MOS;
469 			break;
470 		case 'd':
471 			decr = B_TRUE;
472 			break;
473 		default:
474 			usage();
475 			break;
476 		}
477 	}
478 	argc -= optind;
479 	argv += optind;
480 
481 	if (argc < 2) {
482 		(void) fprintf(stderr, "error: missing feature or pool name\n");
483 		usage();
484 	}
485 	target = argv[0];
486 	feature.fi_guid = argv[1];
487 
488 	if (!zfeature_is_valid_guid(feature.fi_guid))
489 		fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);
490 
491 	zhack_spa_open(target, B_FALSE, FTAG, &spa);
492 	mos = spa->spa_meta_objset;
493 
494 	if (zfeature_is_supported(feature.fi_guid)) {
495 		fatal(spa, FTAG,
496 		    "'%s' is a real feature, will not change refcount",
497 		    feature.fi_guid);
498 	}
499 
500 	if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
501 	    feature.fi_guid)) {
502 		feature.fi_flags &= ~ZFEATURE_FLAG_READONLY_COMPAT;
503 	} else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
504 	    feature.fi_guid)) {
505 		feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
506 	} else {
507 		fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
508 	}
509 
510 	if (decr) {
511 		uint64_t count;
512 		if (feature_get_refcount_from_disk(spa, &feature,
513 		    &count) == 0 && count == 0) {
514 			fatal(spa, FTAG, "feature refcount already 0: %s",
515 			    feature.fi_guid);
516 		}
517 	}
518 
519 	VERIFY0(dsl_sync_task(spa_name(spa), NULL,
520 	    decr ? feature_decr_sync : feature_incr_sync, &feature,
521 	    5, ZFS_SPACE_CHECK_NORMAL));
522 
523 	spa_close(spa, FTAG);
524 }
525 
526 static int
zhack_do_feature(int argc,char ** argv)527 zhack_do_feature(int argc, char **argv)
528 {
529 	char *subcommand;
530 
531 	argc--;
532 	argv++;
533 	if (argc == 0) {
534 		(void) fprintf(stderr,
535 		    "error: no feature operation specified\n");
536 		usage();
537 	}
538 
539 	subcommand = argv[0];
540 	if (strcmp(subcommand, "stat") == 0) {
541 		zhack_do_feature_stat(argc, argv);
542 	} else if (strcmp(subcommand, "enable") == 0) {
543 		zhack_do_feature_enable(argc, argv);
544 	} else if (strcmp(subcommand, "ref") == 0) {
545 		zhack_do_feature_ref(argc, argv);
546 	} else {
547 		(void) fprintf(stderr, "error: unknown subcommand: %s\n",
548 		    subcommand);
549 		usage();
550 	}
551 
552 	return (0);
553 }
554 
555 static void
zhack_do_action_idle(int argc,char ** argv)556 zhack_do_action_idle(int argc, char **argv)
557 {
558 	spa_t *spa;
559 	char *target, *tmp;
560 	int idle_time = 0;
561 	int c;
562 
563 	optind = 1;
564 	while ((c = getopt(argc, argv, "+t:")) != -1) {
565 		switch (c) {
566 		case 't':
567 			idle_time = strtol(optarg, &tmp, 0);
568 			if (*tmp) {
569 				(void) fprintf(stderr, "error: time must "
570 				    "be an integer in seconds: %s\n", tmp);
571 				usage();
572 			}
573 			if (idle_time < 0) {
574 				(void) fprintf(stderr, "error: time must "
575 				    "not be negative: %d\n", idle_time);
576 				usage();
577 			}
578 			break;
579 		default:
580 			usage();
581 			break;
582 		}
583 	}
584 	argc -= optind;
585 	argv += optind;
586 
587 	if (argc < 1) {
588 		(void) fprintf(stderr, "error: missing pool name\n");
589 		usage();
590 	}
591 	target = argv[0];
592 
593 	zhack_spa_open(target, B_FALSE, FTAG, &spa);
594 
595 	fprintf(stdout, "Imported pool %s, idle for %d seconds\n",
596 	    target, idle_time);
597 	sleep(idle_time);
598 
599 	spa_close(spa, FTAG);
600 }
601 
602 /*
603  * Collect the mirror legs this host could not open.  vdev_not_present is set
604  * during import for any leaf whose open failed (vdev.c), and a leg in that
605  * state is what the relaxed claim forgives, so it is also what has to be
606  * marked offline for the ordinary imports which follow to succeed.
607  */
608 static void
zhack_collect_absent(vdev_t * vd,uint64_t * guids,uint_t * n,uint_t max)609 zhack_collect_absent(vdev_t *vd, uint64_t *guids, uint_t *n, uint_t max)
610 {
611 	/*
612 	 * Skip the same subtrees mmp_claim_uberblock_sync() skips.  The claim
613 	 * never counts these, so offlining them buys nothing, and offlining a
614 	 * log leg would drag in spa_reset_logs().  Pruned at the interior node
615 	 * because the log flag lives on the top-level vdev.
616 	 */
617 	if (vd->vdev_islog || vd->vdev_isspare || vd->vdev_isl2cache ||
618 	    vd->vdev_ishole || vd->vdev_ops == &vdev_indirect_ops)
619 		return;
620 
621 	for (uint64_t c = 0; c < vd->vdev_children; c++)
622 		zhack_collect_absent(vd->vdev_child[c], guids, n, max);
623 
624 	if (!vd->vdev_ops->vdev_op_leaf || !vd->vdev_not_present)
625 		return;
626 
627 	/*
628 	 * Take only the legs the relaxed claim can forgive, which are the
629 	 * direct children of a top-level mirror: the relaxation lives in the
630 	 * nparity == 0 branch and walks that vdev's children.  A raidz or
631 	 * draid member is required as parity+1 in aggregate and never demanded
632 	 * individually, so an absent one does not raise the requirement and
633 	 * offlining it would be a persistent change that buys nothing.
634 	 */
635 	if (vd->vdev_parent != vd->vdev_top ||
636 	    vdev_get_nparity(vd->vdev_top) != 0)
637 		return;
638 
639 	VERIFY3U(*n, <, max);
640 	guids[(*n)++] = vd->vdev_guid;
641 }
642 
643 static int
zhack_do_mmp_reclaim(int argc,char ** argv)644 zhack_do_mmp_reclaim(int argc, char **argv)
645 {
646 	spa_t *spa;
647 	char *target;
648 	uint64_t *guids;
649 	uint_t nguids = 0, max;
650 	int c, failed = 0;
651 
652 	optind = 1;
653 	while ((c = getopt(argc, argv, "+")) != -1) {
654 		switch (c) {
655 		default:
656 			usage();
657 			break;
658 		}
659 	}
660 	argc -= optind;
661 	argv += optind;
662 
663 	if (argc < 1) {
664 		(void) fprintf(stderr, "error: missing pool name\n");
665 		usage();
666 	}
667 	target = argv[0];
668 
669 	/*
670 	 * Relax the claim for this import only.  The write, the wait and the
671 	 * re-read are untouched, so a competing importer which shares any
672 	 * visibility with us is still refused.
673 	 */
674 	mmp_claim_relaxed = B_TRUE;
675 	zhack_spa_open(target, B_FALSE, FTAG, &spa);
676 	mmp_claim_relaxed = B_FALSE;
677 
678 	/*
679 	 * Nothing to recover on a pool without multihost: no claim runs, so an
680 	 * ordinary import already succeeds with the absent leaves simply
681 	 * missing.  Offlining them here would be a permanent change to a pool
682 	 * that never needed this tool.
683 	 */
684 	if (!spa_multihost(spa)) {
685 		(void) fprintf(stderr, "%s: multihost is off, so no uberblock "
686 		    "claim runs and an ordinary import will succeed; refusing "
687 		    "to offline anything\n", target);
688 		spa_close(spa, FTAG);
689 		return (1);
690 	}
691 
692 	/* Takes SCL_VDEV itself, so size the array before we hold it. */
693 	max = MAX(vdev_count_leaves(spa), 1);
694 	guids = umem_zalloc(max * sizeof (uint64_t), UMEM_NOFAIL);
695 
696 	spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
697 	zhack_collect_absent(spa->spa_root_vdev, guids, &nguids, max);
698 	spa_config_exit(spa, SCL_VDEV, FTAG);
699 
700 	if (nguids == 0) {
701 		(void) fprintf(stdout, "%s: imported, no absent leaves to "
702 		    "mark offline\n", target);
703 	}
704 
705 	for (uint_t i = 0; i < nguids; i++) {
706 		int error = vdev_offline(spa, guids[i], 0);
707 
708 		if (error == 0) {
709 			(void) fprintf(stdout, "%s: marked absent leaf %llu "
710 			    "offline\n", target, (u_longlong_t)guids[i]);
711 			continue;
712 		}
713 
714 		failed++;
715 		if (error == EBUSY) {
716 			(void) fprintf(stderr, "%s: leaf %llu holds data no "
717 			    "other leaf has, left online\n", target,
718 			    (u_longlong_t)guids[i]);
719 		} else {
720 			(void) fprintf(stderr, "%s: could not offline leaf "
721 			    "%llu: %s\n", target, (u_longlong_t)guids[i],
722 			    strerror(error));
723 		}
724 	}
725 
726 	if (failed != 0) {
727 		/*
728 		 * Not "the pool still needs zhack": this run exports cleanly
729 		 * under our own hostid, so the next import here skips the
730 		 * activity check entirely.  The cost lands on the next host
731 		 * to take the pool, whose claim will count the leaves left
732 		 * online and refuse.
733 		 */
734 		(void) fprintf(stderr, "%s: %d absent leaves are still "
735 		    "online; a later import from another host will count "
736 		    "them and be refused\n", target, failed);
737 	}
738 
739 	umem_free(guids, max * sizeof (uint64_t));
740 	spa_close(spa, FTAG);
741 
742 	return (failed == 0 ? 0 : 1);
743 }
744 
745 static int
zhack_do_mmp(int argc,char ** argv)746 zhack_do_mmp(int argc, char **argv)
747 {
748 	char *subcommand;
749 
750 	argc--;
751 	argv++;
752 	if (argc == 0) {
753 		(void) fprintf(stderr,
754 		    "error: no mmp operation specified\n");
755 		usage();
756 	}
757 
758 	subcommand = argv[0];
759 	if (strcmp(subcommand, "reclaim") == 0) {
760 		return (zhack_do_mmp_reclaim(argc, argv));
761 	} else {
762 		(void) fprintf(stderr, "error: unknown subcommand: %s\n",
763 		    subcommand);
764 		usage();
765 	}
766 
767 	return (0);
768 }
769 
770 static int
zhack_do_action(int argc,char ** argv)771 zhack_do_action(int argc, char **argv)
772 {
773 	char *subcommand;
774 
775 	argc--;
776 	argv++;
777 	if (argc == 0) {
778 		(void) fprintf(stderr,
779 		    "error: no import operation specified\n");
780 		usage();
781 	}
782 
783 	subcommand = argv[0];
784 	if (strcmp(subcommand, "idle") == 0) {
785 		zhack_do_action_idle(argc, argv);
786 	} else {
787 		(void) fprintf(stderr, "error: unknown subcommand: %s\n",
788 		    subcommand);
789 		usage();
790 	}
791 
792 	return (0);
793 }
794 
795 
796 static boolean_t
strstarts(const char * a,const char * b)797 strstarts(const char *a, const char *b)
798 {
799 	return (strncmp(a, b, strlen(b)) == 0);
800 }
801 
802 static void
metaslab_force_alloc(metaslab_t * msp,uint64_t start,uint64_t size,dmu_tx_t * tx)803 metaslab_force_alloc(metaslab_t *msp, uint64_t start, uint64_t size,
804     dmu_tx_t *tx)
805 {
806 	ASSERT(msp->ms_disabled);
807 	ASSERT(MUTEX_HELD(&msp->ms_lock));
808 	uint64_t txg = dmu_tx_get_txg(tx);
809 
810 	uint64_t off = start;
811 	while (off < start + size) {
812 		uint64_t ostart, osize;
813 		boolean_t found = zfs_range_tree_find_in(msp->ms_allocatable,
814 		    off, start + size - off, &ostart, &osize);
815 		if (!found)
816 			break;
817 		zfs_range_tree_remove(msp->ms_allocatable, ostart, osize);
818 
819 		if (zfs_range_tree_is_empty(msp->ms_allocating[txg & TXG_MASK]))
820 			vdev_dirty(msp->ms_group->mg_vd, VDD_METASLAB, msp,
821 			    txg);
822 
823 		zfs_range_tree_add(msp->ms_allocating[txg & TXG_MASK], ostart,
824 		    osize);
825 		msp->ms_allocating_total += osize;
826 		off = ostart + osize;
827 	}
828 }
829 
830 static void
zhack_do_metaslab_leak(int argc,char ** argv)831 zhack_do_metaslab_leak(int argc, char **argv)
832 {
833 	int c;
834 	char *target;
835 	spa_t *spa;
836 
837 	optind = 1;
838 	boolean_t force = B_FALSE;
839 	while ((c = getopt(argc, argv, "f")) != -1) {
840 		switch (c) {
841 		case 'f':
842 			force = B_TRUE;
843 			break;
844 		default:
845 			usage();
846 			break;
847 		}
848 	}
849 
850 	argc -= optind;
851 	argv += optind;
852 
853 	if (argc < 1) {
854 		(void) fprintf(stderr, "error: missing pool name\n");
855 		usage();
856 	}
857 	target = argv[0];
858 
859 	zhack_spa_open(target, B_FALSE, FTAG, &spa);
860 	spa_config_enter(spa, SCL_VDEV | SCL_ALLOC, FTAG, RW_READER);
861 
862 	char *line = NULL;
863 	size_t cap = 0;
864 
865 	vdev_t *vd = NULL;
866 	metaslab_t *prev = NULL;
867 	dmu_tx_t *tx = NULL;
868 	while (getline(&line, &cap, stdin) > 0) {
869 		if (strstarts(line, "\tvdev ")) {
870 			uint64_t vdev_id, ms_shift;
871 			if (sscanf(line,
872 			    "\tvdev %10"PRIu64"\t%*s  metaslab shift %4"PRIu64,
873 			    &vdev_id, &ms_shift) == 1) {
874 				VERIFY3U(sscanf(line, "\tvdev %"PRIu64
875 				    "\t  metaslab shift %4"PRIu64,
876 				    &vdev_id, &ms_shift), ==, 2);
877 			}
878 			vd = vdev_lookup_top(spa, vdev_id);
879 			if (vd == NULL) {
880 				fprintf(stderr, "error: no such vdev with "
881 				    "id %"PRIu64"\n", vdev_id);
882 				break;
883 			}
884 			if (tx) {
885 				dmu_tx_commit(tx);
886 				mutex_exit(&prev->ms_lock);
887 				metaslab_enable(prev, B_FALSE, B_FALSE);
888 				tx = NULL;
889 				prev = NULL;
890 			}
891 			if (vd->vdev_ms_shift != ms_shift) {
892 				fprintf(stderr, "error: ms_shift mismatch: %"
893 				    PRIu64" != %"PRIu64"\n", vd->vdev_ms_shift,
894 				    ms_shift);
895 				break;
896 			}
897 		} else if (strstarts(line, "\tmetaslabs ")) {
898 			uint64_t ms_count;
899 			VERIFY3U(sscanf(line, "\tmetaslabs %"PRIu64, &ms_count),
900 			    ==, 1);
901 			ASSERT(vd);
902 			if (!force && vd->vdev_ms_count != ms_count) {
903 				fprintf(stderr, "error: ms_count mismatch: %"
904 				    PRIu64" != %"PRIu64"\n", vd->vdev_ms_count,
905 				    ms_count);
906 				break;
907 			}
908 		} else if (strstarts(line, "ALLOC:")) {
909 			uint64_t start, size;
910 			VERIFY3U(sscanf(line, "ALLOC: %"PRIu64" %"PRIu64"\n",
911 			    &start, &size), ==, 2);
912 
913 			ASSERT(vd);
914 			size_t idx;
915 			idx = start >> vd->vdev_ms_shift;
916 			if (idx >= vd->vdev_ms_count)
917 				continue;
918 			metaslab_t *cur = vd->vdev_ms[idx];
919 			if (prev != cur) {
920 				if (prev) {
921 					dmu_tx_commit(tx);
922 					mutex_exit(&prev->ms_lock);
923 					metaslab_enable(prev, B_FALSE, B_FALSE);
924 				}
925 				ASSERT(cur);
926 				metaslab_disable(cur);
927 				mutex_enter(&cur->ms_lock);
928 				metaslab_load(cur);
929 				prev = cur;
930 				tx = dmu_tx_create_dd(
931 				    spa_get_dsl(vd->vdev_spa)->dp_root_dir);
932 				dmu_tx_assign(tx, DMU_TX_WAIT);
933 			}
934 
935 			metaslab_force_alloc(cur, start, size, tx);
936 		} else {
937 			continue;
938 		}
939 	}
940 	if (tx) {
941 		dmu_tx_commit(tx);
942 		mutex_exit(&prev->ms_lock);
943 		metaslab_enable(prev, B_FALSE, B_FALSE);
944 		tx = NULL;
945 		prev = NULL;
946 	}
947 	if (line)
948 		free(line);
949 
950 	spa_config_exit(spa, SCL_VDEV | SCL_ALLOC, FTAG);
951 	spa_close(spa, FTAG);
952 }
953 
954 static int
zhack_do_metaslab(int argc,char ** argv)955 zhack_do_metaslab(int argc, char **argv)
956 {
957 	char *subcommand;
958 
959 	argc--;
960 	argv++;
961 	if (argc == 0) {
962 		(void) fprintf(stderr,
963 		    "error: no metaslab operation specified\n");
964 		usage();
965 	}
966 
967 	subcommand = argv[0];
968 	if (strcmp(subcommand, "leak") == 0) {
969 		zhack_do_metaslab_leak(argc, argv);
970 	} else {
971 		(void) fprintf(stderr, "error: unknown subcommand: %s\n",
972 		    subcommand);
973 		usage();
974 	}
975 
976 	return (0);
977 }
978 
979 #define	ASHIFT_UBERBLOCK_SHIFT(ashift)	\
980 	MIN(MAX(ashift, UBERBLOCK_SHIFT), \
981 	MAX_UBERBLOCK_SHIFT)
982 #define	ASHIFT_UBERBLOCK_SIZE(ashift) \
983 	(1ULL << ASHIFT_UBERBLOCK_SHIFT(ashift))
984 
985 #define	REPAIR_LABEL_STATUS_CKSUM (1 << 0)
986 #define	REPAIR_LABEL_STATUS_UB    (1 << 1)
987 
988 static int
zhack_repair_read_label(const int fd,vdev_label_t * vl,const uint64_t label_offset,const int l)989 zhack_repair_read_label(const int fd, vdev_label_t *vl,
990     const uint64_t label_offset, const int l)
991 {
992 	const int err = pread64(fd, vl, sizeof (vdev_label_t), label_offset);
993 
994 	if (err == -1) {
995 		(void) fprintf(stderr,
996 		    "error: cannot read label %d: %s\n",
997 		    l, strerror(errno));
998 		return (err);
999 	} else if (err != sizeof (vdev_label_t)) {
1000 		(void) fprintf(stderr,
1001 		    "error: bad label %d read size\n", l);
1002 		return (err);
1003 	}
1004 
1005 	return (0);
1006 }
1007 
1008 static int
zhack_repair_get_byteswap(const zio_eck_t * vdev_eck,const int l,int * byteswap)1009 zhack_repair_get_byteswap(const zio_eck_t *vdev_eck, const int l, int *byteswap)
1010 {
1011 	if (vdev_eck->zec_magic == ZEC_MAGIC) {
1012 		*byteswap = B_FALSE;
1013 	} else if (vdev_eck->zec_magic == BSWAP_64((uint64_t)ZEC_MAGIC)) {
1014 		*byteswap = B_TRUE;
1015 	} else {
1016 		(void) fprintf(stderr, "error: label %d: "
1017 		    "Expected the nvlist checksum magic number but instead got "
1018 		    "0x%" PRIx64 "\n",
1019 		    l, vdev_eck->zec_magic);
1020 		return (1);
1021 	}
1022 	return (0);
1023 }
1024 
1025 static void
zhack_repair_calc_cksum(const int byteswap,void * data,const uint64_t offset,const uint64_t abdsize,zio_eck_t * eck,zio_cksum_t * cksum)1026 zhack_repair_calc_cksum(const int byteswap, void *data, const uint64_t offset,
1027     const uint64_t abdsize, zio_eck_t *eck, zio_cksum_t *cksum)
1028 {
1029 	zio_cksum_t verifier;
1030 	zio_cksum_t current_cksum;
1031 	zio_checksum_info_t *ci;
1032 	abd_t *abd;
1033 
1034 	ZIO_SET_CHECKSUM(&verifier, offset, 0, 0, 0);
1035 
1036 	if (byteswap)
1037 		byteswap_uint64_array(&verifier, sizeof (zio_cksum_t));
1038 
1039 	current_cksum = eck->zec_cksum;
1040 	eck->zec_cksum = verifier;
1041 
1042 	ci = &zio_checksum_table[ZIO_CHECKSUM_LABEL];
1043 	abd = abd_get_from_buf(data, abdsize);
1044 	ci->ci_func[byteswap](abd, abdsize, NULL, cksum);
1045 	abd_free(abd);
1046 
1047 	eck->zec_cksum = current_cksum;
1048 }
1049 
1050 static int
zhack_repair_get_ashift(nvlist_t * cfg,const int l,uint64_t * ashift)1051 zhack_repair_get_ashift(nvlist_t *cfg, const int l, uint64_t *ashift)
1052 {
1053 	int err;
1054 	nvlist_t *vdev_tree_cfg;
1055 
1056 	err = nvlist_lookup_nvlist(cfg,
1057 	    ZPOOL_CONFIG_VDEV_TREE, &vdev_tree_cfg);
1058 	if (err) {
1059 		(void) fprintf(stderr,
1060 		    "error: label %d: cannot find nvlist key %s\n",
1061 		    l, ZPOOL_CONFIG_VDEV_TREE);
1062 		return (err);
1063 	}
1064 
1065 	err = nvlist_lookup_uint64(vdev_tree_cfg,
1066 	    ZPOOL_CONFIG_ASHIFT, ashift);
1067 	if (err) {
1068 		(void) fprintf(stderr,
1069 		    "error: label %d: cannot find nvlist key %s\n",
1070 		    l, ZPOOL_CONFIG_ASHIFT);
1071 		return (err);
1072 	}
1073 
1074 	if (*ashift == 0) {
1075 		(void) fprintf(stderr,
1076 		    "error: label %d: nvlist key %s is zero\n",
1077 		    l, ZPOOL_CONFIG_ASHIFT);
1078 		return (1);
1079 	}
1080 
1081 	return (0);
1082 }
1083 
1084 static int
zhack_repair_undetach(uberblock_t * ub,nvlist_t * cfg,const int l)1085 zhack_repair_undetach(uberblock_t *ub, nvlist_t *cfg, const int l)
1086 {
1087 	/*
1088 	 * Uberblock root block pointer has valid birth TXG.
1089 	 * Copying it to the label NVlist
1090 	 */
1091 	if (BP_GET_LOGICAL_BIRTH(&ub->ub_rootbp) != 0) {
1092 		const uint64_t txg = BP_GET_LOGICAL_BIRTH(&ub->ub_rootbp);
1093 		int err;
1094 
1095 		ub->ub_txg = txg;
1096 
1097 		err = nvlist_remove_all(cfg, ZPOOL_CONFIG_CREATE_TXG);
1098 		if (err) {
1099 			(void) fprintf(stderr,
1100 			    "error: label %d: "
1101 			    "Failed to remove pool creation TXG\n",
1102 			    l);
1103 			return (err);
1104 		}
1105 
1106 		err = nvlist_remove_all(cfg, ZPOOL_CONFIG_POOL_TXG);
1107 		if (err) {
1108 			(void) fprintf(stderr,
1109 			    "error: label %d: Failed to remove pool TXG to "
1110 			    "be replaced.\n",
1111 			    l);
1112 			return (err);
1113 		}
1114 
1115 		err = nvlist_add_uint64(cfg, ZPOOL_CONFIG_POOL_TXG, txg);
1116 		if (err) {
1117 			(void) fprintf(stderr,
1118 			    "error: label %d: "
1119 			    "Failed to add pool TXG of %" PRIu64 "\n",
1120 			    l, txg);
1121 			return (err);
1122 		}
1123 	}
1124 
1125 	return (0);
1126 }
1127 
1128 static boolean_t
zhack_repair_write_label(const int l,const int fd,const int byteswap,void * data,zio_eck_t * eck,const uint64_t offset,const uint64_t abdsize)1129 zhack_repair_write_label(const int l, const int fd, const int byteswap,
1130     void *data, zio_eck_t *eck, const uint64_t offset, const uint64_t abdsize)
1131 {
1132 	zio_cksum_t actual_cksum;
1133 	zhack_repair_calc_cksum(byteswap, data, offset, abdsize, eck,
1134 	    &actual_cksum);
1135 	zio_cksum_t expected_cksum = eck->zec_cksum;
1136 	ssize_t err;
1137 
1138 	if (ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum))
1139 		return (B_FALSE);
1140 
1141 	eck->zec_cksum = actual_cksum;
1142 
1143 	err = pwrite64(fd, data, abdsize, offset);
1144 	if (err == -1) {
1145 		(void) fprintf(stderr, "error: cannot write label %d: %s\n",
1146 		    l, strerror(errno));
1147 		return (B_FALSE);
1148 	} else if (err != abdsize) {
1149 		(void) fprintf(stderr, "error: bad write size label %d\n", l);
1150 		return (B_FALSE);
1151 	} else {
1152 		(void) fprintf(stderr,
1153 		    "label %d: wrote %" PRIu64 " bytes at offset %" PRIu64 "\n",
1154 		    l, abdsize, offset);
1155 	}
1156 
1157 	return (B_TRUE);
1158 }
1159 
1160 static void
zhack_repair_write_uberblock(vdev_label_t * vl,const int l,const uint64_t ashift,const int fd,const int byteswap,const uint64_t label_offset,uint32_t * labels_repaired)1161 zhack_repair_write_uberblock(vdev_label_t *vl, const int l,
1162     const uint64_t ashift, const int fd, const int byteswap,
1163     const uint64_t label_offset, uint32_t *labels_repaired)
1164 {
1165 	void *ub_data =
1166 	    (char *)vl + offsetof(vdev_label_t, vl_uberblock);
1167 	zio_eck_t *ub_eck =
1168 	    (zio_eck_t *)
1169 	    ((char *)(ub_data) + (ASHIFT_UBERBLOCK_SIZE(ashift))) - 1;
1170 
1171 	if (ub_eck->zec_magic != 0) {
1172 		(void) fprintf(stderr,
1173 		    "error: label %d: "
1174 		    "Expected Uberblock checksum magic number to "
1175 		    "be 0, but got %" PRIu64 "\n",
1176 		    l, ub_eck->zec_magic);
1177 		(void) fprintf(stderr, "It would appear there's already "
1178 		    "a checksum for the uberblock.\n");
1179 		return;
1180 	}
1181 
1182 
1183 	ub_eck->zec_magic = byteswap ? BSWAP_64(ZEC_MAGIC) : ZEC_MAGIC;
1184 
1185 	if (zhack_repair_write_label(l, fd, byteswap,
1186 	    ub_data, ub_eck,
1187 	    label_offset + offsetof(vdev_label_t, vl_uberblock),
1188 	    ASHIFT_UBERBLOCK_SIZE(ashift)))
1189 			labels_repaired[l] |= REPAIR_LABEL_STATUS_UB;
1190 }
1191 
1192 static void
zhack_repair_print_cksum(FILE * stream,const zio_cksum_t * cksum)1193 zhack_repair_print_cksum(FILE *stream, const zio_cksum_t *cksum)
1194 {
1195 	(void) fprintf(stream,
1196 	    "%016llx:%016llx:%016llx:%016llx",
1197 	    (u_longlong_t)cksum->zc_word[0],
1198 	    (u_longlong_t)cksum->zc_word[1],
1199 	    (u_longlong_t)cksum->zc_word[2],
1200 	    (u_longlong_t)cksum->zc_word[3]);
1201 }
1202 
1203 static int
zhack_repair_test_cksum(const int byteswap,void * vdev_data,zio_eck_t * vdev_eck,const uint64_t vdev_phys_offset,const int l)1204 zhack_repair_test_cksum(const int byteswap, void *vdev_data,
1205     zio_eck_t *vdev_eck, const uint64_t vdev_phys_offset, const int l)
1206 {
1207 	const zio_cksum_t expected_cksum = vdev_eck->zec_cksum;
1208 	zio_cksum_t actual_cksum;
1209 	zhack_repair_calc_cksum(byteswap, vdev_data, vdev_phys_offset,
1210 	    VDEV_PHYS_SIZE, vdev_eck, &actual_cksum);
1211 	const uint64_t expected_magic = byteswap ?
1212 	    BSWAP_64(ZEC_MAGIC) : ZEC_MAGIC;
1213 	const uint64_t actual_magic = vdev_eck->zec_magic;
1214 	int err = 0;
1215 
1216 	if (actual_magic != expected_magic) {
1217 		(void) fprintf(stderr, "error: label %d: "
1218 		    "Expected "
1219 		    "the nvlist checksum magic number to not be %"
1220 		    PRIu64 " not %" PRIu64 "\n",
1221 		    l, expected_magic, actual_magic);
1222 		err = ECKSUM;
1223 	}
1224 	if (!ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum)) {
1225 		(void) fprintf(stderr, "error: label %d: "
1226 		    "Expected the nvlist checksum to be ", l);
1227 		(void) zhack_repair_print_cksum(stderr,
1228 		    &expected_cksum);
1229 		(void) fprintf(stderr, " not ");
1230 		zhack_repair_print_cksum(stderr, &actual_cksum);
1231 		(void) fprintf(stderr, "\n");
1232 		err = ECKSUM;
1233 	}
1234 	return (err);
1235 }
1236 
1237 static int
zhack_repair_unpack_cfg(vdev_label_t * vl,const int l,nvlist_t ** cfg)1238 zhack_repair_unpack_cfg(vdev_label_t *vl, const int l, nvlist_t **cfg)
1239 {
1240 	const char *cfg_keys[] = { ZPOOL_CONFIG_VERSION,
1241 	    ZPOOL_CONFIG_POOL_STATE, ZPOOL_CONFIG_GUID };
1242 	int err;
1243 
1244 	err = nvlist_unpack(vl->vl_vdev_phys.vp_nvlist,
1245 	    VDEV_PHYS_SIZE - sizeof (zio_eck_t), cfg, 0);
1246 	if (err) {
1247 		(void) fprintf(stderr,
1248 		    "error: cannot unpack nvlist label %d\n", l);
1249 		return (err);
1250 	}
1251 
1252 	for (int i = 0; i < ARRAY_SIZE(cfg_keys); i++) {
1253 		uint64_t val;
1254 		err = nvlist_lookup_uint64(*cfg, cfg_keys[i], &val);
1255 		if (err) {
1256 			(void) fprintf(stderr,
1257 			    "error: label %d, %d: "
1258 			    "cannot find nvlist key %s\n",
1259 			    l, i, cfg_keys[i]);
1260 			return (err);
1261 		}
1262 	}
1263 
1264 	return (0);
1265 }
1266 
1267 static void
zhack_repair_one_label(const zhack_repair_op_t op,const int fd,vdev_label_t * vl,const uint64_t label_offset,const int l,uint32_t * labels_repaired)1268 zhack_repair_one_label(const zhack_repair_op_t op, const int fd,
1269     vdev_label_t *vl, const uint64_t label_offset, const int l,
1270     uint32_t *labels_repaired)
1271 {
1272 	ssize_t err;
1273 	uberblock_t *ub = (uberblock_t *)vl->vl_uberblock;
1274 	void *vdev_data =
1275 	    (char *)vl + offsetof(vdev_label_t, vl_vdev_phys);
1276 	zio_eck_t *vdev_eck =
1277 	    (zio_eck_t *)((char *)(vdev_data) + VDEV_PHYS_SIZE) - 1;
1278 	const uint64_t vdev_phys_offset =
1279 	    label_offset + offsetof(vdev_label_t, vl_vdev_phys);
1280 	nvlist_t *cfg;
1281 	uint64_t ashift;
1282 	int byteswap;
1283 
1284 	err = zhack_repair_read_label(fd, vl, label_offset, l);
1285 	if (err)
1286 		return;
1287 
1288 	err = zhack_repair_get_byteswap(vdev_eck, l, &byteswap);
1289 	if (err)
1290 		return;
1291 
1292 	if (byteswap) {
1293 		byteswap_uint64_array(&vdev_eck->zec_cksum,
1294 		    sizeof (zio_cksum_t));
1295 		vdev_eck->zec_magic = BSWAP_64(vdev_eck->zec_magic);
1296 	}
1297 
1298 	if ((op & ZHACK_REPAIR_OP_CKSUM) == 0 &&
1299 	    zhack_repair_test_cksum(byteswap, vdev_data, vdev_eck,
1300 	    vdev_phys_offset, l) != 0) {
1301 		(void) fprintf(stderr, "It would appear checksums are "
1302 		    "corrupted. Try zhack repair label -c <device>\n");
1303 		return;
1304 	}
1305 
1306 	err = zhack_repair_unpack_cfg(vl, l, &cfg);
1307 	if (err)
1308 		return;
1309 
1310 	if ((op & ZHACK_REPAIR_OP_UNDETACH) != 0) {
1311 		char *buf;
1312 		size_t buflen;
1313 
1314 		if (ub->ub_txg != 0) {
1315 			(void) fprintf(stderr,
1316 			    "error: label %d: UB TXG of 0 expected, but got %"
1317 			    PRIu64 "\n", l, ub->ub_txg);
1318 			(void) fprintf(stderr, "It would appear the device was "
1319 			    "not properly detached.\n");
1320 			return;
1321 		}
1322 
1323 		err = zhack_repair_get_ashift(cfg, l, &ashift);
1324 		if (err)
1325 			return;
1326 
1327 		err = zhack_repair_undetach(ub, cfg, l);
1328 		if (err)
1329 			return;
1330 
1331 		buf = vl->vl_vdev_phys.vp_nvlist;
1332 		buflen = VDEV_PHYS_SIZE - sizeof (zio_eck_t);
1333 		if (nvlist_pack(cfg, &buf, &buflen, NV_ENCODE_XDR, 0) != 0) {
1334 			(void) fprintf(stderr,
1335 			    "error: label %d: Failed to pack nvlist\n", l);
1336 			return;
1337 		}
1338 
1339 		zhack_repair_write_uberblock(vl,
1340 		    l, ashift, fd, byteswap, label_offset, labels_repaired);
1341 	}
1342 
1343 	if (zhack_repair_write_label(l, fd, byteswap, vdev_data, vdev_eck,
1344 	    vdev_phys_offset, VDEV_PHYS_SIZE))
1345 			labels_repaired[l] |= REPAIR_LABEL_STATUS_CKSUM;
1346 
1347 	fsync(fd);
1348 }
1349 
1350 static const char *
zhack_repair_label_status(const uint32_t label_status,const uint32_t to_check)1351 zhack_repair_label_status(const uint32_t label_status,
1352     const uint32_t to_check)
1353 {
1354 	return ((label_status & to_check) != 0 ? "repaired" : "skipped");
1355 }
1356 
1357 static int
zhack_label_repair(const zhack_repair_op_t op,const int argc,char ** argv)1358 zhack_label_repair(const zhack_repair_op_t op, const int argc, char **argv)
1359 {
1360 	uint32_t labels_repaired[VDEV_LABELS] = {0};
1361 	vdev_label_t labels[VDEV_LABELS] = {{{0}}};
1362 	struct stat64 st;
1363 	int fd;
1364 	off_t filesize;
1365 	uint32_t repaired = 0;
1366 
1367 	abd_init();
1368 
1369 	if (argc < 1) {
1370 		(void) fprintf(stderr, "error: missing device\n");
1371 		usage();
1372 	}
1373 
1374 	if ((fd = open(argv[0], O_RDWR)) == -1)
1375 		fatal(NULL, FTAG, "cannot open '%s': %s", argv[0],
1376 		    strerror(errno));
1377 
1378 	if (fstat64_blk(fd, &st) != 0)
1379 		fatal(NULL, FTAG, "cannot stat '%s': %s", argv[0],
1380 		    strerror(errno));
1381 
1382 	filesize = st.st_size;
1383 	(void) fprintf(stderr, "Calculated filesize to be %jd\n",
1384 	    (intmax_t)filesize);
1385 
1386 	if (filesize % sizeof (vdev_label_t) != 0)
1387 		filesize =
1388 		    (filesize / sizeof (vdev_label_t)) * sizeof (vdev_label_t);
1389 
1390 	for (int l = 0; l < VDEV_LABELS; l++) {
1391 		zhack_repair_one_label(op, fd, &labels[l],
1392 		    vdev_label_offset(filesize, l, 0), l, labels_repaired);
1393 	}
1394 
1395 	close(fd);
1396 
1397 	abd_fini();
1398 
1399 	for (int l = 0; l < VDEV_LABELS; l++) {
1400 		const uint32_t lr = labels_repaired[l];
1401 		(void) printf("label %d: ", l);
1402 		(void) printf("uberblock: %s ",
1403 		    zhack_repair_label_status(lr, REPAIR_LABEL_STATUS_UB));
1404 		(void) printf("checksum: %s\n",
1405 		    zhack_repair_label_status(lr, REPAIR_LABEL_STATUS_CKSUM));
1406 		repaired |= lr;
1407 	}
1408 
1409 	if (repaired > 0)
1410 		return (0);
1411 
1412 	return (1);
1413 }
1414 
1415 static int
zhack_do_label_repair(int argc,char ** argv)1416 zhack_do_label_repair(int argc, char **argv)
1417 {
1418 	zhack_repair_op_t op = ZHACK_REPAIR_OP_UNKNOWN;
1419 	int c;
1420 
1421 	optind = 1;
1422 	while ((c = getopt(argc, argv, "+cu")) != -1) {
1423 		switch (c) {
1424 		case 'c':
1425 			op |= ZHACK_REPAIR_OP_CKSUM;
1426 			break;
1427 		case 'u':
1428 			op |= ZHACK_REPAIR_OP_UNDETACH;
1429 			break;
1430 		default:
1431 			usage();
1432 			break;
1433 		}
1434 	}
1435 
1436 	argc -= optind;
1437 	argv += optind;
1438 
1439 	if (op == ZHACK_REPAIR_OP_UNKNOWN)
1440 		op = ZHACK_REPAIR_OP_CKSUM;
1441 
1442 	return (zhack_label_repair(op, argc, argv));
1443 }
1444 
1445 static int
zhack_do_label(int argc,char ** argv)1446 zhack_do_label(int argc, char **argv)
1447 {
1448 	char *subcommand;
1449 	int err;
1450 
1451 	argc--;
1452 	argv++;
1453 	if (argc == 0) {
1454 		(void) fprintf(stderr,
1455 		    "error: no label operation specified\n");
1456 		usage();
1457 	}
1458 
1459 	subcommand = argv[0];
1460 	if (strcmp(subcommand, "repair") == 0) {
1461 		err = zhack_do_label_repair(argc, argv);
1462 	} else {
1463 		(void) fprintf(stderr, "error: unknown subcommand: %s\n",
1464 		    subcommand);
1465 		usage();
1466 	}
1467 
1468 	return (err);
1469 }
1470 
1471 #define	MAX_NUM_PATHS 1024
1472 
1473 int
main(int argc,char ** argv)1474 main(int argc, char **argv)
1475 {
1476 	struct sigaction action;
1477 	char *path[MAX_NUM_PATHS];
1478 	const char *subcommand;
1479 	int rv = 0;
1480 	int c;
1481 
1482 	/*
1483 	 * Set up signal handlers, so if we crash due to bad on-disk data we
1484 	 * can get more info. Unlike ztest, we don't bail out if we can't set
1485 	 * up signal handlers, because zhack is very useful without them.
1486 	 */
1487 	action.sa_handler = sig_handler;
1488 	sigemptyset(&action.sa_mask);
1489 	action.sa_flags = 0;
1490 	if (sigaction(SIGSEGV, &action, NULL) < 0) {
1491 		(void) fprintf(stderr, "zhack: cannot catch SIGSEGV: %s\n",
1492 		    strerror(errno));
1493 	}
1494 	if (sigaction(SIGABRT, &action, NULL) < 0) {
1495 		(void) fprintf(stderr, "zhack: cannot catch SIGABRT: %s\n",
1496 		    strerror(errno));
1497 	}
1498 
1499 	g_importargs.path = path;
1500 
1501 	dprintf_setup(&argc, argv);
1502 	zfs_prop_init();
1503 
1504 	while ((c = getopt(argc, argv, "+c:d:Go:")) != -1) {
1505 		switch (c) {
1506 		case 'c':
1507 			g_importargs.cachefile = optarg;
1508 			break;
1509 		case 'd':
1510 			assert(g_importargs.paths < MAX_NUM_PATHS);
1511 			g_importargs.path[g_importargs.paths++] = optarg;
1512 			break;
1513 		case 'G':
1514 			g_dump_dbgmsg = B_TRUE;
1515 			break;
1516 		case 'o':
1517 			if (handle_tunable_option(optarg, B_FALSE) != 0)
1518 				exit(1);
1519 			break;
1520 		default:
1521 			usage();
1522 			break;
1523 		}
1524 	}
1525 
1526 	argc -= optind;
1527 	argv += optind;
1528 	optind = 1;
1529 
1530 	if (argc == 0) {
1531 		(void) fprintf(stderr, "error: no command specified\n");
1532 		usage();
1533 	}
1534 
1535 	subcommand = argv[0];
1536 
1537 	if (strcmp(subcommand, "action") == 0) {
1538 		rv = zhack_do_action(argc, argv);
1539 	} else if (strcmp(subcommand, "feature") == 0) {
1540 		rv = zhack_do_feature(argc, argv);
1541 	} else if (strcmp(subcommand, "mmp") == 0) {
1542 		rv = zhack_do_mmp(argc, argv);
1543 	} else if (strcmp(subcommand, "label") == 0) {
1544 		return (zhack_do_label(argc, argv));
1545 	} else if (strcmp(subcommand, "metaslab") == 0) {
1546 		rv = zhack_do_metaslab(argc, argv);
1547 	} else {
1548 		(void) fprintf(stderr, "error: unknown subcommand: %s\n",
1549 		    subcommand);
1550 		usage();
1551 	}
1552 
1553 	if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_FALSE) != 0) {
1554 		fatal(NULL, FTAG, "pool export failed; "
1555 		    "changes may not be committed to disk\n");
1556 	}
1557 
1558 	if (g_dump_dbgmsg)
1559 		dump_debug_buffer();
1560 
1561 	kernel_fini();
1562 
1563 	return (rv);
1564 }
1565