Print this page
2882 implement libzfs_core
2883 changing "canmount" property to "on" should not always remount dataset
2900 "zfs snapshot" should be able to create multiple, arbitrary snapshots at once
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Chris Siden <christopher.siden@delphix.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Bill Pijewski <wdp@joyent.com>
Reviewed by: Dan Kruchinin <dan.kruchinin@gmail.com>
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
↓ open down ↓ |
271 lines elided |
↑ open up ↑ |
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 + spa_history_log_internal(spa, "zhack enable feature", tx,
283 + "name=%s can_readonly=%u",
284 + feature->fi_guid, feature->fi_can_readonly);
282 285 }
283 286
284 287 static void
285 288 zhack_do_feature_enable(int argc, char **argv)
286 289 {
287 290 char c;
288 291 char *desc, *target;
289 292 spa_t *spa;
290 293 objset_t *mos;
291 294 zfeature_info_t feature;
292 295 zfeature_info_t *nodeps[] = { NULL };
293 296
294 297 /*
295 298 * Features are not added to the pool's label until their refcounts
296 299 * are incremented, so fi_mos can just be left as false for now.
297 300 */
298 301 desc = NULL;
299 302 feature.fi_uname = "zhack";
300 303 feature.fi_mos = B_FALSE;
301 304 feature.fi_can_readonly = B_FALSE;
302 305 feature.fi_depends = nodeps;
303 306
304 307 optind = 1;
305 308 while ((c = getopt(argc, argv, "rmd:")) != -1) {
306 309 switch (c) {
307 310 case 'r':
308 311 feature.fi_can_readonly = B_TRUE;
309 312 break;
310 313 case 'd':
311 314 desc = strdup(optarg);
312 315 break;
313 316 default:
314 317 usage();
315 318 break;
316 319 }
317 320 }
318 321
319 322 if (desc == NULL)
320 323 desc = strdup("zhack injected");
321 324 feature.fi_desc = desc;
322 325
323 326 argc -= optind;
324 327 argv += optind;
325 328
326 329 if (argc < 2) {
327 330 (void) fprintf(stderr, "error: missing feature or pool name\n");
328 331 usage();
329 332 }
330 333 target = argv[0];
331 334 feature.fi_guid = argv[1];
332 335
333 336 if (!zfeature_is_valid_guid(feature.fi_guid))
334 337 fatal("invalid feature guid: %s", feature.fi_guid);
335 338
336 339 zhack_spa_open(target, B_FALSE, FTAG, &spa);
337 340 mos = spa->spa_meta_objset;
338 341
339 342 if (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
340 343 fatal("'%s' is a real feature, will not enable");
341 344 if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
342 345 fatal("feature already enabled: %s", feature.fi_guid);
343 346
344 347 VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
345 348 feature_enable_sync, spa, &feature, 5));
346 349
347 350 spa_close(spa, FTAG);
348 351
↓ open down ↓ |
57 lines elided |
↑ open up ↑ |
349 352 free(desc);
350 353 }
351 354
352 355 static void
353 356 feature_incr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
354 357 {
355 358 spa_t *spa = arg1;
356 359 zfeature_info_t *feature = arg2;
357 360
358 361 spa_feature_incr(spa, feature, tx);
362 + spa_history_log_internal(spa, "zhack feature incr", tx,
363 + "name=%s", feature->fi_guid);
359 364 }
360 365
361 366 static void
362 367 feature_decr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
363 368 {
364 369 spa_t *spa = arg1;
365 370 zfeature_info_t *feature = arg2;
366 371
367 372 spa_feature_decr(spa, feature, tx);
373 + spa_history_log_internal(spa, "zhack feature decr", tx,
374 + "name=%s", feature->fi_guid);
368 375 }
369 376
370 377 static void
371 378 zhack_do_feature_ref(int argc, char **argv)
372 379 {
373 380 char c;
374 381 char *target;
375 382 boolean_t decr = B_FALSE;
376 383 spa_t *spa;
377 384 objset_t *mos;
378 385 zfeature_info_t feature;
379 386 zfeature_info_t *nodeps[] = { NULL };
380 387
381 388 /*
382 389 * fi_desc does not matter here because it was written to disk
383 390 * when the feature was enabled, but we need to properly set the
384 391 * feature for read or write based on the information we read off
385 392 * disk later.
386 393 */
387 394 feature.fi_uname = "zhack";
388 395 feature.fi_mos = B_FALSE;
389 396 feature.fi_desc = NULL;
390 397 feature.fi_depends = nodeps;
391 398
392 399 optind = 1;
393 400 while ((c = getopt(argc, argv, "md")) != -1) {
394 401 switch (c) {
395 402 case 'm':
396 403 feature.fi_mos = B_TRUE;
397 404 break;
398 405 case 'd':
399 406 decr = B_TRUE;
400 407 break;
401 408 default:
402 409 usage();
403 410 break;
404 411 }
405 412 }
406 413 argc -= optind;
407 414 argv += optind;
408 415
409 416 if (argc < 2) {
410 417 (void) fprintf(stderr, "error: missing feature or pool name\n");
411 418 usage();
412 419 }
413 420 target = argv[0];
414 421 feature.fi_guid = argv[1];
415 422
416 423 if (!zfeature_is_valid_guid(feature.fi_guid))
417 424 fatal("invalid feature guid: %s", feature.fi_guid);
418 425
419 426 zhack_spa_open(target, B_FALSE, FTAG, &spa);
420 427 mos = spa->spa_meta_objset;
421 428
422 429 if (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
423 430 fatal("'%s' is a real feature, will not change refcount");
424 431
425 432 if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
426 433 feature.fi_guid)) {
427 434 feature.fi_can_readonly = B_FALSE;
428 435 } else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
429 436 feature.fi_guid)) {
430 437 feature.fi_can_readonly = B_TRUE;
431 438 } else {
432 439 fatal("feature is not enabled: %s", feature.fi_guid);
433 440 }
434 441
435 442 if (decr && !spa_feature_is_active(spa, &feature))
436 443 fatal("feature refcount already 0: %s", feature.fi_guid);
437 444
438 445 VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
439 446 decr ? feature_decr_sync : feature_incr_sync, spa, &feature, 5));
440 447
441 448 spa_close(spa, FTAG);
442 449 }
443 450
444 451 static int
445 452 zhack_do_feature(int argc, char **argv)
446 453 {
447 454 char *subcommand;
448 455
449 456 argc--;
450 457 argv++;
451 458 if (argc == 0) {
452 459 (void) fprintf(stderr,
453 460 "error: no feature operation specified\n");
454 461 usage();
455 462 }
456 463
457 464 subcommand = argv[0];
458 465 if (strcmp(subcommand, "stat") == 0) {
459 466 zhack_do_feature_stat(argc, argv);
460 467 } else if (strcmp(subcommand, "enable") == 0) {
461 468 zhack_do_feature_enable(argc, argv);
462 469 } else if (strcmp(subcommand, "ref") == 0) {
463 470 zhack_do_feature_ref(argc, argv);
464 471 } else {
465 472 (void) fprintf(stderr, "error: unknown subcommand: %s\n",
466 473 subcommand);
467 474 usage();
468 475 }
469 476
470 477 return (0);
471 478 }
472 479
473 480 #define MAX_NUM_PATHS 1024
474 481
475 482 int
476 483 main(int argc, char **argv)
477 484 {
478 485 extern void zfs_prop_init(void);
479 486
480 487 char *path[MAX_NUM_PATHS];
481 488 const char *subcommand;
482 489 int rv = 0;
483 490 char c;
484 491
485 492 g_importargs.path = path;
486 493
487 494 dprintf_setup(&argc, argv);
488 495 zfs_prop_init();
489 496
490 497 while ((c = getopt(argc, argv, "c:d:")) != -1) {
491 498 switch (c) {
492 499 case 'c':
493 500 g_importargs.cachefile = optarg;
494 501 break;
495 502 case 'd':
496 503 assert(g_importargs.paths < MAX_NUM_PATHS);
497 504 g_importargs.path[g_importargs.paths++] = optarg;
498 505 break;
499 506 default:
500 507 usage();
501 508 break;
502 509 }
503 510 }
504 511
505 512 argc -= optind;
506 513 argv += optind;
507 514 optind = 1;
508 515
509 516 if (argc == 0) {
510 517 (void) fprintf(stderr, "error: no command specified\n");
511 518 usage();
512 519 }
513 520
514 521 subcommand = argv[0];
515 522
516 523 if (strcmp(subcommand, "feature") == 0) {
517 524 rv = zhack_do_feature(argc, argv);
518 525 } else {
519 526 (void) fprintf(stderr, "error: unknown subcommand: %s\n",
520 527 subcommand);
521 528 usage();
522 529 }
523 530
524 531 if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_TRUE) != 0) {
525 532 fatal("pool export failed; "
526 533 "changes may not be committed to disk\n");
527 534 }
528 535
529 536 libzfs_fini(g_zfs);
530 537 kernel_fini();
531 538
532 539 return (rv);
533 540 }
↓ open down ↓ |
156 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX