Print this page
3006 VERIFY[S,U,P] and ASSERT[S,U,P] frequently check if first argument is zero
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/zhack/zhack.c
+++ new/usr/src/cmd/zhack/zhack.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2012 by Delphix. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * zhack is a debugging tool that can write changes to ZFS pool using libzpool
28 28 * for testing purposes. Altering pools with zhack is unsupported and may
29 29 * result in corrupted pools.
30 30 */
31 31
32 32 #include <stdio.h>
33 33 #include <stdlib.h>
34 34 #include <ctype.h>
35 35 #include <sys/zfs_context.h>
36 36 #include <sys/spa.h>
37 37 #include <sys/spa_impl.h>
38 38 #include <sys/dmu.h>
39 39 #include <sys/zap.h>
40 40 #include <sys/zfs_znode.h>
41 41 #include <sys/dsl_synctask.h>
42 42 #include <sys/vdev.h>
43 43 #include <sys/fs/zfs.h>
44 44 #include <sys/dmu_objset.h>
45 45 #include <sys/dsl_pool.h>
46 46 #include <sys/zio_checksum.h>
47 47 #include <sys/zio_compress.h>
48 48 #include <sys/zfeature.h>
49 49 #undef ZFS_MAXNAMELEN
50 50 #undef verify
51 51 #include <libzfs.h>
52 52
53 53 extern boolean_t zfeature_checks_disable;
54 54
55 55 const char cmdname[] = "zhack";
56 56 libzfs_handle_t *g_zfs;
57 57 static importargs_t g_importargs;
58 58 static char *g_pool;
59 59 static boolean_t g_readonly;
60 60
61 61 static void
62 62 usage(void)
63 63 {
64 64 (void) fprintf(stderr,
65 65 "Usage: %s [-c cachefile] [-d dir] <subcommand> <args> ...\n"
66 66 "where <subcommand> <args> is one of the following:\n"
67 67 "\n", cmdname);
68 68
69 69 (void) fprintf(stderr,
70 70 " feature stat <pool>\n"
71 71 " print information about enabled features\n"
72 72 " feature enable [-d desc] <pool> <feature>\n"
73 73 " add a new enabled feature to the pool\n"
74 74 " -d <desc> sets the feature's description\n"
75 75 " feature ref [-md] <pool> <feature>\n"
76 76 " change the refcount on the given feature\n"
77 77 " -d decrease instead of increase the refcount\n"
78 78 " -m add the feature to the label if increasing refcount\n"
79 79 "\n"
80 80 " <feature> : should be a feature guid\n");
81 81 exit(1);
82 82 }
83 83
84 84
85 85 static void
86 86 fatal(const char *fmt, ...)
87 87 {
88 88 va_list ap;
89 89
90 90 va_start(ap, fmt);
91 91 (void) fprintf(stderr, "%s: ", cmdname);
92 92 (void) vfprintf(stderr, fmt, ap);
93 93 va_end(ap);
94 94 (void) fprintf(stderr, "\n");
95 95
96 96 exit(1);
97 97 }
98 98
99 99 /* ARGSUSED */
100 100 static int
101 101 space_delta_cb(dmu_object_type_t bonustype, void *data,
102 102 uint64_t *userp, uint64_t *groupp)
103 103 {
104 104 /*
105 105 * Is it a valid type of object to track?
106 106 */
107 107 if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA)
108 108 return (ENOENT);
109 109 (void) fprintf(stderr, "modifying object that needs user accounting");
110 110 abort();
111 111 /* NOTREACHED */
112 112 }
113 113
114 114 /*
115 115 * Target is the dataset whose pool we want to open.
116 116 */
117 117 static void
118 118 import_pool(const char *target, boolean_t readonly)
119 119 {
120 120 nvlist_t *config;
121 121 nvlist_t *pools;
122 122 int error;
123 123 char *sepp;
124 124 spa_t *spa;
125 125 nvpair_t *elem;
126 126 nvlist_t *props;
127 127 const char *name;
128 128
129 129 kernel_init(readonly ? FREAD : (FREAD | FWRITE));
130 130 g_zfs = libzfs_init();
131 131 ASSERT(g_zfs != NULL);
132 132
133 133 dmu_objset_register_type(DMU_OST_ZFS, space_delta_cb);
134 134
135 135 g_readonly = readonly;
136 136
137 137 /*
138 138 * If we only want readonly access, it's OK if we find
139 139 * a potentially-active (ie, imported into the kernel) pool from the
140 140 * default cachefile.
141 141 */
142 142 if (readonly && spa_open(target, &spa, FTAG) == 0) {
143 143 spa_close(spa, FTAG);
144 144 return;
145 145 }
146 146
147 147 g_importargs.unique = B_TRUE;
148 148 g_importargs.can_be_active = readonly;
149 149 g_pool = strdup(target);
150 150 if ((sepp = strpbrk(g_pool, "/@")) != NULL)
151 151 *sepp = '\0';
152 152 g_importargs.poolname = g_pool;
153 153 pools = zpool_search_import(g_zfs, &g_importargs);
154 154
155 155 if (pools == NULL || nvlist_next_nvpair(pools, NULL) == NULL) {
156 156 if (!g_importargs.can_be_active) {
157 157 g_importargs.can_be_active = B_TRUE;
158 158 if (zpool_search_import(g_zfs, &g_importargs) != NULL ||
159 159 spa_open(target, &spa, FTAG) == 0) {
160 160 fatal("cannot import '%s': pool is active; run "
161 161 "\"zpool export %s\" first\n",
162 162 g_pool, g_pool);
163 163 }
164 164 }
165 165
166 166 fatal("cannot import '%s': no such pool available\n", g_pool);
167 167 }
168 168
169 169 elem = nvlist_next_nvpair(pools, NULL);
170 170 name = nvpair_name(elem);
171 171 verify(nvpair_value_nvlist(elem, &config) == 0);
172 172
173 173 props = NULL;
174 174 if (readonly) {
175 175 verify(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
176 176 verify(nvlist_add_uint64(props,
177 177 zpool_prop_to_name(ZPOOL_PROP_READONLY), 1) == 0);
178 178 }
179 179
180 180 zfeature_checks_disable = B_TRUE;
181 181 error = spa_import(name, config, props, ZFS_IMPORT_NORMAL);
182 182 zfeature_checks_disable = B_FALSE;
183 183 if (error == EEXIST)
184 184 error = 0;
185 185
186 186 if (error)
187 187 fatal("can't import '%s': %s", name, strerror(error));
188 188 }
189 189
190 190 static void
191 191 zhack_spa_open(const char *target, boolean_t readonly, void *tag, spa_t **spa)
192 192 {
193 193 int err;
194 194
195 195 import_pool(target, readonly);
196 196
197 197 zfeature_checks_disable = B_TRUE;
198 198 err = spa_open(target, spa, tag);
199 199 zfeature_checks_disable = B_FALSE;
200 200
201 201 if (err != 0)
202 202 fatal("cannot open '%s': %s", target, strerror(err));
203 203 if (spa_version(*spa) < SPA_VERSION_FEATURES) {
204 204 fatal("'%s' has version %d, features not enabled", target,
205 205 (int)spa_version(*spa));
206 206 }
207 207 }
208 208
209 209 static void
210 210 dump_obj(objset_t *os, uint64_t obj, const char *name)
211 211 {
212 212 zap_cursor_t zc;
213 213 zap_attribute_t za;
214 214
215 215 (void) printf("%s_obj:\n", name);
216 216
217 217 for (zap_cursor_init(&zc, os, obj);
218 218 zap_cursor_retrieve(&zc, &za) == 0;
219 219 zap_cursor_advance(&zc)) {
220 220 if (za.za_integer_length == 8) {
221 221 ASSERT(za.za_num_integers == 1);
222 222 (void) printf("\t%s = %llu\n",
223 223 za.za_name, (u_longlong_t)za.za_first_integer);
224 224 } else {
225 225 ASSERT(za.za_integer_length == 1);
226 226 char val[1024];
227 227 VERIFY(zap_lookup(os, obj, za.za_name,
228 228 1, sizeof (val), val) == 0);
229 229 (void) printf("\t%s = %s\n", za.za_name, val);
230 230 }
231 231 }
232 232 zap_cursor_fini(&zc);
233 233 }
234 234
235 235 static void
236 236 dump_mos(spa_t *spa)
237 237 {
238 238 nvlist_t *nv = spa->spa_label_features;
239 239
240 240 (void) printf("label config:\n");
241 241 for (nvpair_t *pair = nvlist_next_nvpair(nv, NULL);
242 242 pair != NULL;
243 243 pair = nvlist_next_nvpair(nv, pair)) {
244 244 (void) printf("\t%s\n", nvpair_name(pair));
245 245 }
246 246 }
247 247
248 248 static void
249 249 zhack_do_feature_stat(int argc, char **argv)
250 250 {
251 251 spa_t *spa;
252 252 objset_t *os;
253 253 char *target;
254 254
255 255 argc--;
256 256 argv++;
257 257
258 258 if (argc < 1) {
259 259 (void) fprintf(stderr, "error: missing pool name\n");
260 260 usage();
261 261 }
262 262 target = argv[0];
263 263
264 264 zhack_spa_open(target, B_TRUE, FTAG, &spa);
265 265 os = spa->spa_meta_objset;
266 266
267 267 dump_obj(os, spa->spa_feat_for_read_obj, "for_read");
268 268 dump_obj(os, spa->spa_feat_for_write_obj, "for_write");
269 269 dump_obj(os, spa->spa_feat_desc_obj, "descriptions");
270 270 dump_mos(spa);
271 271
272 272 spa_close(spa, FTAG);
273 273 }
274 274
275 275 static void
276 276 feature_enable_sync(void *arg1, void *arg2, dmu_tx_t *tx)
277 277 {
278 278 spa_t *spa = arg1;
279 279 zfeature_info_t *feature = arg2;
280 280
281 281 spa_feature_enable(spa, feature, tx);
282 282 spa_history_log_internal(spa, "zhack enable feature", tx,
283 283 "name=%s can_readonly=%u",
284 284 feature->fi_guid, feature->fi_can_readonly);
285 285 }
286 286
287 287 static void
288 288 zhack_do_feature_enable(int argc, char **argv)
289 289 {
290 290 char c;
291 291 char *desc, *target;
292 292 spa_t *spa;
293 293 objset_t *mos;
294 294 zfeature_info_t feature;
295 295 zfeature_info_t *nodeps[] = { NULL };
296 296
297 297 /*
298 298 * Features are not added to the pool's label until their refcounts
299 299 * are incremented, so fi_mos can just be left as false for now.
300 300 */
301 301 desc = NULL;
302 302 feature.fi_uname = "zhack";
303 303 feature.fi_mos = B_FALSE;
304 304 feature.fi_can_readonly = B_FALSE;
305 305 feature.fi_depends = nodeps;
306 306
307 307 optind = 1;
308 308 while ((c = getopt(argc, argv, "rmd:")) != -1) {
309 309 switch (c) {
310 310 case 'r':
311 311 feature.fi_can_readonly = B_TRUE;
312 312 break;
313 313 case 'd':
314 314 desc = strdup(optarg);
315 315 break;
316 316 default:
317 317 usage();
318 318 break;
319 319 }
320 320 }
321 321
322 322 if (desc == NULL)
323 323 desc = strdup("zhack injected");
324 324 feature.fi_desc = desc;
325 325
326 326 argc -= optind;
327 327 argv += optind;
328 328
329 329 if (argc < 2) {
330 330 (void) fprintf(stderr, "error: missing feature or pool name\n");
331 331 usage();
332 332 }
333 333 target = argv[0];
334 334 feature.fi_guid = argv[1];
335 335
336 336 if (!zfeature_is_valid_guid(feature.fi_guid))
↓ open down ↓ |
336 lines elided |
↑ open up ↑ |
337 337 fatal("invalid feature guid: %s", feature.fi_guid);
338 338
339 339 zhack_spa_open(target, B_FALSE, FTAG, &spa);
340 340 mos = spa->spa_meta_objset;
341 341
342 342 if (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
343 343 fatal("'%s' is a real feature, will not enable");
344 344 if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
345 345 fatal("feature already enabled: %s", feature.fi_guid);
346 346
347 - VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
347 + VERIFY0(dsl_sync_task_do(spa->spa_dsl_pool, NULL,
348 348 feature_enable_sync, spa, &feature, 5));
349 349
350 350 spa_close(spa, FTAG);
351 351
352 352 free(desc);
353 353 }
354 354
355 355 static void
356 356 feature_incr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
357 357 {
358 358 spa_t *spa = arg1;
359 359 zfeature_info_t *feature = arg2;
360 360
361 361 spa_feature_incr(spa, feature, tx);
362 362 spa_history_log_internal(spa, "zhack feature incr", tx,
363 363 "name=%s", feature->fi_guid);
364 364 }
365 365
366 366 static void
367 367 feature_decr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
368 368 {
369 369 spa_t *spa = arg1;
370 370 zfeature_info_t *feature = arg2;
371 371
372 372 spa_feature_decr(spa, feature, tx);
373 373 spa_history_log_internal(spa, "zhack feature decr", tx,
374 374 "name=%s", feature->fi_guid);
375 375 }
376 376
377 377 static void
378 378 zhack_do_feature_ref(int argc, char **argv)
379 379 {
380 380 char c;
381 381 char *target;
382 382 boolean_t decr = B_FALSE;
383 383 spa_t *spa;
384 384 objset_t *mos;
385 385 zfeature_info_t feature;
386 386 zfeature_info_t *nodeps[] = { NULL };
387 387
388 388 /*
389 389 * fi_desc does not matter here because it was written to disk
390 390 * when the feature was enabled, but we need to properly set the
391 391 * feature for read or write based on the information we read off
392 392 * disk later.
393 393 */
394 394 feature.fi_uname = "zhack";
395 395 feature.fi_mos = B_FALSE;
396 396 feature.fi_desc = NULL;
397 397 feature.fi_depends = nodeps;
398 398
399 399 optind = 1;
400 400 while ((c = getopt(argc, argv, "md")) != -1) {
401 401 switch (c) {
402 402 case 'm':
403 403 feature.fi_mos = B_TRUE;
404 404 break;
405 405 case 'd':
406 406 decr = B_TRUE;
407 407 break;
408 408 default:
409 409 usage();
410 410 break;
411 411 }
412 412 }
413 413 argc -= optind;
414 414 argv += optind;
415 415
416 416 if (argc < 2) {
417 417 (void) fprintf(stderr, "error: missing feature or pool name\n");
418 418 usage();
419 419 }
420 420 target = argv[0];
421 421 feature.fi_guid = argv[1];
422 422
423 423 if (!zfeature_is_valid_guid(feature.fi_guid))
424 424 fatal("invalid feature guid: %s", feature.fi_guid);
425 425
426 426 zhack_spa_open(target, B_FALSE, FTAG, &spa);
427 427 mos = spa->spa_meta_objset;
428 428
429 429 if (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
430 430 fatal("'%s' is a real feature, will not change refcount");
431 431
432 432 if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
433 433 feature.fi_guid)) {
434 434 feature.fi_can_readonly = B_FALSE;
↓ open down ↓ |
77 lines elided |
↑ open up ↑ |
435 435 } else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
436 436 feature.fi_guid)) {
437 437 feature.fi_can_readonly = B_TRUE;
438 438 } else {
439 439 fatal("feature is not enabled: %s", feature.fi_guid);
440 440 }
441 441
442 442 if (decr && !spa_feature_is_active(spa, &feature))
443 443 fatal("feature refcount already 0: %s", feature.fi_guid);
444 444
445 - VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
445 + VERIFY0(dsl_sync_task_do(spa->spa_dsl_pool, NULL,
446 446 decr ? feature_decr_sync : feature_incr_sync, spa, &feature, 5));
447 447
448 448 spa_close(spa, FTAG);
449 449 }
450 450
451 451 static int
452 452 zhack_do_feature(int argc, char **argv)
453 453 {
454 454 char *subcommand;
455 455
456 456 argc--;
457 457 argv++;
458 458 if (argc == 0) {
459 459 (void) fprintf(stderr,
460 460 "error: no feature operation specified\n");
461 461 usage();
462 462 }
463 463
464 464 subcommand = argv[0];
465 465 if (strcmp(subcommand, "stat") == 0) {
466 466 zhack_do_feature_stat(argc, argv);
467 467 } else if (strcmp(subcommand, "enable") == 0) {
468 468 zhack_do_feature_enable(argc, argv);
469 469 } else if (strcmp(subcommand, "ref") == 0) {
470 470 zhack_do_feature_ref(argc, argv);
471 471 } else {
472 472 (void) fprintf(stderr, "error: unknown subcommand: %s\n",
473 473 subcommand);
474 474 usage();
475 475 }
476 476
477 477 return (0);
478 478 }
479 479
480 480 #define MAX_NUM_PATHS 1024
481 481
482 482 int
483 483 main(int argc, char **argv)
484 484 {
485 485 extern void zfs_prop_init(void);
486 486
487 487 char *path[MAX_NUM_PATHS];
488 488 const char *subcommand;
489 489 int rv = 0;
490 490 char c;
491 491
492 492 g_importargs.path = path;
493 493
494 494 dprintf_setup(&argc, argv);
495 495 zfs_prop_init();
496 496
497 497 while ((c = getopt(argc, argv, "c:d:")) != -1) {
498 498 switch (c) {
499 499 case 'c':
500 500 g_importargs.cachefile = optarg;
501 501 break;
502 502 case 'd':
503 503 assert(g_importargs.paths < MAX_NUM_PATHS);
504 504 g_importargs.path[g_importargs.paths++] = optarg;
505 505 break;
506 506 default:
507 507 usage();
508 508 break;
509 509 }
510 510 }
511 511
512 512 argc -= optind;
513 513 argv += optind;
514 514 optind = 1;
515 515
516 516 if (argc == 0) {
517 517 (void) fprintf(stderr, "error: no command specified\n");
518 518 usage();
519 519 }
520 520
521 521 subcommand = argv[0];
522 522
523 523 if (strcmp(subcommand, "feature") == 0) {
524 524 rv = zhack_do_feature(argc, argv);
525 525 } else {
526 526 (void) fprintf(stderr, "error: unknown subcommand: %s\n",
527 527 subcommand);
528 528 usage();
529 529 }
530 530
531 531 if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_TRUE) != 0) {
532 532 fatal("pool export failed; "
533 533 "changes may not be committed to disk\n");
534 534 }
535 535
536 536 libzfs_fini(g_zfs);
537 537 kernel_fini();
538 538
539 539 return (rv);
540 540 }
↓ open down ↓ |
85 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX