Print this page
12764 Holes prevent TRIM
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/zpool/zpool_main.c
+++ new/usr/src/cmd/zpool/zpool_main.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) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
25 25 * Copyright (c) 2012 by Frederik Wessels. All rights reserved.
26 26 * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
27 27 * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
28 28 * Copyright 2016 Nexenta Systems, Inc.
29 29 * Copyright (c) 2017 Datto Inc.
30 30 * Copyright (c) 2017, Intel Corporation.
31 31 * Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com>
32 32 * Copyright 2020 Joyent, Inc.
33 33 * Copyright (c) 2012 by Cyril Plisko. All rights reserved.
34 34 * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
35 35 */
36 36
37 37 #include <assert.h>
38 38 #include <ctype.h>
39 39 #include <dirent.h>
40 40 #include <errno.h>
41 41 #include <fcntl.h>
42 42 #include <getopt.h>
43 43 #include <libgen.h>
44 44 #include <libintl.h>
45 45 #include <libuutil.h>
46 46 #include <locale.h>
47 47 #include <stdio.h>
48 48 #include <stdlib.h>
49 49 #include <string.h>
50 50 #include <strings.h>
51 51 #include <unistd.h>
52 52 #include <priv.h>
53 53 #include <pwd.h>
54 54 #include <zone.h>
55 55 #include <zfs_prop.h>
56 56 #include <sys/fs/zfs.h>
57 57 #include <sys/stat.h>
58 58 #include <sys/debug.h>
59 59 #include <math.h>
60 60 #include <sys/sysmacros.h>
61 61 #include <sys/termios.h>
62 62
63 63 #include <libzfs.h>
64 64 #include <libzutil.h>
65 65
66 66 #include "zpool_util.h"
67 67 #include "zfs_comutil.h"
68 68 #include "zfeature_common.h"
69 69
70 70 #include "statcommon.h"
71 71
72 72 static int zpool_do_create(int, char **);
73 73 static int zpool_do_destroy(int, char **);
74 74
75 75 static int zpool_do_add(int, char **);
76 76 static int zpool_do_remove(int, char **);
77 77 static int zpool_do_labelclear(int, char **);
78 78
79 79 static int zpool_do_checkpoint(int, char **);
80 80
81 81 static int zpool_do_list(int, char **);
82 82 static int zpool_do_iostat(int, char **);
83 83 static int zpool_do_status(int, char **);
84 84
85 85 static int zpool_do_online(int, char **);
86 86 static int zpool_do_offline(int, char **);
87 87 static int zpool_do_clear(int, char **);
88 88 static int zpool_do_reopen(int, char **);
89 89
90 90 static int zpool_do_reguid(int, char **);
91 91
92 92 static int zpool_do_attach(int, char **);
93 93 static int zpool_do_detach(int, char **);
94 94 static int zpool_do_replace(int, char **);
95 95 static int zpool_do_split(int, char **);
96 96
97 97 static int zpool_do_initialize(int, char **);
98 98 static int zpool_do_scrub(int, char **);
99 99 static int zpool_do_resilver(int, char **);
100 100 static int zpool_do_trim(int, char **);
101 101
102 102 static int zpool_do_import(int, char **);
103 103 static int zpool_do_export(int, char **);
104 104
105 105 static int zpool_do_upgrade(int, char **);
106 106
107 107 static int zpool_do_history(int, char **);
108 108
109 109 static int zpool_do_get(int, char **);
110 110 static int zpool_do_set(int, char **);
111 111
112 112 static int zpool_do_sync(int, char **);
113 113
114 114 /*
115 115 * These libumem hooks provide a reasonable set of defaults for the allocator's
116 116 * debugging facilities.
117 117 */
118 118
119 119 #ifdef DEBUG
120 120 const char *
121 121 _umem_debug_init(void)
122 122 {
123 123 return ("default,verbose"); /* $UMEM_DEBUG setting */
124 124 }
125 125
126 126 const char *
127 127 _umem_logging_init(void)
128 128 {
129 129 return ("fail,contents"); /* $UMEM_LOGGING setting */
130 130 }
131 131 #endif
132 132
133 133 typedef enum {
134 134 HELP_ADD,
135 135 HELP_ATTACH,
136 136 HELP_CLEAR,
137 137 HELP_CREATE,
138 138 HELP_CHECKPOINT,
139 139 HELP_DESTROY,
140 140 HELP_DETACH,
141 141 HELP_EXPORT,
142 142 HELP_HISTORY,
143 143 HELP_IMPORT,
144 144 HELP_IOSTAT,
145 145 HELP_LABELCLEAR,
146 146 HELP_LIST,
147 147 HELP_OFFLINE,
148 148 HELP_ONLINE,
149 149 HELP_REPLACE,
150 150 HELP_REMOVE,
151 151 HELP_INITIALIZE,
152 152 HELP_SCRUB,
153 153 HELP_RESILVER,
154 154 HELP_TRIM,
155 155 HELP_STATUS,
156 156 HELP_UPGRADE,
157 157 HELP_GET,
158 158 HELP_SET,
159 159 HELP_SPLIT,
160 160 HELP_SYNC,
161 161 HELP_REGUID,
162 162 HELP_REOPEN
163 163 } zpool_help_t;
164 164
165 165
166 166 /*
167 167 * Flags for stats to display with "zpool iostats"
168 168 */
169 169 enum iostat_type {
170 170 IOS_DEFAULT = 0,
171 171 IOS_LATENCY = 1,
172 172 IOS_QUEUES = 2,
173 173 IOS_L_HISTO = 3,
174 174 IOS_RQ_HISTO = 4,
175 175 IOS_COUNT, /* always last element */
176 176 };
177 177
178 178 /* iostat_type entries as bitmasks */
179 179 #define IOS_DEFAULT_M (1ULL << IOS_DEFAULT)
180 180 #define IOS_LATENCY_M (1ULL << IOS_LATENCY)
181 181 #define IOS_QUEUES_M (1ULL << IOS_QUEUES)
182 182 #define IOS_L_HISTO_M (1ULL << IOS_L_HISTO)
183 183 #define IOS_RQ_HISTO_M (1ULL << IOS_RQ_HISTO)
184 184
185 185 /* Mask of all the histo bits */
186 186 #define IOS_ANYHISTO_M (IOS_L_HISTO_M | IOS_RQ_HISTO_M)
187 187
188 188 /*
189 189 * Lookup table for iostat flags to nvlist names. Basically a list
190 190 * of all the nvlists a flag requires. Also specifies the order in
191 191 * which data gets printed in zpool iostat.
192 192 */
193 193 static const char *vsx_type_to_nvlist[IOS_COUNT][13] = {
194 194 [IOS_L_HISTO] = {
195 195 ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO,
196 196 ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO,
197 197 ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO,
198 198 ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO,
199 199 ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO,
200 200 ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO,
201 201 ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO,
202 202 ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO,
203 203 ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO,
204 204 ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO,
205 205 NULL},
206 206 [IOS_LATENCY] = {
207 207 ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO,
208 208 ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO,
209 209 ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO,
210 210 ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO,
211 211 ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO,
212 212 NULL},
213 213 [IOS_QUEUES] = {
214 214 ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE,
215 215 ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE,
216 216 ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE,
217 217 ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE,
218 218 ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE,
219 219 ZPOOL_CONFIG_VDEV_TRIM_ACTIVE_QUEUE,
220 220 NULL},
221 221 [IOS_RQ_HISTO] = {
222 222 ZPOOL_CONFIG_VDEV_SYNC_IND_R_HISTO,
223 223 ZPOOL_CONFIG_VDEV_SYNC_AGG_R_HISTO,
224 224 ZPOOL_CONFIG_VDEV_SYNC_IND_W_HISTO,
225 225 ZPOOL_CONFIG_VDEV_SYNC_AGG_W_HISTO,
226 226 ZPOOL_CONFIG_VDEV_ASYNC_IND_R_HISTO,
227 227 ZPOOL_CONFIG_VDEV_ASYNC_AGG_R_HISTO,
228 228 ZPOOL_CONFIG_VDEV_ASYNC_IND_W_HISTO,
229 229 ZPOOL_CONFIG_VDEV_ASYNC_AGG_W_HISTO,
230 230 ZPOOL_CONFIG_VDEV_IND_SCRUB_HISTO,
231 231 ZPOOL_CONFIG_VDEV_AGG_SCRUB_HISTO,
232 232 ZPOOL_CONFIG_VDEV_IND_TRIM_HISTO,
233 233 ZPOOL_CONFIG_VDEV_AGG_TRIM_HISTO,
234 234 NULL},
235 235 };
236 236
237 237
238 238 /*
239 239 * Given a cb->cb_flags with a histogram bit set, return the iostat_type.
240 240 * Right now, only one histo bit is ever set at one time, so we can
241 241 * just do a highbit64(a)
242 242 */
243 243 #define IOS_HISTO_IDX(a) (highbit64(a & IOS_ANYHISTO_M) - 1)
244 244
245 245 typedef struct zpool_command {
246 246 const char *name;
247 247 int (*func)(int, char **);
248 248 zpool_help_t usage;
249 249 } zpool_command_t;
250 250
251 251 /*
252 252 * Master command table. Each ZFS command has a name, associated function, and
253 253 * usage message. The usage messages need to be internationalized, so we have
254 254 * to have a function to return the usage message based on a command index.
255 255 *
256 256 * These commands are organized according to how they are displayed in the usage
257 257 * message. An empty command (one with a NULL name) indicates an empty line in
258 258 * the generic usage message.
259 259 */
260 260 static zpool_command_t command_table[] = {
261 261 { "create", zpool_do_create, HELP_CREATE },
262 262 { "destroy", zpool_do_destroy, HELP_DESTROY },
263 263 { NULL },
264 264 { "add", zpool_do_add, HELP_ADD },
265 265 { "remove", zpool_do_remove, HELP_REMOVE },
266 266 { NULL },
267 267 { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR },
268 268 { NULL },
269 269 { "checkpoint", zpool_do_checkpoint, HELP_CHECKPOINT },
270 270 { NULL },
271 271 { "list", zpool_do_list, HELP_LIST },
272 272 { "iostat", zpool_do_iostat, HELP_IOSTAT },
273 273 { "status", zpool_do_status, HELP_STATUS },
274 274 { NULL },
275 275 { "online", zpool_do_online, HELP_ONLINE },
276 276 { "offline", zpool_do_offline, HELP_OFFLINE },
277 277 { "clear", zpool_do_clear, HELP_CLEAR },
278 278 { "reopen", zpool_do_reopen, HELP_REOPEN },
279 279 { NULL },
280 280 { "attach", zpool_do_attach, HELP_ATTACH },
281 281 { "detach", zpool_do_detach, HELP_DETACH },
282 282 { "replace", zpool_do_replace, HELP_REPLACE },
283 283 { "split", zpool_do_split, HELP_SPLIT },
284 284 { NULL },
285 285 { "initialize", zpool_do_initialize, HELP_INITIALIZE },
286 286 { "resilver", zpool_do_resilver, HELP_RESILVER },
287 287 { "scrub", zpool_do_scrub, HELP_SCRUB },
288 288 { "trim", zpool_do_trim, HELP_TRIM },
289 289 { NULL },
290 290 { "import", zpool_do_import, HELP_IMPORT },
291 291 { "export", zpool_do_export, HELP_EXPORT },
292 292 { "upgrade", zpool_do_upgrade, HELP_UPGRADE },
293 293 { "reguid", zpool_do_reguid, HELP_REGUID },
294 294 { NULL },
295 295 { "history", zpool_do_history, HELP_HISTORY },
296 296 { "get", zpool_do_get, HELP_GET },
297 297 { "set", zpool_do_set, HELP_SET },
298 298 { "sync", zpool_do_sync, HELP_SYNC },
299 299 };
300 300
301 301 #define NCOMMAND (ARRAY_SIZE(command_table))
302 302
303 303 #define VDEV_ALLOC_CLASS_LOGS "logs"
304 304
305 305 static zpool_command_t *current_command;
306 306 static char history_str[HIS_MAX_RECORD_LEN];
307 307 static boolean_t log_history = B_TRUE;
308 308 static uint_t timestamp_fmt = NODATE;
309 309
310 310 static const char *
311 311 get_usage(zpool_help_t idx)
312 312 {
313 313 switch (idx) {
314 314 case HELP_ADD:
315 315 return (gettext("\tadd [-fgLnP] [-o property=value] "
316 316 "<pool> <vdev> ...\n"));
317 317 case HELP_ATTACH:
318 318 return (gettext("\tattach [-f] [-o property=value] "
319 319 "<pool> <device> <new-device>\n"));
320 320 case HELP_CLEAR:
321 321 return (gettext("\tclear [-nF] <pool> [device]\n"));
322 322 case HELP_CREATE:
323 323 return (gettext("\tcreate [-fnd] [-B] "
324 324 "[-o property=value] ... \n"
325 325 "\t [-O file-system-property=value] ...\n"
326 326 "\t [-m mountpoint] [-R root] [-t tempname] "
327 327 "<pool> <vdev> ...\n"));
328 328 case HELP_CHECKPOINT:
329 329 return (gettext("\tcheckpoint [--discard] <pool> ...\n"));
330 330 case HELP_DESTROY:
331 331 return (gettext("\tdestroy [-f] <pool>\n"));
332 332 case HELP_DETACH:
333 333 return (gettext("\tdetach <pool> <device>\n"));
334 334 case HELP_EXPORT:
335 335 return (gettext("\texport [-f] <pool> ...\n"));
336 336 case HELP_HISTORY:
337 337 return (gettext("\thistory [-il] [<pool>] ...\n"));
338 338 case HELP_IMPORT:
339 339 return (gettext("\timport [-d dir] [-D]\n"
340 340 "\timport [-d dir | -c cachefile] [-F [-n]] [-l] "
341 341 "<pool | id>\n"
342 342 "\timport [-o mntopts] [-o property=value] ... \n"
343 343 "\t [-d dir | -c cachefile] [-D] [-l] [-f] [-m] [-N] "
344 344 "[-R root] [-F [-n]] -a\n"
345 345 "\timport [-o mntopts] [-o property=value] ... \n"
346 346 "\t [-d dir | -c cachefile] [-D] [-l] [-f] [-m] [-N] "
347 347 "[-R root] [-F [-n]] [-t]\n"
348 348 "\t [--rewind-to-checkpoint] <pool | id> [newpool]\n"));
349 349 case HELP_IOSTAT:
350 350 return (gettext("\tiostat "
351 351 "[[-lq]|[-rw]] [-T d | u] [-ghHLpPvy]\n"
352 352 "\t [[pool] ...]|[pool vdev ...]|[vdev ...]]"
353 353 " [[-n] interval [count]]\n"));
354 354 case HELP_LABELCLEAR:
355 355 return (gettext("\tlabelclear [-f] <vdev>\n"));
356 356 case HELP_LIST:
357 357 return (gettext("\tlist [-gHLpPv] [-o property[,...]] "
358 358 "[-T d|u] [pool] ... [interval [count]]\n"));
359 359 case HELP_OFFLINE:
360 360 return (gettext("\toffline [-t] <pool> <device> ...\n"));
361 361 case HELP_ONLINE:
362 362 return (gettext("\tonline <pool> <device> ...\n"));
363 363 case HELP_REPLACE:
364 364 return (gettext("\treplace [-f] <pool> <device> "
365 365 "[new-device]\n"));
366 366 case HELP_REMOVE:
367 367 return (gettext("\tremove [-nps] <pool> <device> ...\n"));
368 368 case HELP_REOPEN:
369 369 return (gettext("\treopen <pool>\n"));
370 370 case HELP_INITIALIZE:
371 371 return (gettext("\tinitialize [-c | -s] <pool> "
372 372 "[<device> ...]\n"));
373 373 case HELP_SCRUB:
374 374 return (gettext("\tscrub [-s | -p] <pool> ...\n"));
375 375 case HELP_RESILVER:
376 376 return (gettext("\tresilver <pool> ...\n"));
377 377 case HELP_TRIM:
378 378 return (gettext("\ttrim [-d] [-r <rate>] [-c | -s] <pool> "
379 379 "[<device> ...]\n"));
380 380 case HELP_STATUS:
381 381 return (gettext("\tstatus "
382 382 "[-igLpPsvxD] [-T d|u] [pool] ... "
383 383 "[interval [count]]\n"));
384 384 case HELP_UPGRADE:
385 385 return (gettext("\tupgrade\n"
386 386 "\tupgrade -v\n"
387 387 "\tupgrade [-V version] <-a | pool ...>\n"));
388 388 case HELP_GET:
389 389 return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] "
390 390 "<\"all\" | property[,...]> <pool> ...\n"));
391 391 case HELP_SET:
392 392 return (gettext("\tset <property=value> <pool> \n"));
393 393 case HELP_SPLIT:
394 394 return (gettext("\tsplit [-gLlnP] [-R altroot] [-o mntopts]\n"
395 395 "\t [-o property=value] <pool> <newpool> "
396 396 "[<device> ...]\n"));
397 397 case HELP_REGUID:
398 398 return (gettext("\treguid <pool>\n"));
399 399 case HELP_SYNC:
400 400 return (gettext("\tsync [pool] ...\n"));
401 401 }
402 402
403 403 abort();
404 404 /* NOTREACHED */
405 405 }
406 406
407 407 static void
408 408 zpool_collect_leaves(zpool_handle_t *zhp, nvlist_t *nvroot, nvlist_t *res)
409 409 {
↓ open down ↓ |
409 lines elided |
↑ open up ↑ |
410 410 uint_t children = 0;
411 411 nvlist_t **child;
412 412 uint_t i;
413 413
414 414 (void) nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
415 415 &child, &children);
416 416
417 417 if (children == 0) {
418 418 char *path = zpool_vdev_name(g_zfs, zhp, nvroot, 0);
419 419
420 - if (strcmp(path, VDEV_TYPE_INDIRECT) != 0)
420 + if (strcmp(path, VDEV_TYPE_INDIRECT) != 0 &&
421 + strcmp(path, VDEV_TYPE_HOLE) != 0)
421 422 fnvlist_add_boolean(res, path);
422 423
423 424 free(path);
424 425 return;
425 426 }
426 427
427 428 for (i = 0; i < children; i++) {
428 429 zpool_collect_leaves(zhp, child[i], res);
429 430 }
430 431 }
431 432
432 433 /*
433 434 * Callback routine that will print out a pool property value.
434 435 */
435 436 static int
436 437 print_prop_cb(int prop, void *cb)
437 438 {
438 439 FILE *fp = cb;
439 440
440 441 (void) fprintf(fp, "\t%-19s ", zpool_prop_to_name(prop));
441 442
442 443 if (zpool_prop_readonly(prop))
443 444 (void) fprintf(fp, " NO ");
444 445 else
445 446 (void) fprintf(fp, " YES ");
446 447
447 448 if (zpool_prop_values(prop) == NULL)
448 449 (void) fprintf(fp, "-\n");
449 450 else
450 451 (void) fprintf(fp, "%s\n", zpool_prop_values(prop));
451 452
452 453 return (ZPROP_CONT);
453 454 }
454 455
455 456 /*
456 457 * Display usage message. If we're inside a command, display only the usage for
457 458 * that command. Otherwise, iterate over the entire command table and display
458 459 * a complete usage message.
459 460 */
460 461 void
461 462 usage(boolean_t requested)
462 463 {
463 464 FILE *fp = requested ? stdout : stderr;
464 465
465 466 if (current_command == NULL) {
466 467 int i;
467 468
468 469 (void) fprintf(fp, gettext("usage: zpool command args ...\n"));
469 470 (void) fprintf(fp,
470 471 gettext("where 'command' is one of the following:\n\n"));
471 472
472 473 for (i = 0; i < NCOMMAND; i++) {
473 474 if (command_table[i].name == NULL)
474 475 (void) fprintf(fp, "\n");
475 476 else
476 477 (void) fprintf(fp, "%s",
477 478 get_usage(command_table[i].usage));
478 479 }
479 480 } else {
480 481 (void) fprintf(fp, gettext("usage:\n"));
481 482 (void) fprintf(fp, "%s", get_usage(current_command->usage));
482 483 }
483 484
484 485 if (current_command != NULL &&
485 486 ((strcmp(current_command->name, "set") == 0) ||
486 487 (strcmp(current_command->name, "get") == 0) ||
487 488 (strcmp(current_command->name, "list") == 0))) {
488 489
489 490 (void) fprintf(fp,
490 491 gettext("\nthe following properties are supported:\n"));
491 492
492 493 (void) fprintf(fp, "\n\t%-19s %s %s\n\n",
493 494 "PROPERTY", "EDIT", "VALUES");
494 495
495 496 /* Iterate over all properties */
496 497 (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
497 498 ZFS_TYPE_POOL);
498 499
499 500 (void) fprintf(fp, "\t%-19s ", "feature@...");
500 501 (void) fprintf(fp, "YES disabled | enabled | active\n");
501 502
502 503 (void) fprintf(fp, gettext("\nThe feature@ properties must be "
503 504 "appended with a feature name.\nSee zpool-features(5).\n"));
504 505 }
505 506
506 507 /*
507 508 * See comments at end of main().
508 509 */
509 510 if (getenv("ZFS_ABORT") != NULL) {
510 511 (void) printf("dumping core by request\n");
511 512 abort();
512 513 }
513 514
514 515 exit(requested ? 0 : 2);
515 516 }
516 517
517 518 /*
518 519 * print a pool vdev config for dry runs
519 520 */
520 521 static void
521 522 print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
522 523 const char *match, int name_flags)
523 524 {
524 525 nvlist_t **child;
525 526 uint_t c, children;
526 527 char *vname;
527 528 boolean_t printed = B_FALSE;
528 529
529 530 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
530 531 &child, &children) != 0) {
531 532 if (name != NULL)
532 533 (void) printf("\t%*s%s\n", indent, "", name);
533 534 return;
534 535 }
535 536
536 537 for (c = 0; c < children; c++) {
537 538 uint64_t is_log = B_FALSE;
538 539 char *class = "";
539 540
540 541 (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
541 542 &is_log);
542 543 if (is_log)
543 544 class = VDEV_ALLOC_BIAS_LOG;
544 545 (void) nvlist_lookup_string(child[c],
545 546 ZPOOL_CONFIG_ALLOCATION_BIAS, &class);
546 547 if (strcmp(match, class) != 0)
547 548 continue;
548 549
549 550 if (!printed && name != NULL) {
550 551 (void) printf("\t%*s%s\n", indent, "", name);
551 552 printed = B_TRUE;
552 553 }
553 554 vname = zpool_vdev_name(g_zfs, zhp, child[c], name_flags);
554 555 print_vdev_tree(zhp, vname, child[c], indent + 2, "",
555 556 name_flags);
556 557 free(vname);
557 558 }
558 559 }
559 560
560 561 static boolean_t
561 562 prop_list_contains_feature(nvlist_t *proplist)
562 563 {
563 564 nvpair_t *nvp;
564 565 for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp;
565 566 nvp = nvlist_next_nvpair(proplist, nvp)) {
566 567 if (zpool_prop_feature(nvpair_name(nvp)))
567 568 return (B_TRUE);
568 569 }
569 570 return (B_FALSE);
570 571 }
571 572
572 573 /*
573 574 * Add a property pair (name, string-value) into a property nvlist.
574 575 */
575 576 static int
576 577 add_prop_list(const char *propname, char *propval, nvlist_t **props,
577 578 boolean_t poolprop)
578 579 {
579 580 zpool_prop_t prop = ZPOOL_PROP_INVAL;
580 581 zfs_prop_t fprop;
581 582 nvlist_t *proplist;
582 583 const char *normnm;
583 584 char *strval;
584 585
585 586 if (*props == NULL &&
586 587 nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
587 588 (void) fprintf(stderr,
588 589 gettext("internal error: out of memory\n"));
589 590 return (1);
590 591 }
591 592
592 593 proplist = *props;
593 594
594 595 if (poolprop) {
595 596 const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
596 597
597 598 if ((prop = zpool_name_to_prop(propname)) == ZPOOL_PROP_INVAL &&
598 599 !zpool_prop_feature(propname)) {
599 600 (void) fprintf(stderr, gettext("property '%s' is "
600 601 "not a valid pool property\n"), propname);
601 602 return (2);
602 603 }
603 604
604 605 /*
605 606 * feature@ properties and version should not be specified
606 607 * at the same time.
607 608 */
608 609 if ((prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname) &&
609 610 nvlist_exists(proplist, vname)) ||
610 611 (prop == ZPOOL_PROP_VERSION &&
611 612 prop_list_contains_feature(proplist))) {
612 613 (void) fprintf(stderr, gettext("'feature@' and "
613 614 "'version' properties cannot be specified "
614 615 "together\n"));
615 616 return (2);
616 617 }
617 618
618 619
619 620 if (zpool_prop_feature(propname))
620 621 normnm = propname;
621 622 else
622 623 normnm = zpool_prop_to_name(prop);
623 624 } else {
624 625 if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
625 626 normnm = zfs_prop_to_name(fprop);
626 627 } else {
627 628 normnm = propname;
628 629 }
629 630 }
630 631
631 632 if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
632 633 prop != ZPOOL_PROP_CACHEFILE) {
633 634 (void) fprintf(stderr, gettext("property '%s' "
634 635 "specified multiple times\n"), propname);
635 636 return (2);
636 637 }
637 638
638 639 if (nvlist_add_string(proplist, normnm, propval) != 0) {
639 640 (void) fprintf(stderr, gettext("internal "
640 641 "error: out of memory\n"));
641 642 return (1);
642 643 }
643 644
644 645 return (0);
645 646 }
646 647
647 648 /*
648 649 * Set a default property pair (name, string-value) in a property nvlist
649 650 */
650 651 static int
651 652 add_prop_list_default(const char *propname, char *propval, nvlist_t **props,
652 653 boolean_t poolprop)
653 654 {
654 655 char *pval;
655 656
656 657 if (nvlist_lookup_string(*props, propname, &pval) == 0)
657 658 return (0);
658 659
659 660 return (add_prop_list(propname, propval, props, poolprop));
660 661 }
661 662
662 663 /*
663 664 * zpool add [-fgLnP] [-o property=value] <pool> <vdev> ...
664 665 *
665 666 * -f Force addition of devices, even if they appear in use
666 667 * -g Display guid for individual vdev name.
667 668 * -L Follow links when resolving vdev path name.
668 669 * -n Do not add the devices, but display the resulting layout if
669 670 * they were to be added.
670 671 * -P Display full path for vdev name.
671 672 * -o Set property=value.
672 673 *
673 674 * Adds the given vdevs to 'pool'. As with create, the bulk of this work is
674 675 * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
675 676 * libzfs.
676 677 */
677 678 int
678 679 zpool_do_add(int argc, char **argv)
679 680 {
680 681 boolean_t force = B_FALSE;
681 682 boolean_t dryrun = B_FALSE;
682 683 int name_flags = 0;
683 684 int c;
684 685 nvlist_t *nvroot;
685 686 char *poolname;
686 687 zpool_boot_label_t boot_type;
687 688 uint64_t boot_size;
688 689 int ret;
689 690 zpool_handle_t *zhp;
690 691 nvlist_t *config;
691 692 nvlist_t *props = NULL;
692 693 char *propval;
693 694
694 695 /* check options */
695 696 while ((c = getopt(argc, argv, "fgLnPo:")) != -1) {
696 697 switch (c) {
697 698 case 'f':
698 699 force = B_TRUE;
699 700 break;
700 701 case 'g':
701 702 name_flags |= VDEV_NAME_GUID;
702 703 break;
703 704 case 'L':
704 705 name_flags |= VDEV_NAME_FOLLOW_LINKS;
705 706 break;
706 707 case 'n':
707 708 dryrun = B_TRUE;
708 709 break;
709 710 case 'P':
710 711 name_flags |= VDEV_NAME_PATH;
711 712 break;
712 713 case 'o':
713 714 if ((propval = strchr(optarg, '=')) == NULL) {
714 715 (void) fprintf(stderr, gettext("missing "
715 716 "'=' for -o option\n"));
716 717 usage(B_FALSE);
717 718 }
718 719 *propval = '\0';
719 720 propval++;
720 721
721 722 if ((strcmp(optarg, ZPOOL_CONFIG_ASHIFT) != 0) ||
722 723 (add_prop_list(optarg, propval, &props, B_TRUE)))
723 724 usage(B_FALSE);
724 725 break;
725 726 case '?':
726 727 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
727 728 optopt);
728 729 usage(B_FALSE);
729 730 }
730 731 }
731 732
732 733 argc -= optind;
733 734 argv += optind;
734 735
735 736 /* get pool name and check number of arguments */
736 737 if (argc < 1) {
737 738 (void) fprintf(stderr, gettext("missing pool name argument\n"));
738 739 usage(B_FALSE);
739 740 }
740 741 if (argc < 2) {
741 742 (void) fprintf(stderr, gettext("missing vdev specification\n"));
742 743 usage(B_FALSE);
743 744 }
744 745
745 746 poolname = argv[0];
746 747
747 748 argc--;
748 749 argv++;
749 750
750 751 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
751 752 return (1);
752 753
753 754 if ((config = zpool_get_config(zhp, NULL)) == NULL) {
754 755 (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
755 756 poolname);
756 757 zpool_close(zhp);
757 758 return (1);
758 759 }
759 760
760 761 if (zpool_is_bootable(zhp))
761 762 boot_type = ZPOOL_COPY_BOOT_LABEL;
762 763 else
763 764 boot_type = ZPOOL_NO_BOOT_LABEL;
764 765
765 766 /* unless manually specified use "ashift" pool property (if set) */
766 767 if (!nvlist_exists(props, ZPOOL_CONFIG_ASHIFT)) {
767 768 int intval;
768 769 zprop_source_t src;
769 770 char strval[ZPOOL_MAXPROPLEN];
770 771
771 772 intval = zpool_get_prop_int(zhp, ZPOOL_PROP_ASHIFT, &src);
772 773 if (src != ZPROP_SRC_DEFAULT) {
773 774 (void) sprintf(strval, "%" PRId32, intval);
774 775 verify(add_prop_list(ZPOOL_CONFIG_ASHIFT, strval,
775 776 &props, B_TRUE) == 0);
776 777 }
777 778 }
778 779
779 780 /* pass off to get_vdev_spec for processing */
780 781 boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL);
781 782 nvroot = make_root_vdev(zhp, props, force, !force, B_FALSE, dryrun,
782 783 boot_type, boot_size, argc, argv);
783 784 if (nvroot == NULL) {
784 785 zpool_close(zhp);
785 786 return (1);
786 787 }
787 788
788 789 if (dryrun) {
789 790 nvlist_t *poolnvroot;
790 791
791 792 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
792 793 &poolnvroot) == 0);
793 794
794 795 (void) printf(gettext("would update '%s' to the following "
795 796 "configuration:\n"), zpool_get_name(zhp));
796 797
797 798 /* print original main pool and new tree */
798 799 print_vdev_tree(zhp, poolname, poolnvroot, 0, "",
799 800 name_flags | VDEV_NAME_TYPE_ID);
800 801 print_vdev_tree(zhp, NULL, nvroot, 0, "", name_flags);
801 802
802 803 /* print other classes: 'dedup', 'special', and 'log' */
803 804 print_vdev_tree(zhp, "dedup", poolnvroot, 0,
804 805 VDEV_ALLOC_BIAS_DEDUP, name_flags);
805 806 print_vdev_tree(zhp, NULL, nvroot, 0, VDEV_ALLOC_BIAS_DEDUP,
806 807 name_flags);
807 808
808 809 print_vdev_tree(zhp, "special", poolnvroot, 0,
809 810 VDEV_ALLOC_BIAS_SPECIAL, name_flags);
810 811 print_vdev_tree(zhp, NULL, nvroot, 0, VDEV_ALLOC_BIAS_SPECIAL,
811 812 name_flags);
812 813
813 814 print_vdev_tree(zhp, "logs", poolnvroot, 0, VDEV_ALLOC_BIAS_LOG,
814 815 name_flags);
815 816 print_vdev_tree(zhp, NULL, nvroot, 0, VDEV_ALLOC_BIAS_LOG,
816 817 name_flags);
817 818
818 819 ret = 0;
819 820 } else {
820 821 ret = (zpool_add(zhp, nvroot) != 0);
821 822 }
822 823
823 824 nvlist_free(props);
824 825 nvlist_free(nvroot);
825 826 zpool_close(zhp);
826 827
827 828 return (ret);
828 829 }
829 830
830 831 /*
831 832 * zpool remove <pool> <vdev> ...
832 833 *
833 834 * Removes the given vdev from the pool.
834 835 */
835 836 int
836 837 zpool_do_remove(int argc, char **argv)
837 838 {
838 839 char *poolname;
839 840 int i, ret = 0;
840 841 zpool_handle_t *zhp;
841 842 boolean_t stop = B_FALSE;
842 843 boolean_t noop = B_FALSE;
843 844 boolean_t parsable = B_FALSE;
844 845 char c;
845 846
846 847 /* check options */
847 848 while ((c = getopt(argc, argv, "nps")) != -1) {
848 849 switch (c) {
849 850 case 'n':
850 851 noop = B_TRUE;
851 852 break;
852 853 case 'p':
853 854 parsable = B_TRUE;
854 855 break;
855 856 case 's':
856 857 stop = B_TRUE;
857 858 break;
858 859 case '?':
859 860 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
860 861 optopt);
861 862 usage(B_FALSE);
862 863 }
863 864 }
864 865
865 866 argc -= optind;
866 867 argv += optind;
867 868
868 869 /* get pool name and check number of arguments */
869 870 if (argc < 1) {
870 871 (void) fprintf(stderr, gettext("missing pool name argument\n"));
871 872 usage(B_FALSE);
872 873 }
873 874
874 875 poolname = argv[0];
875 876
876 877 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
877 878 return (1);
878 879
879 880 if (stop && noop) {
880 881 (void) fprintf(stderr, gettext("stop request ignored\n"));
881 882 return (0);
882 883 }
883 884
884 885 if (stop) {
885 886 if (argc > 1) {
886 887 (void) fprintf(stderr, gettext("too many arguments\n"));
887 888 usage(B_FALSE);
888 889 }
889 890 if (zpool_vdev_remove_cancel(zhp) != 0)
890 891 ret = 1;
891 892 } else {
892 893 if (argc < 2) {
893 894 (void) fprintf(stderr, gettext("missing device\n"));
894 895 usage(B_FALSE);
895 896 }
896 897
897 898 for (i = 1; i < argc; i++) {
898 899 if (noop) {
899 900 uint64_t size;
900 901
901 902 if (zpool_vdev_indirect_size(zhp, argv[i],
902 903 &size) != 0) {
903 904 ret = 1;
904 905 break;
905 906 }
906 907 if (parsable) {
907 908 (void) printf("%s %llu\n",
908 909 argv[i], size);
909 910 } else {
910 911 char valstr[32];
911 912 zfs_nicenum(size, valstr,
912 913 sizeof (valstr));
913 914 (void) printf("Memory that will be "
914 915 "used after removing %s: %s\n",
915 916 argv[i], valstr);
916 917 }
917 918 } else {
918 919 if (zpool_vdev_remove(zhp, argv[i]) != 0)
919 920 ret = 1;
920 921 }
921 922 }
922 923 }
923 924
924 925 return (ret);
925 926 }
926 927
927 928 /*
928 929 * zpool labelclear [-f] <vdev>
929 930 *
930 931 * -f Force clearing the label for the vdevs which are members of
931 932 * the exported or foreign pools.
932 933 *
933 934 * Verifies that the vdev is not active and zeros out the label information
934 935 * on the device.
935 936 */
936 937 int
937 938 zpool_do_labelclear(int argc, char **argv)
938 939 {
939 940 char vdev[MAXPATHLEN];
940 941 char *name = NULL;
941 942 struct stat st;
942 943 int c, fd, ret = 0;
943 944 nvlist_t *config;
944 945 pool_state_t state;
945 946 boolean_t inuse = B_FALSE;
946 947 boolean_t force = B_FALSE;
947 948
948 949 /* check options */
949 950 while ((c = getopt(argc, argv, "f")) != -1) {
950 951 switch (c) {
951 952 case 'f':
952 953 force = B_TRUE;
953 954 break;
954 955 default:
955 956 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
956 957 optopt);
957 958 usage(B_FALSE);
958 959 }
959 960 }
960 961
961 962 argc -= optind;
962 963 argv += optind;
963 964
964 965 /* get vdev name */
965 966 if (argc < 1) {
966 967 (void) fprintf(stderr, gettext("missing vdev name\n"));
967 968 usage(B_FALSE);
968 969 }
969 970 if (argc > 1) {
970 971 (void) fprintf(stderr, gettext("too many arguments\n"));
971 972 usage(B_FALSE);
972 973 }
973 974
974 975 /*
975 976 * Check if we were given absolute path and use it as is.
976 977 * Otherwise if the provided vdev name doesn't point to a file,
977 978 * try prepending dsk path and appending s0.
978 979 */
979 980 (void) strlcpy(vdev, argv[0], sizeof (vdev));
980 981 if (vdev[0] != '/' && stat(vdev, &st) != 0) {
981 982 char *s;
982 983
983 984 (void) snprintf(vdev, sizeof (vdev), "%s/%s",
984 985 ZFS_DISK_ROOT, argv[0]);
985 986 if ((s = strrchr(argv[0], 's')) == NULL ||
986 987 !isdigit(*(s + 1)))
987 988 (void) strlcat(vdev, "s0", sizeof (vdev));
988 989 if (stat(vdev, &st) != 0) {
989 990 (void) fprintf(stderr, gettext(
990 991 "failed to find device %s, try specifying absolute "
991 992 "path instead\n"), argv[0]);
992 993 return (1);
993 994 }
994 995 }
995 996
996 997 if ((fd = open(vdev, O_RDWR)) < 0) {
997 998 (void) fprintf(stderr, gettext("failed to open %s: %s\n"),
998 999 vdev, strerror(errno));
999 1000 return (1);
1000 1001 }
1001 1002
1002 1003 if (zpool_read_label(fd, &config, NULL) != 0) {
1003 1004 (void) fprintf(stderr,
1004 1005 gettext("failed to read label from %s\n"), vdev);
1005 1006 return (1);
1006 1007 }
1007 1008 nvlist_free(config);
1008 1009
1009 1010 ret = zpool_in_use(g_zfs, fd, &state, &name, &inuse);
1010 1011 if (ret != 0) {
1011 1012 (void) fprintf(stderr,
1012 1013 gettext("failed to check state for %s\n"), vdev);
1013 1014 return (1);
1014 1015 }
1015 1016
1016 1017 if (!inuse)
1017 1018 goto wipe_label;
1018 1019
1019 1020 switch (state) {
1020 1021 default:
1021 1022 case POOL_STATE_ACTIVE:
1022 1023 case POOL_STATE_SPARE:
1023 1024 case POOL_STATE_L2CACHE:
1024 1025 (void) fprintf(stderr, gettext(
1025 1026 "%s is a member (%s) of pool \"%s\"\n"),
1026 1027 vdev, zpool_pool_state_to_name(state), name);
1027 1028 ret = 1;
1028 1029 goto errout;
1029 1030
1030 1031 case POOL_STATE_EXPORTED:
1031 1032 if (force)
1032 1033 break;
1033 1034 (void) fprintf(stderr, gettext(
1034 1035 "use '-f' to override the following error:\n"
1035 1036 "%s is a member of exported pool \"%s\"\n"),
1036 1037 vdev, name);
1037 1038 ret = 1;
1038 1039 goto errout;
1039 1040
1040 1041 case POOL_STATE_POTENTIALLY_ACTIVE:
1041 1042 if (force)
1042 1043 break;
1043 1044 (void) fprintf(stderr, gettext(
1044 1045 "use '-f' to override the following error:\n"
1045 1046 "%s is a member of potentially active pool \"%s\"\n"),
1046 1047 vdev, name);
1047 1048 ret = 1;
1048 1049 goto errout;
1049 1050
1050 1051 case POOL_STATE_DESTROYED:
1051 1052 /* inuse should never be set for a destroyed pool */
1052 1053 assert(0);
1053 1054 break;
1054 1055 }
1055 1056
1056 1057 wipe_label:
1057 1058 ret = zpool_clear_label(fd);
1058 1059 if (ret != 0) {
1059 1060 (void) fprintf(stderr,
1060 1061 gettext("failed to clear label for %s\n"), vdev);
1061 1062 }
1062 1063
1063 1064 errout:
1064 1065 free(name);
1065 1066 (void) close(fd);
1066 1067
1067 1068 return (ret);
1068 1069 }
1069 1070
1070 1071 /*
1071 1072 * zpool create [-fnd] [-B] [-o property=value] ...
1072 1073 * [-O file-system-property=value] ...
1073 1074 * [-R root] [-m mountpoint] [-t tempname] <pool> <dev> ...
1074 1075 *
1075 1076 * -B Create boot partition.
1076 1077 * -f Force creation, even if devices appear in use
1077 1078 * -n Do not create the pool, but display the resulting layout if it
1078 1079 * were to be created.
1079 1080 * -R Create a pool under an alternate root
1080 1081 * -m Set default mountpoint for the root dataset. By default it's
1081 1082 * '/<pool>'
1082 1083 * -t Use the temporary name until the pool is exported.
1083 1084 * -o Set property=value.
1084 1085 * -o Set feature@feature=enabled|disabled.
1085 1086 * -d Don't automatically enable all supported pool features
1086 1087 * (individual features can be enabled with -o).
1087 1088 * -O Set fsproperty=value in the pool's root file system
1088 1089 *
1089 1090 * Creates the named pool according to the given vdev specification. The
1090 1091 * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once
1091 1092 * we get the nvlist back from get_vdev_spec(), we either print out the contents
1092 1093 * (if '-n' was specified), or pass it to libzfs to do the creation.
1093 1094 */
1094 1095
1095 1096 #define SYSTEM256 (256 * 1024 * 1024)
1096 1097 int
1097 1098 zpool_do_create(int argc, char **argv)
1098 1099 {
1099 1100 boolean_t force = B_FALSE;
1100 1101 boolean_t dryrun = B_FALSE;
1101 1102 boolean_t enable_all_pool_feat = B_TRUE;
1102 1103 zpool_boot_label_t boot_type = ZPOOL_NO_BOOT_LABEL;
1103 1104 uint64_t boot_size = 0;
1104 1105 int c;
1105 1106 nvlist_t *nvroot = NULL;
1106 1107 char *poolname;
1107 1108 char *tname = NULL;
1108 1109 int ret = 1;
1109 1110 char *altroot = NULL;
1110 1111 char *mountpoint = NULL;
1111 1112 nvlist_t *fsprops = NULL;
1112 1113 nvlist_t *props = NULL;
1113 1114 char *propval;
1114 1115
1115 1116 /* check options */
1116 1117 while ((c = getopt(argc, argv, ":fndBR:m:o:O:t:")) != -1) {
1117 1118 switch (c) {
1118 1119 case 'f':
1119 1120 force = B_TRUE;
1120 1121 break;
1121 1122 case 'n':
1122 1123 dryrun = B_TRUE;
1123 1124 break;
1124 1125 case 'd':
1125 1126 enable_all_pool_feat = B_FALSE;
1126 1127 break;
1127 1128 case 'B':
1128 1129 /*
1129 1130 * We should create the system partition.
1130 1131 * Also make sure the size is set.
1131 1132 */
1132 1133 boot_type = ZPOOL_CREATE_BOOT_LABEL;
1133 1134 if (boot_size == 0)
1134 1135 boot_size = SYSTEM256;
1135 1136 break;
1136 1137 case 'R':
1137 1138 altroot = optarg;
1138 1139 if (add_prop_list(zpool_prop_to_name(
1139 1140 ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1140 1141 goto errout;
1141 1142 if (add_prop_list_default(zpool_prop_to_name(
1142 1143 ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1143 1144 goto errout;
1144 1145 break;
1145 1146 case 'm':
1146 1147 /* Equivalent to -O mountpoint=optarg */
1147 1148 mountpoint = optarg;
1148 1149 break;
1149 1150 case 'o':
1150 1151 if ((propval = strchr(optarg, '=')) == NULL) {
1151 1152 (void) fprintf(stderr, gettext("missing "
1152 1153 "'=' for -o option\n"));
1153 1154 goto errout;
1154 1155 }
1155 1156 *propval = '\0';
1156 1157 propval++;
1157 1158
1158 1159 if (add_prop_list(optarg, propval, &props, B_TRUE))
1159 1160 goto errout;
1160 1161
1161 1162 /*
1162 1163 * Get bootsize value for make_root_vdev().
1163 1164 */
1164 1165 if (zpool_name_to_prop(optarg) == ZPOOL_PROP_BOOTSIZE) {
1165 1166 if (zfs_nicestrtonum(g_zfs, propval,
1166 1167 &boot_size) < 0 || boot_size == 0) {
1167 1168 (void) fprintf(stderr,
1168 1169 gettext("bad boot partition size "
1169 1170 "'%s': %s\n"), propval,
1170 1171 libzfs_error_description(g_zfs));
1171 1172 goto errout;
1172 1173 }
1173 1174 }
1174 1175
1175 1176 /*
1176 1177 * If the user is creating a pool that doesn't support
1177 1178 * feature flags, don't enable any features.
1178 1179 */
1179 1180 if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) {
1180 1181 char *end;
1181 1182 u_longlong_t ver;
1182 1183
1183 1184 ver = strtoull(propval, &end, 10);
1184 1185 if (*end == '\0' &&
1185 1186 ver < SPA_VERSION_FEATURES) {
1186 1187 enable_all_pool_feat = B_FALSE;
1187 1188 }
1188 1189 }
1189 1190 if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT)
1190 1191 altroot = propval;
1191 1192 break;
1192 1193 case 'O':
1193 1194 if ((propval = strchr(optarg, '=')) == NULL) {
1194 1195 (void) fprintf(stderr, gettext("missing "
1195 1196 "'=' for -O option\n"));
1196 1197 goto errout;
1197 1198 }
1198 1199 *propval = '\0';
1199 1200 propval++;
1200 1201
1201 1202 /*
1202 1203 * Mountpoints are checked and then added later.
1203 1204 * Uniquely among properties, they can be specified
1204 1205 * more than once, to avoid conflict with -m.
1205 1206 */
1206 1207 if (0 == strcmp(optarg,
1207 1208 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) {
1208 1209 mountpoint = propval;
1209 1210 } else if (add_prop_list(optarg, propval, &fsprops,
1210 1211 B_FALSE)) {
1211 1212 goto errout;
1212 1213 }
1213 1214 break;
1214 1215 case 't':
1215 1216 /*
1216 1217 * Sanity check temporary pool name.
1217 1218 */
1218 1219 if (strchr(optarg, '/') != NULL) {
1219 1220 (void) fprintf(stderr, gettext("cannot create "
1220 1221 "'%s': invalid character '/' in temporary "
1221 1222 "name\n"), optarg);
1222 1223 (void) fprintf(stderr, gettext("use 'zfs "
1223 1224 "create' to create a dataset\n"));
1224 1225 goto errout;
1225 1226 }
1226 1227
1227 1228 if (add_prop_list(zpool_prop_to_name(
1228 1229 ZPOOL_PROP_TNAME), optarg, &props, B_TRUE))
1229 1230 goto errout;
1230 1231 if (add_prop_list_default(zpool_prop_to_name(
1231 1232 ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1232 1233 goto errout;
1233 1234 tname = optarg;
1234 1235 break;
1235 1236 case ':':
1236 1237 (void) fprintf(stderr, gettext("missing argument for "
1237 1238 "'%c' option\n"), optopt);
1238 1239 goto badusage;
1239 1240 case '?':
1240 1241 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
1241 1242 optopt);
1242 1243 goto badusage;
1243 1244 }
1244 1245 }
1245 1246
1246 1247 argc -= optind;
1247 1248 argv += optind;
1248 1249
1249 1250 /* get pool name and check number of arguments */
1250 1251 if (argc < 1) {
1251 1252 (void) fprintf(stderr, gettext("missing pool name argument\n"));
1252 1253 goto badusage;
1253 1254 }
1254 1255 if (argc < 2) {
1255 1256 (void) fprintf(stderr, gettext("missing vdev specification\n"));
1256 1257 goto badusage;
1257 1258 }
1258 1259
1259 1260 poolname = argv[0];
1260 1261
1261 1262 /*
1262 1263 * As a special case, check for use of '/' in the name, and direct the
1263 1264 * user to use 'zfs create' instead.
1264 1265 */
1265 1266 if (strchr(poolname, '/') != NULL) {
1266 1267 (void) fprintf(stderr, gettext("cannot create '%s': invalid "
1267 1268 "character '/' in pool name\n"), poolname);
1268 1269 (void) fprintf(stderr, gettext("use 'zfs create' to "
1269 1270 "create a dataset\n"));
1270 1271 goto errout;
1271 1272 }
1272 1273
1273 1274 /*
1274 1275 * Make sure the bootsize is set when ZPOOL_CREATE_BOOT_LABEL is used,
1275 1276 * and not set otherwise.
1276 1277 */
1277 1278 if (boot_type == ZPOOL_CREATE_BOOT_LABEL) {
1278 1279 const char *propname;
1279 1280 char *strptr, *buf = NULL;
1280 1281 int rv;
1281 1282
1282 1283 propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE);
1283 1284 if (nvlist_lookup_string(props, propname, &strptr) != 0) {
1284 1285 (void) asprintf(&buf, "%" PRIu64, boot_size);
1285 1286 if (buf == NULL) {
1286 1287 (void) fprintf(stderr,
1287 1288 gettext("internal error: out of memory\n"));
1288 1289 goto errout;
1289 1290 }
1290 1291 rv = add_prop_list(propname, buf, &props, B_TRUE);
1291 1292 free(buf);
1292 1293 if (rv != 0)
1293 1294 goto errout;
1294 1295 }
1295 1296 } else {
1296 1297 const char *propname;
1297 1298 char *strptr;
1298 1299
1299 1300 propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE);
1300 1301 if (nvlist_lookup_string(props, propname, &strptr) == 0) {
1301 1302 (void) fprintf(stderr, gettext("error: setting boot "
1302 1303 "partition size requires option '-B'\n"));
1303 1304 goto errout;
1304 1305 }
1305 1306 }
1306 1307
1307 1308 /* pass off to get_vdev_spec for bulk processing */
1308 1309 nvroot = make_root_vdev(NULL, props, force, !force, B_FALSE, dryrun,
1309 1310 boot_type, boot_size, argc - 1, argv + 1);
1310 1311 if (nvroot == NULL)
1311 1312 goto errout;
1312 1313
1313 1314 /* make_root_vdev() allows 0 toplevel children if there are spares */
1314 1315 if (!zfs_allocatable_devs(nvroot)) {
1315 1316 (void) fprintf(stderr, gettext("invalid vdev "
1316 1317 "specification: at least one toplevel vdev must be "
1317 1318 "specified\n"));
1318 1319 goto errout;
1319 1320 }
1320 1321
1321 1322 if (altroot != NULL && altroot[0] != '/') {
1322 1323 (void) fprintf(stderr, gettext("invalid alternate root '%s': "
1323 1324 "must be an absolute path\n"), altroot);
1324 1325 goto errout;
1325 1326 }
1326 1327
1327 1328 /*
1328 1329 * Check the validity of the mountpoint and direct the user to use the
1329 1330 * '-m' mountpoint option if it looks like its in use.
1330 1331 */
1331 1332 if (mountpoint == NULL ||
1332 1333 (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
1333 1334 strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
1334 1335 char buf[MAXPATHLEN];
1335 1336 DIR *dirp;
1336 1337
1337 1338 if (mountpoint && mountpoint[0] != '/') {
1338 1339 (void) fprintf(stderr, gettext("invalid mountpoint "
1339 1340 "'%s': must be an absolute path, 'legacy', or "
1340 1341 "'none'\n"), mountpoint);
1341 1342 goto errout;
1342 1343 }
1343 1344
1344 1345 if (mountpoint == NULL) {
1345 1346 if (altroot != NULL)
1346 1347 (void) snprintf(buf, sizeof (buf), "%s/%s",
1347 1348 altroot, poolname);
1348 1349 else
1349 1350 (void) snprintf(buf, sizeof (buf), "/%s",
1350 1351 poolname);
1351 1352 } else {
1352 1353 if (altroot != NULL)
1353 1354 (void) snprintf(buf, sizeof (buf), "%s%s",
1354 1355 altroot, mountpoint);
1355 1356 else
1356 1357 (void) snprintf(buf, sizeof (buf), "%s",
1357 1358 mountpoint);
1358 1359 }
1359 1360
1360 1361 if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
1361 1362 (void) fprintf(stderr, gettext("mountpoint '%s' : "
1362 1363 "%s\n"), buf, strerror(errno));
1363 1364 (void) fprintf(stderr, gettext("use '-m' "
1364 1365 "option to provide a different default\n"));
1365 1366 goto errout;
1366 1367 } else if (dirp) {
1367 1368 int count = 0;
1368 1369
1369 1370 while (count < 3 && readdir(dirp) != NULL)
1370 1371 count++;
1371 1372 (void) closedir(dirp);
1372 1373
1373 1374 if (count > 2) {
1374 1375 (void) fprintf(stderr, gettext("mountpoint "
1375 1376 "'%s' exists and is not empty\n"), buf);
1376 1377 (void) fprintf(stderr, gettext("use '-m' "
1377 1378 "option to provide a "
1378 1379 "different default\n"));
1379 1380 goto errout;
1380 1381 }
1381 1382 }
1382 1383 }
1383 1384
1384 1385 /*
1385 1386 * Now that the mountpoint's validity has been checked, ensure that
1386 1387 * the property is set appropriately prior to creating the pool.
1387 1388 */
1388 1389 if (mountpoint != NULL) {
1389 1390 ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1390 1391 mountpoint, &fsprops, B_FALSE);
1391 1392 if (ret != 0)
1392 1393 goto errout;
1393 1394 }
1394 1395
1395 1396 ret = 1;
1396 1397 if (dryrun) {
1397 1398 /*
1398 1399 * For a dry run invocation, print out a basic message and run
1399 1400 * through all the vdevs in the list and print out in an
1400 1401 * appropriate hierarchy.
1401 1402 */
1402 1403 (void) printf(gettext("would create '%s' with the "
1403 1404 "following layout:\n\n"), poolname);
1404 1405
1405 1406 print_vdev_tree(NULL, poolname, nvroot, 0, "", 0);
1406 1407 print_vdev_tree(NULL, "dedup", nvroot, 0,
1407 1408 VDEV_ALLOC_BIAS_DEDUP, 0);
1408 1409 print_vdev_tree(NULL, "special", nvroot, 0,
1409 1410 VDEV_ALLOC_BIAS_SPECIAL, 0);
1410 1411 print_vdev_tree(NULL, "logs", nvroot, 0,
1411 1412 VDEV_ALLOC_BIAS_LOG, 0);
1412 1413
1413 1414 ret = 0;
1414 1415 } else {
1415 1416 /*
1416 1417 * Hand off to libzfs.
1417 1418 */
1418 1419
1419 1420 spa_feature_t i;
1420 1421 for (i = 0; i < SPA_FEATURES; i++) {
1421 1422 char propname[MAXPATHLEN];
1422 1423 char *propval;
1423 1424 zfeature_info_t *feat = &spa_feature_table[i];
1424 1425 (void) snprintf(propname, sizeof (propname),
1425 1426 "feature@%s", feat->fi_uname);
1426 1427
1427 1428 /*
1428 1429 * Only features contained in props will be enabled:
1429 1430 * remove from the nvlist every ZFS_FEATURE_DISABLED
1430 1431 * value and add every missing ZFS_FEATURE_ENABLED if
1431 1432 * enable_all_pool_feat is set.
1432 1433 */
1433 1434 if (!nvlist_lookup_string(props, propname, &propval)) {
1434 1435 if (strcmp(propval, ZFS_FEATURE_DISABLED) == 0)
1435 1436 (void) nvlist_remove_all(props,
1436 1437 propname);
1437 1438 } else if (enable_all_pool_feat) {
1438 1439 ret = add_prop_list(propname,
1439 1440 ZFS_FEATURE_ENABLED, &props, B_TRUE);
1440 1441 if (ret != 0)
1441 1442 goto errout;
1442 1443 }
1443 1444 }
1444 1445
1445 1446 ret = 1;
1446 1447 if (zpool_create(g_zfs, poolname,
1447 1448 nvroot, props, fsprops) == 0) {
1448 1449 zfs_handle_t *pool = zfs_open(g_zfs,
1449 1450 tname ? tname : poolname, ZFS_TYPE_FILESYSTEM);
1450 1451 if (pool != NULL) {
1451 1452 if (zfs_mount(pool, NULL, 0) == 0)
1452 1453 ret = zfs_shareall(pool);
1453 1454 zfs_close(pool);
1454 1455 }
1455 1456 } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
1456 1457 (void) fprintf(stderr, gettext("pool name may have "
1457 1458 "been omitted\n"));
1458 1459 }
1459 1460 }
1460 1461
1461 1462 errout:
1462 1463 nvlist_free(nvroot);
1463 1464 nvlist_free(fsprops);
1464 1465 nvlist_free(props);
1465 1466 return (ret);
1466 1467 badusage:
1467 1468 nvlist_free(fsprops);
1468 1469 nvlist_free(props);
1469 1470 usage(B_FALSE);
1470 1471 return (2);
1471 1472 }
1472 1473
1473 1474 /*
1474 1475 * zpool destroy <pool>
1475 1476 *
1476 1477 * -f Forcefully unmount any datasets
1477 1478 *
1478 1479 * Destroy the given pool. Automatically unmounts any datasets in the pool.
1479 1480 */
1480 1481 int
1481 1482 zpool_do_destroy(int argc, char **argv)
1482 1483 {
1483 1484 boolean_t force = B_FALSE;
1484 1485 int c;
1485 1486 char *pool;
1486 1487 zpool_handle_t *zhp;
1487 1488 int ret;
1488 1489
1489 1490 /* check options */
1490 1491 while ((c = getopt(argc, argv, "f")) != -1) {
1491 1492 switch (c) {
1492 1493 case 'f':
1493 1494 force = B_TRUE;
1494 1495 break;
1495 1496 case '?':
1496 1497 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
1497 1498 optopt);
1498 1499 usage(B_FALSE);
1499 1500 }
1500 1501 }
1501 1502
1502 1503 argc -= optind;
1503 1504 argv += optind;
1504 1505
1505 1506 /* check arguments */
1506 1507 if (argc < 1) {
1507 1508 (void) fprintf(stderr, gettext("missing pool argument\n"));
1508 1509 usage(B_FALSE);
1509 1510 }
1510 1511 if (argc > 1) {
1511 1512 (void) fprintf(stderr, gettext("too many arguments\n"));
1512 1513 usage(B_FALSE);
1513 1514 }
1514 1515
1515 1516 pool = argv[0];
1516 1517
1517 1518 if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
1518 1519 /*
1519 1520 * As a special case, check for use of '/' in the name, and
1520 1521 * direct the user to use 'zfs destroy' instead.
1521 1522 */
1522 1523 if (strchr(pool, '/') != NULL)
1523 1524 (void) fprintf(stderr, gettext("use 'zfs destroy' to "
1524 1525 "destroy a dataset\n"));
1525 1526 return (1);
1526 1527 }
1527 1528
1528 1529 if (zpool_disable_datasets(zhp, force) != 0) {
1529 1530 (void) fprintf(stderr, gettext("could not destroy '%s': "
1530 1531 "could not unmount datasets\n"), zpool_get_name(zhp));
1531 1532 return (1);
1532 1533 }
1533 1534
1534 1535 /* The history must be logged as part of the export */
1535 1536 log_history = B_FALSE;
1536 1537
1537 1538 ret = (zpool_destroy(zhp, history_str) != 0);
1538 1539
1539 1540 zpool_close(zhp);
1540 1541
1541 1542 return (ret);
1542 1543 }
1543 1544
1544 1545 /*
1545 1546 * zpool export [-f] <pool> ...
1546 1547 *
1547 1548 * -f Forcefully unmount datasets
1548 1549 *
1549 1550 * Export the given pools. By default, the command will attempt to cleanly
1550 1551 * unmount any active datasets within the pool. If the '-f' flag is specified,
1551 1552 * then the datasets will be forcefully unmounted.
1552 1553 */
1553 1554 int
1554 1555 zpool_do_export(int argc, char **argv)
1555 1556 {
1556 1557 boolean_t force = B_FALSE;
1557 1558 boolean_t hardforce = B_FALSE;
1558 1559 int c;
1559 1560 zpool_handle_t *zhp;
1560 1561 int ret;
1561 1562 int i;
1562 1563
1563 1564 /* check options */
1564 1565 while ((c = getopt(argc, argv, "fF")) != -1) {
1565 1566 switch (c) {
1566 1567 case 'f':
1567 1568 force = B_TRUE;
1568 1569 break;
1569 1570 case 'F':
1570 1571 hardforce = B_TRUE;
1571 1572 break;
1572 1573 case '?':
1573 1574 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
1574 1575 optopt);
1575 1576 usage(B_FALSE);
1576 1577 }
1577 1578 }
1578 1579
1579 1580 argc -= optind;
1580 1581 argv += optind;
1581 1582
1582 1583 /* check arguments */
1583 1584 if (argc < 1) {
1584 1585 (void) fprintf(stderr, gettext("missing pool argument\n"));
1585 1586 usage(B_FALSE);
1586 1587 }
1587 1588
1588 1589 ret = 0;
1589 1590 for (i = 0; i < argc; i++) {
1590 1591 if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
1591 1592 ret = 1;
1592 1593 continue;
1593 1594 }
1594 1595
1595 1596 if (zpool_disable_datasets(zhp, force) != 0) {
1596 1597 ret = 1;
1597 1598 zpool_close(zhp);
1598 1599 continue;
1599 1600 }
1600 1601
1601 1602 /* The history must be logged as part of the export */
1602 1603 log_history = B_FALSE;
1603 1604
1604 1605 if (hardforce) {
1605 1606 if (zpool_export_force(zhp, history_str) != 0)
1606 1607 ret = 1;
1607 1608 } else if (zpool_export(zhp, force, history_str) != 0) {
1608 1609 ret = 1;
1609 1610 }
1610 1611
1611 1612 zpool_close(zhp);
1612 1613 }
1613 1614
1614 1615 return (ret);
1615 1616 }
1616 1617
1617 1618 /*
1618 1619 * Given a vdev configuration, determine the maximum width needed for the device
1619 1620 * name column.
1620 1621 */
1621 1622 static int
1622 1623 max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max,
1623 1624 int name_flags)
1624 1625 {
1625 1626 char *name;
1626 1627 nvlist_t **child;
1627 1628 uint_t c, children;
1628 1629 int ret;
1629 1630
1630 1631 name = zpool_vdev_name(g_zfs, zhp, nv, name_flags | VDEV_NAME_TYPE_ID);
1631 1632 if (strlen(name) + depth > max)
1632 1633 max = strlen(name) + depth;
1633 1634
1634 1635 free(name);
1635 1636
1636 1637 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1637 1638 &child, &children) == 0) {
1638 1639 for (c = 0; c < children; c++)
1639 1640 if ((ret = max_width(zhp, child[c], depth + 2,
1640 1641 max, name_flags)) > max)
1641 1642 max = ret;
1642 1643 }
1643 1644
1644 1645 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1645 1646 &child, &children) == 0) {
1646 1647 for (c = 0; c < children; c++)
1647 1648 if ((ret = max_width(zhp, child[c], depth + 2,
1648 1649 max, name_flags)) > max)
1649 1650 max = ret;
1650 1651 }
1651 1652
1652 1653 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1653 1654 &child, &children) == 0) {
1654 1655 for (c = 0; c < children; c++)
1655 1656 if ((ret = max_width(zhp, child[c], depth + 2,
1656 1657 max, name_flags)) > max)
1657 1658 max = ret;
1658 1659 }
1659 1660
1660 1661 return (max);
1661 1662 }
1662 1663
1663 1664 typedef struct spare_cbdata {
1664 1665 uint64_t cb_guid;
1665 1666 zpool_handle_t *cb_zhp;
1666 1667 } spare_cbdata_t;
1667 1668
1668 1669 static boolean_t
1669 1670 find_vdev(nvlist_t *nv, uint64_t search)
1670 1671 {
1671 1672 uint64_t guid;
1672 1673 nvlist_t **child;
1673 1674 uint_t c, children;
1674 1675
1675 1676 if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
1676 1677 search == guid)
1677 1678 return (B_TRUE);
1678 1679
1679 1680 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1680 1681 &child, &children) == 0) {
1681 1682 for (c = 0; c < children; c++)
1682 1683 if (find_vdev(child[c], search))
1683 1684 return (B_TRUE);
1684 1685 }
1685 1686
1686 1687 return (B_FALSE);
1687 1688 }
1688 1689
1689 1690 static int
1690 1691 find_spare(zpool_handle_t *zhp, void *data)
1691 1692 {
1692 1693 spare_cbdata_t *cbp = data;
1693 1694 nvlist_t *config, *nvroot;
1694 1695
1695 1696 config = zpool_get_config(zhp, NULL);
1696 1697 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1697 1698 &nvroot) == 0);
1698 1699
1699 1700 if (find_vdev(nvroot, cbp->cb_guid)) {
1700 1701 cbp->cb_zhp = zhp;
1701 1702 return (1);
1702 1703 }
1703 1704
1704 1705 zpool_close(zhp);
1705 1706 return (0);
1706 1707 }
1707 1708
1708 1709 typedef struct status_cbdata {
1709 1710 int cb_count;
1710 1711 int cb_name_flags;
1711 1712 int cb_namewidth;
1712 1713 boolean_t cb_allpools;
1713 1714 boolean_t cb_verbose;
1714 1715 boolean_t cb_literal;
1715 1716 boolean_t cb_explain;
1716 1717 boolean_t cb_first;
1717 1718 boolean_t cb_dedup_stats;
1718 1719 boolean_t cb_print_status;
1719 1720 boolean_t cb_print_slow_ios;
1720 1721 boolean_t cb_print_vdev_init;
1721 1722 boolean_t cb_print_vdev_trim;
1722 1723 } status_cbdata_t;
1723 1724
1724 1725 /*
1725 1726 * Print vdev initialization status for leaves
1726 1727 */
1727 1728 static void
1728 1729 print_status_initialize(vdev_stat_t *vs, boolean_t verbose)
1729 1730 {
1730 1731 if (verbose) {
1731 1732 if ((vs->vs_initialize_state == VDEV_INITIALIZE_ACTIVE ||
1732 1733 vs->vs_initialize_state == VDEV_INITIALIZE_SUSPENDED ||
1733 1734 vs->vs_initialize_state == VDEV_INITIALIZE_COMPLETE) &&
1734 1735 !vs->vs_scan_removing) {
1735 1736 char zbuf[1024];
1736 1737 char tbuf[256];
1737 1738 struct tm zaction_ts;
1738 1739
1739 1740 time_t t = vs->vs_initialize_action_time;
1740 1741 int initialize_pct = 100;
1741 1742 if (vs->vs_initialize_state !=
1742 1743 VDEV_INITIALIZE_COMPLETE) {
1743 1744 initialize_pct = (vs->vs_initialize_bytes_done *
1744 1745 100 / (vs->vs_initialize_bytes_est + 1));
1745 1746 }
1746 1747
1747 1748 (void) localtime_r(&t, &zaction_ts);
1748 1749 (void) strftime(tbuf, sizeof (tbuf), "%c", &zaction_ts);
1749 1750
1750 1751 switch (vs->vs_initialize_state) {
1751 1752 case VDEV_INITIALIZE_SUSPENDED:
1752 1753 (void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
1753 1754 gettext("suspended, started at"), tbuf);
1754 1755 break;
1755 1756 case VDEV_INITIALIZE_ACTIVE:
1756 1757 (void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
1757 1758 gettext("started at"), tbuf);
1758 1759 break;
1759 1760 case VDEV_INITIALIZE_COMPLETE:
1760 1761 (void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
1761 1762 gettext("completed at"), tbuf);
1762 1763 break;
1763 1764 }
1764 1765
1765 1766 (void) printf(gettext(" (%d%% initialized%s)"),
1766 1767 initialize_pct, zbuf);
1767 1768 } else {
1768 1769 (void) printf(gettext(" (uninitialized)"));
1769 1770 }
1770 1771 } else if (vs->vs_initialize_state == VDEV_INITIALIZE_ACTIVE) {
1771 1772 (void) printf(gettext(" (initializing)"));
1772 1773 }
1773 1774 }
1774 1775
1775 1776 /*
1776 1777 * Print vdev TRIM status for leaves
1777 1778 */
1778 1779 static void
1779 1780 print_status_trim(vdev_stat_t *vs, boolean_t verbose)
1780 1781 {
1781 1782 if (verbose) {
1782 1783 if ((vs->vs_trim_state == VDEV_TRIM_ACTIVE ||
1783 1784 vs->vs_trim_state == VDEV_TRIM_SUSPENDED ||
1784 1785 vs->vs_trim_state == VDEV_TRIM_COMPLETE) &&
1785 1786 !vs->vs_scan_removing) {
1786 1787 char zbuf[1024];
1787 1788 char tbuf[256];
1788 1789 struct tm zaction_ts;
1789 1790
1790 1791 time_t t = vs->vs_trim_action_time;
1791 1792 int trim_pct = 100;
1792 1793 if (vs->vs_trim_state != VDEV_TRIM_COMPLETE) {
1793 1794 trim_pct = (vs->vs_trim_bytes_done *
1794 1795 100 / (vs->vs_trim_bytes_est + 1));
1795 1796 }
1796 1797
1797 1798 (void) localtime_r(&t, &zaction_ts);
1798 1799 (void) strftime(tbuf, sizeof (tbuf), "%c", &zaction_ts);
1799 1800
1800 1801 switch (vs->vs_trim_state) {
1801 1802 case VDEV_TRIM_SUSPENDED:
1802 1803 (void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
1803 1804 gettext("suspended, started at"), tbuf);
1804 1805 break;
1805 1806 case VDEV_TRIM_ACTIVE:
1806 1807 (void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
1807 1808 gettext("started at"), tbuf);
1808 1809 break;
1809 1810 case VDEV_TRIM_COMPLETE:
1810 1811 (void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
1811 1812 gettext("completed at"), tbuf);
1812 1813 break;
1813 1814 }
1814 1815
1815 1816 (void) printf(gettext(" (%d%% trimmed%s)"),
1816 1817 trim_pct, zbuf);
1817 1818 } else if (vs->vs_trim_notsup) {
1818 1819 (void) printf(gettext(" (trim unsupported)"));
1819 1820 } else {
1820 1821 (void) printf(gettext(" (untrimmed)"));
1821 1822 }
1822 1823 } else if (vs->vs_trim_state == VDEV_TRIM_ACTIVE) {
1823 1824 (void) printf(gettext(" (trimming)"));
1824 1825 }
1825 1826 }
1826 1827
1827 1828 /*
1828 1829 * Print out configuration state as requested by status_callback.
1829 1830 */
1830 1831 static void
1831 1832 print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
1832 1833 nvlist_t *nv, int depth, boolean_t isspare)
1833 1834 {
1834 1835 nvlist_t **child, *root;
1835 1836 uint_t c, children;
1836 1837 pool_scan_stat_t *ps = NULL;
1837 1838 vdev_stat_t *vs;
1838 1839 char rbuf[6], wbuf[6], cbuf[6];
1839 1840 char *vname;
1840 1841 uint64_t notpresent;
1841 1842 spare_cbdata_t spare_cb;
1842 1843 const char *state;
1843 1844 char *type;
1844 1845
1845 1846 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1846 1847 &child, &children) != 0)
1847 1848 children = 0;
1848 1849
1849 1850 verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1850 1851 (uint64_t **)&vs, &c) == 0);
1851 1852
1852 1853 verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
1853 1854
1854 1855 if (strcmp(type, VDEV_TYPE_INDIRECT) == 0)
1855 1856 return;
1856 1857
1857 1858 state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1858 1859 if (isspare) {
1859 1860 /*
1860 1861 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
1861 1862 * online drives.
1862 1863 */
1863 1864 if (vs->vs_aux == VDEV_AUX_SPARED)
1864 1865 state = "INUSE";
1865 1866 else if (vs->vs_state == VDEV_STATE_HEALTHY)
1866 1867 state = "AVAIL";
1867 1868 }
1868 1869
1869 1870 (void) printf("\t%*s%-*s %-8s", depth, "", cb->cb_namewidth - depth,
1870 1871 name, state);
1871 1872
1872 1873 if (!isspare) {
1873 1874 if (cb->cb_literal) {
1874 1875 printf(" %5llu %5llu %5llu",
1875 1876 (u_longlong_t)vs->vs_read_errors,
1876 1877 (u_longlong_t)vs->vs_write_errors,
1877 1878 (u_longlong_t)vs->vs_checksum_errors);
1878 1879 } else {
1879 1880 zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
1880 1881 zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
1881 1882 zfs_nicenum(vs->vs_checksum_errors, cbuf,
1882 1883 sizeof (cbuf));
1883 1884 printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
1884 1885 }
1885 1886
1886 1887 if (cb->cb_print_slow_ios) {
1887 1888 if (children == 0) {
1888 1889 /* Only leafs vdevs have slow IOs */
1889 1890 zfs_nicenum(vs->vs_slow_ios, rbuf,
1890 1891 sizeof (rbuf));
1891 1892 } else {
1892 1893 (void) snprintf(rbuf, sizeof (rbuf), "-");
1893 1894 }
1894 1895
1895 1896 if (cb->cb_literal)
1896 1897 printf(" %5llu", (u_longlong_t)vs->vs_slow_ios);
1897 1898 else
1898 1899 printf(" %5s", rbuf);
1899 1900 }
1900 1901
1901 1902 }
1902 1903
1903 1904 if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1904 1905 ¬present) == 0) {
1905 1906 char *path;
1906 1907 verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
1907 1908 (void) printf(" was %s", path);
1908 1909 } else if (vs->vs_aux != 0) {
1909 1910 (void) printf(" ");
1910 1911
1911 1912 switch (vs->vs_aux) {
1912 1913 case VDEV_AUX_OPEN_FAILED:
1913 1914 (void) printf(gettext("cannot open"));
1914 1915 break;
1915 1916
1916 1917 case VDEV_AUX_BAD_GUID_SUM:
1917 1918 (void) printf(gettext("missing device"));
1918 1919 break;
1919 1920
1920 1921 case VDEV_AUX_NO_REPLICAS:
1921 1922 (void) printf(gettext("insufficient replicas"));
1922 1923 break;
1923 1924
1924 1925 case VDEV_AUX_VERSION_NEWER:
1925 1926 (void) printf(gettext("newer version"));
1926 1927 break;
1927 1928
1928 1929 case VDEV_AUX_UNSUP_FEAT:
1929 1930 (void) printf(gettext("unsupported feature(s)"));
1930 1931 break;
1931 1932
1932 1933 case VDEV_AUX_SPARED:
1933 1934 verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1934 1935 &spare_cb.cb_guid) == 0);
1935 1936 if (zpool_iter(g_zfs, find_spare, &spare_cb) == 1) {
1936 1937 if (strcmp(zpool_get_name(spare_cb.cb_zhp),
1937 1938 zpool_get_name(zhp)) == 0)
1938 1939 (void) printf(gettext("currently in "
1939 1940 "use"));
1940 1941 else
1941 1942 (void) printf(gettext("in use by "
1942 1943 "pool '%s'"),
1943 1944 zpool_get_name(spare_cb.cb_zhp));
1944 1945 zpool_close(spare_cb.cb_zhp);
1945 1946 } else {
1946 1947 (void) printf(gettext("currently in use"));
1947 1948 }
1948 1949 break;
1949 1950
1950 1951 case VDEV_AUX_ERR_EXCEEDED:
1951 1952 (void) printf(gettext("too many errors"));
1952 1953 break;
1953 1954
1954 1955 case VDEV_AUX_IO_FAILURE:
1955 1956 (void) printf(gettext("experienced I/O failures"));
1956 1957 break;
1957 1958
1958 1959 case VDEV_AUX_BAD_LOG:
1959 1960 (void) printf(gettext("bad intent log"));
1960 1961 break;
1961 1962
1962 1963 case VDEV_AUX_EXTERNAL:
1963 1964 (void) printf(gettext("external device fault"));
1964 1965 break;
1965 1966
1966 1967 case VDEV_AUX_SPLIT_POOL:
1967 1968 (void) printf(gettext("split into new pool"));
1968 1969 break;
1969 1970
1970 1971 case VDEV_AUX_ACTIVE:
1971 1972 (void) printf(gettext("currently in use"));
1972 1973 break;
1973 1974
1974 1975 case VDEV_AUX_CHILDREN_OFFLINE:
1975 1976 (void) printf(gettext("all children offline"));
1976 1977 break;
1977 1978
1978 1979 default:
1979 1980 (void) printf(gettext("corrupted data"));
1980 1981 break;
1981 1982 }
1982 1983 }
1983 1984
1984 1985 /* The root vdev has the scrub/resilver stats */
1985 1986 root = fnvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
1986 1987 ZPOOL_CONFIG_VDEV_TREE);
1987 1988 (void) nvlist_lookup_uint64_array(root, ZPOOL_CONFIG_SCAN_STATS,
1988 1989 (uint64_t **)&ps, &c);
1989 1990
1990 1991 if (ps != NULL && ps->pss_state == DSS_SCANNING && children == 0) {
1991 1992 if (vs->vs_scan_processed != 0) {
1992 1993 (void) printf(gettext(" (%s)"),
1993 1994 (ps->pss_func == POOL_SCAN_RESILVER) ?
1994 1995 "resilvering" : "repairing");
1995 1996 } else if (vs->vs_resilver_deferred) {
1996 1997 (void) printf(gettext(" (awaiting resilver)"));
1997 1998 }
1998 1999 }
1999 2000
2000 2001 /* Display vdev initialization and trim status for leaves */
2001 2002 if (children == 0) {
2002 2003 print_status_initialize(vs, cb->cb_print_vdev_init);
2003 2004 print_status_trim(vs, cb->cb_print_vdev_trim);
2004 2005 }
2005 2006
2006 2007 (void) printf("\n");
2007 2008
2008 2009 for (c = 0; c < children; c++) {
2009 2010 uint64_t islog = B_FALSE, ishole = B_FALSE;
2010 2011
2011 2012 /* Don't print logs or holes here */
2012 2013 (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
2013 2014 &islog);
2014 2015 (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
2015 2016 &ishole);
2016 2017 if (islog || ishole)
2017 2018 continue;
2018 2019 /* Only print normal classes here */
2019 2020 if (nvlist_exists(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
2020 2021 continue;
2021 2022
2022 2023 vname = zpool_vdev_name(g_zfs, zhp, child[c],
2023 2024 cb->cb_name_flags | VDEV_NAME_TYPE_ID);
2024 2025
2025 2026 print_status_config(zhp, cb, vname, child[c], depth + 2,
2026 2027 isspare);
2027 2028 free(vname);
2028 2029 }
2029 2030 }
2030 2031
2031 2032 /*
2032 2033 * Print the configuration of an exported pool. Iterate over all vdevs in the
2033 2034 * pool, printing out the name and status for each one.
2034 2035 */
2035 2036 static void
2036 2037 print_import_config(status_cbdata_t *cb, const char *name, nvlist_t *nv,
2037 2038 int depth)
2038 2039 {
2039 2040 nvlist_t **child;
2040 2041 uint_t c, children;
2041 2042 vdev_stat_t *vs;
2042 2043 char *type, *vname;
2043 2044
2044 2045 verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
2045 2046 if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
2046 2047 strcmp(type, VDEV_TYPE_HOLE) == 0)
2047 2048 return;
2048 2049
2049 2050 verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
2050 2051 (uint64_t **)&vs, &c) == 0);
2051 2052
2052 2053 (void) printf("\t%*s%-*s", depth, "", cb->cb_namewidth - depth, name);
2053 2054 (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
2054 2055
2055 2056 if (vs->vs_aux != 0) {
2056 2057 (void) printf(" ");
2057 2058
2058 2059 switch (vs->vs_aux) {
2059 2060 case VDEV_AUX_OPEN_FAILED:
2060 2061 (void) printf(gettext("cannot open"));
2061 2062 break;
2062 2063
2063 2064 case VDEV_AUX_BAD_GUID_SUM:
2064 2065 (void) printf(gettext("missing device"));
2065 2066 break;
2066 2067
2067 2068 case VDEV_AUX_NO_REPLICAS:
2068 2069 (void) printf(gettext("insufficient replicas"));
2069 2070 break;
2070 2071
2071 2072 case VDEV_AUX_VERSION_NEWER:
2072 2073 (void) printf(gettext("newer version"));
2073 2074 break;
2074 2075
2075 2076 case VDEV_AUX_UNSUP_FEAT:
2076 2077 (void) printf(gettext("unsupported feature(s)"));
2077 2078 break;
2078 2079
2079 2080 case VDEV_AUX_ERR_EXCEEDED:
2080 2081 (void) printf(gettext("too many errors"));
2081 2082 break;
2082 2083
2083 2084 case VDEV_AUX_ACTIVE:
2084 2085 (void) printf(gettext("currently in use"));
2085 2086 break;
2086 2087
2087 2088 case VDEV_AUX_CHILDREN_OFFLINE:
2088 2089 (void) printf(gettext("all children offline"));
2089 2090 break;
2090 2091
2091 2092 default:
2092 2093 (void) printf(gettext("corrupted data"));
2093 2094 break;
2094 2095 }
2095 2096 }
2096 2097 (void) printf("\n");
2097 2098
2098 2099 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2099 2100 &child, &children) != 0)
2100 2101 return;
2101 2102
2102 2103 for (c = 0; c < children; c++) {
2103 2104 uint64_t is_log = B_FALSE;
2104 2105
2105 2106 (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
2106 2107 &is_log);
2107 2108 if (is_log)
2108 2109 continue;
2109 2110 if (nvlist_exists(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
2110 2111 continue;
2111 2112
2112 2113 vname = zpool_vdev_name(g_zfs, NULL, child[c],
2113 2114 cb->cb_name_flags | VDEV_NAME_TYPE_ID);
2114 2115 print_import_config(cb, vname, child[c], depth + 2);
2115 2116 free(vname);
2116 2117 }
2117 2118
2118 2119 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
2119 2120 &child, &children) == 0) {
2120 2121 (void) printf(gettext("\tcache\n"));
2121 2122 for (c = 0; c < children; c++) {
2122 2123 vname = zpool_vdev_name(g_zfs, NULL, child[c],
2123 2124 cb->cb_name_flags);
2124 2125 (void) printf("\t %s\n", vname);
2125 2126 free(vname);
2126 2127 }
2127 2128 }
2128 2129
2129 2130 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
2130 2131 &child, &children) == 0) {
2131 2132 (void) printf(gettext("\tspares\n"));
2132 2133 for (c = 0; c < children; c++) {
2133 2134 vname = zpool_vdev_name(g_zfs, NULL, child[c],
2134 2135 cb->cb_name_flags);
2135 2136 (void) printf("\t %s\n", vname);
2136 2137 free(vname);
2137 2138 }
2138 2139 }
2139 2140 }
2140 2141
2141 2142 /*
2142 2143 * Print specialized class vdevs.
2143 2144 *
2144 2145 * These are recorded as top level vdevs in the main pool child array
2145 2146 * but with "is_log" set to 1 or an "alloc_bias" string. We use either
2146 2147 * print_status_config() or print_import_config() to print the top level
2147 2148 * class vdevs then any of their children (eg mirrored slogs) are printed
2148 2149 * recursively - which works because only the top level vdev is marked.
2149 2150 */
2150 2151 static void
2151 2152 print_class_vdevs(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
2152 2153 const char *class)
2153 2154 {
2154 2155 uint_t c, children;
2155 2156 nvlist_t **child;
2156 2157 boolean_t printed = B_FALSE;
2157 2158
2158 2159 assert(zhp != NULL || !cb->cb_verbose);
2159 2160
2160 2161 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
2161 2162 &children) != 0)
2162 2163 return;
2163 2164
2164 2165 for (c = 0; c < children; c++) {
2165 2166 uint64_t is_log = B_FALSE;
2166 2167 char *bias = NULL;
2167 2168 char *type = NULL;
2168 2169
2169 2170 (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
2170 2171 &is_log);
2171 2172
2172 2173 if (is_log) {
2173 2174 bias = VDEV_ALLOC_CLASS_LOGS;
2174 2175 } else {
2175 2176 (void) nvlist_lookup_string(child[c],
2176 2177 ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
2177 2178 (void) nvlist_lookup_string(child[c],
2178 2179 ZPOOL_CONFIG_TYPE, &type);
2179 2180 }
2180 2181
2181 2182 if (bias == NULL || strcmp(bias, class) != 0)
2182 2183 continue;
2183 2184 if (!is_log && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
2184 2185 continue;
2185 2186
2186 2187 if (!printed) {
2187 2188 (void) printf("\t%s\t\n", gettext(class));
2188 2189 printed = B_TRUE;
2189 2190 }
2190 2191
2191 2192 char *name = zpool_vdev_name(g_zfs, zhp, child[c],
2192 2193 cb->cb_name_flags | VDEV_NAME_TYPE_ID);
2193 2194 if (cb->cb_print_status)
2194 2195 print_status_config(zhp, cb, name, child[c], 2,
2195 2196 B_FALSE);
2196 2197 else
2197 2198 print_import_config(cb, name, child[c], 2);
2198 2199 free(name);
2199 2200 }
2200 2201 }
2201 2202
2202 2203 /*
2203 2204 * Display the status for the given pool.
2204 2205 */
2205 2206 static void
2206 2207 show_import(nvlist_t *config)
2207 2208 {
2208 2209 uint64_t pool_state;
2209 2210 vdev_stat_t *vs;
2210 2211 char *name;
2211 2212 uint64_t guid;
2212 2213 uint64_t hostid = 0;
2213 2214 char *msgid;
2214 2215 char *hostname = "unknown";
2215 2216 nvlist_t *nvroot, *nvinfo;
2216 2217 int reason;
2217 2218 zpool_errata_t errata;
2218 2219 const char *health;
2219 2220 uint_t vsc;
2220 2221 char *comment;
2221 2222 status_cbdata_t cb = { 0 };
2222 2223
2223 2224 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
2224 2225 &name) == 0);
2225 2226 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
2226 2227 &guid) == 0);
2227 2228 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
2228 2229 &pool_state) == 0);
2229 2230 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2230 2231 &nvroot) == 0);
2231 2232
2232 2233 verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
2233 2234 (uint64_t **)&vs, &vsc) == 0);
2234 2235 health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
2235 2236
2236 2237 reason = zpool_import_status(config, &msgid, &errata);
2237 2238
2238 2239 (void) printf(gettext(" pool: %s\n"), name);
2239 2240 (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid);
2240 2241 (void) printf(gettext(" state: %s"), health);
2241 2242 if (pool_state == POOL_STATE_DESTROYED)
2242 2243 (void) printf(gettext(" (DESTROYED)"));
2243 2244 (void) printf("\n");
2244 2245
2245 2246 switch (reason) {
2246 2247 case ZPOOL_STATUS_MISSING_DEV_R:
2247 2248 case ZPOOL_STATUS_MISSING_DEV_NR:
2248 2249 case ZPOOL_STATUS_BAD_GUID_SUM:
2249 2250 (void) printf(gettext(" status: One or more devices are "
2250 2251 "missing from the system.\n"));
2251 2252 break;
2252 2253
2253 2254 case ZPOOL_STATUS_CORRUPT_LABEL_R:
2254 2255 case ZPOOL_STATUS_CORRUPT_LABEL_NR:
2255 2256 (void) printf(gettext(" status: One or more devices contains "
2256 2257 "corrupted data.\n"));
2257 2258 break;
2258 2259
2259 2260 case ZPOOL_STATUS_CORRUPT_DATA:
2260 2261 (void) printf(
2261 2262 gettext(" status: The pool data is corrupted.\n"));
2262 2263 break;
2263 2264
2264 2265 case ZPOOL_STATUS_OFFLINE_DEV:
2265 2266 (void) printf(gettext(" status: One or more devices "
2266 2267 "are offlined.\n"));
2267 2268 break;
2268 2269
2269 2270 case ZPOOL_STATUS_CORRUPT_POOL:
2270 2271 (void) printf(gettext(" status: The pool metadata is "
2271 2272 "corrupted.\n"));
2272 2273 break;
2273 2274
2274 2275 case ZPOOL_STATUS_VERSION_OLDER:
2275 2276 (void) printf(gettext(" status: The pool is formatted using a "
2276 2277 "legacy on-disk version.\n"));
2277 2278 break;
2278 2279
2279 2280 case ZPOOL_STATUS_VERSION_NEWER:
2280 2281 (void) printf(gettext(" status: The pool is formatted using an "
2281 2282 "incompatible version.\n"));
2282 2283 break;
2283 2284
2284 2285 case ZPOOL_STATUS_FEAT_DISABLED:
2285 2286 (void) printf(gettext(" status: Some supported features are "
2286 2287 "not enabled on the pool.\n"));
2287 2288 break;
2288 2289
2289 2290 case ZPOOL_STATUS_UNSUP_FEAT_READ:
2290 2291 (void) printf(gettext("status: The pool uses the following "
2291 2292 "feature(s) not supported on this system:\n"));
2292 2293 zpool_print_unsup_feat(config);
2293 2294 break;
2294 2295
2295 2296 case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
2296 2297 (void) printf(gettext("status: The pool can only be accessed "
2297 2298 "in read-only mode on this system. It\n\tcannot be "
2298 2299 "accessed in read-write mode because it uses the "
2299 2300 "following\n\tfeature(s) not supported on this system:\n"));
2300 2301 zpool_print_unsup_feat(config);
2301 2302 break;
2302 2303
2303 2304 case ZPOOL_STATUS_HOSTID_ACTIVE:
2304 2305 (void) printf(gettext(" status: The pool is currently "
2305 2306 "imported by another system.\n"));
2306 2307 break;
2307 2308
2308 2309 case ZPOOL_STATUS_HOSTID_REQUIRED:
2309 2310 (void) printf(gettext(" status: The pool has the "
2310 2311 "multihost property on. It cannot\n\tbe safely imported "
2311 2312 "when the system hostid is not set.\n"));
2312 2313 break;
2313 2314
2314 2315 case ZPOOL_STATUS_HOSTID_MISMATCH:
2315 2316 (void) printf(gettext(" status: The pool was last accessed by "
2316 2317 "another system.\n"));
2317 2318 break;
2318 2319
2319 2320 case ZPOOL_STATUS_FAULTED_DEV_R:
2320 2321 case ZPOOL_STATUS_FAULTED_DEV_NR:
2321 2322 (void) printf(gettext(" status: One or more devices are "
2322 2323 "faulted.\n"));
2323 2324 break;
2324 2325
2325 2326 case ZPOOL_STATUS_BAD_LOG:
2326 2327 (void) printf(gettext(" status: An intent log record cannot be "
2327 2328 "read.\n"));
2328 2329 break;
2329 2330
2330 2331 case ZPOOL_STATUS_RESILVERING:
2331 2332 (void) printf(gettext(" status: One or more devices were being "
2332 2333 "resilvered.\n"));
2333 2334 break;
2334 2335
2335 2336 case ZPOOL_STATUS_ERRATA:
2336 2337 (void) printf(gettext(" status: Errata #%d detected.\n"),
2337 2338 errata);
2338 2339 break;
2339 2340
2340 2341 default:
2341 2342 /*
2342 2343 * No other status can be seen when importing pools.
2343 2344 */
2344 2345 assert(reason == ZPOOL_STATUS_OK);
2345 2346 }
2346 2347
2347 2348 /*
2348 2349 * Print out an action according to the overall state of the pool.
2349 2350 */
2350 2351 if (vs->vs_state == VDEV_STATE_HEALTHY) {
2351 2352 if (reason == ZPOOL_STATUS_VERSION_OLDER ||
2352 2353 reason == ZPOOL_STATUS_FEAT_DISABLED) {
2353 2354 (void) printf(gettext(" action: The pool can be "
2354 2355 "imported using its name or numeric identifier, "
2355 2356 "though\n\tsome features will not be available "
2356 2357 "without an explicit 'zpool upgrade'.\n"));
2357 2358 } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) {
2358 2359 (void) printf(gettext(" action: The pool can be "
2359 2360 "imported using its name or numeric "
2360 2361 "identifier and\n\tthe '-f' flag.\n"));
2361 2362 } else if (reason == ZPOOL_STATUS_ERRATA) {
2362 2363 switch (errata) {
2363 2364 case ZPOOL_ERRATA_NONE:
2364 2365 break;
2365 2366
2366 2367 case ZPOOL_ERRATA_ZOL_2094_SCRUB:
2367 2368 (void) printf(gettext(" action: The pool can "
2368 2369 "be imported using its name or numeric "
2369 2370 "identifier,\n\thowever there is a compat"
2370 2371 "ibility issue which should be corrected"
2371 2372 "\n\tby running 'zpool scrub'\n"));
2372 2373 break;
2373 2374
2374 2375 case ZPOOL_ERRATA_ZOL_2094_ASYNC_DESTROY:
2375 2376 (void) printf(gettext(" action: The pool can"
2376 2377 "not be imported with this version of ZFS "
2377 2378 "due to\n\tan active asynchronous destroy. "
2378 2379 "Revert to an earlier version\n\tand "
2379 2380 "allow the destroy to complete before "
2380 2381 "updating.\n"));
2381 2382 break;
2382 2383
2383 2384 case ZPOOL_ERRATA_ZOL_6845_ENCRYPTION:
2384 2385 (void) printf(gettext(" action: Existing "
2385 2386 "encrypted datasets contain an on-disk "
2386 2387 "incompatibility, which\n\tneeds to be "
2387 2388 "corrected. Backup these datasets to new "
2388 2389 "encrypted datasets\n\tand destroy the "
2389 2390 "old ones.\n"));
2390 2391 break;
2391 2392 case ZPOOL_ERRATA_ZOL_8308_ENCRYPTION:
2392 2393 (void) printf(gettext(" action: Any existing "
2393 2394 "encrypted datasets contain an on-disk "
2394 2395 "incompatibility which\n\tmay cause "
2395 2396 "on-disk corruption with 'zfs recv' and "
2396 2397 "which needs to be\n\tcorrected. Enable "
2397 2398 "the bookmark_v2 feature and backup "
2398 2399 "these datasets to new encrypted "
2399 2400 "datasets and\n\tdestroy the old ones. "
2400 2401 "If this pool does not contain any "
2401 2402 "encrypted datasets, simply enable\n\t"
2402 2403 "the bookmark_v2 feature.\n"));
2403 2404 break;
2404 2405 default:
2405 2406 /*
2406 2407 * All errata must contain an action message.
2407 2408 */
2408 2409 assert(0);
2409 2410 }
2410 2411 } else {
2411 2412 (void) printf(gettext(" action: The pool can be "
2412 2413 "imported using its name or numeric "
2413 2414 "identifier.\n"));
2414 2415 }
2415 2416 } else if (vs->vs_state == VDEV_STATE_DEGRADED) {
2416 2417 (void) printf(gettext(" action: The pool can be imported "
2417 2418 "despite missing or damaged devices. The\n\tfault "
2418 2419 "tolerance of the pool may be compromised if imported.\n"));
2419 2420 } else {
2420 2421 switch (reason) {
2421 2422 case ZPOOL_STATUS_VERSION_NEWER:
2422 2423 (void) printf(gettext(" action: The pool cannot be "
2423 2424 "imported. Access the pool on a system running "
2424 2425 "newer\n\tsoftware, or recreate the pool from "
2425 2426 "backup.\n"));
2426 2427 break;
2427 2428 case ZPOOL_STATUS_UNSUP_FEAT_READ:
2428 2429 (void) printf(gettext("action: The pool cannot be "
2429 2430 "imported. Access the pool on a system that "
2430 2431 "supports\n\tthe required feature(s), or recreate "
2431 2432 "the pool from backup.\n"));
2432 2433 break;
2433 2434 case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
2434 2435 (void) printf(gettext("action: The pool cannot be "
2435 2436 "imported in read-write mode. Import the pool "
2436 2437 "with\n"
2437 2438 "\t\"-o readonly=on\", access the pool on a system "
2438 2439 "that supports the\n\trequired feature(s), or "
2439 2440 "recreate the pool from backup.\n"));
2440 2441 break;
2441 2442 case ZPOOL_STATUS_MISSING_DEV_R:
2442 2443 case ZPOOL_STATUS_MISSING_DEV_NR:
2443 2444 case ZPOOL_STATUS_BAD_GUID_SUM:
2444 2445 (void) printf(gettext(" action: The pool cannot be "
2445 2446 "imported. Attach the missing\n\tdevices and try "
2446 2447 "again.\n"));
2447 2448 break;
2448 2449 case ZPOOL_STATUS_HOSTID_ACTIVE:
2449 2450 VERIFY0(nvlist_lookup_nvlist(config,
2450 2451 ZPOOL_CONFIG_LOAD_INFO, &nvinfo));
2451 2452
2452 2453 if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTNAME))
2453 2454 hostname = fnvlist_lookup_string(nvinfo,
2454 2455 ZPOOL_CONFIG_MMP_HOSTNAME);
2455 2456
2456 2457 if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTID))
2457 2458 hostid = fnvlist_lookup_uint64(nvinfo,
2458 2459 ZPOOL_CONFIG_MMP_HOSTID);
2459 2460
2460 2461 (void) printf(gettext(" action: The pool must be "
2461 2462 "exported from %s (hostid=%lx)\n\tbefore it "
2462 2463 "can be safely imported.\n"), hostname,
2463 2464 (unsigned long) hostid);
2464 2465 break;
2465 2466 case ZPOOL_STATUS_HOSTID_REQUIRED:
2466 2467 (void) printf(gettext(" action: Check the SMF "
2467 2468 "svc:/system/hostid service.\n"));
2468 2469 break;
2469 2470 default:
2470 2471 (void) printf(gettext(" action: The pool cannot be "
2471 2472 "imported due to damaged devices or data.\n"));
2472 2473 }
2473 2474 }
2474 2475
2475 2476 /* Print the comment attached to the pool. */
2476 2477 if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
2477 2478 (void) printf(gettext("comment: %s\n"), comment);
2478 2479
2479 2480 /*
2480 2481 * If the state is "closed" or "can't open", and the aux state
2481 2482 * is "corrupt data":
2482 2483 */
2483 2484 if (((vs->vs_state == VDEV_STATE_CLOSED) ||
2484 2485 (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
2485 2486 (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
2486 2487 if (pool_state == POOL_STATE_DESTROYED)
2487 2488 (void) printf(gettext("\tThe pool was destroyed, "
2488 2489 "but can be imported using the '-Df' flags.\n"));
2489 2490 else if (pool_state != POOL_STATE_EXPORTED)
2490 2491 (void) printf(gettext("\tThe pool may be active on "
2491 2492 "another system, but can be imported using\n\t"
2492 2493 "the '-f' flag.\n"));
2493 2494 }
2494 2495
2495 2496 if (msgid != NULL)
2496 2497 (void) printf(gettext(" see: http://illumos.org/msg/%s\n"),
2497 2498 msgid);
2498 2499
2499 2500 (void) printf(gettext(" config:\n\n"));
2500 2501
2501 2502 cb.cb_namewidth = max_width(NULL, nvroot, 0, strlen(name),
2502 2503 VDEV_NAME_TYPE_ID);
2503 2504 if (cb.cb_namewidth < 10)
2504 2505 cb.cb_namewidth = 10;
2505 2506
2506 2507 print_import_config(&cb, name, nvroot, 0);
2507 2508
2508 2509 print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_BIAS_DEDUP);
2509 2510 print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_BIAS_SPECIAL);
2510 2511 print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_CLASS_LOGS);
2511 2512
2512 2513 if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
2513 2514 (void) printf(gettext("\n\tAdditional devices are known to "
2514 2515 "be part of this pool, though their\n\texact "
2515 2516 "configuration cannot be determined.\n"));
2516 2517 }
2517 2518 }
2518 2519
2519 2520 static boolean_t
2520 2521 zfs_force_import_required(nvlist_t *config)
2521 2522 {
2522 2523 uint64_t state;
2523 2524 uint64_t hostid = 0;
2524 2525 nvlist_t *nvinfo;
2525 2526
2526 2527 state = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE);
2527 2528 (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
2528 2529
2529 2530 if (state != POOL_STATE_EXPORTED && hostid != get_system_hostid())
2530 2531 return (B_TRUE);
2531 2532
2532 2533 nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
2533 2534 if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_STATE)) {
2534 2535 mmp_state_t mmp_state = fnvlist_lookup_uint64(nvinfo,
2535 2536 ZPOOL_CONFIG_MMP_STATE);
2536 2537
2537 2538 if (mmp_state != MMP_STATE_INACTIVE)
2538 2539 return (B_TRUE);
2539 2540 }
2540 2541
2541 2542 return (B_FALSE);
2542 2543 }
2543 2544
2544 2545 /*
2545 2546 * Perform the import for the given configuration. This passes the heavy
2546 2547 * lifting off to zpool_import_props(), and then mounts the datasets contained
2547 2548 * within the pool.
2548 2549 */
2549 2550 static int
2550 2551 do_import(nvlist_t *config, const char *newname, const char *mntopts,
2551 2552 nvlist_t *props, int flags)
2552 2553 {
2553 2554 int ret = 0;
2554 2555 zpool_handle_t *zhp;
2555 2556 char *name;
2556 2557 uint64_t version;
2557 2558
2558 2559 name = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME);
2559 2560 version = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION);
2560 2561
2561 2562 if (!SPA_VERSION_IS_SUPPORTED(version)) {
2562 2563 (void) fprintf(stderr, gettext("cannot import '%s': pool "
2563 2564 "is formatted using an unsupported ZFS version\n"), name);
2564 2565 return (1);
2565 2566 } else if (zfs_force_import_required(config) &&
2566 2567 !(flags & ZFS_IMPORT_ANY_HOST)) {
2567 2568 mmp_state_t mmp_state = MMP_STATE_INACTIVE;
2568 2569 nvlist_t *nvinfo;
2569 2570
2570 2571 nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
2571 2572 if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_STATE))
2572 2573 mmp_state = fnvlist_lookup_uint64(nvinfo,
2573 2574 ZPOOL_CONFIG_MMP_STATE);
2574 2575
2575 2576 if (mmp_state == MMP_STATE_ACTIVE) {
2576 2577 char *hostname = "<unknown>";
2577 2578 uint64_t hostid = 0;
2578 2579
2579 2580 if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTNAME))
2580 2581 hostname = fnvlist_lookup_string(nvinfo,
2581 2582 ZPOOL_CONFIG_MMP_HOSTNAME);
2582 2583
2583 2584 if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTID))
2584 2585 hostid = fnvlist_lookup_uint64(nvinfo,
2585 2586 ZPOOL_CONFIG_MMP_HOSTID);
2586 2587
2587 2588 (void) fprintf(stderr, gettext("cannot import '%s': "
2588 2589 "pool is imported on %s (hostid: "
2589 2590 "0x%lx)\nExport the pool on the other system, "
2590 2591 "then run 'zpool import'.\n"),
2591 2592 name, hostname, (unsigned long) hostid);
2592 2593 } else if (mmp_state == MMP_STATE_NO_HOSTID) {
2593 2594 (void) fprintf(stderr, gettext("Cannot import '%s': "
2594 2595 "pool has the multihost property on and the\n"
2595 2596 "system's hostid is not set.\n"), name);
2596 2597 } else {
2597 2598 char *hostname = "<unknown>";
2598 2599 uint64_t timestamp = 0;
2599 2600 uint64_t hostid = 0;
2600 2601
2601 2602 if (nvlist_exists(config, ZPOOL_CONFIG_HOSTNAME))
2602 2603 hostname = fnvlist_lookup_string(config,
2603 2604 ZPOOL_CONFIG_HOSTNAME);
2604 2605
2605 2606 if (nvlist_exists(config, ZPOOL_CONFIG_TIMESTAMP))
2606 2607 timestamp = fnvlist_lookup_uint64(config,
2607 2608 ZPOOL_CONFIG_TIMESTAMP);
2608 2609
2609 2610 if (nvlist_exists(config, ZPOOL_CONFIG_HOSTID))
2610 2611 hostid = fnvlist_lookup_uint64(config,
2611 2612 ZPOOL_CONFIG_HOSTID);
2612 2613
2613 2614 (void) fprintf(stderr, gettext("cannot import '%s': "
2614 2615 "pool was previously in use from another system.\n"
2615 2616 "Last accessed by %s (hostid=%lx) at %s"
2616 2617 "The pool can be imported, use 'zpool import -f' "
2617 2618 "to import the pool.\n"), name, hostname,
2618 2619 (unsigned long)hostid, ctime((time_t *)×tamp));
2619 2620
2620 2621 }
2621 2622
2622 2623 return (1);
2623 2624 }
2624 2625
2625 2626 if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
2626 2627 return (1);
2627 2628
2628 2629 if (newname != NULL)
2629 2630 name = (char *)newname;
2630 2631
2631 2632 if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
2632 2633 return (1);
2633 2634
2634 2635 /*
2635 2636 * Loading keys is best effort. We don't want to return immediately
2636 2637 * if it fails but we do want to give the error to the caller.
2637 2638 */
2638 2639 if (flags & ZFS_IMPORT_LOAD_KEYS) {
2639 2640 ret = zfs_crypto_attempt_load_keys(g_zfs, name);
2640 2641 if (ret != 0)
2641 2642 ret = 1;
2642 2643 }
2643 2644
2644 2645 if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
2645 2646 !(flags & ZFS_IMPORT_ONLY) &&
2646 2647 zpool_enable_datasets(zhp, mntopts, 0) != 0) {
2647 2648 zpool_close(zhp);
2648 2649 return (1);
2649 2650 }
2650 2651
2651 2652 zpool_close(zhp);
2652 2653 return (ret);
2653 2654 }
2654 2655
2655 2656 typedef struct target_exists_args {
2656 2657 const char *poolname;
2657 2658 uint64_t poolguid;
2658 2659 } target_exists_args_t;
2659 2660
2660 2661 static int
2661 2662 name_or_guid_exists(zpool_handle_t *zhp, void *data)
2662 2663 {
2663 2664 target_exists_args_t *args = data;
2664 2665 nvlist_t *config = zpool_get_config(zhp, NULL);
2665 2666 int found = 0;
2666 2667
2667 2668 if (config == NULL)
2668 2669 return (0);
2669 2670
2670 2671 if (args->poolname != NULL) {
2671 2672 char *pool_name;
2672 2673
2673 2674 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
2674 2675 &pool_name) == 0);
2675 2676 if (strcmp(pool_name, args->poolname) == 0)
2676 2677 found = 1;
2677 2678 } else {
2678 2679 uint64_t pool_guid;
2679 2680
2680 2681 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
2681 2682 &pool_guid) == 0);
2682 2683 if (pool_guid == args->poolguid)
2683 2684 found = 1;
2684 2685 }
2685 2686 zpool_close(zhp);
2686 2687
2687 2688 return (found);
2688 2689 }
2689 2690 /*
2690 2691 * zpool checkpoint <pool>
2691 2692 * checkpoint --discard <pool>
2692 2693 *
2693 2694 * -d Discard the checkpoint from a checkpointed
2694 2695 * --discard pool.
2695 2696 *
2696 2697 * Checkpoints the specified pool, by taking a "snapshot" of its
2697 2698 * current state. A pool can only have one checkpoint at a time.
2698 2699 */
2699 2700 int
2700 2701 zpool_do_checkpoint(int argc, char **argv)
2701 2702 {
2702 2703 boolean_t discard;
2703 2704 char *pool;
2704 2705 zpool_handle_t *zhp;
2705 2706 int c, err;
2706 2707
2707 2708 struct option long_options[] = {
2708 2709 {"discard", no_argument, NULL, 'd'},
2709 2710 {0, 0, 0, 0}
2710 2711 };
2711 2712
2712 2713 discard = B_FALSE;
2713 2714 while ((c = getopt_long(argc, argv, ":d", long_options, NULL)) != -1) {
2714 2715 switch (c) {
2715 2716 case 'd':
2716 2717 discard = B_TRUE;
2717 2718 break;
2718 2719 case '?':
2719 2720 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
2720 2721 optopt);
2721 2722 usage(B_FALSE);
2722 2723 }
2723 2724 }
2724 2725
2725 2726 argc -= optind;
2726 2727 argv += optind;
2727 2728
2728 2729 if (argc < 1) {
2729 2730 (void) fprintf(stderr, gettext("missing pool argument\n"));
2730 2731 usage(B_FALSE);
2731 2732 }
2732 2733
2733 2734 if (argc > 1) {
2734 2735 (void) fprintf(stderr, gettext("too many arguments\n"));
2735 2736 usage(B_FALSE);
2736 2737 }
2737 2738
2738 2739 pool = argv[0];
2739 2740
2740 2741 if ((zhp = zpool_open(g_zfs, pool)) == NULL) {
2741 2742 /* As a special case, check for use of '/' in the name */
2742 2743 if (strchr(pool, '/') != NULL)
2743 2744 (void) fprintf(stderr, gettext("'zpool checkpoint' "
2744 2745 "doesn't work on datasets. To save the state "
2745 2746 "of a dataset from a specific point in time "
2746 2747 "please use 'zfs snapshot'\n"));
2747 2748 return (1);
2748 2749 }
2749 2750
2750 2751 if (discard)
2751 2752 err = (zpool_discard_checkpoint(zhp) != 0);
2752 2753 else
2753 2754 err = (zpool_checkpoint(zhp) != 0);
2754 2755
2755 2756 zpool_close(zhp);
2756 2757
2757 2758 return (err);
2758 2759 }
2759 2760
2760 2761 #define CHECKPOINT_OPT 1024
2761 2762
2762 2763 /*
2763 2764 * zpool import [-d dir] [-D]
2764 2765 * import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-l]
2765 2766 * [-d dir | -c cachefile] [-f] -a
2766 2767 * import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-l]
2767 2768 * [-d dir | -c cachefile] [-f] [-n] [-F] [-t]
2768 2769 * <pool | id> [newpool]
2769 2770 *
2770 2771 * -c Read pool information from a cachefile instead of searching
2771 2772 * devices.
2772 2773 *
2773 2774 * -d Scan in a specific directory, other than /dev/dsk. More than
2774 2775 * one directory can be specified using multiple '-d' options.
2775 2776 *
2776 2777 * -D Scan for previously destroyed pools or import all or only
2777 2778 * specified destroyed pools.
2778 2779 *
2779 2780 * -R Temporarily import the pool, with all mountpoints relative to
2780 2781 * the given root. The pool will remain exported when the machine
2781 2782 * is rebooted.
2782 2783 *
2783 2784 * -V Import even in the presence of faulted vdevs. This is an
2784 2785 * intentionally undocumented option for testing purposes, and
2785 2786 * treats the pool configuration as complete, leaving any bad
2786 2787 * vdevs in the FAULTED state. In other words, it does verbatim
2787 2788 * import.
2788 2789 *
2789 2790 * -f Force import, even if it appears that the pool is active.
2790 2791 *
2791 2792 * -F Attempt rewind if necessary.
2792 2793 *
2793 2794 * -n See if rewind would work, but don't actually rewind.
2794 2795 *
2795 2796 * -N Import the pool but don't mount datasets.
2796 2797 *
2797 2798 * -t Use newpool as a temporary pool name instead of renaming
2798 2799 * the pool.
2799 2800 *
2800 2801 * -T Specify a starting txg to use for import. This option is
2801 2802 * intentionally undocumented option for testing purposes.
2802 2803 *
2803 2804 * -a Import all pools found.
2804 2805 *
2805 2806 * -o Set property=value and/or temporary mount options (without '=').
2806 2807 * -l Load encryption keys while importing.
2807 2808 *
2808 2809 * --rewind-to-checkpoint
2809 2810 * Import the pool and revert back to the checkpoint.
2810 2811 *
2811 2812 * The import command scans for pools to import, and import pools based on pool
2812 2813 * name and GUID. The pool can also be renamed as part of the import process.
2813 2814 */
2814 2815 int
2815 2816 zpool_do_import(int argc, char **argv)
2816 2817 {
2817 2818 char **searchdirs = NULL;
2818 2819 int nsearch = 0;
2819 2820 int c;
2820 2821 int err = 0;
2821 2822 nvlist_t *pools = NULL;
2822 2823 boolean_t do_all = B_FALSE;
2823 2824 boolean_t do_destroyed = B_FALSE;
2824 2825 char *mntopts = NULL;
2825 2826 nvpair_t *elem;
2826 2827 nvlist_t *config;
2827 2828 uint64_t searchguid = 0;
2828 2829 char *searchname = NULL;
2829 2830 char *propval;
2830 2831 nvlist_t *found_config;
2831 2832 nvlist_t *policy = NULL;
2832 2833 nvlist_t *props = NULL;
2833 2834 boolean_t first;
2834 2835 int flags = ZFS_IMPORT_NORMAL;
2835 2836 uint32_t rewind_policy = ZPOOL_NO_REWIND;
2836 2837 boolean_t dryrun = B_FALSE;
2837 2838 boolean_t do_rewind = B_FALSE;
2838 2839 boolean_t xtreme_rewind = B_FALSE;
2839 2840 boolean_t pool_exists = B_FALSE;
2840 2841 uint64_t pool_state, txg = -1ULL;
2841 2842 char *cachefile = NULL;
2842 2843 importargs_t idata = { 0 };
2843 2844 char *endptr;
2844 2845
2845 2846
2846 2847 struct option long_options[] = {
2847 2848 {"rewind-to-checkpoint", no_argument, NULL, CHECKPOINT_OPT},
2848 2849 {0, 0, 0, 0}
2849 2850 };
2850 2851
2851 2852 /* check options */
2852 2853 while ((c = getopt_long(argc, argv, ":aCc:d:DEfFlmnNo:rR:tT:VX",
2853 2854 long_options, NULL)) != -1) {
2854 2855 switch (c) {
2855 2856 case 'a':
2856 2857 do_all = B_TRUE;
2857 2858 break;
2858 2859 case 'c':
2859 2860 cachefile = optarg;
2860 2861 break;
2861 2862 case 'd':
2862 2863 if (searchdirs == NULL) {
2863 2864 searchdirs = safe_malloc(sizeof (char *));
2864 2865 } else {
2865 2866 char **tmp = safe_malloc((nsearch + 1) *
2866 2867 sizeof (char *));
2867 2868 bcopy(searchdirs, tmp, nsearch *
2868 2869 sizeof (char *));
2869 2870 free(searchdirs);
2870 2871 searchdirs = tmp;
2871 2872 }
2872 2873 searchdirs[nsearch++] = optarg;
2873 2874 break;
2874 2875 case 'D':
2875 2876 do_destroyed = B_TRUE;
2876 2877 break;
2877 2878 case 'f':
2878 2879 flags |= ZFS_IMPORT_ANY_HOST;
2879 2880 break;
2880 2881 case 'F':
2881 2882 do_rewind = B_TRUE;
2882 2883 break;
2883 2884 case 'l':
2884 2885 flags |= ZFS_IMPORT_LOAD_KEYS;
2885 2886 break;
2886 2887 case 'm':
2887 2888 flags |= ZFS_IMPORT_MISSING_LOG;
2888 2889 break;
2889 2890 case 'n':
2890 2891 dryrun = B_TRUE;
2891 2892 break;
2892 2893 case 'N':
2893 2894 flags |= ZFS_IMPORT_ONLY;
2894 2895 break;
2895 2896 case 'o':
2896 2897 if ((propval = strchr(optarg, '=')) != NULL) {
2897 2898 *propval = '\0';
2898 2899 propval++;
2899 2900 if (add_prop_list(optarg, propval,
2900 2901 &props, B_TRUE))
2901 2902 goto error;
2902 2903 } else {
2903 2904 mntopts = optarg;
2904 2905 }
2905 2906 break;
2906 2907 case 'R':
2907 2908 if (add_prop_list(zpool_prop_to_name(
2908 2909 ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
2909 2910 goto error;
2910 2911 if (add_prop_list_default(zpool_prop_to_name(
2911 2912 ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
2912 2913 goto error;
2913 2914 break;
2914 2915 case 't':
2915 2916 flags |= ZFS_IMPORT_TEMP_NAME;
2916 2917 if (add_prop_list_default(zpool_prop_to_name(
2917 2918 ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
2918 2919 goto error;
2919 2920 break;
2920 2921 case 'T':
2921 2922 errno = 0;
2922 2923 txg = strtoull(optarg, &endptr, 0);
2923 2924 if (errno != 0 || *endptr != '\0') {
2924 2925 (void) fprintf(stderr,
2925 2926 gettext("invalid txg value\n"));
2926 2927 usage(B_FALSE);
2927 2928 }
2928 2929 rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
2929 2930 break;
2930 2931 case 'V':
2931 2932 flags |= ZFS_IMPORT_VERBATIM;
2932 2933 break;
2933 2934 case 'X':
2934 2935 xtreme_rewind = B_TRUE;
2935 2936 break;
2936 2937 case CHECKPOINT_OPT:
2937 2938 flags |= ZFS_IMPORT_CHECKPOINT;
2938 2939 break;
2939 2940 case ':':
2940 2941 (void) fprintf(stderr, gettext("missing argument for "
2941 2942 "'%c' option\n"), optopt);
2942 2943 usage(B_FALSE);
2943 2944 break;
2944 2945 case '?':
2945 2946 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
2946 2947 optopt);
2947 2948 usage(B_FALSE);
2948 2949 }
2949 2950 }
2950 2951
2951 2952 argc -= optind;
2952 2953 argv += optind;
2953 2954
2954 2955 if (cachefile && nsearch != 0) {
2955 2956 (void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
2956 2957 usage(B_FALSE);
2957 2958 }
2958 2959
2959 2960 if ((flags & ZFS_IMPORT_LOAD_KEYS) && (flags & ZFS_IMPORT_ONLY)) {
2960 2961 (void) fprintf(stderr, gettext("-l is incompatible with -N\n"));
2961 2962 usage(B_FALSE);
2962 2963 }
2963 2964
2964 2965 if ((flags & ZFS_IMPORT_LOAD_KEYS) && !do_all && argc == 0) {
2965 2966 (void) fprintf(stderr, gettext("-l is only meaningful during "
2966 2967 "an import\n"));
2967 2968 usage(B_FALSE);
2968 2969 }
2969 2970
2970 2971 if ((dryrun || xtreme_rewind) && !do_rewind) {
2971 2972 (void) fprintf(stderr,
2972 2973 gettext("-n or -X only meaningful with -F\n"));
2973 2974 usage(B_FALSE);
2974 2975 }
2975 2976 if (dryrun)
2976 2977 rewind_policy = ZPOOL_TRY_REWIND;
2977 2978 else if (do_rewind)
2978 2979 rewind_policy = ZPOOL_DO_REWIND;
2979 2980 if (xtreme_rewind)
2980 2981 rewind_policy |= ZPOOL_EXTREME_REWIND;
2981 2982
2982 2983 /* In the future, we can capture further policy and include it here */
2983 2984 if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
2984 2985 nvlist_add_uint64(policy, ZPOOL_LOAD_REQUEST_TXG, txg) != 0 ||
2985 2986 nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY,
2986 2987 rewind_policy) != 0)
2987 2988 goto error;
2988 2989
2989 2990 if (searchdirs == NULL) {
2990 2991 searchdirs = safe_malloc(sizeof (char *));
2991 2992 searchdirs[0] = ZFS_DISK_ROOT;
2992 2993 nsearch = 1;
2993 2994 }
2994 2995
2995 2996 /* check argument count */
2996 2997 if (do_all) {
2997 2998 if (argc != 0) {
2998 2999 (void) fprintf(stderr, gettext("too many arguments\n"));
2999 3000 usage(B_FALSE);
3000 3001 }
3001 3002 } else {
3002 3003 if (argc > 2) {
3003 3004 (void) fprintf(stderr, gettext("too many arguments\n"));
3004 3005 usage(B_FALSE);
3005 3006 }
3006 3007
3007 3008 /*
3008 3009 * Check for the SYS_CONFIG privilege. We do this explicitly
3009 3010 * here because otherwise any attempt to discover pools will
3010 3011 * silently fail.
3011 3012 */
3012 3013 if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
3013 3014 (void) fprintf(stderr, gettext("cannot "
3014 3015 "discover pools: permission denied\n"));
3015 3016 free(searchdirs);
3016 3017 nvlist_free(policy);
3017 3018 return (1);
3018 3019 }
3019 3020 }
3020 3021
3021 3022 /*
3022 3023 * Depending on the arguments given, we do one of the following:
3023 3024 *
3024 3025 * <none> Iterate through all pools and display information about
3025 3026 * each one.
3026 3027 *
3027 3028 * -a Iterate through all pools and try to import each one.
3028 3029 *
3029 3030 * <id> Find the pool that corresponds to the given GUID/pool
3030 3031 * name and import that one.
3031 3032 *
3032 3033 * -D Above options applies only to destroyed pools.
3033 3034 */
3034 3035 if (argc != 0) {
3035 3036 char *endptr;
3036 3037
3037 3038 errno = 0;
3038 3039 searchguid = strtoull(argv[0], &endptr, 10);
3039 3040 if (errno != 0 || *endptr != '\0') {
3040 3041 searchname = argv[0];
3041 3042 searchguid = 0;
3042 3043 }
3043 3044 found_config = NULL;
3044 3045
3045 3046 /*
3046 3047 * User specified a name or guid. Ensure it's unique.
3047 3048 */
3048 3049 target_exists_args_t search = {searchname, searchguid};
3049 3050 pool_exists = zpool_iter(g_zfs, name_or_guid_exists, &search);
3050 3051 }
3051 3052
3052 3053 idata.path = searchdirs;
3053 3054 idata.paths = nsearch;
3054 3055 idata.poolname = searchname;
3055 3056 idata.guid = searchguid;
3056 3057 idata.cachefile = cachefile;
3057 3058 idata.policy = policy;
3058 3059
3059 3060 pools = zpool_search_import(g_zfs, &idata, &libzfs_config_ops);
3060 3061
3061 3062 if (pools != NULL && pool_exists &&
3062 3063 (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
3063 3064 (void) fprintf(stderr, gettext("cannot import '%s': "
3064 3065 "a pool with that name already exists\n"),
3065 3066 argv[0]);
3066 3067 (void) fprintf(stderr, gettext("use the form 'zpool import "
3067 3068 "[-t] <pool | id> <newpool>' to give it a new temporary "
3068 3069 "or permanent name\n"));
3069 3070 err = 1;
3070 3071 } else if (pools == NULL && pool_exists) {
3071 3072 (void) fprintf(stderr, gettext("cannot import '%s': "
3072 3073 "a pool with that name is already created/imported,\n"),
3073 3074 argv[0]);
3074 3075 (void) fprintf(stderr, gettext("and no additional pools "
3075 3076 "with that name were found\n"));
3076 3077 err = 1;
3077 3078 } else if (pools == NULL) {
3078 3079 if (argc != 0) {
3079 3080 (void) fprintf(stderr, gettext("cannot import '%s': "
3080 3081 "no such pool available\n"), argv[0]);
3081 3082 }
3082 3083 err = 1;
3083 3084 }
3084 3085
3085 3086 if (err == 1) {
3086 3087 free(searchdirs);
3087 3088 nvlist_free(policy);
3088 3089 return (1);
3089 3090 }
3090 3091
3091 3092 /*
3092 3093 * At this point we have a list of import candidate configs. Even if
3093 3094 * we were searching by pool name or guid, we still need to
3094 3095 * post-process the list to deal with pool state and possible
3095 3096 * duplicate names.
3096 3097 */
3097 3098 err = 0;
3098 3099 elem = NULL;
3099 3100 first = B_TRUE;
3100 3101 while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
3101 3102
3102 3103 verify(nvpair_value_nvlist(elem, &config) == 0);
3103 3104
3104 3105 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
3105 3106 &pool_state) == 0);
3106 3107 if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
3107 3108 continue;
3108 3109 if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
3109 3110 continue;
3110 3111
3111 3112 verify(nvlist_add_nvlist(config, ZPOOL_LOAD_POLICY,
3112 3113 policy) == 0);
3113 3114
3114 3115 if (argc == 0) {
3115 3116 if (first)
3116 3117 first = B_FALSE;
3117 3118 else if (!do_all)
3118 3119 (void) printf("\n");
3119 3120
3120 3121 if (do_all) {
3121 3122 err |= do_import(config, NULL, mntopts,
3122 3123 props, flags);
3123 3124 } else {
3124 3125 show_import(config);
3125 3126 }
3126 3127 } else if (searchname != NULL) {
3127 3128 char *name;
3128 3129
3129 3130 /*
3130 3131 * We are searching for a pool based on name.
3131 3132 */
3132 3133 verify(nvlist_lookup_string(config,
3133 3134 ZPOOL_CONFIG_POOL_NAME, &name) == 0);
3134 3135
3135 3136 if (strcmp(name, searchname) == 0) {
3136 3137 if (found_config != NULL) {
3137 3138 (void) fprintf(stderr, gettext(
3138 3139 "cannot import '%s': more than "
3139 3140 "one matching pool\n"), searchname);
3140 3141 (void) fprintf(stderr, gettext(
3141 3142 "import by numeric ID instead\n"));
3142 3143 err = B_TRUE;
3143 3144 }
3144 3145 found_config = config;
3145 3146 }
3146 3147 } else {
3147 3148 uint64_t guid;
3148 3149
3149 3150 /*
3150 3151 * Search for a pool by guid.
3151 3152 */
3152 3153 verify(nvlist_lookup_uint64(config,
3153 3154 ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
3154 3155
3155 3156 if (guid == searchguid)
3156 3157 found_config = config;
3157 3158 }
3158 3159 }
3159 3160
3160 3161 /*
3161 3162 * If we were searching for a specific pool, verify that we found a
3162 3163 * pool, and then do the import.
3163 3164 */
3164 3165 if (argc != 0 && err == 0) {
3165 3166 if (found_config == NULL) {
3166 3167 (void) fprintf(stderr, gettext("cannot import '%s': "
3167 3168 "no such pool available\n"), argv[0]);
3168 3169 err = B_TRUE;
3169 3170 } else {
3170 3171 err |= do_import(found_config, argc == 1 ? NULL :
3171 3172 argv[1], mntopts, props, flags);
3172 3173 }
3173 3174 }
3174 3175
3175 3176 /*
3176 3177 * If we were just looking for pools, report an error if none were
3177 3178 * found.
3178 3179 */
3179 3180 if (argc == 0 && first)
3180 3181 (void) fprintf(stderr,
3181 3182 gettext("no pools available to import\n"));
3182 3183
3183 3184 error:
3184 3185 nvlist_free(props);
3185 3186 nvlist_free(pools);
3186 3187 nvlist_free(policy);
3187 3188 free(searchdirs);
3188 3189
3189 3190 return (err ? 1 : 0);
3190 3191 }
3191 3192
3192 3193 /*
3193 3194 * zpool sync [-f] [pool] ...
3194 3195 *
3195 3196 * -f (undocumented) force uberblock (and config including zpool cache file)
3196 3197 * update.
3197 3198 *
3198 3199 * Sync the specified pool(s).
3199 3200 * Without arguments "zpool sync" will sync all pools.
3200 3201 * This command initiates TXG sync(s) and will return after the TXG(s) commit.
3201 3202 *
3202 3203 */
3203 3204 static int
3204 3205 zpool_do_sync(int argc, char **argv)
3205 3206 {
3206 3207 int ret;
3207 3208 boolean_t force = B_FALSE;
3208 3209
3209 3210 /* check options */
3210 3211 while ((ret = getopt(argc, argv, "f")) != -1) {
3211 3212 switch (ret) {
3212 3213 case 'f':
3213 3214 force = B_TRUE;
3214 3215 break;
3215 3216 case '?':
3216 3217 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3217 3218 optopt);
3218 3219 usage(B_FALSE);
3219 3220 }
3220 3221 }
3221 3222
3222 3223 argc -= optind;
3223 3224 argv += optind;
3224 3225
3225 3226 /* if argc == 0 we will execute zpool_sync_one on all pools */
3226 3227 ret = for_each_pool(argc, argv, B_FALSE, NULL, zpool_sync_one, &force);
3227 3228
3228 3229 return (ret);
3229 3230 }
3230 3231
3231 3232 typedef struct iostat_cbdata {
3232 3233 uint64_t cb_flags;
3233 3234 int cb_name_flags;
3234 3235 int cb_namewidth;
3235 3236 int cb_iteration;
3236 3237 char **cb_vdev_names; /* Only show these vdevs */
3237 3238 unsigned int cb_vdev_names_count;
3238 3239 boolean_t cb_verbose;
3239 3240 boolean_t cb_literal;
3240 3241 boolean_t cb_scripted;
3241 3242 zpool_list_t *cb_list;
3242 3243 } iostat_cbdata_t;
3243 3244
3244 3245 /* iostat labels */
3245 3246 typedef struct name_and_columns {
3246 3247 const char *name; /* Column name */
3247 3248 unsigned int columns; /* Center name to this number of columns */
3248 3249 } name_and_columns_t;
3249 3250
3250 3251 #define IOSTAT_MAX_LABELS 13 /* Max number of labels on one line */
3251 3252
3252 3253 static const name_and_columns_t iostat_top_labels[][IOSTAT_MAX_LABELS] =
3253 3254 {
3254 3255 [IOS_DEFAULT] = {{"capacity", 2}, {"operations", 2}, {"bandwidth", 2},
3255 3256 {NULL}},
3256 3257 [IOS_LATENCY] = {{"total_wait", 2}, {"disk_wait", 2}, {"syncq_wait", 2},
3257 3258 {"asyncq_wait", 2}, {"scrub"}, {"trim", 1}, {NULL}},
3258 3259 [IOS_QUEUES] = {{"syncq_read", 2}, {"syncq_write", 2},
3259 3260 {"asyncq_read", 2}, {"asyncq_write", 2}, {"scrubq_read", 2},
3260 3261 {"trimq_write", 2}, {NULL}},
3261 3262 [IOS_L_HISTO] = {{"total_wait", 2}, {"disk_wait", 2}, {"syncq_wait", 2},
3262 3263 {"asyncq_wait", 2}, {NULL}},
3263 3264 [IOS_RQ_HISTO] = {{"sync_read", 2}, {"sync_write", 2},
3264 3265 {"async_read", 2}, {"async_write", 2}, {"scrub", 2},
3265 3266 {"trim", 2}, {NULL}},
3266 3267
3267 3268 };
3268 3269
3269 3270 /* Shorthand - if "columns" field not set, default to 1 column */
3270 3271 static const name_and_columns_t iostat_bottom_labels[][IOSTAT_MAX_LABELS] =
3271 3272 {
3272 3273 [IOS_DEFAULT] = {{"alloc"}, {"free"}, {"read"}, {"write"}, {"read"},
3273 3274 {"write"}, {NULL}},
3274 3275 [IOS_LATENCY] = {{"read"}, {"write"}, {"read"}, {"write"}, {"read"},
3275 3276 {"write"}, {"read"}, {"write"}, {"wait"}, {"wait"}, {NULL}},
3276 3277 [IOS_QUEUES] = {{"pend"}, {"activ"}, {"pend"}, {"activ"}, {"pend"},
3277 3278 {"activ"}, {"pend"}, {"activ"}, {"pend"}, {"activ"},
3278 3279 {"pend"}, {"activ"}, {NULL}},
3279 3280 [IOS_L_HISTO] = {{"read"}, {"write"}, {"read"}, {"write"}, {"read"},
3280 3281 {"write"}, {"read"}, {"write"}, {"scrub"}, {"trim"}, {NULL}},
3281 3282 [IOS_RQ_HISTO] = {{"ind"}, {"agg"}, {"ind"}, {"agg"}, {"ind"}, {"agg"},
3282 3283 {"ind"}, {"agg"}, {"ind"}, {"agg"}, {"ind"}, {"agg"}, {NULL}},
3283 3284 };
3284 3285
3285 3286 static const char *histo_to_title[] = {
3286 3287 [IOS_L_HISTO] = "latency",
3287 3288 [IOS_RQ_HISTO] = "req_size",
3288 3289 };
3289 3290
3290 3291 /*
3291 3292 * Return the number of labels in a null-terminated name_and_columns_t
3292 3293 * array.
3293 3294 *
3294 3295 */
3295 3296 static unsigned int
3296 3297 label_array_len(const name_and_columns_t *labels)
3297 3298 {
3298 3299 int i = 0;
3299 3300
3300 3301 while (labels[i].name)
3301 3302 i++;
3302 3303
3303 3304 return (i);
3304 3305 }
3305 3306
3306 3307 /*
3307 3308 * Return the number of strings in a null-terminated string array.
3308 3309 * For example:
3309 3310 *
3310 3311 * const char foo[] = {"bar", "baz", NULL}
3311 3312 *
3312 3313 * returns 2
3313 3314 */
3314 3315 static uint64_t
3315 3316 str_array_len(const char *array[])
3316 3317 {
3317 3318 uint64_t i = 0;
3318 3319 while (array[i])
3319 3320 i++;
3320 3321
3321 3322 return (i);
3322 3323 }
3323 3324
3324 3325
3325 3326 /*
3326 3327 * Return a default column width for default/latency/queue columns. This does
3327 3328 * not include histograms, which have their columns autosized.
3328 3329 */
3329 3330 static unsigned int
3330 3331 default_column_width(iostat_cbdata_t *cb, enum iostat_type type)
3331 3332 {
3332 3333 unsigned long column_width = 5; /* Normal niceprint */
3333 3334 static unsigned long widths[] = {
3334 3335 /*
3335 3336 * Choose some sane default column sizes for printing the
3336 3337 * raw numbers.
3337 3338 */
3338 3339 [IOS_DEFAULT] = 15, /* 1PB capacity */
3339 3340 [IOS_LATENCY] = 10, /* 1B ns = 10sec */
3340 3341 [IOS_QUEUES] = 6, /* 1M queue entries */
3341 3342 [IOS_L_HISTO] = 10, /* 1B ns = 10sec */
3342 3343 [IOS_RQ_HISTO] = 6, /* 1M queue entries */
3343 3344 };
3344 3345
3345 3346 if (cb->cb_literal)
3346 3347 column_width = widths[type];
3347 3348
3348 3349 return (column_width);
3349 3350 }
3350 3351
3351 3352 /*
3352 3353 * Print the column labels, i.e:
3353 3354 *
3354 3355 * capacity operations bandwidth
3355 3356 * alloc free read write read write ...
3356 3357 *
3357 3358 * If force_column_width is set, use it for the column width. If not set, use
3358 3359 * the default column width.
3359 3360 */
3360 3361 void
3361 3362 print_iostat_labels(iostat_cbdata_t *cb, unsigned int force_column_width,
3362 3363 const name_and_columns_t labels[][IOSTAT_MAX_LABELS])
3363 3364 {
3364 3365 int i, idx, s;
3365 3366 int text_start, rw_column_width, spaces_to_end;
3366 3367 uint64_t flags = cb->cb_flags;
3367 3368 uint64_t f;
3368 3369 unsigned int column_width = force_column_width;
3369 3370
3370 3371 /* For each bit set in flags */
3371 3372 for (f = flags; f; f &= ~(1ULL << idx)) {
3372 3373 idx = lowbit64(f) - 1;
3373 3374 if (!force_column_width)
3374 3375 column_width = default_column_width(cb, idx);
3375 3376 /* Print our top labels centered over "read write" label. */
3376 3377 for (i = 0; i < label_array_len(labels[idx]); i++) {
3377 3378 const char *name = labels[idx][i].name;
3378 3379 /*
3379 3380 * We treat labels[][].columns == 0 as shorthand
3380 3381 * for one column. It makes writing out the label
3381 3382 * tables more concise.
3382 3383 */
3383 3384 unsigned int columns = MAX(1, labels[idx][i].columns);
3384 3385 unsigned int slen = strlen(name);
3385 3386
3386 3387 rw_column_width = (column_width * columns) +
3387 3388 (2 * (columns - 1));
3388 3389
3389 3390 text_start = (int)((rw_column_width) / columns -
3390 3391 slen / columns);
3391 3392 if (text_start < 0)
3392 3393 text_start = 0;
3393 3394
3394 3395 printf(" "); /* Two spaces between columns */
3395 3396
3396 3397 /* Space from beginning of column to label */
3397 3398 for (s = 0; s < text_start; s++)
3398 3399 printf(" ");
3399 3400
3400 3401 printf("%s", name);
3401 3402
3402 3403 /* Print space after label to end of column */
3403 3404 spaces_to_end = rw_column_width - text_start - slen;
3404 3405 if (spaces_to_end < 0)
3405 3406 spaces_to_end = 0;
3406 3407
3407 3408 for (s = 0; s < spaces_to_end; s++)
3408 3409 printf(" ");
3409 3410 }
3410 3411 }
3411 3412 }
3412 3413
3413 3414 /*
3414 3415 * Utility function to print out a line of dashes like:
3415 3416 *
3416 3417 * -------------------------------- ----- ----- ----- ----- -----
3417 3418 *
3418 3419 * ...or a dashed named-row line like:
3419 3420 *
3420 3421 * logs - - - - -
3421 3422 *
3422 3423 * @cb: iostat data
3423 3424 *
3424 3425 * @force_column_width If non-zero, use the value as the column width.
3425 3426 * Otherwise use the default column widths.
3426 3427 *
3427 3428 * @name: Print a dashed named-row line starting
3428 3429 * with @name. Otherwise, print a regular
3429 3430 * dashed line.
3430 3431 */
3431 3432 static void
3432 3433 print_iostat_dashes(iostat_cbdata_t *cb, unsigned int force_column_width,
3433 3434 const char *name)
3434 3435 {
3435 3436 int i;
3436 3437 unsigned int namewidth;
3437 3438 uint64_t flags = cb->cb_flags;
3438 3439 uint64_t f;
3439 3440 int idx;
3440 3441 const name_and_columns_t *labels;
3441 3442 const char *title;
3442 3443
3443 3444
3444 3445 if (cb->cb_flags & IOS_ANYHISTO_M) {
3445 3446 title = histo_to_title[IOS_HISTO_IDX(cb->cb_flags)];
3446 3447 } else if (cb->cb_vdev_names_count) {
3447 3448 title = "vdev";
3448 3449 } else {
3449 3450 title = "pool";
3450 3451 }
3451 3452
3452 3453 namewidth = MAX(MAX(strlen(title), cb->cb_namewidth),
3453 3454 name ? strlen(name) : 0);
3454 3455
3455 3456
3456 3457 if (name) {
3457 3458 printf("%-*s", namewidth, name);
3458 3459 } else {
3459 3460 for (i = 0; i < namewidth; i++)
3460 3461 (void) printf("-");
3461 3462 }
3462 3463
3463 3464 /* For each bit in flags */
3464 3465 for (f = flags; f; f &= ~(1ULL << idx)) {
3465 3466 unsigned int column_width;
3466 3467 idx = lowbit64(f) - 1;
3467 3468 if (force_column_width)
3468 3469 column_width = force_column_width;
3469 3470 else
3470 3471 column_width = default_column_width(cb, idx);
3471 3472
3472 3473 labels = iostat_bottom_labels[idx];
3473 3474 for (i = 0; i < label_array_len(labels); i++) {
3474 3475 if (name)
3475 3476 printf(" %*s-", column_width - 1, " ");
3476 3477 else
3477 3478 printf(" %.*s", column_width,
3478 3479 "--------------------");
3479 3480 }
3480 3481 }
3481 3482 }
3482 3483
3483 3484
3484 3485 static void
3485 3486 print_iostat_separator_impl(iostat_cbdata_t *cb,
3486 3487 unsigned int force_column_width)
3487 3488 {
3488 3489 print_iostat_dashes(cb, force_column_width, NULL);
3489 3490 }
3490 3491
3491 3492 static void
3492 3493 print_iostat_separator(iostat_cbdata_t *cb)
3493 3494 {
3494 3495 print_iostat_separator_impl(cb, 0);
3495 3496 }
3496 3497
3497 3498 static void
3498 3499 print_iostat_header_impl(iostat_cbdata_t *cb, unsigned int force_column_width,
3499 3500 const char *histo_vdev_name)
3500 3501 {
3501 3502 unsigned int namewidth;
3502 3503 const char *title;
3503 3504
3504 3505 if (cb->cb_flags & IOS_ANYHISTO_M) {
3505 3506 title = histo_to_title[IOS_HISTO_IDX(cb->cb_flags)];
3506 3507 } else if (cb->cb_vdev_names_count) {
3507 3508 title = "vdev";
3508 3509 } else {
3509 3510 title = "pool";
3510 3511 }
3511 3512
3512 3513 namewidth = MAX(MAX(strlen(title), cb->cb_namewidth),
3513 3514 histo_vdev_name ? strlen(histo_vdev_name) : 0);
3514 3515
3515 3516 if (histo_vdev_name)
3516 3517 printf("%-*s", namewidth, histo_vdev_name);
3517 3518 else
3518 3519 printf("%*s", namewidth, "");
3519 3520
3520 3521
3521 3522 print_iostat_labels(cb, force_column_width, iostat_top_labels);
3522 3523 printf("\n");
3523 3524
3524 3525 printf("%-*s", namewidth, title);
3525 3526
3526 3527 print_iostat_labels(cb, force_column_width, iostat_bottom_labels);
3527 3528
3528 3529 printf("\n");
3529 3530
3530 3531 print_iostat_separator_impl(cb, force_column_width);
3531 3532
3532 3533 printf("\n");
3533 3534 }
3534 3535
3535 3536 static void
3536 3537 print_iostat_header(iostat_cbdata_t *cb)
3537 3538 {
3538 3539 print_iostat_header_impl(cb, 0, NULL);
3539 3540 }
3540 3541
3541 3542 /*
3542 3543 * Display a single statistic.
3543 3544 */
3544 3545 static void
3545 3546 print_one_stat(uint64_t value, enum zfs_nicenum_format format,
3546 3547 unsigned int column_size, boolean_t scripted)
3547 3548 {
3548 3549 char buf[64];
3549 3550
3550 3551 zfs_nicenum_format(value, buf, sizeof (buf), format);
3551 3552
3552 3553 if (scripted)
3553 3554 printf("\t%s", buf);
3554 3555 else
3555 3556 printf(" %*s", column_size, buf);
3556 3557 }
3557 3558
3558 3559 /*
3559 3560 * Calculate the default vdev stats
3560 3561 *
3561 3562 * Subtract oldvs from newvs, apply a scaling factor, and save the resulting
3562 3563 * stats into calcvs.
3563 3564 */
3564 3565 static void
3565 3566 calc_default_iostats(vdev_stat_t *oldvs, vdev_stat_t *newvs,
3566 3567 vdev_stat_t *calcvs)
3567 3568 {
3568 3569 int i;
3569 3570
3570 3571 memcpy(calcvs, newvs, sizeof (*calcvs));
3571 3572 for (i = 0; i < ARRAY_SIZE(calcvs->vs_ops); i++)
3572 3573 calcvs->vs_ops[i] = (newvs->vs_ops[i] - oldvs->vs_ops[i]);
3573 3574
3574 3575 for (i = 0; i < ARRAY_SIZE(calcvs->vs_bytes); i++)
3575 3576 calcvs->vs_bytes[i] = (newvs->vs_bytes[i] - oldvs->vs_bytes[i]);
3576 3577 }
3577 3578
3578 3579 /*
3579 3580 * Internal representation of the extended iostats data.
3580 3581 *
3581 3582 * The extended iostat stats are exported in nvlists as either uint64_t arrays
3582 3583 * or single uint64_t's. We make both look like arrays to make them easier
3583 3584 * to process. In order to make single uint64_t's look like arrays, we set
3584 3585 * __data to the stat data, and then set *data = &__data with count = 1. Then,
3585 3586 * we can just use *data and count.
3586 3587 */
3587 3588 struct stat_array {
3588 3589 uint64_t *data;
3589 3590 uint_t count; /* Number of entries in data[] */
3590 3591 uint64_t __data; /* Only used when data is a single uint64_t */
3591 3592 };
3592 3593
3593 3594 static uint64_t
3594 3595 stat_histo_max(struct stat_array *nva, unsigned int len)
3595 3596 {
3596 3597 uint64_t max = 0;
3597 3598 int i;
3598 3599 for (i = 0; i < len; i++)
3599 3600 max = MAX(max, array64_max(nva[i].data, nva[i].count));
3600 3601
3601 3602 return (max);
3602 3603 }
3603 3604
3604 3605 /*
3605 3606 * Helper function to lookup a uint64_t array or uint64_t value and store its
3606 3607 * data as a stat_array. If the nvpair is a single uint64_t value, then we make
3607 3608 * it look like a one element array to make it easier to process.
3608 3609 */
3609 3610 static int
3610 3611 nvpair64_to_stat_array(nvlist_t *nvl, const char *name,
3611 3612 struct stat_array *nva)
3612 3613 {
3613 3614 nvpair_t *tmp;
3614 3615 int ret;
3615 3616
3616 3617 verify(nvlist_lookup_nvpair(nvl, name, &tmp) == 0);
3617 3618 switch (nvpair_type(tmp)) {
3618 3619 case DATA_TYPE_UINT64_ARRAY:
3619 3620 ret = nvpair_value_uint64_array(tmp, &nva->data, &nva->count);
3620 3621 break;
3621 3622 case DATA_TYPE_UINT64:
3622 3623 ret = nvpair_value_uint64(tmp, &nva->__data);
3623 3624 nva->data = &nva->__data;
3624 3625 nva->count = 1;
3625 3626 break;
3626 3627 default:
3627 3628 /* Not a uint64_t */
3628 3629 ret = EINVAL;
3629 3630 break;
3630 3631 }
3631 3632
3632 3633 return (ret);
3633 3634 }
3634 3635
3635 3636 /*
3636 3637 * Given a list of nvlist names, look up the extended stats in newnv and oldnv,
3637 3638 * subtract them, and return the results in a newly allocated stat_array.
3638 3639 * You must free the returned array after you are done with it with
3639 3640 * free_calc_stats().
3640 3641 *
3641 3642 * Additionally, you can set "oldnv" to NULL if you simply want the newnv
3642 3643 * values.
3643 3644 */
3644 3645 static struct stat_array *
3645 3646 calc_and_alloc_stats_ex(const char **names, unsigned int len, nvlist_t *oldnv,
3646 3647 nvlist_t *newnv)
3647 3648 {
3648 3649 nvlist_t *oldnvx = NULL, *newnvx;
3649 3650 struct stat_array *oldnva, *newnva, *calcnva;
3650 3651 int i, j;
3651 3652 unsigned int alloc_size = (sizeof (struct stat_array)) * len;
3652 3653
3653 3654 /* Extract our extended stats nvlist from the main list */
3654 3655 verify(nvlist_lookup_nvlist(newnv, ZPOOL_CONFIG_VDEV_STATS_EX,
3655 3656 &newnvx) == 0);
3656 3657 if (oldnv) {
3657 3658 verify(nvlist_lookup_nvlist(oldnv, ZPOOL_CONFIG_VDEV_STATS_EX,
3658 3659 &oldnvx) == 0);
3659 3660 }
3660 3661
3661 3662 newnva = safe_malloc(alloc_size);
3662 3663 oldnva = safe_malloc(alloc_size);
3663 3664 calcnva = safe_malloc(alloc_size);
3664 3665
3665 3666 for (j = 0; j < len; j++) {
3666 3667 verify(nvpair64_to_stat_array(newnvx, names[j],
3667 3668 &newnva[j]) == 0);
3668 3669 calcnva[j].count = newnva[j].count;
3669 3670 alloc_size = calcnva[j].count * sizeof (calcnva[j].data[0]);
3670 3671 calcnva[j].data = safe_malloc(alloc_size);
3671 3672 memcpy(calcnva[j].data, newnva[j].data, alloc_size);
3672 3673
3673 3674 if (oldnvx) {
3674 3675 verify(nvpair64_to_stat_array(oldnvx, names[j],
3675 3676 &oldnva[j]) == 0);
3676 3677 for (i = 0; i < oldnva[j].count; i++)
3677 3678 calcnva[j].data[i] -= oldnva[j].data[i];
3678 3679 }
3679 3680 }
3680 3681 free(newnva);
3681 3682 free(oldnva);
3682 3683 return (calcnva);
3683 3684 }
3684 3685
3685 3686 static void
3686 3687 free_calc_stats(struct stat_array *nva, unsigned int len)
3687 3688 {
3688 3689 int i;
3689 3690 for (i = 0; i < len; i++)
3690 3691 free(nva[i].data);
3691 3692
3692 3693 free(nva);
3693 3694 }
3694 3695
3695 3696 static void
3696 3697 print_iostat_histo(struct stat_array *nva, unsigned int len,
3697 3698 iostat_cbdata_t *cb, unsigned int column_width, unsigned int namewidth,
3698 3699 double scale)
3699 3700 {
3700 3701 int i, j;
3701 3702 char buf[6];
3702 3703 uint64_t val;
3703 3704 enum zfs_nicenum_format format;
3704 3705 unsigned int buckets;
3705 3706 unsigned int start_bucket;
3706 3707
3707 3708 if (cb->cb_literal)
3708 3709 format = ZFS_NICENUM_RAW;
3709 3710 else
3710 3711 format = ZFS_NICENUM_1024;
3711 3712
3712 3713 /* All these histos are the same size, so just use nva[0].count */
3713 3714 buckets = nva[0].count;
3714 3715
3715 3716 if (cb->cb_flags & IOS_RQ_HISTO_M) {
3716 3717 /* Start at 512 - req size should never be lower than this */
3717 3718 start_bucket = 9;
3718 3719 } else {
3719 3720 start_bucket = 0;
3720 3721 }
3721 3722
3722 3723 for (j = start_bucket; j < buckets; j++) {
3723 3724 /* Print histogram bucket label */
3724 3725 if (cb->cb_flags & IOS_L_HISTO_M) {
3725 3726 /* Ending range of this bucket */
3726 3727 val = (1ULL << (j + 1)) - 1;
3727 3728 zfs_nicetime(val, buf, sizeof (buf));
3728 3729 } else {
3729 3730 /* Request size (starting range of bucket) */
3730 3731 val = (1UL << j);
3731 3732 zfs_nicenum(val, buf, sizeof (buf));
3732 3733 }
3733 3734
3734 3735 if (cb->cb_scripted)
3735 3736 printf("%llu", (u_longlong_t)val);
3736 3737 else
3737 3738 printf("%-*s", namewidth, buf);
3738 3739
3739 3740 /* Print the values on the line */
3740 3741 for (i = 0; i < len; i++) {
3741 3742 print_one_stat(nva[i].data[j] * scale, format,
3742 3743 column_width, cb->cb_scripted);
3743 3744 }
3744 3745 printf("\n");
3745 3746 }
3746 3747 }
3747 3748
3748 3749 static void
3749 3750 print_solid_separator(unsigned int length)
3750 3751 {
3751 3752 while (length--)
3752 3753 printf("-");
3753 3754 printf("\n");
3754 3755 }
3755 3756
3756 3757 static void
3757 3758 print_iostat_histos(iostat_cbdata_t *cb, nvlist_t *oldnv,
3758 3759 nvlist_t *newnv, double scale, const char *name)
3759 3760 {
3760 3761 unsigned int column_width;
3761 3762 unsigned int namewidth;
3762 3763 unsigned int entire_width;
3763 3764 enum iostat_type type;
3764 3765 struct stat_array *nva;
3765 3766 const char **names;
3766 3767 unsigned int names_len;
3767 3768
3768 3769 /* What type of histo are we? */
3769 3770 type = IOS_HISTO_IDX(cb->cb_flags);
3770 3771
3771 3772 /* Get NULL-terminated array of nvlist names for our histo */
3772 3773 names = vsx_type_to_nvlist[type];
3773 3774 names_len = str_array_len(names); /* num of names */
3774 3775
3775 3776 nva = calc_and_alloc_stats_ex(names, names_len, oldnv, newnv);
3776 3777
3777 3778 if (cb->cb_literal) {
3778 3779 column_width = MAX(5,
3779 3780 (unsigned int) log10(stat_histo_max(nva, names_len)) + 1);
3780 3781 } else {
3781 3782 column_width = 5;
3782 3783 }
3783 3784
3784 3785 namewidth = MAX(cb->cb_namewidth,
3785 3786 strlen(histo_to_title[IOS_HISTO_IDX(cb->cb_flags)]));
3786 3787
3787 3788 /*
3788 3789 * Calculate the entire line width of what we're printing. The
3789 3790 * +2 is for the two spaces between columns:
3790 3791 */
3791 3792 /* read write */
3792 3793 /* ----- ----- */
3793 3794 /* |___| <---------- column_width */
3794 3795 /* */
3795 3796 /* |__________| <--- entire_width */
3796 3797 /* */
3797 3798 entire_width = namewidth + (column_width + 2) *
3798 3799 label_array_len(iostat_bottom_labels[type]);
3799 3800
3800 3801 if (cb->cb_scripted)
3801 3802 printf("%s\n", name);
3802 3803 else
3803 3804 print_iostat_header_impl(cb, column_width, name);
3804 3805
3805 3806 print_iostat_histo(nva, names_len, cb, column_width,
3806 3807 namewidth, scale);
3807 3808
3808 3809 free_calc_stats(nva, names_len);
3809 3810 if (!cb->cb_scripted)
3810 3811 print_solid_separator(entire_width);
3811 3812 }
3812 3813
3813 3814 /*
3814 3815 * Calculate the average latency of a power-of-two latency histogram
3815 3816 */
3816 3817 static uint64_t
3817 3818 single_histo_average(uint64_t *histo, unsigned int buckets)
3818 3819 {
3819 3820 int i;
3820 3821 uint64_t count = 0, total = 0;
3821 3822
3822 3823 for (i = 0; i < buckets; i++) {
3823 3824 /*
3824 3825 * Our buckets are power-of-two latency ranges. Use the
3825 3826 * midpoint latency of each bucket to calculate the average.
3826 3827 * For example:
3827 3828 *
3828 3829 * Bucket Midpoint
3829 3830 * 8ns-15ns: 12ns
3830 3831 * 16ns-31ns: 24ns
3831 3832 * ...
3832 3833 */
3833 3834 if (histo[i] != 0) {
3834 3835 total += histo[i] * (((1UL << i) + ((1UL << i)/2)));
3835 3836 count += histo[i];
3836 3837 }
3837 3838 }
3838 3839
3839 3840 /* Prevent divide by zero */
3840 3841 return (count == 0 ? 0 : total / count);
3841 3842 }
3842 3843
3843 3844 static void
3844 3845 print_iostat_queues(iostat_cbdata_t *cb, nvlist_t *oldnv,
3845 3846 nvlist_t *newnv)
3846 3847 {
3847 3848 int i;
3848 3849 uint64_t val;
3849 3850 const char *names[] = {
3850 3851 ZPOOL_CONFIG_VDEV_SYNC_R_PEND_QUEUE,
3851 3852 ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE,
3852 3853 ZPOOL_CONFIG_VDEV_SYNC_W_PEND_QUEUE,
3853 3854 ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE,
3854 3855 ZPOOL_CONFIG_VDEV_ASYNC_R_PEND_QUEUE,
3855 3856 ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE,
3856 3857 ZPOOL_CONFIG_VDEV_ASYNC_W_PEND_QUEUE,
3857 3858 ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE,
3858 3859 ZPOOL_CONFIG_VDEV_SCRUB_PEND_QUEUE,
3859 3860 ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE,
3860 3861 ZPOOL_CONFIG_VDEV_TRIM_PEND_QUEUE,
3861 3862 ZPOOL_CONFIG_VDEV_TRIM_ACTIVE_QUEUE,
3862 3863 };
3863 3864
3864 3865 struct stat_array *nva;
3865 3866
3866 3867 unsigned int column_width = default_column_width(cb, IOS_QUEUES);
3867 3868 enum zfs_nicenum_format format;
3868 3869
3869 3870 nva = calc_and_alloc_stats_ex(names, ARRAY_SIZE(names), NULL, newnv);
3870 3871
3871 3872 if (cb->cb_literal)
3872 3873 format = ZFS_NICENUM_RAW;
3873 3874 else
3874 3875 format = ZFS_NICENUM_1024;
3875 3876
3876 3877 for (i = 0; i < ARRAY_SIZE(names); i++) {
3877 3878 val = nva[i].data[0];
3878 3879 print_one_stat(val, format, column_width, cb->cb_scripted);
3879 3880 }
3880 3881
3881 3882 free_calc_stats(nva, ARRAY_SIZE(names));
3882 3883 }
3883 3884
3884 3885 static void
3885 3886 print_iostat_latency(iostat_cbdata_t *cb, nvlist_t *oldnv,
3886 3887 nvlist_t *newnv)
3887 3888 {
3888 3889 int i;
3889 3890 uint64_t val;
3890 3891 const char *names[] = {
3891 3892 ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO,
3892 3893 ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO,
3893 3894 ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO,
3894 3895 ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO,
3895 3896 ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO,
3896 3897 ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO,
3897 3898 ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO,
3898 3899 ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO,
3899 3900 ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO,
3900 3901 ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO,
3901 3902 };
3902 3903 struct stat_array *nva;
3903 3904
3904 3905 unsigned int column_width = default_column_width(cb, IOS_LATENCY);
3905 3906 enum zfs_nicenum_format format;
3906 3907
3907 3908 nva = calc_and_alloc_stats_ex(names, ARRAY_SIZE(names), oldnv, newnv);
3908 3909
3909 3910 if (cb->cb_literal)
3910 3911 format = ZFS_NICENUM_RAWTIME;
3911 3912 else
3912 3913 format = ZFS_NICENUM_TIME;
3913 3914
3914 3915 /* Print our avg latencies on the line */
3915 3916 for (i = 0; i < ARRAY_SIZE(names); i++) {
3916 3917 /* Compute average latency for a latency histo */
3917 3918 val = single_histo_average(nva[i].data, nva[i].count);
3918 3919 print_one_stat(val, format, column_width, cb->cb_scripted);
3919 3920 }
3920 3921 free_calc_stats(nva, ARRAY_SIZE(names));
3921 3922 }
3922 3923
3923 3924 /*
3924 3925 * Print default statistics (capacity/operations/bandwidth)
3925 3926 */
3926 3927 static void
3927 3928 print_iostat_default(vdev_stat_t *vs, iostat_cbdata_t *cb, double scale)
3928 3929 {
3929 3930 unsigned int column_width = default_column_width(cb, IOS_DEFAULT);
3930 3931 enum zfs_nicenum_format format;
3931 3932 char na; /* char to print for "not applicable" values */
3932 3933
3933 3934 if (cb->cb_literal) {
3934 3935 format = ZFS_NICENUM_RAW;
3935 3936 na = '0';
3936 3937 } else {
3937 3938 format = ZFS_NICENUM_1024;
3938 3939 na = '-';
3939 3940 }
3940 3941
3941 3942 /* only toplevel vdevs have capacity stats */
3942 3943 if (vs->vs_space == 0) {
3943 3944 if (cb->cb_scripted)
3944 3945 printf("\t%c\t%c", na, na);
3945 3946 else
3946 3947 printf(" %*c %*c", column_width, na, column_width,
3947 3948 na);
3948 3949 } else {
3949 3950 print_one_stat(vs->vs_alloc, format, column_width,
3950 3951 cb->cb_scripted);
3951 3952 print_one_stat(vs->vs_space - vs->vs_alloc, format,
3952 3953 column_width, cb->cb_scripted);
3953 3954 }
3954 3955
3955 3956 print_one_stat((uint64_t)(vs->vs_ops[ZIO_TYPE_READ] * scale),
3956 3957 format, column_width, cb->cb_scripted);
3957 3958 print_one_stat((uint64_t)(vs->vs_ops[ZIO_TYPE_WRITE] * scale),
3958 3959 format, column_width, cb->cb_scripted);
3959 3960 print_one_stat((uint64_t)(vs->vs_bytes[ZIO_TYPE_READ] * scale),
3960 3961 format, column_width, cb->cb_scripted);
3961 3962 print_one_stat((uint64_t)(vs->vs_bytes[ZIO_TYPE_WRITE] * scale),
3962 3963 format, column_width, cb->cb_scripted);
3963 3964 }
3964 3965
3965 3966 static const char *class_name[] = {
3966 3967 VDEV_ALLOC_BIAS_DEDUP,
3967 3968 VDEV_ALLOC_BIAS_SPECIAL,
3968 3969 VDEV_ALLOC_CLASS_LOGS
3969 3970 };
3970 3971
3971 3972 /*
3972 3973 * Print out all the statistics for the given vdev. This can either be the
3973 3974 * toplevel configuration, or called recursively. If 'name' is NULL, then this
3974 3975 * is a verbose output, and we don't want to display the toplevel pool stats.
3975 3976 *
3976 3977 * Returns the number of stat lines printed.
3977 3978 */
3978 3979 unsigned int
3979 3980 print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
3980 3981 nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
3981 3982 {
3982 3983 nvlist_t **oldchild, **newchild;
3983 3984 uint_t c, children, oldchildren;
3984 3985 vdev_stat_t *oldvs, *newvs, *calcvs;
3985 3986 vdev_stat_t zerovs = { 0 };
3986 3987 char *vname;
3987 3988 int i;
3988 3989 int ret = 0;
3989 3990 uint64_t tdelta;
3990 3991 double scale;
3991 3992
3992 3993 if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
3993 3994 return (0);
3994 3995
3995 3996 calcvs = safe_malloc(sizeof (*calcvs));
3996 3997
3997 3998 if (oldnv != NULL) {
3998 3999 verify(nvlist_lookup_uint64_array(oldnv,
3999 4000 ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
4000 4001 } else {
4001 4002 oldvs = &zerovs;
4002 4003 }
4003 4004
4004 4005 /* Do we only want to see a specific vdev? */
4005 4006 for (i = 0; i < cb->cb_vdev_names_count; i++) {
4006 4007 /* Yes we do. Is this the vdev? */
4007 4008 if (strcmp(name, cb->cb_vdev_names[i]) == 0) {
4008 4009 /*
4009 4010 * This is our vdev. Since it is the only vdev we
4010 4011 * will be displaying, make depth = 0 so that it
4011 4012 * doesn't get indented.
4012 4013 */
4013 4014 depth = 0;
4014 4015 break;
4015 4016 }
4016 4017 }
4017 4018
4018 4019 if (cb->cb_vdev_names_count && (i == cb->cb_vdev_names_count)) {
4019 4020 /* Couldn't match the name */
4020 4021 goto children;
4021 4022 }
4022 4023
4023 4024
4024 4025 verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
4025 4026 (uint64_t **)&newvs, &c) == 0);
4026 4027
4027 4028 /*
4028 4029 * Print the vdev name unless it's is a histogram. Histograms
4029 4030 * display the vdev name in the header itself.
4030 4031 */
4031 4032 if (!(cb->cb_flags & IOS_ANYHISTO_M)) {
4032 4033 if (cb->cb_scripted) {
4033 4034 printf("%s", name);
4034 4035 } else {
4035 4036 if (strlen(name) + depth > cb->cb_namewidth)
4036 4037 (void) printf("%*s%s", depth, "", name);
4037 4038 else
4038 4039 (void) printf("%*s%s%*s", depth, "", name,
4039 4040 (int)(cb->cb_namewidth - strlen(name) -
4040 4041 depth), "");
4041 4042 }
4042 4043 }
4043 4044
4044 4045 /* Calculate our scaling factor */
4045 4046 tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
4046 4047 if ((oldvs->vs_timestamp == 0) && (cb->cb_flags & IOS_ANYHISTO_M)) {
4047 4048 /*
4048 4049 * If we specify printing histograms with no time interval, then
4049 4050 * print the histogram numbers over the entire lifetime of the
4050 4051 * vdev.
4051 4052 */
4052 4053 scale = 1;
4053 4054 } else {
4054 4055 if (tdelta == 0)
4055 4056 scale = 1.0;
4056 4057 else
4057 4058 scale = (double)NANOSEC / tdelta;
4058 4059 }
4059 4060
4060 4061 if (cb->cb_flags & IOS_DEFAULT_M) {
4061 4062 calc_default_iostats(oldvs, newvs, calcvs);
4062 4063 print_iostat_default(calcvs, cb, scale);
4063 4064 }
4064 4065 if (cb->cb_flags & IOS_LATENCY_M)
4065 4066 print_iostat_latency(cb, oldnv, newnv);
4066 4067 if (cb->cb_flags & IOS_QUEUES_M)
4067 4068 print_iostat_queues(cb, oldnv, newnv);
4068 4069 if (cb->cb_flags & IOS_ANYHISTO_M) {
4069 4070 printf("\n");
4070 4071 print_iostat_histos(cb, oldnv, newnv, scale, name);
4071 4072 }
4072 4073
4073 4074 if (!(cb->cb_flags & IOS_ANYHISTO_M))
4074 4075 printf("\n");
4075 4076
4076 4077 ret++;
4077 4078
4078 4079 children:
4079 4080
4080 4081 free(calcvs);
4081 4082
4082 4083 if (!cb->cb_verbose)
4083 4084 return (ret);
4084 4085
4085 4086 if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
4086 4087 &newchild, &children) != 0)
4087 4088 return (ret);
4088 4089
4089 4090 if (oldnv) {
4090 4091 if (nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
4091 4092 &oldchild, &oldchildren) != 0)
4092 4093 return (ret);
4093 4094
4094 4095 children = MIN(oldchildren, children);
4095 4096 }
4096 4097
4097 4098 /*
4098 4099 * print normal top-level devices
4099 4100 */
4100 4101 for (c = 0; c < children; c++) {
4101 4102 uint64_t ishole = B_FALSE, islog = B_FALSE;
4102 4103
4103 4104 (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE,
4104 4105 &ishole);
4105 4106
4106 4107 (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
4107 4108 &islog);
4108 4109
4109 4110 if (ishole || islog)
4110 4111 continue;
4111 4112
4112 4113 if (nvlist_exists(newchild[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
4113 4114 continue;
4114 4115
4115 4116 vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
4116 4117 cb->cb_name_flags);
4117 4118 ret += print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
4118 4119 newchild[c], cb, depth + 2);
4119 4120 free(vname);
4120 4121 }
4121 4122
4122 4123 /*
4123 4124 * print all other top-level devices
4124 4125 */
4125 4126 for (uint_t n = 0; n < 3; n++) {
4126 4127 boolean_t printed = B_FALSE;
4127 4128
4128 4129 for (c = 0; c < children; c++) {
4129 4130 uint64_t islog = B_FALSE;
4130 4131 char *bias = NULL;
4131 4132 char *type = NULL;
4132 4133
4133 4134 (void) nvlist_lookup_uint64(newchild[c],
4134 4135 ZPOOL_CONFIG_IS_LOG, &islog);
4135 4136 if (islog) {
4136 4137 bias = VDEV_ALLOC_CLASS_LOGS;
4137 4138 } else {
4138 4139 (void) nvlist_lookup_string(newchild[c],
4139 4140 ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
4140 4141 (void) nvlist_lookup_string(newchild[c],
4141 4142 ZPOOL_CONFIG_TYPE, &type);
4142 4143 }
4143 4144 if (bias == NULL || strcmp(bias, class_name[n]) != 0)
4144 4145 continue;
4145 4146 if (!islog && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
4146 4147 continue;
4147 4148
4148 4149 if (!printed) {
4149 4150 if ((!(cb->cb_flags & IOS_ANYHISTO_M)) &&
4150 4151 !cb->cb_scripted && !cb->cb_vdev_names) {
4151 4152 print_iostat_dashes(cb, 0,
4152 4153 class_name[n]);
4153 4154 }
4154 4155 printf("\n");
4155 4156 printed = B_TRUE;
4156 4157 }
4157 4158
4158 4159 vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
4159 4160 cb->cb_name_flags);
4160 4161 ret += print_vdev_stats(zhp, vname, oldnv ?
4161 4162 oldchild[c] : NULL, newchild[c], cb, depth + 2);
4162 4163 free(vname);
4163 4164 }
4164 4165
4165 4166 }
4166 4167
4167 4168 /*
4168 4169 * Include level 2 ARC devices in iostat output
4169 4170 */
4170 4171 if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
4171 4172 &newchild, &children) != 0)
4172 4173 return (ret);
4173 4174
4174 4175 if (oldnv) {
4175 4176 if (nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
4176 4177 &oldchild, &oldchildren) != 0)
4177 4178 return (ret);
4178 4179
4179 4180 children = MIN(oldchildren, children);
4180 4181 }
4181 4182
4182 4183 if (children > 0) {
4183 4184 if ((!(cb->cb_flags & IOS_ANYHISTO_M)) && !cb->cb_scripted &&
4184 4185 !cb->cb_vdev_names) {
4185 4186 print_iostat_dashes(cb, 0, "cache");
4186 4187 }
4187 4188 printf("\n");
4188 4189
4189 4190 for (c = 0; c < children; c++) {
4190 4191 vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
4191 4192 cb->cb_name_flags);
4192 4193 ret += print_vdev_stats(zhp, vname, oldnv ? oldchild[c]
4193 4194 : NULL, newchild[c], cb, depth + 2);
4194 4195 free(vname);
4195 4196 }
4196 4197 }
4197 4198
4198 4199 return (ret);
4199 4200 }
4200 4201
4201 4202 static int
4202 4203 refresh_iostat(zpool_handle_t *zhp, void *data)
4203 4204 {
4204 4205 iostat_cbdata_t *cb = data;
4205 4206 boolean_t missing;
4206 4207
4207 4208 /*
4208 4209 * If the pool has disappeared, remove it from the list and continue.
4209 4210 */
4210 4211 if (zpool_refresh_stats(zhp, &missing) != 0)
4211 4212 return (-1);
4212 4213
4213 4214 if (missing)
4214 4215 pool_list_remove(cb->cb_list, zhp);
4215 4216
4216 4217 return (0);
4217 4218 }
4218 4219
4219 4220 /*
4220 4221 * Callback to print out the iostats for the given pool.
4221 4222 */
4222 4223 int
4223 4224 print_iostat(zpool_handle_t *zhp, void *data)
4224 4225 {
4225 4226 iostat_cbdata_t *cb = data;
4226 4227 nvlist_t *oldconfig, *newconfig;
4227 4228 nvlist_t *oldnvroot, *newnvroot;
4228 4229 int ret;
4229 4230
4230 4231 newconfig = zpool_get_config(zhp, &oldconfig);
4231 4232
4232 4233 if (cb->cb_iteration == 1)
4233 4234 oldconfig = NULL;
4234 4235
4235 4236 verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
4236 4237 &newnvroot) == 0);
4237 4238
4238 4239 if (oldconfig == NULL)
4239 4240 oldnvroot = NULL;
4240 4241 else
4241 4242 verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
4242 4243 &oldnvroot) == 0);
4243 4244
4244 4245 ret = print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot,
4245 4246 cb, 0);
4246 4247 if ((ret != 0) && !(cb->cb_flags & IOS_ANYHISTO_M) &&
4247 4248 !cb->cb_scripted && cb->cb_verbose && !cb->cb_vdev_names_count) {
4248 4249 print_iostat_separator(cb);
4249 4250 printf("\n");
4250 4251 }
4251 4252
4252 4253 return (ret);
4253 4254 }
4254 4255
4255 4256 static int
4256 4257 get_columns(void)
4257 4258 {
4258 4259 struct winsize ws;
4259 4260 int columns = 80;
4260 4261 int error;
4261 4262
4262 4263 if (isatty(STDOUT_FILENO)) {
4263 4264 error = ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
4264 4265 if (error == 0)
4265 4266 columns = ws.ws_col;
4266 4267 } else {
4267 4268 columns = 999;
4268 4269 }
4269 4270
4270 4271 return (columns);
4271 4272 }
4272 4273
4273 4274 /*
4274 4275 * Return the required length of the pool/vdev name column. The minimum
4275 4276 * allowed width and output formatting flags must be provided.
4276 4277 */
4277 4278 static int
4278 4279 get_namewidth(zpool_handle_t *zhp, int min_width, int flags, boolean_t verbose)
4279 4280 {
4280 4281 nvlist_t *config, *nvroot;
4281 4282 int width = min_width;
4282 4283
4283 4284 if ((config = zpool_get_config(zhp, NULL)) != NULL) {
4284 4285 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
4285 4286 &nvroot) == 0);
4286 4287 unsigned int poolname_len = strlen(zpool_get_name(zhp));
4287 4288 if (verbose == B_FALSE) {
4288 4289 width = MAX(poolname_len, min_width);
4289 4290 } else {
4290 4291 width = MAX(poolname_len,
4291 4292 max_width(zhp, nvroot, 0, min_width, flags));
4292 4293 }
4293 4294 }
4294 4295
4295 4296 return (width);
4296 4297 }
4297 4298
4298 4299 /*
4299 4300 * Parse the input string, get the 'interval' and 'count' value if there is one.
4300 4301 */
4301 4302 static void
4302 4303 get_interval_count(int *argcp, char **argv, float *iv,
4303 4304 unsigned long *cnt)
4304 4305 {
4305 4306 float interval = 0;
4306 4307 unsigned long count = 0;
4307 4308 int argc = *argcp, errno;
4308 4309
4309 4310 /*
4310 4311 * Determine if the last argument is an integer or a pool name
4311 4312 */
4312 4313 if (argc > 0 && isnumber(argv[argc - 1])) {
4313 4314 char *end;
4314 4315
4315 4316 errno = 0;
4316 4317 interval = strtof(argv[argc - 1], &end);
4317 4318
4318 4319 if (*end == '\0' && errno == 0) {
4319 4320 if (interval == 0) {
4320 4321 (void) fprintf(stderr, gettext("interval "
4321 4322 "cannot be zero\n"));
4322 4323 usage(B_FALSE);
4323 4324 }
4324 4325 /*
4325 4326 * Ignore the last parameter
4326 4327 */
4327 4328 argc--;
4328 4329 } else {
4329 4330 /*
4330 4331 * If this is not a valid number, just plow on. The
4331 4332 * user will get a more informative error message later
4332 4333 * on.
4333 4334 */
4334 4335 interval = 0;
4335 4336 }
4336 4337 }
4337 4338
4338 4339 /*
4339 4340 * If the last argument is also an integer, then we have both a count
4340 4341 * and an interval.
4341 4342 */
4342 4343 if (argc > 0 && isnumber(argv[argc - 1])) {
4343 4344 char *end;
4344 4345
4345 4346 errno = 0;
4346 4347 count = interval;
4347 4348 interval = strtof(argv[argc - 1], &end);
4348 4349
4349 4350 if (*end == '\0' && errno == 0) {
4350 4351 if (interval == 0) {
4351 4352 (void) fprintf(stderr, gettext("interval "
4352 4353 "cannot be zero\n"));
4353 4354 usage(B_FALSE);
4354 4355 }
4355 4356
4356 4357 /*
4357 4358 * Ignore the last parameter
4358 4359 */
4359 4360 argc--;
4360 4361 } else {
4361 4362 interval = 0;
4362 4363 }
4363 4364 }
4364 4365
4365 4366 *iv = interval;
4366 4367 *cnt = count;
4367 4368 *argcp = argc;
4368 4369 }
4369 4370
4370 4371 static void
4371 4372 get_timestamp_arg(char c)
4372 4373 {
4373 4374 if (c == 'u')
4374 4375 timestamp_fmt = UDATE;
4375 4376 else if (c == 'd')
4376 4377 timestamp_fmt = DDATE;
4377 4378 else
4378 4379 usage(B_FALSE);
4379 4380 }
4380 4381
4381 4382 /*
4382 4383 * Return stat flags that are supported by all pools by both the module and
4383 4384 * zpool iostat. "*data" should be initialized to all 0xFFs before running.
4384 4385 * It will get ANDed down until only the flags that are supported on all pools
4385 4386 * remain.
4386 4387 */
4387 4388 static int
4388 4389 get_stat_flags_cb(zpool_handle_t *zhp, void *data)
4389 4390 {
4390 4391 uint64_t *mask = data;
4391 4392 nvlist_t *config, *nvroot, *nvx;
4392 4393 uint64_t flags = 0;
4393 4394 int i, j;
4394 4395
4395 4396 config = zpool_get_config(zhp, NULL);
4396 4397 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
4397 4398 &nvroot) == 0);
4398 4399
4399 4400 /* Default stats are always supported, but for completeness.. */
4400 4401 if (nvlist_exists(nvroot, ZPOOL_CONFIG_VDEV_STATS))
4401 4402 flags |= IOS_DEFAULT_M;
4402 4403
4403 4404 /* Get our extended stats nvlist from the main list */
4404 4405 if (nvlist_lookup_nvlist(nvroot, ZPOOL_CONFIG_VDEV_STATS_EX,
4405 4406 &nvx) != 0) {
4406 4407 /*
4407 4408 * No extended stats; they're probably running an older
4408 4409 * module. No big deal, we support that too.
4409 4410 */
4410 4411 goto end;
4411 4412 }
4412 4413
4413 4414 /* For each extended stat, make sure all its nvpairs are supported */
4414 4415 for (j = 0; j < ARRAY_SIZE(vsx_type_to_nvlist); j++) {
4415 4416 if (!vsx_type_to_nvlist[j][0])
4416 4417 continue;
4417 4418
4418 4419 /* Start off by assuming the flag is supported, then check */
4419 4420 flags |= (1ULL << j);
4420 4421 for (i = 0; vsx_type_to_nvlist[j][i]; i++) {
4421 4422 if (!nvlist_exists(nvx, vsx_type_to_nvlist[j][i])) {
4422 4423 /* flag isn't supported */
4423 4424 flags = flags & ~(1ULL << j);
4424 4425 break;
4425 4426 }
4426 4427 }
4427 4428 }
4428 4429 end:
4429 4430 *mask = *mask & flags;
4430 4431 return (0);
4431 4432 }
4432 4433
4433 4434 /*
4434 4435 * Return a bitmask of stats that are supported on all pools by both the module
4435 4436 * and zpool iostat.
4436 4437 */
4437 4438 static uint64_t
4438 4439 get_stat_flags(zpool_list_t *list)
4439 4440 {
4440 4441 uint64_t mask = -1;
4441 4442
4442 4443 /*
4443 4444 * get_stat_flags_cb() will lop off bits from "mask" until only the
4444 4445 * flags that are supported on all pools remain.
4445 4446 */
4446 4447 (void) pool_list_iter(list, B_FALSE, get_stat_flags_cb, &mask);
4447 4448 return (mask);
4448 4449 }
4449 4450
4450 4451 /*
4451 4452 * Return 1 if cb_data->cb_vdev_names[0] is this vdev's name, 0 otherwise.
4452 4453 */
4453 4454 static int
4454 4455 is_vdev_cb(zpool_handle_t *zhp, nvlist_t *nv, void *cb_data)
4455 4456 {
4456 4457 iostat_cbdata_t *cb = cb_data;
4457 4458 char *name;
4458 4459
4459 4460 name = zpool_vdev_name(g_zfs, zhp, nv, cb->cb_name_flags);
4460 4461
4461 4462 if (strcmp(name, cb->cb_vdev_names[0]) == 0)
4462 4463 return (1); /* match */
4463 4464
4464 4465 return (0);
4465 4466 }
4466 4467
4467 4468 /*
4468 4469 * Returns 1 if cb_data->cb_vdev_names[0] is a vdev name, 0 otherwise.
4469 4470 */
4470 4471 static int
4471 4472 is_vdev(zpool_handle_t *zhp, void *cb_data)
4472 4473 {
4473 4474 return (for_each_vdev(zhp, is_vdev_cb, cb_data));
4474 4475 }
4475 4476
4476 4477 /*
4477 4478 * Check if vdevs are in a pool
4478 4479 *
4479 4480 * Return 1 if all argv[] strings are vdev names in pool "pool_name". Otherwise
4480 4481 * return 0. If pool_name is NULL, then search all pools.
4481 4482 */
4482 4483 static int
4483 4484 are_vdevs_in_pool(int argc, char **argv, char *pool_name,
4484 4485 iostat_cbdata_t *cb)
4485 4486 {
4486 4487 char **tmp_name;
4487 4488 int ret = 0;
4488 4489 int i;
4489 4490 int pool_count = 0;
4490 4491
4491 4492 if ((argc == 0) || !*argv)
4492 4493 return (0);
4493 4494
4494 4495 if (pool_name)
4495 4496 pool_count = 1;
4496 4497
4497 4498 /* Temporarily hijack cb_vdev_names for a second... */
4498 4499 tmp_name = cb->cb_vdev_names;
4499 4500
4500 4501 /* Go though our list of prospective vdev names */
4501 4502 for (i = 0; i < argc; i++) {
4502 4503 cb->cb_vdev_names = argv + i;
4503 4504
4504 4505 /* Is this name a vdev in our pools? */
4505 4506 ret = for_each_pool(pool_count, &pool_name, B_TRUE, NULL,
4506 4507 is_vdev, cb);
4507 4508 if (!ret) {
4508 4509 /* No match */
4509 4510 break;
4510 4511 }
4511 4512 }
4512 4513
4513 4514 cb->cb_vdev_names = tmp_name;
4514 4515
4515 4516 return (ret);
4516 4517 }
4517 4518
4518 4519 static int
4519 4520 is_pool_cb(zpool_handle_t *zhp, void *data)
4520 4521 {
4521 4522 char *name = data;
4522 4523 if (strcmp(name, zpool_get_name(zhp)) == 0)
4523 4524 return (1);
4524 4525
4525 4526 return (0);
4526 4527 }
4527 4528
4528 4529 /*
4529 4530 * Do we have a pool named *name? If so, return 1, otherwise 0.
4530 4531 */
4531 4532 static int
4532 4533 is_pool(char *name)
4533 4534 {
4534 4535 return (for_each_pool(0, NULL, B_TRUE, NULL, is_pool_cb, name));
4535 4536 }
4536 4537
4537 4538 /* Are all our argv[] strings pool names? If so return 1, 0 otherwise. */
4538 4539 static int
4539 4540 are_all_pools(int argc, char **argv)
4540 4541 {
4541 4542 if ((argc == 0) || !*argv)
4542 4543 return (0);
4543 4544
4544 4545 while (--argc >= 0)
4545 4546 if (!is_pool(argv[argc]))
4546 4547 return (0);
4547 4548
4548 4549 return (1);
4549 4550 }
4550 4551
4551 4552 /*
4552 4553 * Helper function to print out vdev/pool names we can't resolve. Used for an
4553 4554 * error message.
4554 4555 */
4555 4556 static void
4556 4557 error_list_unresolved_vdevs(int argc, char **argv, char *pool_name,
4557 4558 iostat_cbdata_t *cb)
4558 4559 {
4559 4560 int i;
4560 4561 char *name;
4561 4562 char *str;
4562 4563 for (i = 0; i < argc; i++) {
4563 4564 name = argv[i];
4564 4565
4565 4566 if (is_pool(name))
4566 4567 str = gettext("pool");
4567 4568 else if (are_vdevs_in_pool(1, &name, pool_name, cb))
4568 4569 str = gettext("vdev in this pool");
4569 4570 else if (are_vdevs_in_pool(1, &name, NULL, cb))
4570 4571 str = gettext("vdev in another pool");
4571 4572 else
4572 4573 str = gettext("unknown");
4573 4574
4574 4575 fprintf(stderr, "\t%s (%s)\n", name, str);
4575 4576 }
4576 4577 }
4577 4578
4578 4579 /*
4579 4580 * Same as get_interval_count(), but with additional checks to not misinterpret
4580 4581 * guids as interval/count values. Assumes VDEV_NAME_GUID is set in
4581 4582 * cb.cb_name_flags.
4582 4583 */
4583 4584 static void
4584 4585 get_interval_count_filter_guids(int *argc, char **argv, float *interval,
4585 4586 unsigned long *count, iostat_cbdata_t *cb)
4586 4587 {
4587 4588 char **tmpargv = argv;
4588 4589 int argc_for_interval = 0;
4589 4590
4590 4591 /* Is the last arg an interval value? Or a guid? */
4591 4592 if (*argc >= 1 && !are_vdevs_in_pool(1, &argv[*argc - 1], NULL, cb)) {
4592 4593 /*
4593 4594 * The last arg is not a guid, so it's probably an
4594 4595 * interval value.
4595 4596 */
4596 4597 argc_for_interval++;
4597 4598
4598 4599 if (*argc >= 2 &&
4599 4600 !are_vdevs_in_pool(1, &argv[*argc - 2], NULL, cb)) {
4600 4601 /*
4601 4602 * The 2nd to last arg is not a guid, so it's probably
4602 4603 * an interval value.
4603 4604 */
4604 4605 argc_for_interval++;
4605 4606 }
4606 4607 }
4607 4608
4608 4609 /* Point to our list of possible intervals */
4609 4610 tmpargv = &argv[*argc - argc_for_interval];
4610 4611
4611 4612 *argc = *argc - argc_for_interval;
4612 4613 get_interval_count(&argc_for_interval, tmpargv,
4613 4614 interval, count);
4614 4615 }
4615 4616
4616 4617 /*
4617 4618 * Floating point sleep(). Allows you to pass in a floating point value for
4618 4619 * seconds.
4619 4620 */
4620 4621 static void
4621 4622 fsleep(float sec)
4622 4623 {
4623 4624 struct timespec req;
4624 4625 req.tv_sec = floor(sec);
4625 4626 req.tv_nsec = (sec - (float)req.tv_sec) * NANOSEC;
4626 4627 (void) nanosleep(&req, NULL);
4627 4628 }
4628 4629
4629 4630 /*
4630 4631 * Set the minimum pool/vdev name column width. The width must be at least 10,
4631 4632 * but may be as large as the column width - 42 so it still fits on one line.
4632 4633 */
4633 4634 static int
4634 4635 get_namewidth_iostat(zpool_handle_t *zhp, void *data)
4635 4636 {
4636 4637 iostat_cbdata_t *cb = data;
4637 4638 int width, columns;
4638 4639
4639 4640 width = get_namewidth(zhp, cb->cb_namewidth, cb->cb_name_flags,
4640 4641 cb->cb_verbose);
4641 4642 columns = get_columns();
4642 4643
4643 4644 if (width < 10)
4644 4645 width = 10;
4645 4646 if (width > columns - 42)
4646 4647 width = columns - 42;
4647 4648
4648 4649 cb->cb_namewidth = width;
4649 4650
4650 4651 return (0);
4651 4652 }
4652 4653
4653 4654 /*
4654 4655 * zpool iostat [-ghHLpPvy] [[-lq]|[-r|-w]] [-n name] [-T d|u]
4655 4656 * [[ pool ...]|[pool vdev ...]|[vdev ...]]
4656 4657 * [interval [count]]
4657 4658 *
4658 4659 * -g Display guid for individual vdev name.
4659 4660 * -L Follow links when resolving vdev path name.
4660 4661 * -P Display full path for vdev name.
4661 4662 * -v Display statistics for individual vdevs
4662 4663 * -h Display help
4663 4664 * -p Display values in parsable (exact) format.
4664 4665 * -H Scripted mode. Don't display headers, and separate properties
4665 4666 * by a single tab.
4666 4667 * -l Display average latency
4667 4668 * -q Display queue depths
4668 4669 * -w Display latency histograms
4669 4670 * -r Display request size histogram
4670 4671 * -T Display a timestamp in date(1) or Unix format
4671 4672 * -n Only print headers once
4672 4673 *
4673 4674 * This command can be tricky because we want to be able to deal with pool
4674 4675 * creation/destruction as well as vdev configuration changes. The bulk of this
4675 4676 * processing is handled by the pool_list_* routines in zpool_iter.c. We rely
4676 4677 * on pool_list_update() to detect the addition of new pools. Configuration
4677 4678 * changes are all handled within libzfs.
4678 4679 */
4679 4680 int
4680 4681 zpool_do_iostat(int argc, char **argv)
4681 4682 {
4682 4683 int c;
4683 4684 int ret;
4684 4685 int npools;
4685 4686 float interval = 0;
4686 4687 unsigned long count = 0;
4687 4688 int winheight = 24;
4688 4689 struct winsize win;
4689 4690 zpool_list_t *list;
4690 4691 boolean_t verbose = B_FALSE;
4691 4692 boolean_t latency = B_FALSE, l_histo = B_FALSE, rq_histo = B_FALSE;
4692 4693 boolean_t queues = B_FALSE, parseable = B_FALSE, scripted = B_FALSE;
4693 4694 boolean_t omit_since_boot = B_FALSE;
4694 4695 boolean_t guid = B_FALSE;
4695 4696 boolean_t follow_links = B_FALSE;
4696 4697 boolean_t full_name = B_FALSE;
4697 4698 boolean_t headers_once = B_FALSE;
4698 4699 iostat_cbdata_t cb = { 0 };
4699 4700
4700 4701 /* Used for printing error message */
4701 4702 const char flag_to_arg[] = {[IOS_LATENCY] = 'l', [IOS_QUEUES] = 'q',
4702 4703 [IOS_L_HISTO] = 'w', [IOS_RQ_HISTO] = 'r'};
4703 4704
4704 4705 uint64_t unsupported_flags;
4705 4706
4706 4707 /* check options */
4707 4708 while ((c = getopt(argc, argv, "gLPT:vyhplqrwnH")) != -1) {
4708 4709 switch (c) {
4709 4710 case 'g':
4710 4711 guid = B_TRUE;
4711 4712 break;
4712 4713 case 'L':
4713 4714 follow_links = B_TRUE;
4714 4715 break;
4715 4716 case 'P':
4716 4717 full_name = B_TRUE;
4717 4718 break;
4718 4719 case 'T':
4719 4720 get_timestamp_arg(*optarg);
4720 4721 break;
4721 4722 case 'v':
4722 4723 verbose = B_TRUE;
4723 4724 break;
4724 4725 case 'p':
4725 4726 parseable = B_TRUE;
4726 4727 break;
4727 4728 case 'l':
4728 4729 latency = B_TRUE;
4729 4730 break;
4730 4731 case 'q':
4731 4732 queues = B_TRUE;
4732 4733 break;
4733 4734 case 'H':
4734 4735 scripted = B_TRUE;
4735 4736 break;
4736 4737 case 'w':
4737 4738 l_histo = B_TRUE;
4738 4739 break;
4739 4740 case 'r':
4740 4741 rq_histo = B_TRUE;
4741 4742 break;
4742 4743 case 'y':
4743 4744 omit_since_boot = B_TRUE;
4744 4745 break;
4745 4746 case 'n':
4746 4747 headers_once = B_TRUE;
4747 4748 break;
4748 4749 case 'h':
4749 4750 usage(B_FALSE);
4750 4751 break;
4751 4752 case '?':
4752 4753 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
4753 4754 optopt);
4754 4755 usage(B_FALSE);
4755 4756 }
4756 4757 }
4757 4758
4758 4759 argc -= optind;
4759 4760 argv += optind;
4760 4761
4761 4762 cb.cb_literal = parseable;
4762 4763 cb.cb_scripted = scripted;
4763 4764
4764 4765 if (guid)
4765 4766 cb.cb_name_flags |= VDEV_NAME_GUID;
4766 4767 if (follow_links)
4767 4768 cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
4768 4769 if (full_name)
4769 4770 cb.cb_name_flags |= VDEV_NAME_PATH;
4770 4771 cb.cb_iteration = 0;
4771 4772 cb.cb_namewidth = 0;
4772 4773 cb.cb_verbose = verbose;
4773 4774
4774 4775 /* Get our interval and count values (if any) */
4775 4776 if (guid) {
4776 4777 get_interval_count_filter_guids(&argc, argv, &interval,
4777 4778 &count, &cb);
4778 4779 } else {
4779 4780 get_interval_count(&argc, argv, &interval, &count);
4780 4781 }
4781 4782
4782 4783 if (argc == 0) {
4783 4784 /* No args, so just print the defaults. */
4784 4785 } else if (are_all_pools(argc, argv)) {
4785 4786 /* All the args are pool names */
4786 4787 } else if (are_vdevs_in_pool(argc, argv, NULL, &cb)) {
4787 4788 /* All the args are vdevs */
4788 4789 cb.cb_vdev_names = argv;
4789 4790 cb.cb_vdev_names_count = argc;
4790 4791 argc = 0; /* No pools to process */
4791 4792 } else if (are_all_pools(1, argv)) {
4792 4793 /* The first arg is a pool name */
4793 4794 if (are_vdevs_in_pool(argc - 1, argv + 1, argv[0], &cb)) {
4794 4795 /* ...and the rest are vdev names */
4795 4796 cb.cb_vdev_names = argv + 1;
4796 4797 cb.cb_vdev_names_count = argc - 1;
4797 4798 argc = 1; /* One pool to process */
4798 4799 } else {
4799 4800 fprintf(stderr, gettext("Expected either a list of "));
4800 4801 fprintf(stderr, gettext("pools, or list of vdevs in"));
4801 4802 fprintf(stderr, " \"%s\", ", argv[0]);
4802 4803 fprintf(stderr, gettext("but got:\n"));
4803 4804 error_list_unresolved_vdevs(argc - 1, argv + 1,
4804 4805 argv[0], &cb);
4805 4806 fprintf(stderr, "\n");
4806 4807 usage(B_FALSE);
4807 4808 return (1);
4808 4809 }
4809 4810 } else {
4810 4811 /*
4811 4812 * The args don't make sense. The first arg isn't a pool name,
4812 4813 * nor are all the args vdevs.
4813 4814 */
4814 4815 fprintf(stderr, gettext("Unable to parse pools/vdevs list.\n"));
4815 4816 fprintf(stderr, "\n");
4816 4817 return (1);
4817 4818 }
4818 4819
4819 4820 if (cb.cb_vdev_names_count != 0) {
4820 4821 /*
4821 4822 * If user specified vdevs, it implies verbose.
4822 4823 */
4823 4824 cb.cb_verbose = B_TRUE;
4824 4825 }
4825 4826
4826 4827 /*
4827 4828 * Construct the list of all interesting pools.
4828 4829 */
4829 4830 ret = 0;
4830 4831 if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
4831 4832 return (1);
4832 4833
4833 4834 if (pool_list_count(list) == 0 && argc != 0) {
4834 4835 pool_list_free(list);
4835 4836 return (1);
4836 4837 }
4837 4838
4838 4839 if (pool_list_count(list) == 0 && interval == 0) {
4839 4840 pool_list_free(list);
4840 4841 (void) fprintf(stderr, gettext("no pools available\n"));
4841 4842 return (1);
4842 4843 }
4843 4844
4844 4845 if ((l_histo || rq_histo) && (queues || latency)) {
4845 4846 pool_list_free(list);
4846 4847 (void) fprintf(stderr,
4847 4848 gettext("[-r|-w] isn't allowed with [-q|-l]\n"));
4848 4849 usage(B_FALSE);
4849 4850 return (1);
4850 4851 }
4851 4852
4852 4853 if (l_histo && rq_histo) {
4853 4854 pool_list_free(list);
4854 4855 (void) fprintf(stderr,
4855 4856 gettext("Only one of [-r|-w] can be passed at a time\n"));
4856 4857 usage(B_FALSE);
4857 4858 return (1);
4858 4859 }
4859 4860
4860 4861 /*
4861 4862 * Enter the main iostat loop.
4862 4863 */
4863 4864 cb.cb_list = list;
4864 4865
4865 4866 if (l_histo) {
4866 4867 /*
4867 4868 * Histograms tables look out of place when you try to display
4868 4869 * them with the other stats, so make a rule that you can only
4869 4870 * print histograms by themselves.
4870 4871 */
4871 4872 cb.cb_flags = IOS_L_HISTO_M;
4872 4873 } else if (rq_histo) {
4873 4874 cb.cb_flags = IOS_RQ_HISTO_M;
4874 4875 } else {
4875 4876 cb.cb_flags = IOS_DEFAULT_M;
4876 4877 if (latency)
4877 4878 cb.cb_flags |= IOS_LATENCY_M;
4878 4879 if (queues)
4879 4880 cb.cb_flags |= IOS_QUEUES_M;
4880 4881 }
4881 4882
4882 4883 /*
4883 4884 * See if the module supports all the stats we want to display.
4884 4885 */
4885 4886 unsupported_flags = cb.cb_flags & ~get_stat_flags(list);
4886 4887 if (unsupported_flags) {
4887 4888 uint64_t f;
4888 4889 int idx;
4889 4890 fprintf(stderr,
4890 4891 gettext("The loaded zfs module doesn't support:"));
4891 4892
4892 4893 /* for each bit set in unsupported_flags */
4893 4894 for (f = unsupported_flags; f; f &= ~(1ULL << idx)) {
4894 4895 idx = lowbit64(f) - 1;
4895 4896 fprintf(stderr, " -%c", flag_to_arg[idx]);
4896 4897 }
4897 4898
4898 4899 fprintf(stderr, ". Try running a newer module.\n"),
4899 4900 pool_list_free(list);
4900 4901
4901 4902 return (1);
4902 4903 }
4903 4904
4904 4905 for (;;) {
4905 4906 if ((npools = pool_list_count(list)) == 0)
4906 4907 (void) fprintf(stderr, gettext("no pools available\n"));
4907 4908 else {
4908 4909 /*
4909 4910 * If this is the first iteration and -y was supplied
4910 4911 * we skip any printing.
4911 4912 */
4912 4913 boolean_t skip = (omit_since_boot &&
4913 4914 cb.cb_iteration == 0);
4914 4915
4915 4916 /*
4916 4917 * Refresh all statistics. This is done as an
4917 4918 * explicit step before calculating the maximum name
4918 4919 * width, so that any configuration changes are
4919 4920 * properly accounted for.
4920 4921 */
4921 4922 (void) pool_list_iter(list, B_FALSE, refresh_iostat,
4922 4923 &cb);
4923 4924
4924 4925 /*
4925 4926 * Iterate over all pools to determine the maximum width
4926 4927 * for the pool / device name column across all pools.
4927 4928 */
4928 4929 cb.cb_namewidth = 0;
4929 4930 (void) pool_list_iter(list, B_FALSE,
4930 4931 get_namewidth_iostat, &cb);
4931 4932
4932 4933 if (timestamp_fmt != NODATE)
4933 4934 print_timestamp(timestamp_fmt);
4934 4935
4935 4936 /*
4936 4937 * Check terminal size so we can print headers
4937 4938 * even when terminal window has its height
4938 4939 * changed.
4939 4940 */
4940 4941 if (headers_once == B_FALSE) {
4941 4942 if (ioctl(1, TIOCGWINSZ, &win) != -1) {
4942 4943 if (win.ws_row <= 0) {
4943 4944 headers_once = B_TRUE;
4944 4945 } else {
4945 4946 winheight = win.ws_row;
4946 4947 }
4947 4948 }
4948 4949 }
4949 4950 /*
4950 4951 * Are we connected to TTY? If not, headers_once
4951 4952 * should be true, to avoid breaking scripts.
4952 4953 */
4953 4954 if (isatty(fileno(stdout)) == 0)
4954 4955 headers_once = B_TRUE;
4955 4956
4956 4957 /*
4957 4958 * If it's the first time and we're not skipping it,
4958 4959 * or either skip or verbose mode, print the header.
4959 4960 *
4960 4961 * The histogram code explicitly prints its header on
4961 4962 * every vdev, so skip this for histograms.
4962 4963 */
4963 4964 if (((++cb.cb_iteration == 1 && !skip) ||
4964 4965 (skip != verbose) ||
4965 4966 (!headers_once &&
4966 4967 (cb.cb_iteration % winheight) == 0)) &&
4967 4968 (!(cb.cb_flags & IOS_ANYHISTO_M)) &&
4968 4969 !cb.cb_scripted)
4969 4970 print_iostat_header(&cb);
4970 4971
4971 4972 if (skip) {
4972 4973 (void) fsleep(interval);
4973 4974 continue;
4974 4975 }
4975 4976
4976 4977 (void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
4977 4978
4978 4979 /*
4979 4980 * If there's more than one pool, and we're not in
4980 4981 * verbose mode (which prints a separator for us),
4981 4982 * then print a separator.
4982 4983 *
4983 4984 * In addition, if we're printing specific vdevs then
4984 4985 * we also want an ending separator.
4985 4986 */
4986 4987 if (((npools > 1 && !verbose &&
4987 4988 !(cb.cb_flags & IOS_ANYHISTO_M)) ||
4988 4989 (!(cb.cb_flags & IOS_ANYHISTO_M) &&
4989 4990 cb.cb_vdev_names_count)) &&
4990 4991 !cb.cb_scripted) {
4991 4992 print_iostat_separator(&cb);
4992 4993 printf("\n");
4993 4994 }
4994 4995 }
4995 4996
4996 4997 /*
4997 4998 * Flush the output so that redirection to a file isn't buffered
4998 4999 * indefinitely.
4999 5000 */
5000 5001 (void) fflush(stdout);
5001 5002
5002 5003 if (interval == 0)
5003 5004 break;
5004 5005
5005 5006 if (count != 0 && --count == 0)
5006 5007 break;
5007 5008
5008 5009 (void) fsleep(interval);
5009 5010 }
5010 5011
5011 5012 pool_list_free(list);
5012 5013
5013 5014 return (ret);
5014 5015 }
5015 5016
5016 5017 typedef struct list_cbdata {
5017 5018 boolean_t cb_verbose;
5018 5019 int cb_name_flags;
5019 5020 int cb_namewidth;
5020 5021 boolean_t cb_scripted;
5021 5022 zprop_list_t *cb_proplist;
5022 5023 boolean_t cb_literal;
5023 5024 } list_cbdata_t;
5024 5025
5025 5026
5026 5027 /*
5027 5028 * Given a list of columns to display, output appropriate headers for each one.
5028 5029 */
5029 5030 static void
5030 5031 print_header(list_cbdata_t *cb)
5031 5032 {
5032 5033 zprop_list_t *pl = cb->cb_proplist;
5033 5034 char headerbuf[ZPOOL_MAXPROPLEN];
5034 5035 const char *header;
5035 5036 boolean_t first = B_TRUE;
5036 5037 boolean_t right_justify;
5037 5038 size_t width = 0;
5038 5039
5039 5040 for (; pl != NULL; pl = pl->pl_next) {
5040 5041 width = pl->pl_width;
5041 5042 if (first && cb->cb_verbose) {
5042 5043 /*
5043 5044 * Reset the width to accommodate the verbose listing
5044 5045 * of devices.
5045 5046 */
5046 5047 width = cb->cb_namewidth;
5047 5048 }
5048 5049
5049 5050 if (!first)
5050 5051 (void) printf(" ");
5051 5052 else
5052 5053 first = B_FALSE;
5053 5054
5054 5055 right_justify = B_FALSE;
5055 5056 if (pl->pl_prop != ZPROP_INVAL) {
5056 5057 header = zpool_prop_column_name(pl->pl_prop);
5057 5058 right_justify = zpool_prop_align_right(pl->pl_prop);
5058 5059 } else {
5059 5060 int i;
5060 5061
5061 5062 for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
5062 5063 headerbuf[i] = toupper(pl->pl_user_prop[i]);
5063 5064 headerbuf[i] = '\0';
5064 5065 header = headerbuf;
5065 5066 }
5066 5067
5067 5068 if (pl->pl_next == NULL && !right_justify)
5068 5069 (void) printf("%s", header);
5069 5070 else if (right_justify)
5070 5071 (void) printf("%*s", width, header);
5071 5072 else
5072 5073 (void) printf("%-*s", width, header);
5073 5074
5074 5075 }
5075 5076
5076 5077 (void) printf("\n");
5077 5078 }
5078 5079
5079 5080 /*
5080 5081 * Given a pool and a list of properties, print out all the properties according
5081 5082 * to the described layout. Used by zpool_do_list().
5082 5083 */
5083 5084 static void
5084 5085 print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
5085 5086 {
5086 5087 zprop_list_t *pl = cb->cb_proplist;
5087 5088 boolean_t first = B_TRUE;
5088 5089 char property[ZPOOL_MAXPROPLEN];
5089 5090 char *propstr;
5090 5091 boolean_t right_justify;
5091 5092 size_t width;
5092 5093
5093 5094 for (; pl != NULL; pl = pl->pl_next) {
5094 5095
5095 5096 width = pl->pl_width;
5096 5097 if (first && cb->cb_verbose) {
5097 5098 /*
5098 5099 * Reset the width to accommodate the verbose listing
5099 5100 * of devices.
5100 5101 */
5101 5102 width = cb->cb_namewidth;
5102 5103 }
5103 5104
5104 5105 if (!first) {
5105 5106 if (cb->cb_scripted)
5106 5107 (void) printf("\t");
5107 5108 else
5108 5109 (void) printf(" ");
5109 5110 } else {
5110 5111 first = B_FALSE;
5111 5112 }
5112 5113
5113 5114 right_justify = B_FALSE;
5114 5115 if (pl->pl_prop != ZPROP_INVAL) {
5115 5116 if (zpool_get_prop(zhp, pl->pl_prop, property,
5116 5117 sizeof (property), NULL, cb->cb_literal) != 0)
5117 5118 propstr = "-";
5118 5119 else
5119 5120 propstr = property;
5120 5121
5121 5122 right_justify = zpool_prop_align_right(pl->pl_prop);
5122 5123 } else if ((zpool_prop_feature(pl->pl_user_prop) ||
5123 5124 zpool_prop_unsupported(pl->pl_user_prop)) &&
5124 5125 zpool_prop_get_feature(zhp, pl->pl_user_prop, property,
5125 5126 sizeof (property)) == 0) {
5126 5127 propstr = property;
5127 5128 } else {
5128 5129 propstr = "-";
5129 5130 }
5130 5131
5131 5132
5132 5133 /*
5133 5134 * If this is being called in scripted mode, or if this is the
5134 5135 * last column and it is left-justified, don't include a width
5135 5136 * format specifier.
5136 5137 */
5137 5138 if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
5138 5139 (void) printf("%s", propstr);
5139 5140 else if (right_justify)
5140 5141 (void) printf("%*s", width, propstr);
5141 5142 else
5142 5143 (void) printf("%-*s", width, propstr);
5143 5144 }
5144 5145
5145 5146 (void) printf("\n");
5146 5147 }
5147 5148
5148 5149 static void
5149 5150 print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted,
5150 5151 boolean_t valid)
5151 5152 {
5152 5153 char propval[64];
5153 5154 boolean_t fixed;
5154 5155 size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
5155 5156
5156 5157 switch (prop) {
5157 5158 case ZPOOL_PROP_EXPANDSZ:
5158 5159 case ZPOOL_PROP_CHECKPOINT:
5159 5160 if (value == 0)
5160 5161 (void) strlcpy(propval, "-", sizeof (propval));
5161 5162 else
5162 5163 zfs_nicenum(value, propval, sizeof (propval));
5163 5164 break;
5164 5165 case ZPOOL_PROP_FRAGMENTATION:
5165 5166 if (value == ZFS_FRAG_INVALID) {
5166 5167 (void) strlcpy(propval, "-", sizeof (propval));
5167 5168 } else {
5168 5169 (void) snprintf(propval, sizeof (propval), "%llu%%",
5169 5170 value);
5170 5171 }
5171 5172 break;
5172 5173 case ZPOOL_PROP_CAPACITY:
5173 5174 (void) snprintf(propval, sizeof (propval),
5174 5175 value < 1000 ? "%1.2f%%" : value < 10000 ?
5175 5176 "%2.1f%%" : "%3.0f%%", value / 100.0);
5176 5177 break;
5177 5178 default:
5178 5179 zfs_nicenum(value, propval, sizeof (propval));
5179 5180 }
5180 5181
5181 5182 if (!valid)
5182 5183 (void) strlcpy(propval, "-", sizeof (propval));
5183 5184
5184 5185 if (scripted)
5185 5186 (void) printf("\t%s", propval);
5186 5187 else
5187 5188 (void) printf(" %*s", width, propval);
5188 5189 }
5189 5190
5190 5191 /*
5191 5192 * print static default line per vdev
5192 5193 */
5193 5194 void
5194 5195 print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
5195 5196 list_cbdata_t *cb, int depth)
5196 5197 {
5197 5198 nvlist_t **child;
5198 5199 vdev_stat_t *vs;
5199 5200 uint_t c, children;
5200 5201 char *vname;
5201 5202 boolean_t scripted = cb->cb_scripted;
5202 5203 uint64_t islog = B_FALSE;
5203 5204 char *dashes = "%-*s - - - - - -\n";
5204 5205
5205 5206 verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
5206 5207 (uint64_t **)&vs, &c) == 0);
5207 5208
5208 5209 if (name != NULL) {
5209 5210 boolean_t toplevel = (vs->vs_space != 0);
5210 5211 uint64_t cap;
5211 5212
5212 5213 if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
5213 5214 return;
5214 5215
5215 5216 if (scripted)
5216 5217 (void) printf("\t%s", name);
5217 5218 else if (strlen(name) + depth > cb->cb_namewidth)
5218 5219 (void) printf("%*s%s", depth, "", name);
5219 5220 else
5220 5221 (void) printf("%*s%s%*s", depth, "", name,
5221 5222 (int)(cb->cb_namewidth - strlen(name) - depth), "");
5222 5223
5223 5224 /*
5224 5225 * Print the properties for the individual vdevs. Some
5225 5226 * properties are only applicable to toplevel vdevs. The
5226 5227 * 'toplevel' boolean value is passed to the print_one_column()
5227 5228 * to indicate that the value is valid.
5228 5229 */
5229 5230 print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted,
5230 5231 toplevel);
5231 5232 print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted,
5232 5233 toplevel);
5233 5234 print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc,
5234 5235 scripted, toplevel);
5235 5236 print_one_column(ZPOOL_PROP_CHECKPOINT,
5236 5237 vs->vs_checkpoint_space, scripted, toplevel);
5237 5238 print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted,
5238 5239 B_TRUE);
5239 5240 print_one_column(ZPOOL_PROP_FRAGMENTATION,
5240 5241 vs->vs_fragmentation, scripted,
5241 5242 (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel));
5242 5243 cap = (vs->vs_space == 0) ? 0 :
5243 5244 (vs->vs_alloc * 10000 / vs->vs_space);
5244 5245 print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel);
5245 5246 (void) printf("\n");
5246 5247 }
5247 5248
5248 5249 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
5249 5250 &child, &children) != 0)
5250 5251 return;
5251 5252
5252 5253 /* list the normal vdevs first */
5253 5254 for (c = 0; c < children; c++) {
5254 5255 uint64_t ishole = B_FALSE;
5255 5256
5256 5257 if (nvlist_lookup_uint64(child[c],
5257 5258 ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
5258 5259 continue;
5259 5260
5260 5261 if (nvlist_lookup_uint64(child[c],
5261 5262 ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog)
5262 5263 continue;
5263 5264
5264 5265 if (nvlist_exists(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
5265 5266 continue;
5266 5267
5267 5268 vname = zpool_vdev_name(g_zfs, zhp, child[c],
5268 5269 cb->cb_name_flags);
5269 5270 print_list_stats(zhp, vname, child[c], cb, depth + 2);
5270 5271 free(vname);
5271 5272 }
5272 5273
5273 5274 /* list the classes: 'logs', 'dedup', and 'special' */
5274 5275 for (uint_t n = 0; n < 3; n++) {
5275 5276 boolean_t printed = B_FALSE;
5276 5277
5277 5278 for (c = 0; c < children; c++) {
5278 5279 char *bias = NULL;
5279 5280 char *type = NULL;
5280 5281
5281 5282 if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
5282 5283 &islog) == 0 && islog) {
5283 5284 bias = VDEV_ALLOC_CLASS_LOGS;
5284 5285 } else {
5285 5286 (void) nvlist_lookup_string(child[c],
5286 5287 ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
5287 5288 (void) nvlist_lookup_string(child[c],
5288 5289 ZPOOL_CONFIG_TYPE, &type);
5289 5290 }
5290 5291 if (bias == NULL || strcmp(bias, class_name[n]) != 0)
5291 5292 continue;
5292 5293 if (!islog && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
5293 5294 continue;
5294 5295
5295 5296 if (!printed) {
5296 5297 /* LINTED E_SEC_PRINTF_VAR_FMT */
5297 5298 (void) printf(dashes, cb->cb_namewidth,
5298 5299 class_name[n]);
5299 5300 printed = B_TRUE;
5300 5301 }
5301 5302 vname = zpool_vdev_name(g_zfs, zhp, child[c],
5302 5303 cb->cb_name_flags);
5303 5304 print_list_stats(zhp, vname, child[c], cb, depth + 2);
5304 5305 free(vname);
5305 5306 }
5306 5307 }
5307 5308
5308 5309 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
5309 5310 &child, &children) == 0 && children > 0) {
5310 5311 /* LINTED E_SEC_PRINTF_VAR_FMT */
5311 5312 (void) printf(dashes, cb->cb_namewidth, "cache");
5312 5313 for (c = 0; c < children; c++) {
5313 5314 vname = zpool_vdev_name(g_zfs, zhp, child[c],
5314 5315 cb->cb_name_flags);
5315 5316 print_list_stats(zhp, vname, child[c], cb, depth + 2);
5316 5317 free(vname);
5317 5318 }
5318 5319 }
5319 5320
5320 5321 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child,
5321 5322 &children) == 0 && children > 0) {
5322 5323 /* LINTED E_SEC_PRINTF_VAR_FMT */
5323 5324 (void) printf(dashes, cb->cb_namewidth, "spare");
5324 5325 for (c = 0; c < children; c++) {
5325 5326 vname = zpool_vdev_name(g_zfs, zhp, child[c],
5326 5327 cb->cb_name_flags);
5327 5328 print_list_stats(zhp, vname, child[c], cb, depth + 2);
5328 5329 free(vname);
5329 5330 }
5330 5331 }
5331 5332 }
5332 5333
5333 5334 /*
5334 5335 * Generic callback function to list a pool.
5335 5336 */
5336 5337 int
5337 5338 list_callback(zpool_handle_t *zhp, void *data)
5338 5339 {
5339 5340 list_cbdata_t *cbp = data;
5340 5341 nvlist_t *config;
5341 5342 nvlist_t *nvroot;
5342 5343
5343 5344 config = zpool_get_config(zhp, NULL);
5344 5345
5345 5346 if (cbp->cb_verbose) {
5346 5347 config = zpool_get_config(zhp, NULL);
5347 5348
5348 5349 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
5349 5350 &nvroot) == 0);
5350 5351 }
5351 5352
5352 5353 if (cbp->cb_verbose)
5353 5354 cbp->cb_namewidth = max_width(zhp, nvroot, 0, 0,
5354 5355 cbp->cb_name_flags);
5355 5356
5356 5357 print_pool(zhp, cbp);
5357 5358
5358 5359 if (cbp->cb_verbose)
5359 5360 print_list_stats(zhp, NULL, nvroot, cbp, 0);
5360 5361
5361 5362 return (0);
5362 5363 }
5363 5364
5364 5365 /*
5365 5366 * Set the minimum pool/vdev name column width. The width must be at least 9,
5366 5367 * but may be as large as needed.
5367 5368 */
5368 5369 static int
5369 5370 get_namewidth_list(zpool_handle_t *zhp, void *data)
5370 5371 {
5371 5372 list_cbdata_t *cb = data;
5372 5373 int width;
5373 5374
5374 5375 width = get_namewidth(zhp, cb->cb_namewidth, cb->cb_name_flags,
5375 5376 cb->cb_verbose);
5376 5377
5377 5378 if (width < 9)
5378 5379 width = 9;
5379 5380
5380 5381 cb->cb_namewidth = width;
5381 5382
5382 5383 return (0);
5383 5384 }
5384 5385
5385 5386 /*
5386 5387 * zpool list [-gHLP] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
5387 5388 *
5388 5389 * -g Display guid for individual vdev name.
5389 5390 * -H Scripted mode. Don't display headers, and separate properties
5390 5391 * by a single tab.
5391 5392 * -L Follow links when resolving vdev path name.
5392 5393 * -o List of properties to display. Defaults to
5393 5394 * "name,size,allocated,free,expandsize,fragmentation,capacity,"
5394 5395 * "dedupratio,health,altroot"
5395 5396 * -p Diplay values in parsable (exact) format.
5396 5397 * -P Display full path for vdev name.
5397 5398 * -T Display a timestamp in date(1) or Unix format
5398 5399 *
5399 5400 * List all pools in the system, whether or not they're healthy. Output space
5400 5401 * statistics for each one, as well as health status summary.
5401 5402 */
5402 5403 int
5403 5404 zpool_do_list(int argc, char **argv)
5404 5405 {
5405 5406 int c;
5406 5407 int ret;
5407 5408 list_cbdata_t cb = { 0 };
5408 5409 static char default_props[] =
5409 5410 "name,size,allocated,free,checkpoint,expandsize,fragmentation,"
5410 5411 "capacity,dedupratio,health,altroot";
5411 5412 char *props = default_props;
5412 5413 float interval = 0;
5413 5414 unsigned long count = 0;
5414 5415 zpool_list_t *list;
5415 5416 boolean_t first = B_TRUE;
5416 5417
5417 5418 /* check options */
5418 5419 while ((c = getopt(argc, argv, ":gHLo:pPT:v")) != -1) {
5419 5420 switch (c) {
5420 5421 case 'g':
5421 5422 cb.cb_name_flags |= VDEV_NAME_GUID;
5422 5423 break;
5423 5424 case 'H':
5424 5425 cb.cb_scripted = B_TRUE;
5425 5426 break;
5426 5427 case 'L':
5427 5428 cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
5428 5429 break;
5429 5430 case 'o':
5430 5431 props = optarg;
5431 5432 break;
5432 5433 case 'P':
5433 5434 cb.cb_name_flags |= VDEV_NAME_PATH;
5434 5435 break;
5435 5436 case 'p':
5436 5437 cb.cb_literal = B_TRUE;
5437 5438 break;
5438 5439 case 'T':
5439 5440 get_timestamp_arg(*optarg);
5440 5441 break;
5441 5442 case 'v':
5442 5443 cb.cb_verbose = B_TRUE;
5443 5444 cb.cb_namewidth = 8; /* 8 until precalc is avail */
5444 5445 break;
5445 5446 case ':':
5446 5447 (void) fprintf(stderr, gettext("missing argument for "
5447 5448 "'%c' option\n"), optopt);
5448 5449 usage(B_FALSE);
5449 5450 break;
5450 5451 case '?':
5451 5452 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
5452 5453 optopt);
5453 5454 usage(B_FALSE);
5454 5455 }
5455 5456 }
5456 5457
5457 5458 argc -= optind;
5458 5459 argv += optind;
5459 5460
5460 5461 get_interval_count(&argc, argv, &interval, &count);
5461 5462
5462 5463 if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
5463 5464 usage(B_FALSE);
5464 5465
5465 5466 for (;;) {
5466 5467 if ((list = pool_list_get(argc, argv, &cb.cb_proplist,
5467 5468 &ret)) == NULL)
5468 5469 return (1);
5469 5470
5470 5471 if (pool_list_count(list) == 0)
5471 5472 break;
5472 5473
5473 5474 cb.cb_namewidth = 0;
5474 5475 (void) pool_list_iter(list, B_FALSE, get_namewidth_list, &cb);
5475 5476
5476 5477 if (timestamp_fmt != NODATE)
5477 5478 print_timestamp(timestamp_fmt);
5478 5479
5479 5480 if (!cb.cb_scripted && (first || cb.cb_verbose)) {
5480 5481 print_header(&cb);
5481 5482 first = B_FALSE;
5482 5483 }
5483 5484 ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
5484 5485
5485 5486 if (interval == 0)
5486 5487 break;
5487 5488
5488 5489 if (count != 0 && --count == 0)
5489 5490 break;
5490 5491
5491 5492 pool_list_free(list);
5492 5493 (void) fsleep(interval);
5493 5494 }
5494 5495
5495 5496 if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
5496 5497 (void) printf(gettext("no pools available\n"));
5497 5498 ret = 0;
5498 5499 }
5499 5500
5500 5501 pool_list_free(list);
5501 5502 zprop_free_list(cb.cb_proplist);
5502 5503 return (ret);
5503 5504 }
5504 5505
5505 5506 static int
5506 5507 zpool_do_attach_or_replace(int argc, char **argv, int replacing)
5507 5508 {
5508 5509 boolean_t force = B_FALSE;
5509 5510 int c;
5510 5511 nvlist_t *nvroot;
5511 5512 char *poolname, *old_disk, *new_disk;
5512 5513 zpool_handle_t *zhp;
5513 5514 zpool_boot_label_t boot_type;
5514 5515 uint64_t boot_size;
5515 5516 nvlist_t *props = NULL;
5516 5517 char *propval;
5517 5518 int ret;
5518 5519
5519 5520 /* check options */
5520 5521 while ((c = getopt(argc, argv, "fo:")) != -1) {
5521 5522 switch (c) {
5522 5523 case 'f':
5523 5524 force = B_TRUE;
5524 5525 break;
5525 5526 case 'o':
5526 5527 if ((propval = strchr(optarg, '=')) == NULL) {
5527 5528 (void) fprintf(stderr, gettext("missing "
5528 5529 "'=' for -o option\n"));
5529 5530 usage(B_FALSE);
5530 5531 }
5531 5532 *propval = '\0';
5532 5533 propval++;
5533 5534
5534 5535 if ((strcmp(optarg, ZPOOL_CONFIG_ASHIFT) != 0) ||
5535 5536 (add_prop_list(optarg, propval, &props, B_TRUE)))
5536 5537 usage(B_FALSE);
5537 5538 break;
5538 5539 case '?':
5539 5540 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
5540 5541 optopt);
5541 5542 usage(B_FALSE);
5542 5543 }
5543 5544 }
5544 5545
5545 5546 argc -= optind;
5546 5547 argv += optind;
5547 5548
5548 5549 /* get pool name and check number of arguments */
5549 5550 if (argc < 1) {
5550 5551 (void) fprintf(stderr, gettext("missing pool name argument\n"));
5551 5552 usage(B_FALSE);
5552 5553 }
5553 5554
5554 5555 poolname = argv[0];
5555 5556
5556 5557 if (argc < 2) {
5557 5558 (void) fprintf(stderr,
5558 5559 gettext("missing <device> specification\n"));
5559 5560 usage(B_FALSE);
5560 5561 }
5561 5562
5562 5563 old_disk = argv[1];
5563 5564
5564 5565 if (argc < 3) {
5565 5566 if (!replacing) {
5566 5567 (void) fprintf(stderr,
5567 5568 gettext("missing <new_device> specification\n"));
5568 5569 usage(B_FALSE);
5569 5570 }
5570 5571 new_disk = old_disk;
5571 5572 argc -= 1;
5572 5573 argv += 1;
5573 5574 } else {
5574 5575 new_disk = argv[2];
5575 5576 argc -= 2;
5576 5577 argv += 2;
5577 5578 }
5578 5579
5579 5580 if (argc > 1) {
5580 5581 (void) fprintf(stderr, gettext("too many arguments\n"));
5581 5582 usage(B_FALSE);
5582 5583 }
5583 5584
5584 5585 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
5585 5586 return (1);
5586 5587
5587 5588 if (zpool_get_config(zhp, NULL) == NULL) {
5588 5589 (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
5589 5590 poolname);
5590 5591 zpool_close(zhp);
5591 5592 return (1);
5592 5593 }
5593 5594
5594 5595 if (zpool_is_bootable(zhp))
5595 5596 boot_type = ZPOOL_COPY_BOOT_LABEL;
5596 5597 else
5597 5598 boot_type = ZPOOL_NO_BOOT_LABEL;
5598 5599
5599 5600 boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL);
5600 5601
5601 5602 /* unless manually specified use "ashift" pool property (if set) */
5602 5603 if (!nvlist_exists(props, ZPOOL_CONFIG_ASHIFT)) {
5603 5604 int intval;
5604 5605 zprop_source_t src;
5605 5606 char strval[ZPOOL_MAXPROPLEN];
5606 5607
5607 5608 intval = zpool_get_prop_int(zhp, ZPOOL_PROP_ASHIFT, &src);
5608 5609 if (src != ZPROP_SRC_DEFAULT) {
5609 5610 (void) sprintf(strval, "%" PRId32, intval);
5610 5611 verify(add_prop_list(ZPOOL_CONFIG_ASHIFT, strval,
5611 5612 &props, B_TRUE) == 0);
5612 5613 }
5613 5614 }
5614 5615
5615 5616 nvroot = make_root_vdev(zhp, props, force, B_FALSE, replacing, B_FALSE,
5616 5617 boot_type, boot_size, argc, argv);
5617 5618 if (nvroot == NULL) {
5618 5619 zpool_close(zhp);
5619 5620 return (1);
5620 5621 }
5621 5622
5622 5623 ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
5623 5624
5624 5625 nvlist_free(nvroot);
5625 5626 zpool_close(zhp);
5626 5627
5627 5628 return (ret);
5628 5629 }
5629 5630
5630 5631 /*
5631 5632 * zpool replace [-f] <pool> <device> <new_device>
5632 5633 *
5633 5634 * -f Force attach, even if <new_device> appears to be in use.
5634 5635 *
5635 5636 * Replace <device> with <new_device>.
5636 5637 */
5637 5638 /* ARGSUSED */
5638 5639 int
5639 5640 zpool_do_replace(int argc, char **argv)
5640 5641 {
5641 5642 return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
5642 5643 }
5643 5644
5644 5645 /*
5645 5646 * zpool attach [-f] [-o property=value] <pool> <device> <new_device>
5646 5647 *
5647 5648 * -f Force attach, even if <new_device> appears to be in use.
5648 5649 * -o Set property=value.
5649 5650 *
5650 5651 * Attach <new_device> to the mirror containing <device>. If <device> is not
5651 5652 * part of a mirror, then <device> will be transformed into a mirror of
5652 5653 * <device> and <new_device>. In either case, <new_device> will begin life
5653 5654 * with a DTL of [0, now], and will immediately begin to resilver itself.
5654 5655 */
5655 5656 int
5656 5657 zpool_do_attach(int argc, char **argv)
5657 5658 {
5658 5659 return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
5659 5660 }
5660 5661
5661 5662 /*
5662 5663 * zpool detach [-f] <pool> <device>
5663 5664 *
5664 5665 * -f Force detach of <device>, even if DTLs argue against it
5665 5666 * (not supported yet)
5666 5667 *
5667 5668 * Detach a device from a mirror. The operation will be refused if <device>
5668 5669 * is the last device in the mirror, or if the DTLs indicate that this device
5669 5670 * has the only valid copy of some data.
5670 5671 */
5671 5672 /* ARGSUSED */
5672 5673 int
5673 5674 zpool_do_detach(int argc, char **argv)
5674 5675 {
5675 5676 int c;
5676 5677 char *poolname, *path;
5677 5678 zpool_handle_t *zhp;
5678 5679 int ret;
5679 5680
5680 5681 /* check options */
5681 5682 while ((c = getopt(argc, argv, "f")) != -1) {
5682 5683 switch (c) {
5683 5684 case 'f':
5684 5685 case '?':
5685 5686 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
5686 5687 optopt);
5687 5688 usage(B_FALSE);
5688 5689 }
5689 5690 }
5690 5691
5691 5692 argc -= optind;
5692 5693 argv += optind;
5693 5694
5694 5695 /* get pool name and check number of arguments */
5695 5696 if (argc < 1) {
5696 5697 (void) fprintf(stderr, gettext("missing pool name argument\n"));
5697 5698 usage(B_FALSE);
5698 5699 }
5699 5700
5700 5701 if (argc < 2) {
5701 5702 (void) fprintf(stderr,
5702 5703 gettext("missing <device> specification\n"));
5703 5704 usage(B_FALSE);
5704 5705 }
5705 5706
5706 5707 poolname = argv[0];
5707 5708 path = argv[1];
5708 5709
5709 5710 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
5710 5711 return (1);
5711 5712
5712 5713 ret = zpool_vdev_detach(zhp, path);
5713 5714
5714 5715 zpool_close(zhp);
5715 5716
5716 5717 return (ret);
5717 5718 }
5718 5719
5719 5720 /*
5720 5721 * zpool split [-gLnP] [-o prop=val] ...
5721 5722 * [-o mntopt] ...
5722 5723 * [-R altroot] <pool> <newpool> [<device> ...]
5723 5724 *
5724 5725 * -g Display guid for individual vdev name.
5725 5726 * -L Follow links when resolving vdev path name.
5726 5727 * -n Do not split the pool, but display the resulting layout if
5727 5728 * it were to be split.
5728 5729 * -o Set property=value, or set mount options.
5729 5730 * -P Display full path for vdev name.
5730 5731 * -R Mount the split-off pool under an alternate root.
5731 5732 * -l Load encryption keys while importing.
5732 5733 *
5733 5734 * Splits the named pool and gives it the new pool name. Devices to be split
5734 5735 * off may be listed, provided that no more than one device is specified
5735 5736 * per top-level vdev mirror. The newly split pool is left in an exported
5736 5737 * state unless -R is specified.
5737 5738 *
5738 5739 * Restrictions: the top-level of the pool pool must only be made up of
5739 5740 * mirrors; all devices in the pool must be healthy; no device may be
5740 5741 * undergoing a resilvering operation.
5741 5742 */
5742 5743 int
5743 5744 zpool_do_split(int argc, char **argv)
5744 5745 {
5745 5746 char *srcpool, *newpool, *propval;
5746 5747 char *mntopts = NULL;
5747 5748 splitflags_t flags;
5748 5749 int c, ret = 0;
5749 5750 boolean_t loadkeys = B_FALSE;
5750 5751 zpool_handle_t *zhp;
5751 5752 nvlist_t *config, *props = NULL;
5752 5753
5753 5754 flags.dryrun = B_FALSE;
5754 5755 flags.import = B_FALSE;
5755 5756 flags.name_flags = 0;
5756 5757
5757 5758 /* check options */
5758 5759 while ((c = getopt(argc, argv, ":gLR:lno:P")) != -1) {
5759 5760 switch (c) {
5760 5761 case 'g':
5761 5762 flags.name_flags |= VDEV_NAME_GUID;
5762 5763 break;
5763 5764 case 'L':
5764 5765 flags.name_flags |= VDEV_NAME_FOLLOW_LINKS;
5765 5766 break;
5766 5767 case 'R':
5767 5768 flags.import = B_TRUE;
5768 5769 if (add_prop_list(
5769 5770 zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg,
5770 5771 &props, B_TRUE) != 0) {
5771 5772 nvlist_free(props);
5772 5773 usage(B_FALSE);
5773 5774 }
5774 5775 break;
5775 5776 case 'l':
5776 5777 loadkeys = B_TRUE;
5777 5778 break;
5778 5779 case 'n':
5779 5780 flags.dryrun = B_TRUE;
5780 5781 break;
5781 5782 case 'o':
5782 5783 if ((propval = strchr(optarg, '=')) != NULL) {
5783 5784 *propval = '\0';
5784 5785 propval++;
5785 5786 if (add_prop_list(optarg, propval,
5786 5787 &props, B_TRUE) != 0) {
5787 5788 nvlist_free(props);
5788 5789 usage(B_FALSE);
5789 5790 }
5790 5791 } else {
5791 5792 mntopts = optarg;
5792 5793 }
5793 5794 break;
5794 5795 case 'P':
5795 5796 flags.name_flags |= VDEV_NAME_PATH;
5796 5797 break;
5797 5798 case ':':
5798 5799 (void) fprintf(stderr, gettext("missing argument for "
5799 5800 "'%c' option\n"), optopt);
5800 5801 usage(B_FALSE);
5801 5802 break;
5802 5803 case '?':
5803 5804 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
5804 5805 optopt);
5805 5806 usage(B_FALSE);
5806 5807 break;
5807 5808 }
5808 5809 }
5809 5810
5810 5811 if (!flags.import && mntopts != NULL) {
5811 5812 (void) fprintf(stderr, gettext("setting mntopts is only "
5812 5813 "valid when importing the pool\n"));
5813 5814 usage(B_FALSE);
5814 5815 }
5815 5816
5816 5817 if (!flags.import && loadkeys) {
5817 5818 (void) fprintf(stderr, gettext("loading keys is only "
5818 5819 "valid when importing the pool\n"));
5819 5820 usage(B_FALSE);
5820 5821 }
5821 5822
5822 5823 argc -= optind;
5823 5824 argv += optind;
5824 5825
5825 5826 if (argc < 1) {
5826 5827 (void) fprintf(stderr, gettext("Missing pool name\n"));
5827 5828 usage(B_FALSE);
5828 5829 }
5829 5830 if (argc < 2) {
5830 5831 (void) fprintf(stderr, gettext("Missing new pool name\n"));
5831 5832 usage(B_FALSE);
5832 5833 }
5833 5834
5834 5835 srcpool = argv[0];
5835 5836 newpool = argv[1];
5836 5837
5837 5838 argc -= 2;
5838 5839 argv += 2;
5839 5840
5840 5841 if ((zhp = zpool_open(g_zfs, srcpool)) == NULL)
5841 5842 return (1);
5842 5843
5843 5844 config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv);
5844 5845 if (config == NULL) {
5845 5846 ret = 1;
5846 5847 } else {
5847 5848 if (flags.dryrun) {
5848 5849 (void) printf(gettext("would create '%s' with the "
5849 5850 "following layout:\n\n"), newpool);
5850 5851 print_vdev_tree(NULL, newpool, config, 0, "",
5851 5852 flags.name_flags);
5852 5853 }
5853 5854 nvlist_free(config);
5854 5855 }
5855 5856
5856 5857 zpool_close(zhp);
5857 5858
5858 5859 if (ret != 0 || flags.dryrun || !flags.import)
5859 5860 return (ret);
5860 5861
5861 5862 /*
5862 5863 * The split was successful. Now we need to open the new
5863 5864 * pool and import it.
5864 5865 */
5865 5866 if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL)
5866 5867 return (1);
5867 5868
5868 5869 if (loadkeys) {
5869 5870 ret = zfs_crypto_attempt_load_keys(g_zfs, newpool);
5870 5871 if (ret != 0)
5871 5872 ret = 1;
5872 5873 }
5873 5874
5874 5875 if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
5875 5876 zpool_enable_datasets(zhp, mntopts, 0) != 0) {
5876 5877 ret = 1;
5877 5878 (void) fprintf(stderr, gettext("Split was successful, but "
5878 5879 "the datasets could not all be mounted\n"));
5879 5880 (void) fprintf(stderr, gettext("Try doing '%s' with a "
5880 5881 "different altroot\n"), "zpool import");
5881 5882 }
5882 5883 zpool_close(zhp);
5883 5884
5884 5885 return (ret);
5885 5886 }
5886 5887
5887 5888
5888 5889
5889 5890 /*
5890 5891 * zpool online <pool> <device> ...
5891 5892 */
5892 5893 int
5893 5894 zpool_do_online(int argc, char **argv)
5894 5895 {
5895 5896 int c, i;
5896 5897 char *poolname;
5897 5898 zpool_handle_t *zhp;
5898 5899 int ret = 0;
5899 5900 vdev_state_t newstate;
5900 5901 int flags = 0;
5901 5902
5902 5903 /* check options */
5903 5904 while ((c = getopt(argc, argv, "et")) != -1) {
5904 5905 switch (c) {
5905 5906 case 'e':
5906 5907 flags |= ZFS_ONLINE_EXPAND;
5907 5908 break;
5908 5909 case 't':
5909 5910 case '?':
5910 5911 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
5911 5912 optopt);
5912 5913 usage(B_FALSE);
5913 5914 }
5914 5915 }
5915 5916
5916 5917 argc -= optind;
5917 5918 argv += optind;
5918 5919
5919 5920 /* get pool name and check number of arguments */
5920 5921 if (argc < 1) {
5921 5922 (void) fprintf(stderr, gettext("missing pool name\n"));
5922 5923 usage(B_FALSE);
5923 5924 }
5924 5925 if (argc < 2) {
5925 5926 (void) fprintf(stderr, gettext("missing device name\n"));
5926 5927 usage(B_FALSE);
5927 5928 }
5928 5929
5929 5930 poolname = argv[0];
5930 5931
5931 5932 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
5932 5933 return (1);
5933 5934
5934 5935 for (i = 1; i < argc; i++) {
5935 5936 if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
5936 5937 if (newstate != VDEV_STATE_HEALTHY) {
5937 5938 (void) printf(gettext("warning: device '%s' "
5938 5939 "onlined, but remains in faulted state\n"),
5939 5940 argv[i]);
5940 5941 if (newstate == VDEV_STATE_FAULTED)
5941 5942 (void) printf(gettext("use 'zpool "
5942 5943 "clear' to restore a faulted "
5943 5944 "device\n"));
5944 5945 else
5945 5946 (void) printf(gettext("use 'zpool "
5946 5947 "replace' to replace devices "
5947 5948 "that are no longer present\n"));
5948 5949 }
5949 5950 } else {
5950 5951 ret = 1;
5951 5952 }
5952 5953 }
5953 5954
5954 5955 zpool_close(zhp);
5955 5956
5956 5957 return (ret);
5957 5958 }
5958 5959
5959 5960 /*
5960 5961 * zpool offline [-ft] <pool> <device> ...
5961 5962 *
5962 5963 * -f Force the device into the offline state, even if doing
5963 5964 * so would appear to compromise pool availability.
5964 5965 * (not supported yet)
5965 5966 *
5966 5967 * -t Only take the device off-line temporarily. The offline
5967 5968 * state will not be persistent across reboots.
5968 5969 */
5969 5970 /* ARGSUSED */
5970 5971 int
5971 5972 zpool_do_offline(int argc, char **argv)
5972 5973 {
5973 5974 int c, i;
5974 5975 char *poolname;
5975 5976 zpool_handle_t *zhp;
5976 5977 int ret = 0;
5977 5978 boolean_t istmp = B_FALSE;
5978 5979
5979 5980 /* check options */
5980 5981 while ((c = getopt(argc, argv, "ft")) != -1) {
5981 5982 switch (c) {
5982 5983 case 't':
5983 5984 istmp = B_TRUE;
5984 5985 break;
5985 5986 case 'f':
5986 5987 case '?':
5987 5988 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
5988 5989 optopt);
5989 5990 usage(B_FALSE);
5990 5991 }
5991 5992 }
5992 5993
5993 5994 argc -= optind;
5994 5995 argv += optind;
5995 5996
5996 5997 /* get pool name and check number of arguments */
5997 5998 if (argc < 1) {
5998 5999 (void) fprintf(stderr, gettext("missing pool name\n"));
5999 6000 usage(B_FALSE);
6000 6001 }
6001 6002 if (argc < 2) {
6002 6003 (void) fprintf(stderr, gettext("missing device name\n"));
6003 6004 usage(B_FALSE);
6004 6005 }
6005 6006
6006 6007 poolname = argv[0];
6007 6008
6008 6009 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
6009 6010 return (1);
6010 6011
6011 6012 for (i = 1; i < argc; i++) {
6012 6013 if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
6013 6014 ret = 1;
6014 6015 }
6015 6016
6016 6017 zpool_close(zhp);
6017 6018
6018 6019 return (ret);
6019 6020 }
6020 6021
6021 6022 /*
6022 6023 * zpool clear <pool> [device]
6023 6024 *
6024 6025 * Clear all errors associated with a pool or a particular device.
6025 6026 */
6026 6027 int
6027 6028 zpool_do_clear(int argc, char **argv)
6028 6029 {
6029 6030 int c;
6030 6031 int ret = 0;
6031 6032 boolean_t dryrun = B_FALSE;
6032 6033 boolean_t do_rewind = B_FALSE;
6033 6034 boolean_t xtreme_rewind = B_FALSE;
6034 6035 uint32_t rewind_policy = ZPOOL_NO_REWIND;
6035 6036 nvlist_t *policy = NULL;
6036 6037 zpool_handle_t *zhp;
6037 6038 char *pool, *device;
6038 6039
6039 6040 /* check options */
6040 6041 while ((c = getopt(argc, argv, "FnX")) != -1) {
6041 6042 switch (c) {
6042 6043 case 'F':
6043 6044 do_rewind = B_TRUE;
6044 6045 break;
6045 6046 case 'n':
6046 6047 dryrun = B_TRUE;
6047 6048 break;
6048 6049 case 'X':
6049 6050 xtreme_rewind = B_TRUE;
6050 6051 break;
6051 6052 case '?':
6052 6053 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
6053 6054 optopt);
6054 6055 usage(B_FALSE);
6055 6056 }
6056 6057 }
6057 6058
6058 6059 argc -= optind;
6059 6060 argv += optind;
6060 6061
6061 6062 if (argc < 1) {
6062 6063 (void) fprintf(stderr, gettext("missing pool name\n"));
6063 6064 usage(B_FALSE);
6064 6065 }
6065 6066
6066 6067 if (argc > 2) {
6067 6068 (void) fprintf(stderr, gettext("too many arguments\n"));
6068 6069 usage(B_FALSE);
6069 6070 }
6070 6071
6071 6072 if ((dryrun || xtreme_rewind) && !do_rewind) {
6072 6073 (void) fprintf(stderr,
6073 6074 gettext("-n or -X only meaningful with -F\n"));
6074 6075 usage(B_FALSE);
6075 6076 }
6076 6077 if (dryrun)
6077 6078 rewind_policy = ZPOOL_TRY_REWIND;
6078 6079 else if (do_rewind)
6079 6080 rewind_policy = ZPOOL_DO_REWIND;
6080 6081 if (xtreme_rewind)
6081 6082 rewind_policy |= ZPOOL_EXTREME_REWIND;
6082 6083
6083 6084 /* In future, further rewind policy choices can be passed along here */
6084 6085 if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
6085 6086 nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY,
6086 6087 rewind_policy) != 0) {
6087 6088 return (1);
6088 6089 }
6089 6090
6090 6091 pool = argv[0];
6091 6092 device = argc == 2 ? argv[1] : NULL;
6092 6093
6093 6094 if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
6094 6095 nvlist_free(policy);
6095 6096 return (1);
6096 6097 }
6097 6098
6098 6099 if (zpool_clear(zhp, device, policy) != 0)
6099 6100 ret = 1;
6100 6101
6101 6102 zpool_close(zhp);
6102 6103
6103 6104 nvlist_free(policy);
6104 6105
6105 6106 return (ret);
6106 6107 }
6107 6108
6108 6109 /*
6109 6110 * zpool reguid <pool>
6110 6111 */
6111 6112 int
6112 6113 zpool_do_reguid(int argc, char **argv)
6113 6114 {
6114 6115 int c;
6115 6116 char *poolname;
6116 6117 zpool_handle_t *zhp;
6117 6118 int ret = 0;
6118 6119
6119 6120 /* check options */
6120 6121 while ((c = getopt(argc, argv, "")) != -1) {
6121 6122 switch (c) {
6122 6123 case '?':
6123 6124 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
6124 6125 optopt);
6125 6126 usage(B_FALSE);
6126 6127 }
6127 6128 }
6128 6129
6129 6130 argc -= optind;
6130 6131 argv += optind;
6131 6132
6132 6133 /* get pool name and check number of arguments */
6133 6134 if (argc < 1) {
6134 6135 (void) fprintf(stderr, gettext("missing pool name\n"));
6135 6136 usage(B_FALSE);
6136 6137 }
6137 6138
6138 6139 if (argc > 1) {
6139 6140 (void) fprintf(stderr, gettext("too many arguments\n"));
6140 6141 usage(B_FALSE);
6141 6142 }
6142 6143
6143 6144 poolname = argv[0];
6144 6145 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
6145 6146 return (1);
6146 6147
6147 6148 ret = zpool_reguid(zhp);
6148 6149
6149 6150 zpool_close(zhp);
6150 6151 return (ret);
6151 6152 }
6152 6153
6153 6154
6154 6155 /*
6155 6156 * zpool reopen <pool>
6156 6157 *
6157 6158 * Reopen the pool so that the kernel can update the sizes of all vdevs.
6158 6159 */
6159 6160 int
6160 6161 zpool_do_reopen(int argc, char **argv)
6161 6162 {
6162 6163 int c;
6163 6164 int ret = 0;
6164 6165 zpool_handle_t *zhp;
6165 6166 char *pool;
6166 6167
6167 6168 /* check options */
6168 6169 while ((c = getopt(argc, argv, "")) != -1) {
6169 6170 switch (c) {
6170 6171 case '?':
6171 6172 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
6172 6173 optopt);
6173 6174 usage(B_FALSE);
6174 6175 }
6175 6176 }
6176 6177
6177 6178 argc--;
6178 6179 argv++;
6179 6180
6180 6181 if (argc < 1) {
6181 6182 (void) fprintf(stderr, gettext("missing pool name\n"));
6182 6183 usage(B_FALSE);
6183 6184 }
6184 6185
6185 6186 if (argc > 1) {
6186 6187 (void) fprintf(stderr, gettext("too many arguments\n"));
6187 6188 usage(B_FALSE);
6188 6189 }
6189 6190
6190 6191 pool = argv[0];
6191 6192 if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
6192 6193 return (1);
6193 6194
6194 6195 ret = zpool_reopen(zhp);
6195 6196 zpool_close(zhp);
6196 6197 return (ret);
6197 6198 }
6198 6199
6199 6200 typedef struct scrub_cbdata {
6200 6201 int cb_type;
6201 6202 int cb_argc;
6202 6203 char **cb_argv;
6203 6204 pool_scrub_cmd_t cb_scrub_cmd;
6204 6205 } scrub_cbdata_t;
6205 6206
6206 6207 static boolean_t
6207 6208 zpool_has_checkpoint(zpool_handle_t *zhp)
6208 6209 {
6209 6210 nvlist_t *config, *nvroot;
6210 6211
6211 6212 config = zpool_get_config(zhp, NULL);
6212 6213
6213 6214 if (config != NULL) {
6214 6215 pool_checkpoint_stat_t *pcs = NULL;
6215 6216 uint_t c;
6216 6217
6217 6218 nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE);
6218 6219 (void) nvlist_lookup_uint64_array(nvroot,
6219 6220 ZPOOL_CONFIG_CHECKPOINT_STATS, (uint64_t **)&pcs, &c);
6220 6221
6221 6222 if (pcs == NULL || pcs->pcs_state == CS_NONE)
6222 6223 return (B_FALSE);
6223 6224
6224 6225 assert(pcs->pcs_state == CS_CHECKPOINT_EXISTS ||
6225 6226 pcs->pcs_state == CS_CHECKPOINT_DISCARDING);
6226 6227 return (B_TRUE);
6227 6228 }
6228 6229
6229 6230 return (B_FALSE);
6230 6231 }
6231 6232
6232 6233 int
6233 6234 scrub_callback(zpool_handle_t *zhp, void *data)
6234 6235 {
6235 6236 scrub_cbdata_t *cb = data;
6236 6237 int err;
6237 6238
6238 6239 /*
6239 6240 * Ignore faulted pools.
6240 6241 */
6241 6242 if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
6242 6243 (void) fprintf(stderr, gettext("cannot scan '%s': pool is "
6243 6244 "currently unavailable\n"), zpool_get_name(zhp));
6244 6245 return (1);
6245 6246 }
6246 6247
6247 6248 err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd);
6248 6249
6249 6250 if (err == 0 && zpool_has_checkpoint(zhp) &&
6250 6251 cb->cb_type == POOL_SCAN_SCRUB) {
6251 6252 (void) printf(gettext("warning: will not scrub state that "
6252 6253 "belongs to the checkpoint of pool '%s'\n"),
6253 6254 zpool_get_name(zhp));
6254 6255 }
6255 6256
6256 6257 return (err != 0);
6257 6258 }
6258 6259
6259 6260 /*
6260 6261 * zpool scrub [-s | -p] <pool> ...
6261 6262 *
6262 6263 * -s Stop. Stops any in-progress scrub.
6263 6264 * -p Pause. Pause in-progress scrub.
6264 6265 */
6265 6266 int
6266 6267 zpool_do_scrub(int argc, char **argv)
6267 6268 {
6268 6269 int c;
6269 6270 scrub_cbdata_t cb;
6270 6271
6271 6272 cb.cb_type = POOL_SCAN_SCRUB;
6272 6273 cb.cb_scrub_cmd = POOL_SCRUB_NORMAL;
6273 6274
6274 6275 /* check options */
6275 6276 while ((c = getopt(argc, argv, "sp")) != -1) {
6276 6277 switch (c) {
6277 6278 case 's':
6278 6279 cb.cb_type = POOL_SCAN_NONE;
6279 6280 break;
6280 6281 case 'p':
6281 6282 cb.cb_scrub_cmd = POOL_SCRUB_PAUSE;
6282 6283 break;
6283 6284 case '?':
6284 6285 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
6285 6286 optopt);
6286 6287 usage(B_FALSE);
6287 6288 }
6288 6289 }
6289 6290
6290 6291 if (cb.cb_type == POOL_SCAN_NONE &&
6291 6292 cb.cb_scrub_cmd == POOL_SCRUB_PAUSE) {
6292 6293 (void) fprintf(stderr, gettext("invalid option combination: "
6293 6294 "-s and -p are mutually exclusive\n"));
6294 6295 usage(B_FALSE);
6295 6296 }
6296 6297
6297 6298 cb.cb_argc = argc;
6298 6299 cb.cb_argv = argv;
6299 6300 argc -= optind;
6300 6301 argv += optind;
6301 6302
6302 6303 if (argc < 1) {
6303 6304 (void) fprintf(stderr, gettext("missing pool name argument\n"));
6304 6305 usage(B_FALSE);
6305 6306 }
6306 6307
6307 6308 return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
6308 6309 }
6309 6310
6310 6311 /*
6311 6312 * zpool resilver <pool> ...
6312 6313 *
6313 6314 * Restarts any in-progress resilver
6314 6315 */
6315 6316 int
6316 6317 zpool_do_resilver(int argc, char **argv)
6317 6318 {
6318 6319 int c;
6319 6320 scrub_cbdata_t cb;
6320 6321
6321 6322 cb.cb_type = POOL_SCAN_RESILVER;
6322 6323 cb.cb_scrub_cmd = POOL_SCRUB_NORMAL;
6323 6324 cb.cb_argc = argc;
6324 6325 cb.cb_argv = argv;
6325 6326
6326 6327 /* check options */
6327 6328 while ((c = getopt(argc, argv, "")) != -1) {
6328 6329 switch (c) {
6329 6330 case '?':
6330 6331 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
6331 6332 optopt);
6332 6333 usage(B_FALSE);
6333 6334 }
6334 6335 }
6335 6336
6336 6337 argc -= optind;
6337 6338 argv += optind;
6338 6339
6339 6340 if (argc < 1) {
6340 6341 (void) fprintf(stderr, gettext("missing pool name argument\n"));
6341 6342 usage(B_FALSE);
6342 6343 }
6343 6344
6344 6345 return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
6345 6346 }
6346 6347
6347 6348 /*
6348 6349 * zpool trim [-d] [-r <rate>] [-c | -s] <pool> [<device> ...]
6349 6350 *
6350 6351 * -c Cancel. Ends any in-progress trim.
6351 6352 * -d Secure trim. Requires kernel and device support.
6352 6353 * -r <rate> Sets the TRIM rate in bytes (per second). Supports
6353 6354 * adding a multiplier suffix such as 'k' or 'm'.
6354 6355 * -s Suspend. TRIM can then be restarted with no flags.
6355 6356 */
6356 6357 int
6357 6358 zpool_do_trim(int argc, char **argv)
6358 6359 {
6359 6360 struct option long_options[] = {
6360 6361 {"cancel", no_argument, NULL, 'c'},
6361 6362 {"secure", no_argument, NULL, 'd'},
6362 6363 {"rate", required_argument, NULL, 'r'},
6363 6364 {"suspend", no_argument, NULL, 's'},
6364 6365 {0, 0, 0, 0}
6365 6366 };
6366 6367
6367 6368 pool_trim_func_t cmd_type = POOL_TRIM_START;
6368 6369 uint64_t rate = 0;
6369 6370 boolean_t secure = B_FALSE;
6370 6371
6371 6372 int c;
6372 6373 while ((c = getopt_long(argc, argv, "cdr:s", long_options, NULL))
6373 6374 != -1) {
6374 6375 switch (c) {
6375 6376 case 'c':
6376 6377 if (cmd_type != POOL_TRIM_START &&
6377 6378 cmd_type != POOL_TRIM_CANCEL) {
6378 6379 (void) fprintf(stderr, gettext("-c cannot be "
6379 6380 "combined with other options\n"));
6380 6381 usage(B_FALSE);
6381 6382 }
6382 6383 cmd_type = POOL_TRIM_CANCEL;
6383 6384 break;
6384 6385 case 'd':
6385 6386 if (cmd_type != POOL_TRIM_START) {
6386 6387 (void) fprintf(stderr, gettext("-d cannot be "
6387 6388 "combined with the -c or -s options\n"));
6388 6389 usage(B_FALSE);
6389 6390 }
6390 6391 secure = B_TRUE;
6391 6392 break;
6392 6393 case 'r':
6393 6394 if (cmd_type != POOL_TRIM_START) {
6394 6395 (void) fprintf(stderr, gettext("-r cannot be "
6395 6396 "combined with the -c or -s options\n"));
6396 6397 usage(B_FALSE);
6397 6398 }
6398 6399 if (zfs_nicestrtonum(NULL, optarg, &rate) == -1) {
6399 6400 (void) fprintf(stderr,
6400 6401 gettext("invalid value for rate\n"));
6401 6402 usage(B_FALSE);
6402 6403 }
6403 6404 break;
6404 6405 case 's':
6405 6406 if (cmd_type != POOL_TRIM_START &&
6406 6407 cmd_type != POOL_TRIM_SUSPEND) {
6407 6408 (void) fprintf(stderr, gettext("-s cannot be "
6408 6409 "combined with other options\n"));
6409 6410 usage(B_FALSE);
6410 6411 }
6411 6412 cmd_type = POOL_TRIM_SUSPEND;
6412 6413 break;
6413 6414 case '?':
6414 6415 if (optopt != 0) {
6415 6416 (void) fprintf(stderr,
6416 6417 gettext("invalid option '%c'\n"), optopt);
6417 6418 } else {
6418 6419 (void) fprintf(stderr,
6419 6420 gettext("invalid option '%s'\n"),
6420 6421 argv[optind - 1]);
6421 6422 }
6422 6423 usage(B_FALSE);
6423 6424 }
6424 6425 }
6425 6426
6426 6427 argc -= optind;
6427 6428 argv += optind;
6428 6429
6429 6430 if (argc < 1) {
6430 6431 (void) fprintf(stderr, gettext("missing pool name argument\n"));
6431 6432 usage(B_FALSE);
6432 6433 return (-1);
6433 6434 }
6434 6435
6435 6436 char *poolname = argv[0];
6436 6437 zpool_handle_t *zhp = zpool_open(g_zfs, poolname);
6437 6438 if (zhp == NULL)
6438 6439 return (-1);
6439 6440
6440 6441 trimflags_t trim_flags = {
6441 6442 .secure = secure,
6442 6443 .rate = rate,
6443 6444 };
6444 6445
6445 6446 nvlist_t *vdevs = fnvlist_alloc();
6446 6447 if (argc == 1) {
6447 6448 /* no individual leaf vdevs specified, so add them all */
6448 6449 nvlist_t *config = zpool_get_config(zhp, NULL);
6449 6450 nvlist_t *nvroot = fnvlist_lookup_nvlist(config,
6450 6451 ZPOOL_CONFIG_VDEV_TREE);
6451 6452 zpool_collect_leaves(zhp, nvroot, vdevs);
6452 6453 trim_flags.fullpool = B_TRUE;
6453 6454 } else {
6454 6455 trim_flags.fullpool = B_FALSE;
6455 6456 for (int i = 1; i < argc; i++) {
6456 6457 fnvlist_add_boolean(vdevs, argv[i]);
6457 6458 }
6458 6459 }
6459 6460
6460 6461 int error = zpool_trim(zhp, cmd_type, vdevs, &trim_flags);
6461 6462
6462 6463 fnvlist_free(vdevs);
6463 6464 zpool_close(zhp);
6464 6465
6465 6466 return (error);
6466 6467 }
6467 6468
6468 6469 /*
6469 6470 * zpool initialize [-c | -s] <pool> [<vdev> ...]
6470 6471 * Initialize all unused blocks in the specified vdevs, or all vdevs in the pool
6471 6472 * if none specified.
6472 6473 *
6473 6474 * -c Cancel. Ends active initializing.
6474 6475 * -s Suspend. Initializing can then be restarted with no flags.
6475 6476 */
6476 6477 int
6477 6478 zpool_do_initialize(int argc, char **argv)
6478 6479 {
6479 6480 int c;
6480 6481 char *poolname;
6481 6482 zpool_handle_t *zhp;
6482 6483 nvlist_t *vdevs;
6483 6484 int err = 0;
6484 6485
6485 6486 struct option long_options[] = {
6486 6487 {"cancel", no_argument, NULL, 'c'},
6487 6488 {"suspend", no_argument, NULL, 's'},
6488 6489 {0, 0, 0, 0}
6489 6490 };
6490 6491
6491 6492 pool_initialize_func_t cmd_type = POOL_INITIALIZE_START;
6492 6493 while ((c = getopt_long(argc, argv, "cs", long_options, NULL)) != -1) {
6493 6494 switch (c) {
6494 6495 case 'c':
6495 6496 if (cmd_type != POOL_INITIALIZE_START &&
6496 6497 cmd_type != POOL_INITIALIZE_CANCEL) {
6497 6498 (void) fprintf(stderr, gettext("-c cannot be "
6498 6499 "combined with other options\n"));
6499 6500 usage(B_FALSE);
6500 6501 }
6501 6502 cmd_type = POOL_INITIALIZE_CANCEL;
6502 6503 break;
6503 6504 case 's':
6504 6505 if (cmd_type != POOL_INITIALIZE_START &&
6505 6506 cmd_type != POOL_INITIALIZE_SUSPEND) {
6506 6507 (void) fprintf(stderr, gettext("-s cannot be "
6507 6508 "combined with other options\n"));
6508 6509 usage(B_FALSE);
6509 6510 }
6510 6511 cmd_type = POOL_INITIALIZE_SUSPEND;
6511 6512 break;
6512 6513 case '?':
6513 6514 if (optopt != 0) {
6514 6515 (void) fprintf(stderr,
6515 6516 gettext("invalid option '%c'\n"), optopt);
6516 6517 } else {
6517 6518 (void) fprintf(stderr,
6518 6519 gettext("invalid option '%s'\n"),
6519 6520 argv[optind - 1]);
6520 6521 }
6521 6522 usage(B_FALSE);
6522 6523 }
6523 6524 }
6524 6525
6525 6526 argc -= optind;
6526 6527 argv += optind;
6527 6528
6528 6529 if (argc < 1) {
6529 6530 (void) fprintf(stderr, gettext("missing pool name argument\n"));
6530 6531 usage(B_FALSE);
6531 6532 return (-1);
6532 6533 }
6533 6534
6534 6535 poolname = argv[0];
6535 6536 zhp = zpool_open(g_zfs, poolname);
6536 6537 if (zhp == NULL)
6537 6538 return (-1);
6538 6539
6539 6540 vdevs = fnvlist_alloc();
6540 6541 if (argc == 1) {
6541 6542 /* no individual leaf vdevs specified, so add them all */
6542 6543 nvlist_t *config = zpool_get_config(zhp, NULL);
6543 6544 nvlist_t *nvroot = fnvlist_lookup_nvlist(config,
6544 6545 ZPOOL_CONFIG_VDEV_TREE);
6545 6546 zpool_collect_leaves(zhp, nvroot, vdevs);
6546 6547 } else {
6547 6548 for (int i = 1; i < argc; i++) {
6548 6549 fnvlist_add_boolean(vdevs, argv[i]);
6549 6550 }
6550 6551 }
6551 6552
6552 6553 err = zpool_initialize(zhp, cmd_type, vdevs);
6553 6554
6554 6555 fnvlist_free(vdevs);
6555 6556 zpool_close(zhp);
6556 6557
6557 6558 return (err);
6558 6559 }
6559 6560
6560 6561 /*
6561 6562 * Print out detailed scrub status.
6562 6563 */
6563 6564 static void
6564 6565 print_scan_status(pool_scan_stat_t *ps)
6565 6566 {
6566 6567 time_t start, end, pause;
6567 6568 uint64_t total_secs_left;
6568 6569 uint64_t elapsed, secs_left, mins_left, hours_left, days_left;
6569 6570 uint64_t pass_scanned, scanned, pass_issued, issued, total;
6570 6571 uint_t scan_rate, issue_rate;
6571 6572 double fraction_done;
6572 6573 char processed_buf[7], scanned_buf[7], issued_buf[7], total_buf[7];
6573 6574 char srate_buf[7], irate_buf[7];
6574 6575
6575 6576 (void) printf(gettext(" scan: "));
6576 6577
6577 6578 /* If there's never been a scan, there's not much to say. */
6578 6579 if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
6579 6580 ps->pss_func >= POOL_SCAN_FUNCS) {
6580 6581 (void) printf(gettext("none requested\n"));
6581 6582 return;
6582 6583 }
6583 6584
6584 6585 start = ps->pss_start_time;
6585 6586 end = ps->pss_end_time;
6586 6587 pause = ps->pss_pass_scrub_pause;
6587 6588
6588 6589 zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
6589 6590
6590 6591 assert(ps->pss_func == POOL_SCAN_SCRUB ||
6591 6592 ps->pss_func == POOL_SCAN_RESILVER);
6592 6593
6593 6594 /*
6594 6595 * Scan is finished or canceled.
6595 6596 */
6596 6597 if (ps->pss_state == DSS_FINISHED) {
6597 6598 total_secs_left = end - start;
6598 6599 days_left = total_secs_left / 60 / 60 / 24;
6599 6600 hours_left = (total_secs_left / 60 / 60) % 24;
6600 6601 mins_left = (total_secs_left / 60) % 60;
6601 6602 secs_left = (total_secs_left % 60);
6602 6603
6603 6604 if (ps->pss_func == POOL_SCAN_SCRUB) {
6604 6605 (void) printf(gettext("scrub repaired %s "
6605 6606 "in %llu days %02llu:%02llu:%02llu "
6606 6607 "with %llu errors on %s"), processed_buf,
6607 6608 (u_longlong_t)days_left, (u_longlong_t)hours_left,
6608 6609 (u_longlong_t)mins_left, (u_longlong_t)secs_left,
6609 6610 (u_longlong_t)ps->pss_errors, ctime(&end));
6610 6611 } else if (ps->pss_func == POOL_SCAN_RESILVER) {
6611 6612 (void) printf(gettext("resilvered %s "
6612 6613 "in %llu days %02llu:%02llu:%02llu "
6613 6614 "with %llu errors on %s"), processed_buf,
6614 6615 (u_longlong_t)days_left, (u_longlong_t)hours_left,
6615 6616 (u_longlong_t)mins_left, (u_longlong_t)secs_left,
6616 6617 (u_longlong_t)ps->pss_errors, ctime(&end));
6617 6618 }
6618 6619 return;
6619 6620 } else if (ps->pss_state == DSS_CANCELED) {
6620 6621 if (ps->pss_func == POOL_SCAN_SCRUB) {
6621 6622 (void) printf(gettext("scrub canceled on %s"),
6622 6623 ctime(&end));
6623 6624 } else if (ps->pss_func == POOL_SCAN_RESILVER) {
6624 6625 (void) printf(gettext("resilver canceled on %s"),
6625 6626 ctime(&end));
6626 6627 }
6627 6628 return;
6628 6629 }
6629 6630
6630 6631 assert(ps->pss_state == DSS_SCANNING);
6631 6632
6632 6633 /* Scan is in progress. Resilvers can't be paused. */
6633 6634 if (ps->pss_func == POOL_SCAN_SCRUB) {
6634 6635 if (pause == 0) {
6635 6636 (void) printf(gettext("scrub in progress since %s"),
6636 6637 ctime(&start));
6637 6638 } else {
6638 6639 (void) printf(gettext("scrub paused since %s"),
6639 6640 ctime(&pause));
6640 6641 (void) printf(gettext("\tscrub started on %s"),
6641 6642 ctime(&start));
6642 6643 }
6643 6644 } else if (ps->pss_func == POOL_SCAN_RESILVER) {
6644 6645 (void) printf(gettext("resilver in progress since %s"),
6645 6646 ctime(&start));
6646 6647 }
6647 6648
6648 6649 scanned = ps->pss_examined;
6649 6650 pass_scanned = ps->pss_pass_exam;
6650 6651 issued = ps->pss_issued;
6651 6652 pass_issued = ps->pss_pass_issued;
6652 6653 total = ps->pss_to_examine;
6653 6654
6654 6655 /* we are only done with a block once we have issued the IO for it */
6655 6656 fraction_done = (double)issued / total;
6656 6657
6657 6658 /* elapsed time for this pass, rounding up to 1 if it's 0 */
6658 6659 elapsed = time(NULL) - ps->pss_pass_start;
6659 6660 elapsed -= ps->pss_pass_scrub_spent_paused;
6660 6661 elapsed = (elapsed != 0) ? elapsed : 1;
6661 6662
6662 6663 scan_rate = pass_scanned / elapsed;
6663 6664 issue_rate = pass_issued / elapsed;
6664 6665 total_secs_left = (issue_rate != 0 && total >= issued) ?
6665 6666 ((total - issued) / issue_rate) : UINT64_MAX;
6666 6667
6667 6668 days_left = total_secs_left / 60 / 60 / 24;
6668 6669 hours_left = (total_secs_left / 60 / 60) % 24;
6669 6670 mins_left = (total_secs_left / 60) % 60;
6670 6671 secs_left = (total_secs_left % 60);
6671 6672
6672 6673 /* format all of the numbers we will be reporting */
6673 6674 zfs_nicenum(scanned, scanned_buf, sizeof (scanned_buf));
6674 6675 zfs_nicenum(issued, issued_buf, sizeof (issued_buf));
6675 6676 zfs_nicenum(total, total_buf, sizeof (total_buf));
6676 6677 zfs_nicenum(scan_rate, srate_buf, sizeof (srate_buf));
6677 6678 zfs_nicenum(issue_rate, irate_buf, sizeof (irate_buf));
6678 6679
6679 6680 /* do not print estimated time if we have a paused scrub */
6680 6681 if (pause == 0) {
6681 6682 (void) printf(gettext("\t%s scanned at %s/s, "
6682 6683 "%s issued at %s/s, %s total\n"),
6683 6684 scanned_buf, srate_buf, issued_buf, irate_buf, total_buf);
6684 6685 } else {
6685 6686 (void) printf(gettext("\t%s scanned, %s issued, %s total\n"),
6686 6687 scanned_buf, issued_buf, total_buf);
6687 6688 }
6688 6689
6689 6690 if (ps->pss_func == POOL_SCAN_RESILVER) {
6690 6691 (void) printf(gettext("\t%s resilvered, %.2f%% done"),
6691 6692 processed_buf, 100 * fraction_done);
6692 6693 } else if (ps->pss_func == POOL_SCAN_SCRUB) {
6693 6694 (void) printf(gettext("\t%s repaired, %.2f%% done"),
6694 6695 processed_buf, 100 * fraction_done);
6695 6696 }
6696 6697
6697 6698 if (pause == 0) {
6698 6699 if (total_secs_left != UINT64_MAX &&
6699 6700 issue_rate >= 10 * 1024 * 1024) {
6700 6701 (void) printf(gettext(", %llu days "
6701 6702 "%02llu:%02llu:%02llu to go\n"),
6702 6703 (u_longlong_t)days_left, (u_longlong_t)hours_left,
6703 6704 (u_longlong_t)mins_left, (u_longlong_t)secs_left);
6704 6705 } else {
6705 6706 (void) printf(gettext(", no estimated "
6706 6707 "completion time\n"));
6707 6708 }
6708 6709 } else {
6709 6710 (void) printf(gettext("\n"));
6710 6711 }
6711 6712 }
6712 6713
6713 6714 /*
6714 6715 * As we don't scrub checkpointed blocks, we want to warn the
6715 6716 * user that we skipped scanning some blocks if a checkpoint exists
6716 6717 * or existed at any time during the scan.
6717 6718 */
6718 6719 static void
6719 6720 print_checkpoint_scan_warning(pool_scan_stat_t *ps, pool_checkpoint_stat_t *pcs)
6720 6721 {
6721 6722 if (ps == NULL || pcs == NULL)
6722 6723 return;
6723 6724
6724 6725 if (pcs->pcs_state == CS_NONE ||
6725 6726 pcs->pcs_state == CS_CHECKPOINT_DISCARDING)
6726 6727 return;
6727 6728
6728 6729 assert(pcs->pcs_state == CS_CHECKPOINT_EXISTS);
6729 6730
6730 6731 if (ps->pss_state == DSS_NONE)
6731 6732 return;
6732 6733
6733 6734 if ((ps->pss_state == DSS_FINISHED || ps->pss_state == DSS_CANCELED) &&
6734 6735 ps->pss_end_time < pcs->pcs_start_time)
6735 6736 return;
6736 6737
6737 6738 if (ps->pss_state == DSS_FINISHED || ps->pss_state == DSS_CANCELED) {
6738 6739 (void) printf(gettext(" scan warning: skipped blocks "
6739 6740 "that are only referenced by the checkpoint.\n"));
6740 6741 } else {
6741 6742 assert(ps->pss_state == DSS_SCANNING);
6742 6743 (void) printf(gettext(" scan warning: skipping blocks "
6743 6744 "that are only referenced by the checkpoint.\n"));
6744 6745 }
6745 6746 }
6746 6747
6747 6748 /*
6748 6749 * Print out detailed removal status.
6749 6750 */
6750 6751 static void
6751 6752 print_removal_status(zpool_handle_t *zhp, pool_removal_stat_t *prs)
6752 6753 {
6753 6754 char copied_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
6754 6755 time_t start, end;
6755 6756 nvlist_t *config, *nvroot;
6756 6757 nvlist_t **child;
6757 6758 uint_t children;
6758 6759 char *vdev_name;
6759 6760
6760 6761 if (prs == NULL || prs->prs_state == DSS_NONE)
6761 6762 return;
6762 6763
6763 6764 /*
6764 6765 * Determine name of vdev.
6765 6766 */
6766 6767 config = zpool_get_config(zhp, NULL);
6767 6768 nvroot = fnvlist_lookup_nvlist(config,
6768 6769 ZPOOL_CONFIG_VDEV_TREE);
6769 6770 verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
6770 6771 &child, &children) == 0);
6771 6772 assert(prs->prs_removing_vdev < children);
6772 6773 vdev_name = zpool_vdev_name(g_zfs, zhp,
6773 6774 child[prs->prs_removing_vdev], B_TRUE);
6774 6775
6775 6776 (void) printf(gettext("remove: "));
6776 6777
6777 6778 start = prs->prs_start_time;
6778 6779 end = prs->prs_end_time;
6779 6780 zfs_nicenum(prs->prs_copied, copied_buf, sizeof (copied_buf));
6780 6781
6781 6782 /*
6782 6783 * Removal is finished or canceled.
6783 6784 */
6784 6785 if (prs->prs_state == DSS_FINISHED) {
6785 6786 uint64_t minutes_taken = (end - start) / 60;
6786 6787
6787 6788 (void) printf(gettext("Removal of vdev %llu copied %s "
6788 6789 "in %lluh%um, completed on %s"),
6789 6790 (longlong_t)prs->prs_removing_vdev,
6790 6791 copied_buf,
6791 6792 (u_longlong_t)(minutes_taken / 60),
6792 6793 (uint_t)(minutes_taken % 60),
6793 6794 ctime((time_t *)&end));
6794 6795 } else if (prs->prs_state == DSS_CANCELED) {
6795 6796 (void) printf(gettext("Removal of %s canceled on %s"),
6796 6797 vdev_name, ctime(&end));
6797 6798 } else {
6798 6799 uint64_t copied, total, elapsed, mins_left, hours_left;
6799 6800 double fraction_done;
6800 6801 uint_t rate;
6801 6802
6802 6803 assert(prs->prs_state == DSS_SCANNING);
6803 6804
6804 6805 /*
6805 6806 * Removal is in progress.
6806 6807 */
6807 6808 (void) printf(gettext(
6808 6809 "Evacuation of %s in progress since %s"),
6809 6810 vdev_name, ctime(&start));
6810 6811
6811 6812 copied = prs->prs_copied > 0 ? prs->prs_copied : 1;
6812 6813 total = prs->prs_to_copy;
6813 6814 fraction_done = (double)copied / total;
6814 6815
6815 6816 /* elapsed time for this pass */
6816 6817 elapsed = time(NULL) - prs->prs_start_time;
6817 6818 elapsed = elapsed > 0 ? elapsed : 1;
6818 6819 rate = copied / elapsed;
6819 6820 rate = rate > 0 ? rate : 1;
6820 6821 mins_left = ((total - copied) / rate) / 60;
6821 6822 hours_left = mins_left / 60;
6822 6823
6823 6824 zfs_nicenum(copied, examined_buf, sizeof (examined_buf));
6824 6825 zfs_nicenum(total, total_buf, sizeof (total_buf));
6825 6826 zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
6826 6827
6827 6828 /*
6828 6829 * do not print estimated time if hours_left is more than
6829 6830 * 30 days
6830 6831 */
6831 6832 (void) printf(gettext(" %s copied out of %s at %s/s, "
6832 6833 "%.2f%% done"),
6833 6834 examined_buf, total_buf, rate_buf, 100 * fraction_done);
6834 6835 if (hours_left < (30 * 24)) {
6835 6836 (void) printf(gettext(", %lluh%um to go\n"),
6836 6837 (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
6837 6838 } else {
6838 6839 (void) printf(gettext(
6839 6840 ", (copy is slow, no estimated time)\n"));
6840 6841 }
6841 6842 }
6842 6843
6843 6844 if (prs->prs_mapping_memory > 0) {
6844 6845 char mem_buf[7];
6845 6846 zfs_nicenum(prs->prs_mapping_memory, mem_buf, sizeof (mem_buf));
6846 6847 (void) printf(gettext(" %s memory used for "
6847 6848 "removed device mappings\n"),
6848 6849 mem_buf);
6849 6850 }
6850 6851 }
6851 6852
6852 6853 static void
6853 6854 print_checkpoint_status(pool_checkpoint_stat_t *pcs)
6854 6855 {
6855 6856 time_t start;
6856 6857 char space_buf[7];
6857 6858
6858 6859 if (pcs == NULL || pcs->pcs_state == CS_NONE)
6859 6860 return;
6860 6861
6861 6862 (void) printf(gettext("checkpoint: "));
6862 6863
6863 6864 start = pcs->pcs_start_time;
6864 6865 zfs_nicenum(pcs->pcs_space, space_buf, sizeof (space_buf));
6865 6866
6866 6867 if (pcs->pcs_state == CS_CHECKPOINT_EXISTS) {
6867 6868 char *date = ctime(&start);
6868 6869
6869 6870 /*
6870 6871 * ctime() adds a newline at the end of the generated
6871 6872 * string, thus the weird format specifier and the
6872 6873 * strlen() call used to chop it off from the output.
6873 6874 */
6874 6875 (void) printf(gettext("created %.*s, consumes %s\n"),
6875 6876 strlen(date) - 1, date, space_buf);
6876 6877 return;
6877 6878 }
6878 6879
6879 6880 assert(pcs->pcs_state == CS_CHECKPOINT_DISCARDING);
6880 6881
6881 6882 (void) printf(gettext("discarding, %s remaining.\n"),
6882 6883 space_buf);
6883 6884 }
6884 6885
6885 6886 static void
6886 6887 print_error_log(zpool_handle_t *zhp)
6887 6888 {
6888 6889 nvlist_t *nverrlist = NULL;
6889 6890 nvpair_t *elem;
6890 6891 char *pathname;
6891 6892 size_t len = MAXPATHLEN * 2;
6892 6893
6893 6894 if (zpool_get_errlog(zhp, &nverrlist) != 0) {
6894 6895 (void) printf("errors: List of errors unavailable "
6895 6896 "(insufficient privileges)\n");
6896 6897 return;
6897 6898 }
6898 6899
6899 6900 (void) printf("errors: Permanent errors have been "
6900 6901 "detected in the following files:\n\n");
6901 6902
6902 6903 pathname = safe_malloc(len);
6903 6904 elem = NULL;
6904 6905 while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
6905 6906 nvlist_t *nv;
6906 6907 uint64_t dsobj, obj;
6907 6908
6908 6909 verify(nvpair_value_nvlist(elem, &nv) == 0);
6909 6910 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
6910 6911 &dsobj) == 0);
6911 6912 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
6912 6913 &obj) == 0);
6913 6914 zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
6914 6915 (void) printf("%7s %s\n", "", pathname);
6915 6916 }
6916 6917 free(pathname);
6917 6918 nvlist_free(nverrlist);
6918 6919 }
6919 6920
6920 6921 static void
6921 6922 print_spares(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t **spares,
6922 6923 uint_t nspares)
6923 6924 {
6924 6925 uint_t i;
6925 6926 char *name;
6926 6927
6927 6928 if (nspares == 0)
6928 6929 return;
6929 6930
6930 6931 (void) printf(gettext("\tspares\n"));
6931 6932
6932 6933 for (i = 0; i < nspares; i++) {
6933 6934 name = zpool_vdev_name(g_zfs, zhp, spares[i],
6934 6935 cb->cb_name_flags);
6935 6936 print_status_config(zhp, cb, name, spares[i], 2, B_TRUE);
6936 6937 free(name);
6937 6938 }
6938 6939 }
6939 6940
6940 6941 static void
6941 6942 print_l2cache(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t **l2cache,
6942 6943 uint_t nl2cache)
6943 6944 {
6944 6945 uint_t i;
6945 6946 char *name;
6946 6947
6947 6948 if (nl2cache == 0)
6948 6949 return;
6949 6950
6950 6951 (void) printf(gettext("\tcache\n"));
6951 6952
6952 6953 for (i = 0; i < nl2cache; i++) {
6953 6954 name = zpool_vdev_name(g_zfs, zhp, l2cache[i],
6954 6955 cb->cb_name_flags);
6955 6956 print_status_config(zhp, cb, name, l2cache[i], 2, B_FALSE);
6956 6957 free(name);
6957 6958 }
6958 6959 }
6959 6960
6960 6961 static void
6961 6962 print_dedup_stats(nvlist_t *config)
6962 6963 {
6963 6964 ddt_histogram_t *ddh;
6964 6965 ddt_stat_t *dds;
6965 6966 ddt_object_t *ddo;
6966 6967 uint_t c;
6967 6968
6968 6969 /*
6969 6970 * If the pool was faulted then we may not have been able to
6970 6971 * obtain the config. Otherwise, if we have anything in the dedup
6971 6972 * table continue processing the stats.
6972 6973 */
6973 6974 if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
6974 6975 (uint64_t **)&ddo, &c) != 0)
6975 6976 return;
6976 6977
6977 6978 (void) printf("\n");
6978 6979 (void) printf(gettext(" dedup: "));
6979 6980 if (ddo->ddo_count == 0) {
6980 6981 (void) printf(gettext("no DDT entries\n"));
6981 6982 return;
6982 6983 }
6983 6984
6984 6985 (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
6985 6986 (u_longlong_t)ddo->ddo_count,
6986 6987 (u_longlong_t)ddo->ddo_dspace,
6987 6988 (u_longlong_t)ddo->ddo_mspace);
6988 6989
6989 6990 verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
6990 6991 (uint64_t **)&dds, &c) == 0);
6991 6992 verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
6992 6993 (uint64_t **)&ddh, &c) == 0);
6993 6994 zpool_dump_ddt(dds, ddh);
6994 6995 }
6995 6996
6996 6997 /*
6997 6998 * Display a summary of pool status. Displays a summary such as:
6998 6999 *
6999 7000 * pool: tank
7000 7001 * status: DEGRADED
7001 7002 * reason: One or more devices ...
7002 7003 * see: http://illumos.org/msg/ZFS-xxxx-01
7003 7004 * config:
7004 7005 * mirror DEGRADED
7005 7006 * c1t0d0 OK
7006 7007 * c2t0d0 UNAVAIL
7007 7008 *
7008 7009 * When given the '-v' option, we print out the complete config. If the '-e'
7009 7010 * option is specified, then we print out error rate information as well.
7010 7011 */
7011 7012 int
7012 7013 status_callback(zpool_handle_t *zhp, void *data)
7013 7014 {
7014 7015 status_cbdata_t *cbp = data;
7015 7016 nvlist_t *config, *nvroot;
7016 7017 char *msgid;
7017 7018 int reason;
7018 7019 zpool_errata_t errata;
7019 7020 const char *health;
7020 7021 uint_t c;
7021 7022 vdev_stat_t *vs;
7022 7023
7023 7024 config = zpool_get_config(zhp, NULL);
7024 7025 reason = zpool_get_status(zhp, &msgid, &errata);
7025 7026
7026 7027 cbp->cb_count++;
7027 7028
7028 7029 /*
7029 7030 * If we were given 'zpool status -x', only report those pools with
7030 7031 * problems.
7031 7032 */
7032 7033 if (cbp->cb_explain &&
7033 7034 (reason == ZPOOL_STATUS_OK ||
7034 7035 reason == ZPOOL_STATUS_VERSION_OLDER ||
7035 7036 reason == ZPOOL_STATUS_FEAT_DISABLED)) {
7036 7037 if (!cbp->cb_allpools) {
7037 7038 (void) printf(gettext("pool '%s' is healthy\n"),
7038 7039 zpool_get_name(zhp));
7039 7040 if (cbp->cb_first)
7040 7041 cbp->cb_first = B_FALSE;
7041 7042 }
7042 7043 return (0);
7043 7044 }
7044 7045
7045 7046 if (cbp->cb_first)
7046 7047 cbp->cb_first = B_FALSE;
7047 7048 else
7048 7049 (void) printf("\n");
7049 7050
7050 7051 nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE);
7051 7052 verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
7052 7053 (uint64_t **)&vs, &c) == 0);
7053 7054 health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
7054 7055
7055 7056 (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp));
7056 7057 (void) printf(gettext(" state: %s\n"), health);
7057 7058
7058 7059 switch (reason) {
7059 7060 case ZPOOL_STATUS_MISSING_DEV_R:
7060 7061 (void) printf(gettext("status: One or more devices could not "
7061 7062 "be opened. Sufficient replicas exist for\n\tthe pool to "
7062 7063 "continue functioning in a degraded state.\n"));
7063 7064 (void) printf(gettext("action: Attach the missing device and "
7064 7065 "online it using 'zpool online'.\n"));
7065 7066 break;
7066 7067
7067 7068 case ZPOOL_STATUS_MISSING_DEV_NR:
7068 7069 (void) printf(gettext("status: One or more devices could not "
7069 7070 "be opened. There are insufficient\n\treplicas for the "
7070 7071 "pool to continue functioning.\n"));
7071 7072 (void) printf(gettext("action: Attach the missing device and "
7072 7073 "online it using 'zpool online'.\n"));
7073 7074 break;
7074 7075
7075 7076 case ZPOOL_STATUS_CORRUPT_LABEL_R:
7076 7077 (void) printf(gettext("status: One or more devices could not "
7077 7078 "be used because the label is missing or\n\tinvalid. "
7078 7079 "Sufficient replicas exist for the pool to continue\n\t"
7079 7080 "functioning in a degraded state.\n"));
7080 7081 (void) printf(gettext("action: Replace the device using "
7081 7082 "'zpool replace'.\n"));
7082 7083 break;
7083 7084
7084 7085 case ZPOOL_STATUS_CORRUPT_LABEL_NR:
7085 7086 (void) printf(gettext("status: One or more devices could not "
7086 7087 "be used because the label is missing \n\tor invalid. "
7087 7088 "There are insufficient replicas for the pool to "
7088 7089 "continue\n\tfunctioning.\n"));
7089 7090 zpool_explain_recover(zpool_get_handle(zhp),
7090 7091 zpool_get_name(zhp), reason, config);
7091 7092 break;
7092 7093
7093 7094 case ZPOOL_STATUS_FAILING_DEV:
7094 7095 (void) printf(gettext("status: One or more devices has "
7095 7096 "experienced an unrecoverable error. An\n\tattempt was "
7096 7097 "made to correct the error. Applications are "
7097 7098 "unaffected.\n"));
7098 7099 (void) printf(gettext("action: Determine if the device needs "
7099 7100 "to be replaced, and clear the errors\n\tusing "
7100 7101 "'zpool clear' or replace the device with 'zpool "
7101 7102 "replace'.\n"));
7102 7103 break;
7103 7104
7104 7105 case ZPOOL_STATUS_OFFLINE_DEV:
7105 7106 (void) printf(gettext("status: One or more devices has "
7106 7107 "been taken offline by the administrator.\n\tSufficient "
7107 7108 "replicas exist for the pool to continue functioning in "
7108 7109 "a\n\tdegraded state.\n"));
7109 7110 (void) printf(gettext("action: Online the device using "
7110 7111 "'zpool online' or replace the device with\n\t'zpool "
7111 7112 "replace'.\n"));
7112 7113 break;
7113 7114
7114 7115 case ZPOOL_STATUS_REMOVED_DEV:
7115 7116 (void) printf(gettext("status: One or more devices has "
7116 7117 "been removed by the administrator.\n\tSufficient "
7117 7118 "replicas exist for the pool to continue functioning in "
7118 7119 "a\n\tdegraded state.\n"));
7119 7120 (void) printf(gettext("action: Online the device using "
7120 7121 "'zpool online' or replace the device with\n\t'zpool "
7121 7122 "replace'.\n"));
7122 7123 break;
7123 7124
7124 7125 case ZPOOL_STATUS_RESILVERING:
7125 7126 (void) printf(gettext("status: One or more devices is "
7126 7127 "currently being resilvered. The pool will\n\tcontinue "
7127 7128 "to function, possibly in a degraded state.\n"));
7128 7129 (void) printf(gettext("action: Wait for the resilver to "
7129 7130 "complete.\n"));
7130 7131 break;
7131 7132
7132 7133 case ZPOOL_STATUS_CORRUPT_DATA:
7133 7134 (void) printf(gettext("status: One or more devices has "
7134 7135 "experienced an error resulting in data\n\tcorruption. "
7135 7136 "Applications may be affected.\n"));
7136 7137 (void) printf(gettext("action: Restore the file in question "
7137 7138 "if possible. Otherwise restore the\n\tentire pool from "
7138 7139 "backup.\n"));
7139 7140 break;
7140 7141
7141 7142 case ZPOOL_STATUS_CORRUPT_POOL:
7142 7143 (void) printf(gettext("status: The pool metadata is corrupted "
7143 7144 "and the pool cannot be opened.\n"));
7144 7145 zpool_explain_recover(zpool_get_handle(zhp),
7145 7146 zpool_get_name(zhp), reason, config);
7146 7147 break;
7147 7148
7148 7149 case ZPOOL_STATUS_VERSION_OLDER:
7149 7150 (void) printf(gettext("status: The pool is formatted using a "
7150 7151 "legacy on-disk format. The pool can\n\tstill be used, "
7151 7152 "but some features are unavailable.\n"));
7152 7153 (void) printf(gettext("action: Upgrade the pool using 'zpool "
7153 7154 "upgrade'. Once this is done, the\n\tpool will no longer "
7154 7155 "be accessible on software that does not support feature\n"
7155 7156 "\tflags.\n"));
7156 7157 break;
7157 7158
7158 7159 case ZPOOL_STATUS_VERSION_NEWER:
7159 7160 (void) printf(gettext("status: The pool has been upgraded to a "
7160 7161 "newer, incompatible on-disk version.\n\tThe pool cannot "
7161 7162 "be accessed on this system.\n"));
7162 7163 (void) printf(gettext("action: Access the pool from a system "
7163 7164 "running more recent software, or\n\trestore the pool from "
7164 7165 "backup.\n"));
7165 7166 break;
7166 7167
7167 7168 case ZPOOL_STATUS_FEAT_DISABLED:
7168 7169 (void) printf(gettext("status: Some supported features are not "
7169 7170 "enabled on the pool. The pool can\n\tstill be used, but "
7170 7171 "some features are unavailable.\n"));
7171 7172 (void) printf(gettext("action: Enable all features using "
7172 7173 "'zpool upgrade'. Once this is done,\n\tthe pool may no "
7173 7174 "longer be accessible by software that does not support\n\t"
7174 7175 "the features. See zpool-features(5) for details.\n"));
7175 7176 break;
7176 7177
7177 7178 case ZPOOL_STATUS_UNSUP_FEAT_READ:
7178 7179 (void) printf(gettext("status: The pool cannot be accessed on "
7179 7180 "this system because it uses the\n\tfollowing feature(s) "
7180 7181 "not supported on this system:\n"));
7181 7182 zpool_print_unsup_feat(config);
7182 7183 (void) printf("\n");
7183 7184 (void) printf(gettext("action: Access the pool from a system "
7184 7185 "that supports the required feature(s),\n\tor restore the "
7185 7186 "pool from backup.\n"));
7186 7187 break;
7187 7188
7188 7189 case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
7189 7190 (void) printf(gettext("status: The pool can only be accessed "
7190 7191 "in read-only mode on this system. It\n\tcannot be "
7191 7192 "accessed in read-write mode because it uses the "
7192 7193 "following\n\tfeature(s) not supported on this system:\n"));
7193 7194 zpool_print_unsup_feat(config);
7194 7195 (void) printf("\n");
7195 7196 (void) printf(gettext("action: The pool cannot be accessed in "
7196 7197 "read-write mode. Import the pool with\n"
7197 7198 "\t\"-o readonly=on\", access the pool from a system that "
7198 7199 "supports the\n\trequired feature(s), or restore the "
7199 7200 "pool from backup.\n"));
7200 7201 break;
7201 7202
7202 7203 case ZPOOL_STATUS_FAULTED_DEV_R:
7203 7204 (void) printf(gettext("status: One or more devices are "
7204 7205 "faulted in response to persistent errors.\n\tSufficient "
7205 7206 "replicas exist for the pool to continue functioning "
7206 7207 "in a\n\tdegraded state.\n"));
7207 7208 (void) printf(gettext("action: Replace the faulted device, "
7208 7209 "or use 'zpool clear' to mark the device\n\trepaired.\n"));
7209 7210 break;
7210 7211
7211 7212 case ZPOOL_STATUS_FAULTED_DEV_NR:
7212 7213 (void) printf(gettext("status: One or more devices are "
7213 7214 "faulted in response to persistent errors. There are "
7214 7215 "insufficient replicas for the pool to\n\tcontinue "
7215 7216 "functioning.\n"));
7216 7217 (void) printf(gettext("action: Destroy and re-create the pool "
7217 7218 "from a backup source. Manually marking the device\n"
7218 7219 "\trepaired using 'zpool clear' may allow some data "
7219 7220 "to be recovered.\n"));
7220 7221 break;
7221 7222
7222 7223 case ZPOOL_STATUS_IO_FAILURE_MMP:
7223 7224 (void) printf(gettext("status: The pool is suspended because "
7224 7225 "multihost writes failed or were delayed;\n\tanother "
7225 7226 "system could import the pool undetected.\n"));
7226 7227 (void) printf(gettext("action: Make sure the pool's devices "
7227 7228 "are connected, then reboot your system and\n\timport the "
7228 7229 "pool.\n"));
7229 7230 break;
7230 7231
7231 7232 case ZPOOL_STATUS_IO_FAILURE_WAIT:
7232 7233 case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
7233 7234 (void) printf(gettext("status: One or more devices are "
7234 7235 "faulted in response to IO failures.\n"));
7235 7236 (void) printf(gettext("action: Make sure the affected devices "
7236 7237 "are connected, then run 'zpool clear'.\n"));
7237 7238 break;
7238 7239
7239 7240 case ZPOOL_STATUS_BAD_LOG:
7240 7241 (void) printf(gettext("status: An intent log record "
7241 7242 "could not be read.\n"
7242 7243 "\tWaiting for adminstrator intervention to fix the "
7243 7244 "faulted pool.\n"));
7244 7245 (void) printf(gettext("action: Either restore the affected "
7245 7246 "device(s) and run 'zpool online',\n"
7246 7247 "\tor ignore the intent log records by running "
7247 7248 "'zpool clear'.\n"));
7248 7249 break;
7249 7250
7250 7251 case ZPOOL_STATUS_ERRATA:
7251 7252 (void) printf(gettext("status: Errata #%d detected.\n"),
7252 7253 errata);
7253 7254
7254 7255 switch (errata) {
7255 7256 case ZPOOL_ERRATA_NONE:
7256 7257 break;
7257 7258
7258 7259 case ZPOOL_ERRATA_ZOL_2094_SCRUB:
7259 7260 (void) printf(gettext("action: To correct the issue "
7260 7261 "run 'zpool scrub'.\n"));
7261 7262 break;
7262 7263
7263 7264 case ZPOOL_ERRATA_ZOL_6845_ENCRYPTION:
7264 7265 (void) printf(gettext("\tExisting encrypted datasets "
7265 7266 "contain an on-disk incompatibility\n\twhich "
7266 7267 "needs to be corrected.\n"));
7267 7268 (void) printf(gettext("action: To correct the issue "
7268 7269 "backup existing encrypted datasets to new\n\t"
7269 7270 "encrypted datasets and destroy the old ones. "
7270 7271 "'zfs mount -o ro' can\n\tbe used to temporarily "
7271 7272 "mount existing encrypted datasets readonly.\n"));
7272 7273 break;
7273 7274
7274 7275 case ZPOOL_ERRATA_ZOL_8308_ENCRYPTION:
7275 7276 (void) printf(gettext("\tExisting encrypted datasets "
7276 7277 "contain an on-disk incompatibility\n\twhich "
7277 7278 "needs to be corrected.\n"));
7278 7279 (void) printf(gettext("action: To correct the issue "
7279 7280 "enable the bookmark_v2 feature and "
7280 7281 "backup\n\tany existing encrypted datasets to "
7281 7282 "new encrypted datasets and\n\tdestroy the old "
7282 7283 "ones. If this pool does not contain any\n\t"
7283 7284 "encrypted datasets, simply enable the "
7284 7285 "bookmark_v2 feature\n"));
7285 7286 break;
7286 7287
7287 7288 default:
7288 7289 /*
7289 7290 * All errata which allow the pool to be imported
7290 7291 * must contain an action message.
7291 7292 */
7292 7293 assert(0);
7293 7294 }
7294 7295 break;
7295 7296
7296 7297 default:
7297 7298 /*
7298 7299 * The remaining errors can't actually be generated, yet.
7299 7300 */
7300 7301 assert(reason == ZPOOL_STATUS_OK);
7301 7302 }
7302 7303
7303 7304 if (msgid != NULL)
7304 7305 (void) printf(gettext(" see: http://illumos.org/msg/%s\n"),
7305 7306 msgid);
7306 7307
7307 7308 if (config != NULL) {
7308 7309 uint64_t nerr;
7309 7310 nvlist_t **spares, **l2cache;
7310 7311 uint_t nspares, nl2cache;
7311 7312 pool_checkpoint_stat_t *pcs = NULL;
7312 7313 pool_scan_stat_t *ps = NULL;
7313 7314 pool_removal_stat_t *prs = NULL;
7314 7315
7315 7316 (void) nvlist_lookup_uint64_array(nvroot,
7316 7317 ZPOOL_CONFIG_CHECKPOINT_STATS, (uint64_t **)&pcs, &c);
7317 7318 (void) nvlist_lookup_uint64_array(nvroot,
7318 7319 ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
7319 7320 (void) nvlist_lookup_uint64_array(nvroot,
7320 7321 ZPOOL_CONFIG_REMOVAL_STATS, (uint64_t **)&prs, &c);
7321 7322
7322 7323 print_scan_status(ps);
7323 7324 print_checkpoint_scan_warning(ps, pcs);
7324 7325 print_removal_status(zhp, prs);
7325 7326 print_checkpoint_status(pcs);
7326 7327
7327 7328 cbp->cb_namewidth = max_width(zhp, nvroot, 0, 0,
7328 7329 cbp->cb_name_flags);
7329 7330 if (cbp->cb_namewidth < 10)
7330 7331 cbp->cb_namewidth = 10;
7331 7332
7332 7333 (void) printf(gettext("config:\n\n"));
7333 7334 (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"),
7334 7335 cbp->cb_namewidth, "NAME", "STATE", "READ", "WRITE",
7335 7336 "CKSUM");
7336 7337
7337 7338 if (cbp->cb_print_slow_ios)
7338 7339 (void) printf(" %5s", gettext("SLOW"));
7339 7340
7340 7341 print_status_config(zhp, cbp, zpool_get_name(zhp), nvroot, 0,
7341 7342 B_FALSE);
7342 7343
7343 7344 print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_BIAS_DEDUP);
7344 7345 print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_BIAS_SPECIAL);
7345 7346 print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_CLASS_LOGS);
7346 7347
7347 7348 if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
7348 7349 &l2cache, &nl2cache) == 0)
7349 7350 print_l2cache(zhp, cbp, l2cache, nl2cache);
7350 7351
7351 7352 if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
7352 7353 &spares, &nspares) == 0)
7353 7354 print_spares(zhp, cbp, spares, nspares);
7354 7355
7355 7356 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
7356 7357 &nerr) == 0) {
7357 7358 nvlist_t *nverrlist = NULL;
7358 7359
7359 7360 /*
7360 7361 * If the approximate error count is small, get a
7361 7362 * precise count by fetching the entire log and
7362 7363 * uniquifying the results.
7363 7364 */
7364 7365 if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
7365 7366 zpool_get_errlog(zhp, &nverrlist) == 0) {
7366 7367 nvpair_t *elem;
7367 7368
7368 7369 elem = NULL;
7369 7370 nerr = 0;
7370 7371 while ((elem = nvlist_next_nvpair(nverrlist,
7371 7372 elem)) != NULL) {
7372 7373 nerr++;
7373 7374 }
7374 7375 }
7375 7376 nvlist_free(nverrlist);
7376 7377
7377 7378 (void) printf("\n");
7378 7379
7379 7380 if (nerr == 0)
7380 7381 (void) printf(gettext("errors: No known data "
7381 7382 "errors\n"));
7382 7383 else if (!cbp->cb_verbose)
7383 7384 (void) printf(gettext("errors: %llu data "
7384 7385 "errors, use '-v' for a list\n"),
7385 7386 (u_longlong_t)nerr);
7386 7387 else
7387 7388 print_error_log(zhp);
7388 7389 }
7389 7390
7390 7391 if (cbp->cb_dedup_stats)
7391 7392 print_dedup_stats(config);
7392 7393 } else {
7393 7394 (void) printf(gettext("config: The configuration cannot be "
7394 7395 "determined.\n"));
7395 7396 }
7396 7397
7397 7398 return (0);
7398 7399 }
7399 7400
7400 7401 /*
7401 7402 * zpool status [-igLpPstvx] [-T d|u] [pool] ... [interval [count]]
7402 7403 *
7403 7404 * -i Display vdev initialization status.
7404 7405 * -g Display guid for individual vdev name.
7405 7406 * -L Follow links when resolving vdev path name.
7406 7407 * -p Display values in parsable (exact) format.
7407 7408 * -P Display full path for vdev name.
7408 7409 * -s Display slow IOs column.
7409 7410 * -v Display complete error logs
7410 7411 * -x Display only pools with potential problems
7411 7412 * -D Display dedup status (undocumented)
7412 7413 * -t Display vdev TRIM status.
7413 7414 * -T Display a timestamp in date(1) or Unix format
7414 7415 *
7415 7416 * Describes the health status of all pools or some subset.
7416 7417 */
7417 7418 int
7418 7419 zpool_do_status(int argc, char **argv)
7419 7420 {
7420 7421 int c;
7421 7422 int ret;
7422 7423 float interval = 0;
7423 7424 unsigned long count = 0;
7424 7425 status_cbdata_t cb = { 0 };
7425 7426
7426 7427 /* check options */
7427 7428 while ((c = getopt(argc, argv, "igLpPsvxDtT:")) != -1) {
7428 7429 switch (c) {
7429 7430 case 'i':
7430 7431 cb.cb_print_vdev_init = B_TRUE;
7431 7432 break;
7432 7433 case 'g':
7433 7434 cb.cb_name_flags |= VDEV_NAME_GUID;
7434 7435 break;
7435 7436 case 'L':
7436 7437 cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
7437 7438 break;
7438 7439 case 'p':
7439 7440 cb.cb_literal = B_TRUE;
7440 7441 break;
7441 7442 case 'P':
7442 7443 cb.cb_name_flags |= VDEV_NAME_PATH;
7443 7444 break;
7444 7445 case 's':
7445 7446 cb.cb_print_slow_ios = B_TRUE;
7446 7447 break;
7447 7448 case 'v':
7448 7449 cb.cb_verbose = B_TRUE;
7449 7450 break;
7450 7451 case 'x':
7451 7452 cb.cb_explain = B_TRUE;
7452 7453 break;
7453 7454 case 'D':
7454 7455 cb.cb_dedup_stats = B_TRUE;
7455 7456 break;
7456 7457 case 't':
7457 7458 cb.cb_print_vdev_trim = B_TRUE;
7458 7459 break;
7459 7460 case 'T':
7460 7461 get_timestamp_arg(*optarg);
7461 7462 break;
7462 7463 case '?':
7463 7464 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
7464 7465 optopt);
7465 7466 usage(B_FALSE);
7466 7467 }
7467 7468 }
7468 7469
7469 7470 argc -= optind;
7470 7471 argv += optind;
7471 7472
7472 7473 get_interval_count(&argc, argv, &interval, &count);
7473 7474
7474 7475 if (argc == 0)
7475 7476 cb.cb_allpools = B_TRUE;
7476 7477
7477 7478 cb.cb_first = B_TRUE;
7478 7479 cb.cb_print_status = B_TRUE;
7479 7480
7480 7481 for (;;) {
7481 7482 if (timestamp_fmt != NODATE)
7482 7483 print_timestamp(timestamp_fmt);
7483 7484
7484 7485 ret = for_each_pool(argc, argv, B_TRUE, NULL,
7485 7486 status_callback, &cb);
7486 7487
7487 7488 if (argc == 0 && cb.cb_count == 0)
7488 7489 (void) printf(gettext("no pools available\n"));
7489 7490 else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
7490 7491 (void) printf(gettext("all pools are healthy\n"));
7491 7492
7492 7493 if (ret != 0)
7493 7494 return (ret);
7494 7495
7495 7496 if (interval == 0)
7496 7497 break;
7497 7498
7498 7499 if (count != 0 && --count == 0)
7499 7500 break;
7500 7501
7501 7502 (void) fsleep(interval);
7502 7503 }
7503 7504
7504 7505 return (0);
7505 7506 }
7506 7507
7507 7508 typedef struct upgrade_cbdata {
7508 7509 int cb_first;
7509 7510 int cb_argc;
7510 7511 uint64_t cb_version;
7511 7512 char **cb_argv;
7512 7513 } upgrade_cbdata_t;
7513 7514
7514 7515 static int
7515 7516 upgrade_version(zpool_handle_t *zhp, uint64_t version)
7516 7517 {
7517 7518 int ret;
7518 7519 nvlist_t *config;
7519 7520 uint64_t oldversion;
7520 7521
7521 7522 config = zpool_get_config(zhp, NULL);
7522 7523 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
7523 7524 &oldversion) == 0);
7524 7525
7525 7526 assert(SPA_VERSION_IS_SUPPORTED(oldversion));
7526 7527 assert(oldversion < version);
7527 7528
7528 7529 ret = zpool_upgrade(zhp, version);
7529 7530 if (ret != 0)
7530 7531 return (ret);
7531 7532
7532 7533 if (version >= SPA_VERSION_FEATURES) {
7533 7534 (void) printf(gettext("Successfully upgraded "
7534 7535 "'%s' from version %llu to feature flags.\n"),
7535 7536 zpool_get_name(zhp), oldversion);
7536 7537 } else {
7537 7538 (void) printf(gettext("Successfully upgraded "
7538 7539 "'%s' from version %llu to version %llu.\n"),
7539 7540 zpool_get_name(zhp), oldversion, version);
7540 7541 }
7541 7542
7542 7543 return (0);
7543 7544 }
7544 7545
7545 7546 static int
7546 7547 upgrade_enable_all(zpool_handle_t *zhp, int *countp)
7547 7548 {
7548 7549 int i, ret, count;
7549 7550 boolean_t firstff = B_TRUE;
7550 7551 nvlist_t *enabled = zpool_get_features(zhp);
7551 7552
7552 7553 count = 0;
7553 7554 for (i = 0; i < SPA_FEATURES; i++) {
7554 7555 const char *fname = spa_feature_table[i].fi_uname;
7555 7556 const char *fguid = spa_feature_table[i].fi_guid;
7556 7557 if (!nvlist_exists(enabled, fguid)) {
7557 7558 char *propname;
7558 7559 verify(-1 != asprintf(&propname, "feature@%s", fname));
7559 7560 ret = zpool_set_prop(zhp, propname,
7560 7561 ZFS_FEATURE_ENABLED);
7561 7562 if (ret != 0) {
7562 7563 free(propname);
7563 7564 return (ret);
7564 7565 }
7565 7566 count++;
7566 7567
7567 7568 if (firstff) {
7568 7569 (void) printf(gettext("Enabled the "
7569 7570 "following features on '%s':\n"),
7570 7571 zpool_get_name(zhp));
7571 7572 firstff = B_FALSE;
7572 7573 }
7573 7574 (void) printf(gettext(" %s\n"), fname);
7574 7575 free(propname);
7575 7576 }
7576 7577 }
7577 7578
7578 7579 if (countp != NULL)
7579 7580 *countp = count;
7580 7581 return (0);
7581 7582 }
7582 7583
7583 7584 static int
7584 7585 upgrade_cb(zpool_handle_t *zhp, void *arg)
7585 7586 {
7586 7587 upgrade_cbdata_t *cbp = arg;
7587 7588 nvlist_t *config;
7588 7589 uint64_t version;
7589 7590 boolean_t printnl = B_FALSE;
7590 7591 int ret;
7591 7592
7592 7593 config = zpool_get_config(zhp, NULL);
7593 7594 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
7594 7595 &version) == 0);
7595 7596
7596 7597 assert(SPA_VERSION_IS_SUPPORTED(version));
7597 7598
7598 7599 if (version < cbp->cb_version) {
7599 7600 cbp->cb_first = B_FALSE;
7600 7601 ret = upgrade_version(zhp, cbp->cb_version);
7601 7602 if (ret != 0)
7602 7603 return (ret);
7603 7604 printnl = B_TRUE;
7604 7605
7605 7606 /*
7606 7607 * If they did "zpool upgrade -a", then we could
7607 7608 * be doing ioctls to different pools. We need
7608 7609 * to log this history once to each pool, and bypass
7609 7610 * the normal history logging that happens in main().
7610 7611 */
7611 7612 (void) zpool_log_history(g_zfs, history_str);
7612 7613 log_history = B_FALSE;
7613 7614 }
7614 7615
7615 7616 if (cbp->cb_version >= SPA_VERSION_FEATURES) {
7616 7617 int count;
7617 7618 ret = upgrade_enable_all(zhp, &count);
7618 7619 if (ret != 0)
7619 7620 return (ret);
7620 7621
7621 7622 if (count > 0) {
7622 7623 cbp->cb_first = B_FALSE;
7623 7624 printnl = B_TRUE;
7624 7625 }
7625 7626 }
7626 7627
7627 7628 if (printnl) {
7628 7629 (void) printf(gettext("\n"));
7629 7630 }
7630 7631
7631 7632 return (0);
7632 7633 }
7633 7634
7634 7635 static int
7635 7636 upgrade_list_older_cb(zpool_handle_t *zhp, void *arg)
7636 7637 {
7637 7638 upgrade_cbdata_t *cbp = arg;
7638 7639 nvlist_t *config;
7639 7640 uint64_t version;
7640 7641
7641 7642 config = zpool_get_config(zhp, NULL);
7642 7643 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
7643 7644 &version) == 0);
7644 7645
7645 7646 assert(SPA_VERSION_IS_SUPPORTED(version));
7646 7647
7647 7648 if (version < SPA_VERSION_FEATURES) {
7648 7649 if (cbp->cb_first) {
7649 7650 (void) printf(gettext("The following pools are "
7650 7651 "formatted with legacy version numbers and can\n"
7651 7652 "be upgraded to use feature flags. After "
7652 7653 "being upgraded, these pools\nwill no "
7653 7654 "longer be accessible by software that does not "
7654 7655 "support feature\nflags.\n\n"));
7655 7656 (void) printf(gettext("VER POOL\n"));
7656 7657 (void) printf(gettext("--- ------------\n"));
7657 7658 cbp->cb_first = B_FALSE;
7658 7659 }
7659 7660
7660 7661 (void) printf("%2llu %s\n", (u_longlong_t)version,
7661 7662 zpool_get_name(zhp));
7662 7663 }
7663 7664
7664 7665 return (0);
7665 7666 }
7666 7667
7667 7668 static int
7668 7669 upgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg)
7669 7670 {
7670 7671 upgrade_cbdata_t *cbp = arg;
7671 7672 nvlist_t *config;
7672 7673 uint64_t version;
7673 7674
7674 7675 config = zpool_get_config(zhp, NULL);
7675 7676 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
7676 7677 &version) == 0);
7677 7678
7678 7679 if (version >= SPA_VERSION_FEATURES) {
7679 7680 int i;
7680 7681 boolean_t poolfirst = B_TRUE;
7681 7682 nvlist_t *enabled = zpool_get_features(zhp);
7682 7683
7683 7684 for (i = 0; i < SPA_FEATURES; i++) {
7684 7685 const char *fguid = spa_feature_table[i].fi_guid;
7685 7686 const char *fname = spa_feature_table[i].fi_uname;
7686 7687 if (!nvlist_exists(enabled, fguid)) {
7687 7688 if (cbp->cb_first) {
7688 7689 (void) printf(gettext("\nSome "
7689 7690 "supported features are not "
7690 7691 "enabled on the following pools. "
7691 7692 "Once a\nfeature is enabled the "
7692 7693 "pool may become incompatible with "
7693 7694 "software\nthat does not support "
7694 7695 "the feature. See "
7695 7696 "zpool-features(5) for "
7696 7697 "details.\n\n"));
7697 7698 (void) printf(gettext("POOL "
7698 7699 "FEATURE\n"));
7699 7700 (void) printf(gettext("------"
7700 7701 "---------\n"));
7701 7702 cbp->cb_first = B_FALSE;
7702 7703 }
7703 7704
7704 7705 if (poolfirst) {
7705 7706 (void) printf(gettext("%s\n"),
7706 7707 zpool_get_name(zhp));
7707 7708 poolfirst = B_FALSE;
7708 7709 }
7709 7710
7710 7711 (void) printf(gettext(" %s\n"), fname);
7711 7712 }
7712 7713 }
7713 7714 }
7714 7715
7715 7716 return (0);
7716 7717 }
7717 7718
7718 7719 /* ARGSUSED */
7719 7720 static int
7720 7721 upgrade_one(zpool_handle_t *zhp, void *data)
7721 7722 {
7722 7723 boolean_t printnl = B_FALSE;
7723 7724 upgrade_cbdata_t *cbp = data;
7724 7725 uint64_t cur_version;
7725 7726 int ret;
7726 7727
7727 7728 if (strcmp("log", zpool_get_name(zhp)) == 0) {
7728 7729 (void) printf(gettext("'log' is now a reserved word\n"
7729 7730 "Pool 'log' must be renamed using export and import"
7730 7731 " to upgrade.\n"));
7731 7732 return (1);
7732 7733 }
7733 7734
7734 7735 cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
7735 7736 if (cur_version > cbp->cb_version) {
7736 7737 (void) printf(gettext("Pool '%s' is already formatted "
7737 7738 "using more current version '%llu'.\n\n"),
7738 7739 zpool_get_name(zhp), cur_version);
7739 7740 return (0);
7740 7741 }
7741 7742
7742 7743 if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) {
7743 7744 (void) printf(gettext("Pool '%s' is already formatted "
7744 7745 "using version %llu.\n\n"), zpool_get_name(zhp),
7745 7746 cbp->cb_version);
7746 7747 return (0);
7747 7748 }
7748 7749
7749 7750 if (cur_version != cbp->cb_version) {
7750 7751 printnl = B_TRUE;
7751 7752 ret = upgrade_version(zhp, cbp->cb_version);
7752 7753 if (ret != 0)
7753 7754 return (ret);
7754 7755 }
7755 7756
7756 7757 if (cbp->cb_version >= SPA_VERSION_FEATURES) {
7757 7758 int count = 0;
7758 7759 ret = upgrade_enable_all(zhp, &count);
7759 7760 if (ret != 0)
7760 7761 return (ret);
7761 7762
7762 7763 if (count != 0) {
7763 7764 printnl = B_TRUE;
7764 7765 } else if (cur_version == SPA_VERSION) {
7765 7766 (void) printf(gettext("Pool '%s' already has all "
7766 7767 "supported features enabled.\n"),
7767 7768 zpool_get_name(zhp));
7768 7769 }
7769 7770 }
7770 7771
7771 7772 if (printnl) {
7772 7773 (void) printf(gettext("\n"));
7773 7774 }
7774 7775
7775 7776 return (0);
7776 7777 }
7777 7778
7778 7779 /*
7779 7780 * zpool upgrade
7780 7781 * zpool upgrade -v
7781 7782 * zpool upgrade [-V version] <-a | pool ...>
7782 7783 *
7783 7784 * With no arguments, display downrev'd ZFS pool available for upgrade.
7784 7785 * Individual pools can be upgraded by specifying the pool, and '-a' will
7785 7786 * upgrade all pools.
7786 7787 */
7787 7788 int
7788 7789 zpool_do_upgrade(int argc, char **argv)
7789 7790 {
7790 7791 int c;
7791 7792 upgrade_cbdata_t cb = { 0 };
7792 7793 int ret = 0;
7793 7794 boolean_t showversions = B_FALSE;
7794 7795 boolean_t upgradeall = B_FALSE;
7795 7796 char *end;
7796 7797
7797 7798
7798 7799 /* check options */
7799 7800 while ((c = getopt(argc, argv, ":avV:")) != -1) {
7800 7801 switch (c) {
7801 7802 case 'a':
7802 7803 upgradeall = B_TRUE;
7803 7804 break;
7804 7805 case 'v':
7805 7806 showversions = B_TRUE;
7806 7807 break;
7807 7808 case 'V':
7808 7809 cb.cb_version = strtoll(optarg, &end, 10);
7809 7810 if (*end != '\0' ||
7810 7811 !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) {
7811 7812 (void) fprintf(stderr,
7812 7813 gettext("invalid version '%s'\n"), optarg);
7813 7814 usage(B_FALSE);
7814 7815 }
7815 7816 break;
7816 7817 case ':':
7817 7818 (void) fprintf(stderr, gettext("missing argument for "
7818 7819 "'%c' option\n"), optopt);
7819 7820 usage(B_FALSE);
7820 7821 break;
7821 7822 case '?':
7822 7823 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
7823 7824 optopt);
7824 7825 usage(B_FALSE);
7825 7826 }
7826 7827 }
7827 7828
7828 7829 cb.cb_argc = argc;
7829 7830 cb.cb_argv = argv;
7830 7831 argc -= optind;
7831 7832 argv += optind;
7832 7833
7833 7834 if (cb.cb_version == 0) {
7834 7835 cb.cb_version = SPA_VERSION;
7835 7836 } else if (!upgradeall && argc == 0) {
7836 7837 (void) fprintf(stderr, gettext("-V option is "
7837 7838 "incompatible with other arguments\n"));
7838 7839 usage(B_FALSE);
7839 7840 }
7840 7841
7841 7842 if (showversions) {
7842 7843 if (upgradeall || argc != 0) {
7843 7844 (void) fprintf(stderr, gettext("-v option is "
7844 7845 "incompatible with other arguments\n"));
7845 7846 usage(B_FALSE);
7846 7847 }
7847 7848 } else if (upgradeall) {
7848 7849 if (argc != 0) {
7849 7850 (void) fprintf(stderr, gettext("-a option should not "
7850 7851 "be used along with a pool name\n"));
7851 7852 usage(B_FALSE);
7852 7853 }
7853 7854 }
7854 7855
7855 7856 (void) printf(gettext("This system supports ZFS pool feature "
7856 7857 "flags.\n\n"));
7857 7858 if (showversions) {
7858 7859 int i;
7859 7860
7860 7861 (void) printf(gettext("The following features are "
7861 7862 "supported:\n\n"));
7862 7863 (void) printf(gettext("FEAT DESCRIPTION\n"));
7863 7864 (void) printf("----------------------------------------------"
7864 7865 "---------------\n");
7865 7866 for (i = 0; i < SPA_FEATURES; i++) {
7866 7867 zfeature_info_t *fi = &spa_feature_table[i];
7867 7868 const char *ro =
7868 7869 (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
7869 7870 " (read-only compatible)" : "";
7870 7871
7871 7872 (void) printf("%-37s%s\n", fi->fi_uname, ro);
7872 7873 (void) printf(" %s\n", fi->fi_desc);
7873 7874 }
7874 7875 (void) printf("\n");
7875 7876
7876 7877 (void) printf(gettext("The following legacy versions are also "
7877 7878 "supported:\n\n"));
7878 7879 (void) printf(gettext("VER DESCRIPTION\n"));
7879 7880 (void) printf("--- -----------------------------------------"
7880 7881 "---------------\n");
7881 7882 (void) printf(gettext(" 1 Initial ZFS version\n"));
7882 7883 (void) printf(gettext(" 2 Ditto blocks "
7883 7884 "(replicated metadata)\n"));
7884 7885 (void) printf(gettext(" 3 Hot spares and double parity "
7885 7886 "RAID-Z\n"));
7886 7887 (void) printf(gettext(" 4 zpool history\n"));
7887 7888 (void) printf(gettext(" 5 Compression using the gzip "
7888 7889 "algorithm\n"));
7889 7890 (void) printf(gettext(" 6 bootfs pool property\n"));
7890 7891 (void) printf(gettext(" 7 Separate intent log devices\n"));
7891 7892 (void) printf(gettext(" 8 Delegated administration\n"));
7892 7893 (void) printf(gettext(" 9 refquota and refreservation "
7893 7894 "properties\n"));
7894 7895 (void) printf(gettext(" 10 Cache devices\n"));
7895 7896 (void) printf(gettext(" 11 Improved scrub performance\n"));
7896 7897 (void) printf(gettext(" 12 Snapshot properties\n"));
7897 7898 (void) printf(gettext(" 13 snapused property\n"));
7898 7899 (void) printf(gettext(" 14 passthrough-x aclinherit\n"));
7899 7900 (void) printf(gettext(" 15 user/group space accounting\n"));
7900 7901 (void) printf(gettext(" 16 stmf property support\n"));
7901 7902 (void) printf(gettext(" 17 Triple-parity RAID-Z\n"));
7902 7903 (void) printf(gettext(" 18 Snapshot user holds\n"));
7903 7904 (void) printf(gettext(" 19 Log device removal\n"));
7904 7905 (void) printf(gettext(" 20 Compression using zle "
7905 7906 "(zero-length encoding)\n"));
7906 7907 (void) printf(gettext(" 21 Deduplication\n"));
7907 7908 (void) printf(gettext(" 22 Received properties\n"));
7908 7909 (void) printf(gettext(" 23 Slim ZIL\n"));
7909 7910 (void) printf(gettext(" 24 System attributes\n"));
7910 7911 (void) printf(gettext(" 25 Improved scrub stats\n"));
7911 7912 (void) printf(gettext(" 26 Improved snapshot deletion "
7912 7913 "performance\n"));
7913 7914 (void) printf(gettext(" 27 Improved snapshot creation "
7914 7915 "performance\n"));
7915 7916 (void) printf(gettext(" 28 Multiple vdev replacements\n"));
7916 7917 (void) printf(gettext("\nFor more information on a particular "
7917 7918 "version, including supported releases,\n"));
7918 7919 (void) printf(gettext("see the ZFS Administration Guide.\n\n"));
7919 7920 } else if (argc == 0 && upgradeall) {
7920 7921 cb.cb_first = B_TRUE;
7921 7922 ret = zpool_iter(g_zfs, upgrade_cb, &cb);
7922 7923 if (ret == 0 && cb.cb_first) {
7923 7924 if (cb.cb_version == SPA_VERSION) {
7924 7925 (void) printf(gettext("All pools are already "
7925 7926 "formatted using feature flags.\n\n"));
7926 7927 (void) printf(gettext("Every feature flags "
7927 7928 "pool already has all supported features "
7928 7929 "enabled.\n"));
7929 7930 } else {
7930 7931 (void) printf(gettext("All pools are already "
7931 7932 "formatted with version %llu or higher.\n"),
7932 7933 cb.cb_version);
7933 7934 }
7934 7935 }
7935 7936 } else if (argc == 0) {
7936 7937 cb.cb_first = B_TRUE;
7937 7938 ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb);
7938 7939 assert(ret == 0);
7939 7940
7940 7941 if (cb.cb_first) {
7941 7942 (void) printf(gettext("All pools are formatted "
7942 7943 "using feature flags.\n\n"));
7943 7944 } else {
7944 7945 (void) printf(gettext("\nUse 'zpool upgrade -v' "
7945 7946 "for a list of available legacy versions.\n"));
7946 7947 }
7947 7948
7948 7949 cb.cb_first = B_TRUE;
7949 7950 ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb);
7950 7951 assert(ret == 0);
7951 7952
7952 7953 if (cb.cb_first) {
7953 7954 (void) printf(gettext("Every feature flags pool has "
7954 7955 "all supported features enabled.\n"));
7955 7956 } else {
7956 7957 (void) printf(gettext("\n"));
7957 7958 }
7958 7959 } else {
7959 7960 ret = for_each_pool(argc, argv, B_FALSE, NULL,
7960 7961 upgrade_one, &cb);
7961 7962 }
7962 7963
7963 7964 return (ret);
7964 7965 }
7965 7966
7966 7967 typedef struct hist_cbdata {
7967 7968 boolean_t first;
7968 7969 boolean_t longfmt;
7969 7970 boolean_t internal;
7970 7971 } hist_cbdata_t;
7971 7972
7972 7973 static void
7973 7974 print_history_records(nvlist_t *nvhis, hist_cbdata_t *cb)
7974 7975 {
7975 7976 nvlist_t **records;
7976 7977 uint_t numrecords;
7977 7978 int i;
7978 7979
7979 7980 verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
7980 7981 &records, &numrecords) == 0);
7981 7982 for (i = 0; i < numrecords; i++) {
7982 7983 nvlist_t *rec = records[i];
7983 7984 char tbuf[30] = "";
7984 7985
7985 7986 if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
7986 7987 time_t tsec;
7987 7988 struct tm t;
7988 7989
7989 7990 tsec = fnvlist_lookup_uint64(records[i],
7990 7991 ZPOOL_HIST_TIME);
7991 7992 (void) localtime_r(&tsec, &t);
7992 7993 (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
7993 7994 }
7994 7995
7995 7996 if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
7996 7997 (void) printf("%s %s", tbuf,
7997 7998 fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
7998 7999 } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
7999 8000 int ievent =
8000 8001 fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
8001 8002 if (!cb->internal)
8002 8003 continue;
8003 8004 if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
8004 8005 (void) printf("%s unrecognized record:\n",
8005 8006 tbuf);
8006 8007 dump_nvlist(rec, 4);
8007 8008 continue;
8008 8009 }
8009 8010 (void) printf("%s [internal %s txg:%lld] %s", tbuf,
8010 8011 zfs_history_event_names[ievent],
8011 8012 fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
8012 8013 fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
8013 8014 } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
8014 8015 if (!cb->internal)
8015 8016 continue;
8016 8017 (void) printf("%s [txg:%lld] %s", tbuf,
8017 8018 fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
8018 8019 fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
8019 8020 if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
8020 8021 (void) printf(" %s (%llu)",
8021 8022 fnvlist_lookup_string(rec,
8022 8023 ZPOOL_HIST_DSNAME),
8023 8024 fnvlist_lookup_uint64(rec,
8024 8025 ZPOOL_HIST_DSID));
8025 8026 }
8026 8027 (void) printf(" %s", fnvlist_lookup_string(rec,
8027 8028 ZPOOL_HIST_INT_STR));
8028 8029 } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
8029 8030 if (!cb->internal)
8030 8031 continue;
8031 8032 (void) printf("%s ioctl %s\n", tbuf,
8032 8033 fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
8033 8034 if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
8034 8035 (void) printf(" input:\n");
8035 8036 dump_nvlist(fnvlist_lookup_nvlist(rec,
8036 8037 ZPOOL_HIST_INPUT_NVL), 8);
8037 8038 }
8038 8039 if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
8039 8040 (void) printf(" output:\n");
8040 8041 dump_nvlist(fnvlist_lookup_nvlist(rec,
8041 8042 ZPOOL_HIST_OUTPUT_NVL), 8);
8042 8043 }
8043 8044 if (nvlist_exists(rec, ZPOOL_HIST_ERRNO)) {
8044 8045 (void) printf(" errno: %lld\n",
8045 8046 fnvlist_lookup_int64(rec,
8046 8047 ZPOOL_HIST_ERRNO));
8047 8048 }
8048 8049 } else {
8049 8050 if (!cb->internal)
8050 8051 continue;
8051 8052 (void) printf("%s unrecognized record:\n", tbuf);
8052 8053 dump_nvlist(rec, 4);
8053 8054 }
8054 8055
8055 8056 if (!cb->longfmt) {
8056 8057 (void) printf("\n");
8057 8058 continue;
8058 8059 }
8059 8060 (void) printf(" [");
8060 8061 if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
8061 8062 uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
8062 8063 struct passwd *pwd = getpwuid(who);
8063 8064 (void) printf("user %d ", (int)who);
8064 8065 if (pwd != NULL)
8065 8066 (void) printf("(%s) ", pwd->pw_name);
8066 8067 }
8067 8068 if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
8068 8069 (void) printf("on %s",
8069 8070 fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
8070 8071 }
8071 8072 if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
8072 8073 (void) printf(":%s",
8073 8074 fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
8074 8075 }
8075 8076 (void) printf("]");
8076 8077 (void) printf("\n");
8077 8078 }
8078 8079 }
8079 8080
8080 8081 /*
8081 8082 * Print out the command history for a specific pool.
8082 8083 */
8083 8084 static int
8084 8085 get_history_one(zpool_handle_t *zhp, void *data)
8085 8086 {
8086 8087 nvlist_t *nvhis;
8087 8088 int ret;
8088 8089 hist_cbdata_t *cb = (hist_cbdata_t *)data;
8089 8090 uint64_t off = 0;
8090 8091 boolean_t eof = B_FALSE;
8091 8092
8092 8093 cb->first = B_FALSE;
8093 8094
8094 8095 (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
8095 8096
8096 8097 while (!eof) {
8097 8098 if ((ret = zpool_get_history(zhp, &nvhis, &off, &eof)) != 0)
8098 8099 return (ret);
8099 8100
8100 8101 print_history_records(nvhis, cb);
8101 8102 nvlist_free(nvhis);
8102 8103 }
8103 8104 (void) printf("\n");
8104 8105
8105 8106 return (ret);
8106 8107 }
8107 8108
8108 8109 /*
8109 8110 * zpool history <pool>
8110 8111 *
8111 8112 * Displays the history of commands that modified pools.
8112 8113 */
8113 8114 int
8114 8115 zpool_do_history(int argc, char **argv)
8115 8116 {
8116 8117 hist_cbdata_t cbdata = { 0 };
8117 8118 int ret;
8118 8119 int c;
8119 8120
8120 8121 cbdata.first = B_TRUE;
8121 8122 /* check options */
8122 8123 while ((c = getopt(argc, argv, "li")) != -1) {
8123 8124 switch (c) {
8124 8125 case 'l':
8125 8126 cbdata.longfmt = B_TRUE;
8126 8127 break;
8127 8128 case 'i':
8128 8129 cbdata.internal = B_TRUE;
8129 8130 break;
8130 8131 case '?':
8131 8132 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
8132 8133 optopt);
8133 8134 usage(B_FALSE);
8134 8135 }
8135 8136 }
8136 8137 argc -= optind;
8137 8138 argv += optind;
8138 8139
8139 8140 ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one,
8140 8141 &cbdata);
8141 8142
8142 8143 if (argc == 0 && cbdata.first == B_TRUE) {
8143 8144 (void) printf(gettext("no pools available\n"));
8144 8145 return (0);
8145 8146 }
8146 8147
8147 8148 return (ret);
8148 8149 }
8149 8150
8150 8151 static int
8151 8152 get_callback(zpool_handle_t *zhp, void *data)
8152 8153 {
8153 8154 zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
8154 8155 char value[MAXNAMELEN];
8155 8156 zprop_source_t srctype;
8156 8157 zprop_list_t *pl;
8157 8158
8158 8159 for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
8159 8160
8160 8161 /*
8161 8162 * Skip the special fake placeholder. This will also skip
8162 8163 * over the name property when 'all' is specified.
8163 8164 */
8164 8165 if (pl->pl_prop == ZPOOL_PROP_NAME &&
8165 8166 pl == cbp->cb_proplist)
8166 8167 continue;
8167 8168
8168 8169 if (pl->pl_prop == ZPROP_INVAL &&
8169 8170 (zpool_prop_feature(pl->pl_user_prop) ||
8170 8171 zpool_prop_unsupported(pl->pl_user_prop))) {
8171 8172 srctype = ZPROP_SRC_LOCAL;
8172 8173
8173 8174 if (zpool_prop_get_feature(zhp, pl->pl_user_prop,
8174 8175 value, sizeof (value)) == 0) {
8175 8176 zprop_print_one_property(zpool_get_name(zhp),
8176 8177 cbp, pl->pl_user_prop, value, srctype,
8177 8178 NULL, NULL);
8178 8179 }
8179 8180 } else {
8180 8181 if (zpool_get_prop(zhp, pl->pl_prop, value,
8181 8182 sizeof (value), &srctype, cbp->cb_literal) != 0)
8182 8183 continue;
8183 8184
8184 8185 zprop_print_one_property(zpool_get_name(zhp), cbp,
8185 8186 zpool_prop_to_name(pl->pl_prop), value, srctype,
8186 8187 NULL, NULL);
8187 8188 }
8188 8189 }
8189 8190 return (0);
8190 8191 }
8191 8192
8192 8193 /*
8193 8194 * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ...
8194 8195 *
8195 8196 * -H Scripted mode. Don't display headers, and separate properties
8196 8197 * by a single tab.
8197 8198 * -o List of columns to display. Defaults to
8198 8199 * "name,property,value,source".
8199 8200 * -p Diplay values in parsable (exact) format.
8200 8201 *
8201 8202 * Get properties of pools in the system. Output space statistics
8202 8203 * for each one as well as other attributes.
8203 8204 */
8204 8205 int
8205 8206 zpool_do_get(int argc, char **argv)
8206 8207 {
8207 8208 zprop_get_cbdata_t cb = { 0 };
8208 8209 zprop_list_t fake_name = { 0 };
8209 8210 int ret;
8210 8211 int c, i;
8211 8212 char *value;
8212 8213
8213 8214 cb.cb_first = B_TRUE;
8214 8215
8215 8216 /*
8216 8217 * Set up default columns and sources.
8217 8218 */
8218 8219 cb.cb_sources = ZPROP_SRC_ALL;
8219 8220 cb.cb_columns[0] = GET_COL_NAME;
8220 8221 cb.cb_columns[1] = GET_COL_PROPERTY;
8221 8222 cb.cb_columns[2] = GET_COL_VALUE;
8222 8223 cb.cb_columns[3] = GET_COL_SOURCE;
8223 8224 cb.cb_type = ZFS_TYPE_POOL;
8224 8225
8225 8226 /* check options */
8226 8227 while ((c = getopt(argc, argv, ":Hpo:")) != -1) {
8227 8228 switch (c) {
8228 8229 case 'p':
8229 8230 cb.cb_literal = B_TRUE;
8230 8231 break;
8231 8232 case 'H':
8232 8233 cb.cb_scripted = B_TRUE;
8233 8234 break;
8234 8235 case 'o':
8235 8236 bzero(&cb.cb_columns, sizeof (cb.cb_columns));
8236 8237 i = 0;
8237 8238 while (*optarg != '\0') {
8238 8239 static char *col_subopts[] =
8239 8240 { "name", "property", "value", "source",
8240 8241 "all", NULL };
8241 8242
8242 8243 if (i == ZFS_GET_NCOLS) {
8243 8244 (void) fprintf(stderr, gettext("too "
8244 8245 "many fields given to -o "
8245 8246 "option\n"));
8246 8247 usage(B_FALSE);
8247 8248 }
8248 8249
8249 8250 switch (getsubopt(&optarg, col_subopts,
8250 8251 &value)) {
8251 8252 case 0:
8252 8253 cb.cb_columns[i++] = GET_COL_NAME;
8253 8254 break;
8254 8255 case 1:
8255 8256 cb.cb_columns[i++] = GET_COL_PROPERTY;
8256 8257 break;
8257 8258 case 2:
8258 8259 cb.cb_columns[i++] = GET_COL_VALUE;
8259 8260 break;
8260 8261 case 3:
8261 8262 cb.cb_columns[i++] = GET_COL_SOURCE;
8262 8263 break;
8263 8264 case 4:
8264 8265 if (i > 0) {
8265 8266 (void) fprintf(stderr,
8266 8267 gettext("\"all\" conflicts "
8267 8268 "with specific fields "
8268 8269 "given to -o option\n"));
8269 8270 usage(B_FALSE);
8270 8271 }
8271 8272 cb.cb_columns[0] = GET_COL_NAME;
8272 8273 cb.cb_columns[1] = GET_COL_PROPERTY;
8273 8274 cb.cb_columns[2] = GET_COL_VALUE;
8274 8275 cb.cb_columns[3] = GET_COL_SOURCE;
8275 8276 i = ZFS_GET_NCOLS;
8276 8277 break;
8277 8278 default:
8278 8279 (void) fprintf(stderr,
8279 8280 gettext("invalid column name "
8280 8281 "'%s'\n"), value);
8281 8282 usage(B_FALSE);
8282 8283 }
8283 8284 }
8284 8285 break;
8285 8286 case '?':
8286 8287 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
8287 8288 optopt);
8288 8289 usage(B_FALSE);
8289 8290 }
8290 8291 }
8291 8292
8292 8293 argc -= optind;
8293 8294 argv += optind;
8294 8295
8295 8296 if (argc < 1) {
8296 8297 (void) fprintf(stderr, gettext("missing property "
8297 8298 "argument\n"));
8298 8299 usage(B_FALSE);
8299 8300 }
8300 8301
8301 8302 if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist,
8302 8303 ZFS_TYPE_POOL) != 0)
8303 8304 usage(B_FALSE);
8304 8305
8305 8306 argc--;
8306 8307 argv++;
8307 8308
8308 8309 if (cb.cb_proplist != NULL) {
8309 8310 fake_name.pl_prop = ZPOOL_PROP_NAME;
8310 8311 fake_name.pl_width = strlen(gettext("NAME"));
8311 8312 fake_name.pl_next = cb.cb_proplist;
8312 8313 cb.cb_proplist = &fake_name;
8313 8314 }
8314 8315
8315 8316 ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
8316 8317 get_callback, &cb);
8317 8318
8318 8319 if (cb.cb_proplist == &fake_name)
8319 8320 zprop_free_list(fake_name.pl_next);
8320 8321 else
8321 8322 zprop_free_list(cb.cb_proplist);
8322 8323
8323 8324 return (ret);
8324 8325 }
8325 8326
8326 8327 typedef struct set_cbdata {
8327 8328 char *cb_propname;
8328 8329 char *cb_value;
8329 8330 boolean_t cb_any_successful;
8330 8331 } set_cbdata_t;
8331 8332
8332 8333 int
8333 8334 set_callback(zpool_handle_t *zhp, void *data)
8334 8335 {
8335 8336 int error;
8336 8337 set_cbdata_t *cb = (set_cbdata_t *)data;
8337 8338
8338 8339 error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
8339 8340
8340 8341 if (!error)
8341 8342 cb->cb_any_successful = B_TRUE;
8342 8343
8343 8344 return (error);
8344 8345 }
8345 8346
8346 8347 int
8347 8348 zpool_do_set(int argc, char **argv)
8348 8349 {
8349 8350 set_cbdata_t cb = { 0 };
8350 8351 int error;
8351 8352
8352 8353 if (argc > 1 && argv[1][0] == '-') {
8353 8354 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
8354 8355 argv[1][1]);
8355 8356 usage(B_FALSE);
8356 8357 }
8357 8358
8358 8359 if (argc < 2) {
8359 8360 (void) fprintf(stderr, gettext("missing property=value "
8360 8361 "argument\n"));
8361 8362 usage(B_FALSE);
8362 8363 }
8363 8364
8364 8365 if (argc < 3) {
8365 8366 (void) fprintf(stderr, gettext("missing pool name\n"));
8366 8367 usage(B_FALSE);
8367 8368 }
8368 8369
8369 8370 if (argc > 3) {
8370 8371 (void) fprintf(stderr, gettext("too many pool names\n"));
8371 8372 usage(B_FALSE);
8372 8373 }
8373 8374
8374 8375 cb.cb_propname = argv[1];
8375 8376 cb.cb_value = strchr(cb.cb_propname, '=');
8376 8377 if (cb.cb_value == NULL) {
8377 8378 (void) fprintf(stderr, gettext("missing value in "
8378 8379 "property=value argument\n"));
8379 8380 usage(B_FALSE);
8380 8381 }
8381 8382
8382 8383 *(cb.cb_value) = '\0';
8383 8384 cb.cb_value++;
8384 8385
8385 8386 error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
8386 8387 set_callback, &cb);
8387 8388
8388 8389 return (error);
8389 8390 }
8390 8391
8391 8392 static int
8392 8393 find_command_idx(char *command, int *idx)
8393 8394 {
8394 8395 int i;
8395 8396
8396 8397 for (i = 0; i < NCOMMAND; i++) {
8397 8398 if (command_table[i].name == NULL)
8398 8399 continue;
8399 8400
8400 8401 if (strcmp(command, command_table[i].name) == 0) {
8401 8402 *idx = i;
8402 8403 return (0);
8403 8404 }
8404 8405 }
8405 8406 return (1);
8406 8407 }
8407 8408
8408 8409 int
8409 8410 main(int argc, char **argv)
8410 8411 {
8411 8412 int ret = 0;
8412 8413 int i;
8413 8414 char *cmdname;
8414 8415
8415 8416 (void) setlocale(LC_ALL, "");
8416 8417 (void) textdomain(TEXT_DOMAIN);
8417 8418
8418 8419 if ((g_zfs = libzfs_init()) == NULL) {
8419 8420 (void) fprintf(stderr, gettext("internal error: failed to "
8420 8421 "initialize ZFS library\n"));
8421 8422 return (1);
8422 8423 }
8423 8424
8424 8425 libzfs_print_on_error(g_zfs, B_TRUE);
8425 8426
8426 8427 opterr = 0;
8427 8428
8428 8429 /*
8429 8430 * Make sure the user has specified some command.
8430 8431 */
8431 8432 if (argc < 2) {
8432 8433 (void) fprintf(stderr, gettext("missing command\n"));
8433 8434 usage(B_FALSE);
8434 8435 }
8435 8436
8436 8437 cmdname = argv[1];
8437 8438
8438 8439 /*
8439 8440 * Special case '-?'
8440 8441 */
8441 8442 if (strcmp(cmdname, "-?") == 0)
8442 8443 usage(B_TRUE);
8443 8444
8444 8445 zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
8445 8446
8446 8447 /*
8447 8448 * Run the appropriate command.
8448 8449 */
8449 8450 if (find_command_idx(cmdname, &i) == 0) {
8450 8451 current_command = &command_table[i];
8451 8452 ret = command_table[i].func(argc - 1, argv + 1);
8452 8453 } else if (strchr(cmdname, '=')) {
8453 8454 verify(find_command_idx("set", &i) == 0);
8454 8455 current_command = &command_table[i];
8455 8456 ret = command_table[i].func(argc, argv);
8456 8457 } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
8457 8458 /*
8458 8459 * 'freeze' is a vile debugging abomination, so we treat
8459 8460 * it as such.
8460 8461 */
8461 8462 char buf[16384];
8462 8463 int fd = open(ZFS_DEV, O_RDWR);
8463 8464 (void) strcpy((void *)buf, argv[2]);
8464 8465 return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
8465 8466 } else {
8466 8467 (void) fprintf(stderr, gettext("unrecognized "
8467 8468 "command '%s'\n"), cmdname);
8468 8469 usage(B_FALSE);
8469 8470 }
8470 8471
8471 8472 if (ret == 0 && log_history)
8472 8473 (void) zpool_log_history(g_zfs, history_str);
8473 8474
8474 8475 libzfs_fini(g_zfs);
8475 8476
8476 8477 /*
8477 8478 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
8478 8479 * for the purposes of running ::findleaks.
8479 8480 */
8480 8481 if (getenv("ZFS_ABORT") != NULL) {
8481 8482 (void) printf("dumping core by request\n");
8482 8483 abort();
8483 8484 }
8484 8485
8485 8486 return (ret);
8486 8487 }
↓ open down ↓ |
8056 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX