]> git.proxmox.com Git - mirror_zfs.git/blobdiff - cmd/zpool/zpool_main.c
Fix locale-specific time
[mirror_zfs.git] / cmd / zpool / zpool_main.c
index 11486f3f185ea21dea090f735e8b568c58940c58..d670cd1afeb1bf53de1e83fe3b0ea4ff712c4d96 100644 (file)
@@ -22,7 +22,7 @@
 /*
  * 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.
@@ -131,6 +131,13 @@ static int zpool_do_help(int argc, char **argv);
 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.
@@ -347,7 +354,7 @@ get_usage(zpool_help_t idx)
 {
        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] "
@@ -413,7 +420,7 @@ get_usage(zpool_help_t idx)
                    "[<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"
@@ -1009,8 +1016,9 @@ add_prop_list_default(const char *propname, const char *propval,
 }
 
 /*
- * 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.
@@ -1026,8 +1034,11 @@ add_prop_list_default(const char *propname, const char *propval,
 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;
@@ -1038,8 +1049,18 @@ zpool_do_add(int argc, char **argv)
        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;
@@ -1069,6 +1090,15 @@ zpool_do_add(int argc, char **argv)
                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);
@@ -1089,6 +1119,19 @@ zpool_do_add(int argc, char **argv)
                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--;
@@ -1119,8 +1162,8 @@ zpool_do_add(int argc, char **argv)
        }
 
        /* 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);
@@ -1224,7 +1267,7 @@ zpool_do_add(int argc, char **argv)
 
                ret = 0;
        } else {
-               ret = (zpool_add(zhp, nvroot) != 0);
+               ret = (zpool_add(zhp, nvroot, check_ashift) != 0);
        }
 
        nvlist_free(props);
@@ -2161,6 +2204,7 @@ typedef struct status_cbdata {
        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;
@@ -2245,7 +2289,6 @@ print_status_initialize(vdev_stat_t *vs, boolean_t verbose)
                    !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;
@@ -2255,8 +2298,8 @@ print_status_initialize(vdev_stat_t *vs, boolean_t verbose)
                                    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:
@@ -2296,7 +2339,6 @@ print_status_trim(vdev_stat_t *vs, boolean_t verbose)
                    !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;
@@ -2305,8 +2347,8 @@ print_status_trim(vdev_stat_t *vs, boolean_t verbose)
                                    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:
@@ -2357,6 +2399,35 @@ health_str_to_color(const char *health)
        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.
  */
@@ -2375,7 +2446,8 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
        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)
@@ -2402,6 +2474,15 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
                        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);
@@ -2416,6 +2497,9 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
                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",
@@ -2448,9 +2532,10 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
                        }
 
                        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)  {
@@ -2525,7 +2610,13 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
                        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:
@@ -7031,7 +7122,6 @@ zpool_do_split(int argc, char **argv)
        return (ret);
 }
 
-#define        POWER_OPT 1024
 
 /*
  * zpool online [--power] <pool> <device> ...
@@ -7049,7 +7139,7 @@ zpool_do_online(int argc, char **argv)
        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}
        };
 
@@ -7059,7 +7149,7 @@ zpool_do_online(int argc, char **argv)
                case 'e':
                        flags |= ZFS_ONLINE_EXPAND;
                        break;
-               case POWER_OPT:
+               case ZPOOL_OPTION_POWER:
                        is_power_on = B_TRUE;
                        break;
                case '?':
@@ -7172,7 +7262,7 @@ zpool_do_offline(int argc, char **argv)
        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}
        };
 
@@ -7185,7 +7275,7 @@ zpool_do_offline(int argc, char **argv)
                case 't':
                        istmp = B_TRUE;
                        break;
-               case POWER_OPT:
+               case ZPOOL_OPTION_POWER:
                        is_power_off = B_TRUE;
                        break;
                case '?':
@@ -7285,7 +7375,7 @@ zpool_do_clear(int argc, char **argv)
        char *pool, *device;
 
        struct option long_options[] = {
-               {"power", no_argument, NULL, POWER_OPT},
+               {"power", no_argument, NULL, ZPOOL_OPTION_POWER},
                {0, 0, 0, 0}
        };
 
@@ -7302,7 +7392,7 @@ zpool_do_clear(int argc, char **argv)
                case 'X':
                        xtreme_rewind = B_TRUE;
                        break;
-               case POWER_OPT:
+               case ZPOOL_OPTION_POWER:
                        is_power_on = B_TRUE;
                        break;
                case '?':
@@ -9106,9 +9196,11 @@ status_callback(zpool_handle_t *zhp, void *data)
                                (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);
                        }
@@ -9125,21 +9217,22 @@ status_callback(zpool_handle_t *zhp, void *data)
 }
 
 /*
- * 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.
@@ -9155,12 +9248,12 @@ zpool_do_status(int argc, char **argv)
        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':
@@ -9187,12 +9280,18 @@ zpool_do_status(int argc, char **argv)
                        }
                        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;
@@ -9205,22 +9304,19 @@ zpool_do_status(int argc, char **argv)
                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 '?':
@@ -9259,7 +9355,6 @@ zpool_do_status(int argc, char **argv)
 
                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)
@@ -10696,11 +10791,10 @@ found:
                }
        } 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);
        }