* Copyright (c) 2017 Datto Inc.
* Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
* Copyright (c) 2017, Intel Corporation.
+ * Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com>
*/
#include <assert.h>
static int zpool_do_initialize(int, char **);
static int zpool_do_scrub(int, char **);
static int zpool_do_resilver(int, char **);
+static int zpool_do_trim(int, char **);
static int zpool_do_import(int, char **);
static int zpool_do_export(int, char **);
static int zpool_do_sync(int, char **);
+static int zpool_do_version(int, char **);
+
/*
* These libumem hooks provide a reasonable set of defaults for the allocator's
* debugging facilities.
HELP_INITIALIZE,
HELP_SCRUB,
HELP_RESILVER,
+ HELP_TRIM,
HELP_STATUS,
HELP_UPGRADE,
HELP_EVENTS,
HELP_SPLIT,
HELP_SYNC,
HELP_REGUID,
- HELP_REOPEN
+ HELP_REOPEN,
+ HELP_VERSION
} zpool_help_t;
* of all the nvlists a flag requires. Also specifies the order in
* which data gets printed in zpool iostat.
*/
-static const char *vsx_type_to_nvlist[IOS_COUNT][11] = {
+static const char *vsx_type_to_nvlist[IOS_COUNT][13] = {
[IOS_L_HISTO] = {
ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO,
ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO,
ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO,
ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO,
ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO,
+ ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO,
NULL},
[IOS_LATENCY] = {
ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO,
ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO,
ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO,
ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO,
+ ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO,
NULL},
[IOS_QUEUES] = {
ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE,
ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE,
ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE,
ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE,
+ ZPOOL_CONFIG_VDEV_TRIM_ACTIVE_QUEUE,
NULL},
[IOS_RQ_HISTO] = {
ZPOOL_CONFIG_VDEV_SYNC_IND_R_HISTO,
ZPOOL_CONFIG_VDEV_ASYNC_AGG_W_HISTO,
ZPOOL_CONFIG_VDEV_IND_SCRUB_HISTO,
ZPOOL_CONFIG_VDEV_AGG_SCRUB_HISTO,
+ ZPOOL_CONFIG_VDEV_IND_TRIM_HISTO,
+ ZPOOL_CONFIG_VDEV_AGG_TRIM_HISTO,
NULL},
};
* the generic usage message.
*/
static zpool_command_t command_table[] = {
+ { "version", zpool_do_version, HELP_VERSION },
+ { NULL },
{ "create", zpool_do_create, HELP_CREATE },
{ "destroy", zpool_do_destroy, HELP_DESTROY },
{ NULL },
{ "split", zpool_do_split, HELP_SPLIT },
{ NULL },
{ "initialize", zpool_do_initialize, HELP_INITIALIZE },
- { "scrub", zpool_do_scrub, HELP_SCRUB },
{ "resilver", zpool_do_resilver, HELP_RESILVER },
+ { "scrub", zpool_do_scrub, HELP_SCRUB },
+ { "trim", zpool_do_trim, HELP_TRIM },
{ NULL },
{ "import", zpool_do_import, HELP_IMPORT },
{ "export", zpool_do_export, HELP_EXPORT },
return (gettext("\tscrub [-s | -p] <pool> ...\n"));
case HELP_RESILVER:
return (gettext("\tresilver <pool> ...\n"));
+ case HELP_TRIM:
+ return (gettext("\ttrim [-d] [-r <rate>] [-c | -s] <pool> "
+ "[<device> ...]\n"));
case HELP_STATUS:
return (gettext("\tstatus [-c [script1,script2,...]] "
- "[-igLpPsvxD] [-T d|u] [pool] ... \n"
+ "[-igLpPstvxD] [-T d|u] [pool] ... \n"
"\t [interval [count]]\n"));
case HELP_UPGRADE:
return (gettext("\tupgrade\n"
return (gettext("\treguid <pool>\n"));
case HELP_SYNC:
return (gettext("\tsync [pool] ...\n"));
+ case HELP_VERSION:
+ return (gettext("\tversion\n"));
}
abort();
&child, &children);
if (children == 0) {
- char *path = zpool_vdev_name(g_zfs, zhp, nvroot, B_FALSE);
- fnvlist_add_boolean(res, path);
+ char *path = zpool_vdev_name(g_zfs, zhp, nvroot,
+ VDEV_NAME_PATH);
+
+ if (strcmp(path, VDEV_TYPE_INDIRECT) != 0)
+ fnvlist_add_boolean(res, path);
+
free(path);
return;
}
{0, 0, 0, 0}
};
- pool_initialize_func_t cmd_type = POOL_INITIALIZE_DO;
+ pool_initialize_func_t cmd_type = POOL_INITIALIZE_START;
while ((c = getopt_long(argc, argv, "cs", long_options, NULL)) != -1) {
switch (c) {
case 'c':
- if (cmd_type != POOL_INITIALIZE_DO &&
+ if (cmd_type != POOL_INITIALIZE_START &&
cmd_type != POOL_INITIALIZE_CANCEL) {
(void) fprintf(stderr, gettext("-c cannot be "
"combined with other options\n"));
cmd_type = POOL_INITIALIZE_CANCEL;
break;
case 's':
- if (cmd_type != POOL_INITIALIZE_DO &&
+ if (cmd_type != POOL_INITIALIZE_START &&
cmd_type != POOL_INITIALIZE_SUSPEND) {
(void) fprintf(stderr, gettext("-s cannot be "
"combined with other options\n"));
ZPOOL_CONFIG_VDEV_TREE);
zpool_collect_leaves(zhp, nvroot, vdevs);
} else {
- int i;
- for (i = 1; i < argc; i++) {
+ for (int i = 1; i < argc; i++) {
fnvlist_add_boolean(vdevs, argv[i]);
}
}
return (1);
}
- if (ioctl(fd, BLKFLSBUF) != 0)
+ /*
+ * Flush all dirty pages for the block device. This should not be
+ * fatal when the device does not support BLKFLSBUF as would be the
+ * case for a file vdev.
+ */
+ if ((ioctl(fd, BLKFLSBUF) != 0) && (errno != ENOTTY))
(void) fprintf(stderr, gettext("failed to invalidate "
"cache for %s: %s\n"), vdev, strerror(errno));
- if (zpool_read_label(fd, &config, NULL) != 0 || config == NULL) {
+ if (zpool_read_label(fd, &config, NULL) != 0) {
(void) fprintf(stderr,
- gettext("failed to check state for %s\n"), vdev);
+ gettext("failed to read label from %s\n"), vdev);
ret = 1;
goto errout;
}
boolean_t cb_print_status;
boolean_t cb_print_slow_ios;
boolean_t cb_print_vdev_init;
+ boolean_t cb_print_vdev_trim;
vdev_cmd_data_list_t *vcdl;
} status_cbdata_t;
}
}
+/*
+ * Print vdev initialization status for leaves
+ */
+static void
+print_status_initialize(vdev_stat_t *vs, boolean_t verbose)
+{
+ if (verbose) {
+ if ((vs->vs_initialize_state == VDEV_INITIALIZE_ACTIVE ||
+ vs->vs_initialize_state == VDEV_INITIALIZE_SUSPENDED ||
+ vs->vs_initialize_state == VDEV_INITIALIZE_COMPLETE) &&
+ !vs->vs_scan_removing) {
+ char zbuf[1024];
+ char tbuf[256];
+ struct tm zaction_ts;
+
+ time_t t = vs->vs_initialize_action_time;
+ int initialize_pct = 100;
+ if (vs->vs_initialize_state !=
+ VDEV_INITIALIZE_COMPLETE) {
+ initialize_pct = (vs->vs_initialize_bytes_done *
+ 100 / (vs->vs_initialize_bytes_est + 1));
+ }
+
+ (void) localtime_r(&t, &zaction_ts);
+ (void) strftime(tbuf, sizeof (tbuf), "%c", &zaction_ts);
+
+ switch (vs->vs_initialize_state) {
+ case VDEV_INITIALIZE_SUSPENDED:
+ (void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
+ gettext("suspended, started at"), tbuf);
+ break;
+ case VDEV_INITIALIZE_ACTIVE:
+ (void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
+ gettext("started at"), tbuf);
+ break;
+ case VDEV_INITIALIZE_COMPLETE:
+ (void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
+ gettext("completed at"), tbuf);
+ break;
+ }
+
+ (void) printf(gettext(" (%d%% initialized%s)"),
+ initialize_pct, zbuf);
+ } else {
+ (void) printf(gettext(" (uninitialized)"));
+ }
+ } else if (vs->vs_initialize_state == VDEV_INITIALIZE_ACTIVE) {
+ (void) printf(gettext(" (initializing)"));
+ }
+}
+
+/*
+ * Print vdev TRIM status for leaves
+ */
+static void
+print_status_trim(vdev_stat_t *vs, boolean_t verbose)
+{
+ if (verbose) {
+ if ((vs->vs_trim_state == VDEV_TRIM_ACTIVE ||
+ vs->vs_trim_state == VDEV_TRIM_SUSPENDED ||
+ vs->vs_trim_state == VDEV_TRIM_COMPLETE) &&
+ !vs->vs_scan_removing) {
+ char zbuf[1024];
+ char tbuf[256];
+ struct tm zaction_ts;
+
+ time_t t = vs->vs_trim_action_time;
+ int trim_pct = 100;
+ if (vs->vs_trim_state != VDEV_TRIM_COMPLETE) {
+ trim_pct = (vs->vs_trim_bytes_done *
+ 100 / (vs->vs_trim_bytes_est + 1));
+ }
+
+ (void) localtime_r(&t, &zaction_ts);
+ (void) strftime(tbuf, sizeof (tbuf), "%c", &zaction_ts);
+
+ switch (vs->vs_trim_state) {
+ case VDEV_TRIM_SUSPENDED:
+ (void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
+ gettext("suspended, started at"), tbuf);
+ break;
+ case VDEV_TRIM_ACTIVE:
+ (void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
+ gettext("started at"), tbuf);
+ break;
+ case VDEV_TRIM_COMPLETE:
+ (void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
+ gettext("completed at"), tbuf);
+ break;
+ }
+
+ (void) printf(gettext(" (%d%% trimmed%s)"),
+ trim_pct, zbuf);
+ } else if (vs->vs_trim_notsup) {
+ (void) printf(gettext(" (trim unsupported)"));
+ } else {
+ (void) printf(gettext(" (untrimmed)"));
+ }
+ } else if (vs->vs_trim_state == VDEV_TRIM_ACTIVE) {
+ (void) printf(gettext(" (trimming)"));
+ }
+}
+
/*
* Print out configuration state as requested by status_callback.
*/
}
}
- /* Optionally display vdev initialization status for leaves */
- if (cb->cb_print_vdev_init && children == 0) {
- if ((vs->vs_initialize_state == VDEV_INITIALIZE_ACTIVE ||
- vs->vs_initialize_state == VDEV_INITIALIZE_SUSPENDED ||
- vs->vs_initialize_state == VDEV_INITIALIZE_COMPLETE) &&
- !vs->vs_scan_removing) {
- char zbuf[1024];
- char tbuf[256];
- struct tm zaction_ts;
-
- time_t t = vs->vs_initialize_action_time;
- int initialize_pct = 100;
- if (vs->vs_initialize_state !=
- VDEV_INITIALIZE_COMPLETE) {
- initialize_pct = (vs->vs_initialize_bytes_done *
- 100 / (vs->vs_initialize_bytes_est + 1));
- }
-
- (void) localtime_r(&t, &zaction_ts);
- (void) strftime(tbuf, sizeof (tbuf), "%c", &zaction_ts);
-
- switch (vs->vs_initialize_state) {
- case VDEV_INITIALIZE_SUSPENDED:
- (void) snprintf(zbuf, sizeof (zbuf),
- ", suspended, started at %s", tbuf);
- break;
- case VDEV_INITIALIZE_ACTIVE:
- (void) snprintf(zbuf, sizeof (zbuf),
- ", started at %s", tbuf);
- break;
- case VDEV_INITIALIZE_COMPLETE:
- (void) snprintf(zbuf, sizeof (zbuf),
- ", completed at %s", tbuf);
- break;
- }
-
- (void) printf(gettext(" (%d%% initialized%s)"),
- initialize_pct, zbuf);
- } else {
- (void) printf(gettext(" (uninitialized)"));
- }
- } else {
- if (vs->vs_initialize_state == VDEV_INITIALIZE_ACTIVE &&
- children == 0) {
- (void) printf(gettext(" (initializing)"));
- }
+ /* Display vdev initialization and trim status for leaves */
+ if (children == 0) {
+ print_status_initialize(vs, cb->cb_print_vdev_init);
+ print_status_trim(vs, cb->cb_print_vdev_trim);
}
(void) printf("\n");
"old ones.\n"));
break;
+ case ZPOOL_ERRATA_ZOL_8308_ENCRYPTION:
+ (void) printf(gettext(" action: Existing "
+ "encrypted snapshots and bookmarks contain "
+ "an on-disk\n\tincompatibility. This may "
+ "cause on-disk corruption if they are used"
+ "\n\twith 'zfs recv'. To correct the "
+ "issue, enable the bookmark_v2 feature.\n\t"
+ "No additional action is needed if there "
+ "are no encrypted snapshots or\n\t"
+ "bookmarks. If preserving the encrypted "
+ "snapshots and bookmarks is\n\trequired, "
+ "use a non-raw send to backup and restore "
+ "them. Alternately,\n\tthey may be removed"
+ " to resolve the incompatibility.\n"));
+ break;
default:
/*
* All errata must contain an action message.
unsigned int columns; /* Center name to this number of columns */
} name_and_columns_t;
-#define IOSTAT_MAX_LABELS 11 /* Max number of labels on one line */
+#define IOSTAT_MAX_LABELS 13 /* Max number of labels on one line */
static const name_and_columns_t iostat_top_labels[][IOSTAT_MAX_LABELS] =
{
[IOS_DEFAULT] = {{"capacity", 2}, {"operations", 2}, {"bandwidth", 2},
{NULL}},
[IOS_LATENCY] = {{"total_wait", 2}, {"disk_wait", 2}, {"syncq_wait", 2},
- {"asyncq_wait", 2}, {"scrub"}},
+ {"asyncq_wait", 2}, {"scrub", 1}, {"trim", 1}, {NULL}},
[IOS_QUEUES] = {{"syncq_read", 2}, {"syncq_write", 2},
{"asyncq_read", 2}, {"asyncq_write", 2}, {"scrubq_read", 2},
- {NULL}},
- [IOS_L_HISTO] = {{"total_wait", 2}, {"disk_wait", 2},
- {"sync_queue", 2}, {"async_queue", 2}, {NULL}},
+ {"trimq_write", 2}, {NULL}},
+ [IOS_L_HISTO] = {{"total_wait", 2}, {"disk_wait", 2}, {"syncq_wait", 2},
+ {"asyncq_wait", 2}, {NULL}},
[IOS_RQ_HISTO] = {{"sync_read", 2}, {"sync_write", 2},
- {"async_read", 2}, {"async_write", 2}, {"scrub", 2}, {NULL}},
-
+ {"async_read", 2}, {"async_write", 2}, {"scrub", 2},
+ {"trim", 2}, {NULL}},
};
/* Shorthand - if "columns" field not set, default to 1 column */
[IOS_DEFAULT] = {{"alloc"}, {"free"}, {"read"}, {"write"}, {"read"},
{"write"}, {NULL}},
[IOS_LATENCY] = {{"read"}, {"write"}, {"read"}, {"write"}, {"read"},
- {"write"}, {"read"}, {"write"}, {"wait"}, {NULL}},
+ {"write"}, {"read"}, {"write"}, {"wait"}, {"wait"}, {NULL}},
[IOS_QUEUES] = {{"pend"}, {"activ"}, {"pend"}, {"activ"}, {"pend"},
- {"activ"}, {"pend"}, {"activ"}, {"pend"}, {"activ"}, {NULL}},
+ {"activ"}, {"pend"}, {"activ"}, {"pend"}, {"activ"},
+ {"pend"}, {"activ"}, {NULL}},
[IOS_L_HISTO] = {{"read"}, {"write"}, {"read"}, {"write"}, {"read"},
- {"write"}, {"read"}, {"write"}, {"scrub"}, {NULL}},
+ {"write"}, {"read"}, {"write"}, {"scrub"}, {"trim"}, {NULL}},
[IOS_RQ_HISTO] = {{"ind"}, {"agg"}, {"ind"}, {"agg"}, {"ind"}, {"agg"},
- {"ind"}, {"agg"}, {"ind"}, {"agg"}, {NULL}},
+ {"ind"}, {"agg"}, {"ind"}, {"agg"}, {"ind"}, {"agg"}, {NULL}},
};
static const char *histo_to_title[] = {
[IOS_DEFAULT] = 15, /* 1PB capacity */
[IOS_LATENCY] = 10, /* 1B ns = 10sec */
[IOS_QUEUES] = 6, /* 1M queue entries */
+ [IOS_L_HISTO] = 10, /* 1B ns = 10sec */
+ [IOS_RQ_HISTO] = 6, /* 1M queue entries */
};
if (cb->cb_literal)
const name_and_columns_t labels[][IOSTAT_MAX_LABELS])
{
int i, idx, s;
- unsigned int text_start, rw_column_width, spaces_to_end;
+ int text_start, rw_column_width, spaces_to_end;
uint64_t flags = cb->cb_flags;
uint64_t f;
unsigned int column_width = force_column_width;
rw_column_width = (column_width * columns) +
(2 * (columns - 1));
- text_start = (int)((rw_column_width)/columns -
- slen/columns);
+ text_start = (int)((rw_column_width) / columns -
+ slen / columns);
+ if (text_start < 0)
+ text_start = 0;
printf(" "); /* Two spaces between columns */
/* Print space after label to end of column */
spaces_to_end = rw_column_width - text_start - slen;
+ if (spaces_to_end < 0)
+ spaces_to_end = 0;
+
for (s = 0; s < spaces_to_end; s++)
printf(" ");
-
}
}
}
ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE,
ZPOOL_CONFIG_VDEV_SCRUB_PEND_QUEUE,
ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE,
+ ZPOOL_CONFIG_VDEV_TRIM_PEND_QUEUE,
+ ZPOOL_CONFIG_VDEV_TRIM_ACTIVE_QUEUE,
};
struct stat_array *nva;
ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO,
ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO,
ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO,
+ ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO,
};
struct stat_array *nva;
return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
}
+/*
+ * zpool trim [-d] [-r <rate>] [-c | -s] <pool> [<device> ...]
+ *
+ * -c Cancel. Ends any in-progress trim.
+ * -d Secure trim. Requires kernel and device support.
+ * -r <rate> Sets the TRIM rate in bytes (per second). Supports
+ * adding a multiplier suffix such as 'k' or 'm'.
+ * -s Suspend. TRIM can then be restarted with no flags.
+ */
+int
+zpool_do_trim(int argc, char **argv)
+{
+ struct option long_options[] = {
+ {"cancel", no_argument, NULL, 'c'},
+ {"secure", no_argument, NULL, 'd'},
+ {"rate", required_argument, NULL, 'r'},
+ {"suspend", no_argument, NULL, 's'},
+ {0, 0, 0, 0}
+ };
+
+ pool_trim_func_t cmd_type = POOL_TRIM_START;
+ uint64_t rate = 0;
+ boolean_t secure = B_FALSE;
+
+ int c;
+ while ((c = getopt_long(argc, argv, "cdr:s", long_options, NULL))
+ != -1) {
+ switch (c) {
+ case 'c':
+ if (cmd_type != POOL_TRIM_START &&
+ cmd_type != POOL_TRIM_CANCEL) {
+ (void) fprintf(stderr, gettext("-c cannot be "
+ "combined with other options\n"));
+ usage(B_FALSE);
+ }
+ cmd_type = POOL_TRIM_CANCEL;
+ break;
+ case 'd':
+ if (cmd_type != POOL_TRIM_START) {
+ (void) fprintf(stderr, gettext("-d cannot be "
+ "combined with the -c or -s options\n"));
+ usage(B_FALSE);
+ }
+ secure = B_TRUE;
+ break;
+ case 'r':
+ if (cmd_type != POOL_TRIM_START) {
+ (void) fprintf(stderr, gettext("-r cannot be "
+ "combined with the -c or -s options\n"));
+ usage(B_FALSE);
+ }
+ if (zfs_nicestrtonum(NULL, optarg, &rate) == -1) {
+ (void) fprintf(stderr,
+ gettext("invalid value for rate\n"));
+ usage(B_FALSE);
+ }
+ break;
+ case 's':
+ if (cmd_type != POOL_TRIM_START &&
+ cmd_type != POOL_TRIM_SUSPEND) {
+ (void) fprintf(stderr, gettext("-s cannot be "
+ "combined with other options\n"));
+ usage(B_FALSE);
+ }
+ cmd_type = POOL_TRIM_SUSPEND;
+ break;
+ case '?':
+ if (optopt != 0) {
+ (void) fprintf(stderr,
+ gettext("invalid option '%c'\n"), optopt);
+ } else {
+ (void) fprintf(stderr,
+ gettext("invalid option '%s'\n"),
+ argv[optind - 1]);
+ }
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name argument\n"));
+ usage(B_FALSE);
+ return (-1);
+ }
+
+ char *poolname = argv[0];
+ zpool_handle_t *zhp = zpool_open(g_zfs, poolname);
+ if (zhp == NULL)
+ return (-1);
+
+ trimflags_t trim_flags = {
+ .secure = secure,
+ .rate = rate,
+ };
+
+ nvlist_t *vdevs = fnvlist_alloc();
+ if (argc == 1) {
+ /* no individual leaf vdevs specified, so add them all */
+ nvlist_t *config = zpool_get_config(zhp, NULL);
+ nvlist_t *nvroot = fnvlist_lookup_nvlist(config,
+ ZPOOL_CONFIG_VDEV_TREE);
+ zpool_collect_leaves(zhp, nvroot, vdevs);
+ trim_flags.fullpool = B_TRUE;
+ } else {
+ trim_flags.fullpool = B_FALSE;
+ for (int i = 1; i < argc; i++) {
+ fnvlist_add_boolean(vdevs, argv[i]);
+ }
+ }
+
+ int error = zpool_trim(zhp, cmd_type, vdevs, &trim_flags);
+
+ fnvlist_free(vdevs);
+ zpool_close(zhp);
+
+ return (error);
+}
/*
* Print out detailed scrub status.
scan_rate = pass_scanned / elapsed;
issue_rate = pass_issued / elapsed;
- total_secs_left = (issue_rate != 0) ?
+ total_secs_left = (issue_rate != 0 && total >= issued) ?
((total - issued) / issue_rate) : UINT64_MAX;
days_left = total_secs_left / 60 / 60 / 24;
}
if (pause == 0) {
- if (issue_rate >= 10 * 1024 * 1024) {
+ if (total_secs_left != UINT64_MAX &&
+ issue_rate >= 10 * 1024 * 1024) {
(void) printf(gettext(", %llu days "
"%02llu:%02llu:%02llu to go\n"),
(u_longlong_t)days_left, (u_longlong_t)hours_left,
"mount existing encrypted datasets readonly.\n"));
break;
+ case ZPOOL_ERRATA_ZOL_8308_ENCRYPTION:
+ (void) printf(gettext("\tExisting encrypted snapshots "
+ "and bookmarks contain an on-disk\n\tincompat"
+ "ibility. This may cause on-disk corruption if "
+ "they are used\n\twith 'zfs recv'.\n"));
+ (void) printf(gettext("action: To correct the issue, "
+ "enable the bookmark_v2 feature. No additional\n\t"
+ "action is needed if there are no encrypted "
+ "snapshots or bookmarks.\n\tIf preserving the "
+ "encrypted snapshots and bookmarks is required, "
+ "use\n\ta non-raw send to backup and restore them. "
+ "Alternately, they may be\n\tremoved to resolve "
+ "the incompatibility.\n"));
+ break;
+
default:
/*
* All errata which allow the pool to be imported
}
/*
- * zpool status [-c [script1,script2,...]] [-igLpPsvx] [-T d|u] [pool] ...
+ * zpool status [-c [script1,script2,...]] [-igLpPstvx] [-T d|u] [pool] ...
* [interval [count]]
*
* -c CMD For each vdev, run command CMD
* -v Display complete error logs
* -x Display only pools with potential problems
* -D Display dedup status (undocumented)
+ * -t Display vdev TRIM status.
* -T Display a timestamp in date(1) or Unix format
*
* Describes the health status of all pools or some subset.
char *cmd = NULL;
/* check options */
- while ((c = getopt(argc, argv, "c:igLpPsvxDT:")) != -1) {
+ while ((c = getopt(argc, argv, "c:igLpPsvxDtT:")) != -1) {
switch (c) {
case 'c':
if (cmd != NULL) {
case 'D':
cb.cb_dedup_stats = B_TRUE;
break;
+ case 't':
+ cb.cb_print_vdev_trim = B_TRUE;
+ break;
case 'T':
get_timestamp_arg(*optarg);
break;
return (1);
}
+/*
+ * Display version message
+ */
+static int
+zpool_do_version(int argc, char **argv)
+{
+ if (zfs_version_print() == -1)
+ return (1);
+
+ return (0);
+}
+
int
main(int argc, char **argv)
{
if ((strcmp(cmdname, "-?") == 0) || strcmp(cmdname, "--help") == 0)
usage(B_TRUE);
+ /*
+ * Special case '-V|--version'
+ */
+ if ((strcmp(cmdname, "-V") == 0) || (strcmp(cmdname, "--version") == 0))
+ return (zpool_do_version(argc, argv));
+
if ((g_zfs = libzfs_init()) == NULL) {
(void) fprintf(stderr, "%s", libzfs_error_init(errno));
return (1);