/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2024 by Delphix. All rights reserved.
* Copyright (c) 2012 by Frederik Wessels. All rights reserved.
* Copyright (c) 2012 by Cyril Plisko. All rights reserved.
* Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
static zpool_compat_status_t zpool_do_load_compat(
const char *, boolean_t *);
+enum zpool_options {
+ ZPOOL_OPTION_POWER = 1024,
+ ZPOOL_OPTION_ALLOW_INUSE,
+ ZPOOL_OPTION_ALLOW_REPLICATION_MISMATCH,
+ ZPOOL_OPTION_ALLOW_ASHIFT_MISMATCH
+};
+
/*
* These libumem hooks provide a reasonable set of defaults for the allocator's
* debugging facilities.
{
switch (idx) {
case HELP_ADD:
- return (gettext("\tadd [-fgLnP] [-o property=value] "
+ return (gettext("\tadd [-afgLnP] [-o property=value] "
"<pool> <vdev> ...\n"));
case HELP_ATTACH:
return (gettext("\tattach [-fsw] [-o property=value] "
"[<device> ...]\n"));
case HELP_STATUS:
return (gettext("\tstatus [--power] [-c [script1,script2,...]] "
- "[-igLpPstvxD] [-T d|u] [pool] ... \n"
+ "[-DegiLpPstvx] [-T d|u] [pool] ...\n"
"\t [interval [count]]\n"));
case HELP_UPGRADE:
return (gettext("\tupgrade\n"
}
/*
- * zpool add [-fgLnP] [-o property=value] <pool> <vdev> ...
+ * zpool add [-afgLnP] [-o property=value] <pool> <vdev> ...
*
+ * -a Disable the ashift validation checks
* -f Force addition of devices, even if they appear in use
* -g Display guid for individual vdev name.
* -L Follow links when resolving vdev path name.
int
zpool_do_add(int argc, char **argv)
{
- boolean_t force = B_FALSE;
+ boolean_t check_replication = B_TRUE;
+ boolean_t check_inuse = B_TRUE;
boolean_t dryrun = B_FALSE;
+ boolean_t check_ashift = B_TRUE;
+ boolean_t force = B_FALSE;
int name_flags = 0;
int c;
nvlist_t *nvroot;
nvlist_t *props = NULL;
char *propval;
+ struct option long_options[] = {
+ {"allow-in-use", no_argument, NULL, ZPOOL_OPTION_ALLOW_INUSE},
+ {"allow-replication-mismatch", no_argument, NULL,
+ ZPOOL_OPTION_ALLOW_REPLICATION_MISMATCH},
+ {"allow-ashift-mismatch", no_argument, NULL,
+ ZPOOL_OPTION_ALLOW_ASHIFT_MISMATCH},
+ {0, 0, 0, 0}
+ };
+
/* check options */
- while ((c = getopt(argc, argv, "fgLno:P")) != -1) {
+ while ((c = getopt_long(argc, argv, "fgLno:P", long_options, NULL))
+ != -1) {
switch (c) {
case 'f':
force = B_TRUE;
case 'P':
name_flags |= VDEV_NAME_PATH;
break;
+ case ZPOOL_OPTION_ALLOW_INUSE:
+ check_inuse = B_FALSE;
+ break;
+ case ZPOOL_OPTION_ALLOW_REPLICATION_MISMATCH:
+ check_replication = B_FALSE;
+ break;
+ case ZPOOL_OPTION_ALLOW_ASHIFT_MISMATCH:
+ check_ashift = B_FALSE;
+ break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
usage(B_FALSE);
}
+ if (force) {
+ if (!check_inuse || !check_replication || !check_ashift) {
+ (void) fprintf(stderr, gettext("'-f' option is not "
+ "allowed with '--allow-replication-mismatch', "
+ "'--allow-ashift-mismatch', or "
+ "'--allow-in-use'\n"));
+ usage(B_FALSE);
+ }
+ check_inuse = B_FALSE;
+ check_replication = B_FALSE;
+ check_ashift = B_FALSE;
+ }
+
poolname = argv[0];
argc--;
}
/* pass off to make_root_vdev for processing */
- nvroot = make_root_vdev(zhp, props, force, !force, B_FALSE, dryrun,
- argc, argv);
+ nvroot = make_root_vdev(zhp, props, !check_inuse,
+ check_replication, B_FALSE, dryrun, argc, argv);
if (nvroot == NULL) {
zpool_close(zhp);
return (1);
ret = 0;
} else {
- ret = (zpool_add(zhp, nvroot) != 0);
+ ret = (zpool_add(zhp, nvroot, check_ashift) != 0);
}
nvlist_free(props);
boolean_t cb_explain;
boolean_t cb_first;
boolean_t cb_dedup_stats;
+ boolean_t cb_print_unhealthy;
boolean_t cb_print_status;
boolean_t cb_print_slow_ios;
boolean_t cb_print_vdev_init;
!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;
100 / (vs->vs_initialize_bytes_est + 1));
}
- (void) localtime_r(&t, &zaction_ts);
- (void) strftime(tbuf, sizeof (tbuf), "%c", &zaction_ts);
+ (void) ctime_r(&t, tbuf);
+ tbuf[24] = 0;
switch (vs->vs_initialize_state) {
case VDEV_INITIALIZE_SUSPENDED:
!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;
100 / (vs->vs_trim_bytes_est + 1));
}
- (void) localtime_r(&t, &zaction_ts);
- (void) strftime(tbuf, sizeof (tbuf), "%c", &zaction_ts);
+ (void) ctime_r(&t, tbuf);
+ tbuf[24] = 0;
switch (vs->vs_trim_state) {
case VDEV_TRIM_SUSPENDED:
return (NULL);
}
+/*
+ * Called for each leaf vdev. Returns 0 if the vdev is healthy.
+ * A vdev is unhealthy if any of the following are true:
+ * 1) there are read, write, or checksum errors,
+ * 2) its state is not ONLINE, or
+ * 3) slow IO reporting was requested (-s) and there are slow IOs.
+ */
+static int
+vdev_health_check_cb(void *hdl_data, nvlist_t *nv, void *data)
+{
+ status_cbdata_t *cb = data;
+ vdev_stat_t *vs;
+ uint_t vsc;
+ (void) hdl_data;
+
+ if (nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &vsc) != 0)
+ return (1);
+
+ if (vs->vs_checksum_errors || vs->vs_read_errors ||
+ vs->vs_write_errors || vs->vs_state != VDEV_STATE_HEALTHY)
+ return (1);
+
+ if (cb->cb_print_slow_ios && vs->vs_slow_ios)
+ return (1);
+
+ return (0);
+}
+
/*
* Print out configuration state as requested by status_callback.
*/
const char *state;
const char *type;
const char *path = NULL;
- const char *rcolor = NULL, *wcolor = NULL, *ccolor = NULL;
+ const char *rcolor = NULL, *wcolor = NULL, *ccolor = NULL,
+ *scolor = NULL;
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
&child, &children) != 0)
state = gettext("AVAIL");
}
+ /*
+ * If '-e' is specified then top-level vdevs and their children
+ * can be pruned if all of their leaves are healthy.
+ */
+ if (cb->cb_print_unhealthy && depth > 0 &&
+ for_each_vdev_in_nvlist(nv, vdev_health_check_cb, cb) == 0) {
+ return;
+ }
+
printf_color(health_str_to_color(state),
"\t%*s%-*s %-8s", depth, "", cb->cb_namewidth - depth,
name, state);
if (vs->vs_checksum_errors)
ccolor = ANSI_RED;
+ if (vs->vs_slow_ios)
+ scolor = ANSI_BLUE;
+
if (cb->cb_literal) {
fputc(' ', stdout);
printf_color(rcolor, "%5llu",
}
if (cb->cb_literal)
- printf(" %5llu", (u_longlong_t)vs->vs_slow_ios);
+ printf_color(scolor, " %5llu",
+ (u_longlong_t)vs->vs_slow_ios);
else
- printf(" %5s", rbuf);
+ printf_color(scolor, " %5s", rbuf);
}
if (cb->cb_print_power) {
if (children == 0) {
break;
case VDEV_AUX_ERR_EXCEEDED:
- (void) printf(gettext("too many errors"));
+ if (vs->vs_read_errors + vs->vs_write_errors +
+ vs->vs_checksum_errors == 0 && children == 0 &&
+ vs->vs_slow_ios > 0) {
+ (void) printf(gettext("too many slow I/Os"));
+ } else {
+ (void) printf(gettext("too many errors"));
+ }
break;
case VDEV_AUX_IO_FAILURE:
return (ret);
}
-#define POWER_OPT 1024
/*
* zpool online [--power] <pool> <device> ...
int flags = 0;
boolean_t is_power_on = B_FALSE;
struct option long_options[] = {
- {"power", no_argument, NULL, POWER_OPT},
+ {"power", no_argument, NULL, ZPOOL_OPTION_POWER},
{0, 0, 0, 0}
};
case 'e':
flags |= ZFS_ONLINE_EXPAND;
break;
- case POWER_OPT:
+ case ZPOOL_OPTION_POWER:
is_power_on = B_TRUE;
break;
case '?':
boolean_t is_power_off = B_FALSE;
struct option long_options[] = {
- {"power", no_argument, NULL, POWER_OPT},
+ {"power", no_argument, NULL, ZPOOL_OPTION_POWER},
{0, 0, 0, 0}
};
case 't':
istmp = B_TRUE;
break;
- case POWER_OPT:
+ case ZPOOL_OPTION_POWER:
is_power_off = B_TRUE;
break;
case '?':
char *pool, *device;
struct option long_options[] = {
- {"power", no_argument, NULL, POWER_OPT},
+ {"power", no_argument, NULL, ZPOOL_OPTION_POWER},
{0, 0, 0, 0}
};
case 'X':
xtreme_rewind = B_TRUE;
break;
- case POWER_OPT:
+ case ZPOOL_OPTION_POWER:
is_power_on = B_TRUE;
break;
case '?':
(void) printf(gettext(
"errors: No known data errors\n"));
} else if (!cbp->cb_verbose) {
+ color_start(ANSI_RED);
(void) printf(gettext("errors: %llu data "
"errors, use '-v' for a list\n"),
(u_longlong_t)nerr);
+ color_end();
} else {
print_error_log(zhp);
}
}
/*
- * zpool status [-c [script1,script2,...]] [-igLpPstvx] [--power] [-T d|u] ...
+ * zpool status [-c [script1,script2,...]] [-DegiLpPstvx] [--power] [-T d|u] ...
* [pool] [interval [count]]
*
* -c CMD For each vdev, run command CMD
- * -i Display vdev initialization status.
+ * -D Display dedup status (undocumented)
+ * -e Display only unhealthy vdevs
* -g Display guid for individual vdev name.
+ * -i Display vdev initialization status.
* -L Follow links when resolving vdev path name.
* -p Display values in parsable (exact) format.
* -P Display full path for vdev name.
* -s Display slow IOs column.
- * -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
+ * -v Display complete error logs
+ * -x Display only pools with potential problems
* --power Display vdev enclosure slot power status
*
* Describes the health status of all pools or some subset.
char *cmd = NULL;
struct option long_options[] = {
- {"power", no_argument, NULL, POWER_OPT},
+ {"power", no_argument, NULL, ZPOOL_OPTION_POWER},
{0, 0, 0, 0}
};
/* check options */
- while ((c = getopt_long(argc, argv, "c:igLpPsvxDtT:", long_options,
+ while ((c = getopt_long(argc, argv, "c:DegiLpPstT:vx", long_options,
NULL)) != -1) {
switch (c) {
case 'c':
}
cmd = optarg;
break;
- case 'i':
- cb.cb_print_vdev_init = B_TRUE;
+ case 'D':
+ cb.cb_dedup_stats = B_TRUE;
+ break;
+ case 'e':
+ cb.cb_print_unhealthy = B_TRUE;
break;
case 'g':
cb.cb_name_flags |= VDEV_NAME_GUID;
break;
+ case 'i':
+ cb.cb_print_vdev_init = B_TRUE;
+ break;
case 'L':
cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
break;
case 's':
cb.cb_print_slow_ios = B_TRUE;
break;
- case 'v':
- cb.cb_verbose = B_TRUE;
- break;
- case 'x':
- cb.cb_explain = B_TRUE;
- break;
- 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;
- case POWER_OPT:
+ case 'v':
+ cb.cb_verbose = B_TRUE;
+ break;
+ case 'x':
+ cb.cb_explain = B_TRUE;
+ break;
+ case ZPOOL_OPTION_POWER:
cb.cb_print_power = B_TRUE;
break;
case '?':
if (cb.vcdl != NULL)
free_vdev_cmd_data_list(cb.vcdl);
-
if (argc == 0 && cb.cb_count == 0)
(void) fprintf(stderr, gettext("no pools available\n"));
else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
}
} else {
/*
- * The first arg isn't a pool name,
+ * The first arg isn't the name of a valid pool.
*/
- fprintf(stderr, gettext("missing pool name.\n"));
- fprintf(stderr, "\n");
- usage(B_FALSE);
+ fprintf(stderr, gettext("Cannot get properties of %s: "
+ "no such pool available.\n"), argv[0]);
return (1);
}