Add -p switch to "zpool get"
[zfs.git] / cmd / zpool / zpool_main.c
index d0c0a92..2632e8c 100644 (file)
@@ -63,6 +63,7 @@ static int zpool_do_destroy(int, char **);
 
 static int zpool_do_add(int, char **);
 static int zpool_do_remove(int, char **);
+static int zpool_do_labelclear(int, char **);
 
 static int zpool_do_list(int, char **);
 static int zpool_do_iostat(int, char **);
@@ -123,6 +124,7 @@ typedef enum {
        HELP_HISTORY,
        HELP_IMPORT,
        HELP_IOSTAT,
+       HELP_LABELCLEAR,
        HELP_LIST,
        HELP_OFFLINE,
        HELP_ONLINE,
@@ -162,6 +164,8 @@ static zpool_command_t command_table[] = {
        { "add",        zpool_do_add,           HELP_ADD                },
        { "remove",     zpool_do_remove,        HELP_REMOVE             },
        { NULL },
+       { "labelclear", zpool_do_labelclear,    HELP_LABELCLEAR         },
+       { NULL },
        { "list",       zpool_do_list,          HELP_LIST               },
        { "iostat",     zpool_do_iostat,        HELP_IOSTAT             },
        { "status",     zpool_do_status,        HELP_STATUS             },
@@ -233,8 +237,10 @@ get_usage(zpool_help_t idx) {
        case HELP_IOSTAT:
                return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
                    "[count]]\n"));
+       case HELP_LABELCLEAR:
+               return (gettext("\tlabelclear [-f] <vdev>\n"));
        case HELP_LIST:
-               return (gettext("\tlist [-H] [-o property[,...]] "
+               return (gettext("\tlist [-Hv] [-o property[,...]] "
                    "[-T d|u] [pool] ... [interval [count]]\n"));
        case HELP_OFFLINE:
                return (gettext("\toffline [-t] <pool> <device> ...\n"));
@@ -246,7 +252,7 @@ get_usage(zpool_help_t idx) {
        case HELP_REMOVE:
                return (gettext("\tremove <pool> <device> ...\n"));
        case HELP_REOPEN:
-               return (""); /* Undocumented command */
+               return (gettext("\treopen <pool>\n"));
        case HELP_SCRUB:
                return (gettext("\tscrub [-s] <pool> ...\n"));
        case HELP_STATUS:
@@ -259,7 +265,7 @@ get_usage(zpool_help_t idx) {
        case HELP_EVENTS:
                return (gettext("\tevents [-vHfc]\n"));
        case HELP_GET:
-               return (gettext("\tget <\"all\" | property[,...]> "
+               return (gettext("\tget [-p] <\"all\" | property[,...]> "
                    "<pool> ...\n"));
        case HELP_SET:
                return (gettext("\tset <property=value> <pool> \n"));
@@ -391,6 +397,18 @@ print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
        }
 }
 
+static boolean_t
+prop_list_contains_feature(nvlist_t *proplist)
+{
+       nvpair_t *nvp;
+       for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp;
+           nvp = nvlist_next_nvpair(proplist, nvp)) {
+               if (zpool_prop_feature(nvpair_name(nvp)))
+                       return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+
 /*
  * Add a property pair (name, string-value) into a property nvlist.
  */
@@ -414,12 +432,30 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props,
        proplist = *props;
 
        if (poolprop) {
+               const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
+
                if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
                    !zpool_prop_feature(propname)) {
                        (void) fprintf(stderr, gettext("property '%s' is "
                            "not a valid pool property\n"), propname);
                        return (2);
                }
+
+               /*
+                * feature@ properties and version should not be specified
+                * at the same time.
+                */
+               if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) &&
+                   nvlist_exists(proplist, vname)) ||
+                   (prop == ZPOOL_PROP_VERSION &&
+                   prop_list_contains_feature(proplist))) {
+                       (void) fprintf(stderr, gettext("'feature@' and "
+                           "'version' properties cannot be specified "
+                           "together\n"));
+                       return (2);
+               }
+
+
                if (zpool_prop_feature(propname))
                        normnm = propname;
                else
@@ -612,6 +648,127 @@ zpool_do_remove(int argc, char **argv)
 }
 
 /*
+ * zpool labelclear <vdev>
+ *
+ * Verifies that the vdev is not active and zeros out the label information
+ * on the device.
+ */
+int
+zpool_do_labelclear(int argc, char **argv)
+{
+       char *vdev, *name;
+       int c, fd = -1, ret = 0;
+       pool_state_t state;
+       boolean_t inuse = B_FALSE;
+       boolean_t force = B_FALSE;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "f")) != -1) {
+               switch (c) {
+               case 'f':
+                       force = B_TRUE;
+                       break;
+               default:
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* get vdev name */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing vdev device name\n"));
+               usage(B_FALSE);
+       }
+
+       vdev = argv[0];
+       if ((fd = open(vdev, O_RDWR)) < 0) {
+               (void) fprintf(stderr, gettext("Unable to open %s\n"), vdev);
+               return (B_FALSE);
+       }
+
+       name = NULL;
+       if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0) {
+               if (force)
+                       goto wipe_label;
+
+               (void) fprintf(stderr,
+                   gettext("Unable to determine pool state for %s\n"
+                   "Use -f to force the clearing any label data\n"), vdev);
+
+               return (1);
+       }
+
+       if (inuse) {
+               switch (state) {
+               default:
+               case POOL_STATE_ACTIVE:
+               case POOL_STATE_SPARE:
+               case POOL_STATE_L2CACHE:
+                       (void) fprintf(stderr,
+                           gettext("labelclear operation failed.\n"
+                           "\tVdev %s is a member (%s), of pool \"%s\".\n"
+                           "\tTo remove label information from this device, "
+                           "export or destroy\n\tthe pool, or remove %s from "
+                           "the configuration of this pool\n\tand retry the "
+                           "labelclear operation.\n"),
+                           vdev, zpool_pool_state_to_name(state), name, vdev);
+                       ret = 1;
+                       goto errout;
+
+               case POOL_STATE_EXPORTED:
+                       if (force)
+                               break;
+
+                       (void) fprintf(stderr,
+                           gettext("labelclear operation failed.\n\tVdev "
+                           "%s is a member of the exported pool \"%s\".\n"
+                           "\tUse \"zpool labelclear -f %s\" to force the "
+                           "removal of label\n\tinformation.\n"),
+                           vdev, name, vdev);
+                       ret = 1;
+                       goto errout;
+
+               case POOL_STATE_POTENTIALLY_ACTIVE:
+                       if (force)
+                               break;
+
+                       (void) fprintf(stderr,
+                           gettext("labelclear operation failed.\n"
+                           "\tVdev %s is a member of the pool \"%s\".\n"
+                           "\tThis pool is unknown to this system, but may "
+                           "be active on\n\tanother system. Use "
+                           "\'zpool labelclear -f %s\' to force the\n"
+                           "\tremoval of label information.\n"),
+                           vdev, name, vdev);
+                       ret = 1;
+                       goto errout;
+
+               case POOL_STATE_DESTROYED:
+                       /* inuse should never be set for a destroyed pool... */
+                       break;
+               }
+       }
+
+wipe_label:
+       if (zpool_clear_label(fd) != 0) {
+               (void) fprintf(stderr,
+                   gettext("Label clear failed on vdev %s\n"), vdev);
+               ret = 1;
+       }
+
+errout:
+       close(fd);
+       if (name != NULL)
+               free(name);
+
+       return (ret);
+}
+
+/*
  * zpool create [-fnd] [-o property=value] ...
  *             [-O file-system-property=value] ...
  *             [-R root] [-m mountpoint] <pool> <dev> ...
@@ -1482,8 +1639,8 @@ show_import(nvlist_t *config)
                break;
 
        case ZPOOL_STATUS_VERSION_OLDER:
-               (void) printf(gettext(" status: The pool is formatted using an "
-                   "older on-disk version.\n"));
+               (void) printf(gettext(" status: The pool is formatted using a "
+                   "legacy on-disk version.\n"));
                break;
 
        case ZPOOL_STATUS_VERSION_NEWER:
@@ -1491,6 +1648,11 @@ show_import(nvlist_t *config)
                    "incompatible version.\n"));
                break;
 
+       case ZPOOL_STATUS_FEAT_DISABLED:
+               (void) printf(gettext(" status: Some supported features are "
+                   "not enabled on the pool.\n"));
+               break;
+
        case ZPOOL_STATUS_UNSUP_FEAT_READ:
                (void) printf(gettext("status: The pool uses the following "
                    "feature(s) not supported on this sytem:\n"));
@@ -1537,19 +1699,21 @@ show_import(nvlist_t *config)
         * Print out an action according to the overall state of the pool.
         */
        if (vs->vs_state == VDEV_STATE_HEALTHY) {
-               if (reason == ZPOOL_STATUS_VERSION_OLDER)
+               if (reason == ZPOOL_STATUS_VERSION_OLDER ||
+                   reason == ZPOOL_STATUS_FEAT_DISABLED) {
                        (void) printf(gettext(" action: The pool can be "
                            "imported using its name or numeric identifier, "
                            "though\n\tsome features will not be available "
                            "without an explicit 'zpool upgrade'.\n"));
-               else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
+               } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) {
                        (void) printf(gettext(" action: The pool can be "
                            "imported using its name or numeric "
                            "identifier and\n\tthe '-f' flag.\n"));
-               else
+               } else {
                        (void) printf(gettext(" action: The pool can be "
                            "imported using its name or numeric "
                            "identifier.\n"));
+               }
        } else if (vs->vs_state == VDEV_STATE_DEGRADED) {
                (void) printf(gettext(" action: The pool can be imported "
                    "despite missing or damaged devices.  The\n\tfault "
@@ -2895,7 +3059,7 @@ int
 zpool_do_list(int argc, char **argv)
 {
        int c;
-       int ret;
+       int ret = 0;
        list_cbdata_t cb = { 0 };
        static char default_props[] =
            "name,size,allocated,free,capacity,dedupratio,"
@@ -2934,6 +3098,9 @@ zpool_do_list(int argc, char **argv)
 
        argc -= optind;
        argv += optind;
+       fprintf(stderr, "argc = %d\n", argc);
+       for (c=0; c<argc; c++)
+               fprintf(stderr, "argv[%d] = %s\n", argc, argv[c]);
 
        get_interval_count(&argc, argv, &interval, &count);
 
@@ -3575,22 +3742,37 @@ zpool_do_reguid(int argc, char **argv)
  * zpool reopen <pool>
  *
  * Reopen the pool so that the kernel can update the sizes of all vdevs.
- *
- * NOTE: This command is currently undocumented.  If the command is ever
- * exposed then the appropriate usage() messages will need to be made.
  */
 int
 zpool_do_reopen(int argc, char **argv)
 {
+       int c;
        int ret = 0;
        zpool_handle_t *zhp;
        char *pool;
 
+       /* check options */
+       while ((c = getopt(argc, argv, "")) != -1) {
+               switch (c) {
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
        argc--;
        argv++;
 
-       if (argc != 1)
-               return (2);
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool name\n"));
+               usage(B_FALSE);
+       }
+
+       if (argc > 1) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
 
        pool = argv[0];
        if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
@@ -3688,7 +3870,7 @@ print_scan_status(pool_scan_stat_t *ps)
        double fraction_done;
        char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
 
-       (void) printf(gettext(" scan: "));
+       (void) printf(gettext("  scan: "));
 
        /* If there's never been a scan, there's not much to say. */
        if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
@@ -3876,10 +4058,16 @@ print_dedup_stats(nvlist_t *config)
         * table continue processing the stats.
         */
        if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
-           (uint64_t **)&ddo, &c) != 0 || ddo->ddo_count == 0)
+           (uint64_t **)&ddo, &c) != 0)
                return;
 
        (void) printf("\n");
+       (void) printf(gettext(" dedup: "));
+       if (ddo->ddo_count == 0) {
+               (void) printf(gettext("no DDT entries\n"));
+               return;
+       }
+
        (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
            (u_longlong_t)ddo->ddo_count,
            (u_longlong_t)ddo->ddo_dspace,
@@ -3927,7 +4115,10 @@ status_callback(zpool_handle_t *zhp, void *data)
         * If we were given 'zpool status -x', only report those pools with
         * problems.
         */
-       if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
+       if (cbp->cb_explain &&
+           (reason == ZPOOL_STATUS_OK ||
+           reason == ZPOOL_STATUS_VERSION_OLDER ||
+           reason == ZPOOL_STATUS_FEAT_DISABLED)) {
                if (!cbp->cb_allpools) {
                        (void) printf(gettext("pool '%s' is healthy\n"),
                            zpool_get_name(zhp));
@@ -4042,12 +4233,13 @@ status_callback(zpool_handle_t *zhp, void *data)
                break;
 
        case ZPOOL_STATUS_VERSION_OLDER:
-               (void) printf(gettext("status: The pool is formatted using an "
-                   "older on-disk format.  The pool can\n\tstill be used, but "
-                   "some features are unavailable.\n"));
+               (void) printf(gettext("status: The pool is formatted using a "
+                   "legacy on-disk format.  The pool can\n\tstill be used, "
+                   "but some features are unavailable.\n"));
                (void) printf(gettext("action: Upgrade the pool using 'zpool "
                    "upgrade'.  Once this is done, the\n\tpool will no longer "
-                   "be accessible on older software versions.\n"));
+                   "be accessible on software that does not support\n\t"
+                   "feature flags.\n"));
                break;
 
        case ZPOOL_STATUS_VERSION_NEWER:
@@ -4059,6 +4251,16 @@ status_callback(zpool_handle_t *zhp, void *data)
                    "backup.\n"));
                break;
 
+       case ZPOOL_STATUS_FEAT_DISABLED:
+               (void) printf(gettext("status: Some supported features are not "
+                   "enabled on the pool. The pool can\n\tstill be used, but "
+                   "some features are unavailable.\n"));
+               (void) printf(gettext("action: Enable all features using "
+                   "'zpool upgrade'. Once this is done,\n\tthe pool may no "
+                   "longer be accessible by software that does not support\n\t"
+                   "the features. See zpool-features(5) for details.\n"));
+               break;
+
        case ZPOOL_STATUS_UNSUP_FEAT_READ:
                (void) printf(gettext("status: The pool cannot be accessed on "
                    "this system because it uses the\n\tfollowing feature(s) "
@@ -4288,58 +4490,162 @@ zpool_do_status(int argc, char **argv)
 }
 
 typedef struct upgrade_cbdata {
-       int     cb_all;
        int     cb_first;
-       int     cb_newer;
        int     cb_argc;
        uint64_t cb_version;
        char    **cb_argv;
 } upgrade_cbdata_t;
 
 static int
+upgrade_version(zpool_handle_t *zhp, uint64_t version)
+{
+       int ret;
+       nvlist_t *config;
+       uint64_t oldversion;
+
+       config = zpool_get_config(zhp, NULL);
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+           &oldversion) == 0);
+
+       assert(SPA_VERSION_IS_SUPPORTED(oldversion));
+       assert(oldversion < version);
+
+       ret = zpool_upgrade(zhp, version);
+       if (ret != 0)
+               return (ret);
+
+       if (version >= SPA_VERSION_FEATURES) {
+               (void) printf(gettext("Successfully upgraded "
+                   "'%s' from version %llu to feature flags.\n"),
+                   zpool_get_name(zhp), (u_longlong_t) oldversion);
+       } else {
+               (void) printf(gettext("Successfully upgraded "
+                   "'%s' from version %llu to version %llu.\n"),
+                   zpool_get_name(zhp), (u_longlong_t) oldversion,
+                   (u_longlong_t) version);
+       }
+
+       return (0);
+}
+
+static int
+upgrade_enable_all(zpool_handle_t *zhp, int *countp)
+{
+       int i, ret, count;
+       boolean_t firstff = B_TRUE;
+       nvlist_t *enabled = zpool_get_features(zhp);
+
+       count = 0;
+       for (i = 0; i < SPA_FEATURES; i++) {
+               const char *fname = spa_feature_table[i].fi_uname;
+               const char *fguid = spa_feature_table[i].fi_guid;
+               if (!nvlist_exists(enabled, fguid)) {
+                       char *propname;
+                       verify(-1 != asprintf(&propname, "feature@%s", fname));
+                       ret = zpool_set_prop(zhp, propname,
+                           ZFS_FEATURE_ENABLED);
+                       if (ret != 0) {
+                               free(propname);
+                               return (ret);
+                       }
+                       count++;
+
+                       if (firstff) {
+                               (void) printf(gettext("Enabled the "
+                                   "following features on '%s':\n"),
+                                   zpool_get_name(zhp));
+                               firstff = B_FALSE;
+                       }
+                       (void) printf(gettext("  %s\n"), fname);
+                       free(propname);
+               }
+       }
+
+       if (countp != NULL)
+               *countp = count;
+       return (0);
+}
+
+static int
 upgrade_cb(zpool_handle_t *zhp, void *arg)
 {
        upgrade_cbdata_t *cbp = arg;
        nvlist_t *config;
        uint64_t version;
-       int ret = 0;
+       boolean_t printnl = B_FALSE;
+       int ret;
 
        config = zpool_get_config(zhp, NULL);
        verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
            &version) == 0);
 
-       if (!cbp->cb_newer && SPA_VERSION_IS_SUPPORTED(version) &&
-           version != SPA_VERSION) {
-               if (!cbp->cb_all) {
-                       if (cbp->cb_first) {
-                               (void) printf(gettext("The following pools are "
-                                   "out of date, and can be upgraded.  After "
-                                   "being\nupgraded, these pools will no "
-                                   "longer be accessible by older software "
-                                   "versions.\n\n"));
-                               (void) printf(gettext("VER  POOL\n"));
-                               (void) printf(gettext("---  ------------\n"));
-                               cbp->cb_first = B_FALSE;
-                       }
+       assert(SPA_VERSION_IS_SUPPORTED(version));
 
-                       (void) printf("%2llu   %s\n", (u_longlong_t)version,
-                           zpool_get_name(zhp));
-               } else {
+       if (version < cbp->cb_version) {
+               cbp->cb_first = B_FALSE;
+               ret = upgrade_version(zhp, cbp->cb_version);
+               if (ret != 0)
+                       return (ret);
+               printnl = B_TRUE;
+
+#if 0
+               /*
+                * XXX: This code can be enabled when Illumos commit
+                * 4445fffbbb1ea25fd0e9ea68b9380dd7a6709025 is merged.
+                * It reworks the history logging among other things.
+                */
+
+               /*
+                * If they did "zpool upgrade -a", then we could
+                * be doing ioctls to different pools.  We need
+                * to log this history once to each pool, and bypass
+                * the normal history logging that happens in main().
+                */
+               (void) zpool_log_history(g_zfs, history_str);
+               log_history = B_FALSE;
+#endif
+       }
+
+       if (cbp->cb_version >= SPA_VERSION_FEATURES) {
+               int count;
+               ret = upgrade_enable_all(zhp, &count);
+               if (ret != 0)
+                       return (ret);
+
+               if (count > 0) {
                        cbp->cb_first = B_FALSE;
-                       ret = zpool_upgrade(zhp, cbp->cb_version);
-                       if (!ret) {
-                               (void) printf(gettext("Successfully upgraded "
-                                   "'%s'\n\n"), zpool_get_name(zhp));
-                       }
+                       printnl = B_TRUE;
                }
-       } else if (cbp->cb_newer && !SPA_VERSION_IS_SUPPORTED(version)) {
-               assert(!cbp->cb_all);
+       }
+
+       if (printnl) {
+               (void) printf(gettext("\n"));
+       }
+
+       return (0);
+}
+
+static int
+upgrade_list_older_cb(zpool_handle_t *zhp, void *arg)
+{
+       upgrade_cbdata_t *cbp = arg;
+       nvlist_t *config;
+       uint64_t version;
 
+       config = zpool_get_config(zhp, NULL);
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+           &version) == 0);
+
+       assert(SPA_VERSION_IS_SUPPORTED(version));
+
+       if (version < SPA_VERSION_FEATURES) {
                if (cbp->cb_first) {
                        (void) printf(gettext("The following pools are "
-                           "formatted using an unsupported software version "
-                           "and\ncannot be accessed on the current "
-                           "system.\n\n"));
+                           "formatted with legacy version numbers and can\n"
+                           "be upgraded to use feature flags.  After "
+                           "being upgraded, these pools\nwill no "
+                           "longer be accessible by software that does not "
+                           "support feature\nflags.\n\n"));
                        (void) printf(gettext("VER  POOL\n"));
                        (void) printf(gettext("---  ------------\n"));
                        cbp->cb_first = B_FALSE;
@@ -4349,14 +4655,65 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
                    zpool_get_name(zhp));
        }
 
-       zpool_close(zhp);
-       return (ret);
+       return (0);
+}
+
+static int
+upgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg)
+{
+       upgrade_cbdata_t *cbp = arg;
+       nvlist_t *config;
+       uint64_t version;
+
+       config = zpool_get_config(zhp, NULL);
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+           &version) == 0);
+
+       if (version >= SPA_VERSION_FEATURES) {
+               int i;
+               boolean_t poolfirst = B_TRUE;
+               nvlist_t *enabled = zpool_get_features(zhp);
+
+               for (i = 0; i < SPA_FEATURES; i++) {
+                       const char *fguid = spa_feature_table[i].fi_guid;
+                       const char *fname = spa_feature_table[i].fi_uname;
+                       if (!nvlist_exists(enabled, fguid)) {
+                               if (cbp->cb_first) {
+                                       (void) printf(gettext("\nSome "
+                                           "supported features are not "
+                                           "enabled on the following pools. "
+                                           "Once a\nfeature is enabled the "
+                                           "pool may become incompatible with "
+                                           "software\nthat does not support "
+                                           "the feature. See "
+                                           "zpool-features(5) for "
+                                           "details.\n\n"));
+                                       (void) printf(gettext("POOL  "
+                                           "FEATURE\n"));
+                                       (void) printf(gettext("------"
+                                           "---------\n"));
+                                       cbp->cb_first = B_FALSE;
+                               }
+
+                               if (poolfirst) {
+                                       (void) printf(gettext("%s\n"),
+                                           zpool_get_name(zhp));
+                                       poolfirst = B_FALSE;
+                               }
+
+                               (void) printf(gettext("      %s\n"), fname);
+                       }
+               }
+       }
+
+       return (0);
 }
 
 /* ARGSUSED */
 static int
 upgrade_one(zpool_handle_t *zhp, void *data)
 {
+       boolean_t printnl = B_FALSE;
        upgrade_cbdata_t *cbp = data;
        uint64_t cur_version;
        int ret;
@@ -4371,26 +4728,45 @@ upgrade_one(zpool_handle_t *zhp, void *data)
        cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
        if (cur_version > cbp->cb_version) {
                (void) printf(gettext("Pool '%s' is already formatted "
-                   "using more current version '%llu'.\n"),
+                   "using more current version '%llu'.\n\n"),
                    zpool_get_name(zhp), (u_longlong_t) cur_version);
                return (0);
        }
-       if (cur_version == cbp->cb_version) {
+
+       if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) {
                (void) printf(gettext("Pool '%s' is already formatted "
-                   "using the current version.\n"), zpool_get_name(zhp));
+                   "using version %llu.\n\n"), zpool_get_name(zhp),
+                   (u_longlong_t) cbp->cb_version);
                return (0);
        }
 
-       ret = zpool_upgrade(zhp, cbp->cb_version);
+       if (cur_version != cbp->cb_version) {
+               printnl = B_TRUE;
+               ret = upgrade_version(zhp, cbp->cb_version);
+               if (ret != 0)
+                       return (ret);
+       }
+
+       if (cbp->cb_version >= SPA_VERSION_FEATURES) {
+               int count = 0;
+               ret = upgrade_enable_all(zhp, &count);
+               if (ret != 0)
+                       return (ret);
+
+               if (count != 0) {
+                       printnl = B_TRUE;
+               } else if (cur_version == SPA_VERSION) {
+                       (void) printf(gettext("Pool '%s' already has all "
+                           "supported features enabled.\n"),
+                           zpool_get_name(zhp));
+               }
+       }
 
-       if (!ret) {
-               (void) printf(gettext("Successfully upgraded '%s' "
-                   "from version %llu to version %llu\n\n"),
-                   zpool_get_name(zhp), (u_longlong_t)cur_version,
-                   (u_longlong_t)cbp->cb_version);
+       if (printnl) {
+               (void) printf(gettext("\n"));
        }
 
-       return (ret != 0);
+       return (0);
 }
 
 /*
@@ -4409,6 +4785,7 @@ zpool_do_upgrade(int argc, char **argv)
        upgrade_cbdata_t cb = { 0 };
        int ret = 0;
        boolean_t showversions = B_FALSE;
+       boolean_t upgradeall = B_FALSE;
        char *end;
 
 
@@ -4416,7 +4793,7 @@ zpool_do_upgrade(int argc, char **argv)
        while ((c = getopt(argc, argv, ":avV:")) != -1) {
                switch (c) {
                case 'a':
-                       cb.cb_all = B_TRUE;
+                       upgradeall = B_TRUE;
                        break;
                case 'v':
                        showversions = B_TRUE;
@@ -4449,19 +4826,19 @@ zpool_do_upgrade(int argc, char **argv)
 
        if (cb.cb_version == 0) {
                cb.cb_version = SPA_VERSION;
-       } else if (!cb.cb_all && argc == 0) {
+       } else if (!upgradeall && argc == 0) {
                (void) fprintf(stderr, gettext("-V option is "
                    "incompatible with other arguments\n"));
                usage(B_FALSE);
        }
 
        if (showversions) {
-               if (cb.cb_all || argc != 0) {
+               if (upgradeall || argc != 0) {
                        (void) fprintf(stderr, gettext("-v option is "
                            "incompatible with other arguments\n"));
                        usage(B_FALSE);
                }
-       } else if (cb.cb_all) {
+       } else if (upgradeall) {
                if (argc != 0) {
                        (void) fprintf(stderr, gettext("-a option should not "
                            "be used along with a pool name\n"));
@@ -4471,9 +4848,25 @@ zpool_do_upgrade(int argc, char **argv)
 
        (void) printf(gettext("This system supports ZFS pool feature "
            "flags.\n\n"));
-       cb.cb_first = B_TRUE;
        if (showversions) {
-               (void) printf(gettext("The following versions are "
+               int i;
+
+               (void) printf(gettext("The following features are "
+                   "supported:\n\n"));
+               (void) printf(gettext("FEAT DESCRIPTION\n"));
+               (void) printf("----------------------------------------------"
+                   "---------------\n");
+               for (i = 0; i < SPA_FEATURES; i++) {
+                       zfeature_info_t *fi = &spa_feature_table[i];
+                       const char *ro = fi->fi_can_readonly ?
+                           " (read-only compatible)" : "";
+
+                       (void) printf("%-37s%s\n", fi->fi_uname, ro);
+                       (void) printf("     %s\n", fi->fi_desc);
+               }
+               (void) printf("\n");
+
+               (void) printf(gettext("The following legacy versions are also "
                    "supported:\n\n"));
                (void) printf(gettext("VER  DESCRIPTION\n"));
                (void) printf("---  -----------------------------------------"
@@ -4516,32 +4909,44 @@ zpool_do_upgrade(int argc, char **argv)
                (void) printf(gettext("\nFor more information on a particular "
                    "version, including supported releases,\n"));
                (void) printf(gettext("see the ZFS Administration Guide.\n\n"));
-       } else if (argc == 0) {
-               int notfound;
-
+       } else if (argc == 0 && upgradeall) {
+               cb.cb_first = B_TRUE;
                ret = zpool_iter(g_zfs, upgrade_cb, &cb);
-               notfound = cb.cb_first;
-
-               if (!cb.cb_all && ret == 0) {
-                       if (!cb.cb_first)
-                               (void) printf("\n");
-                       cb.cb_first = B_TRUE;
-                       cb.cb_newer = B_TRUE;
-                       ret = zpool_iter(g_zfs, upgrade_cb, &cb);
-                       if (!cb.cb_first) {
-                               notfound = B_FALSE;
-                               (void) printf("\n");
+               if (ret == 0 && cb.cb_first) {
+                       if (cb.cb_version == SPA_VERSION) {
+                               (void) printf(gettext("All pools are already "
+                                   "formatted using feature flags.\n\n"));
+                               (void) printf(gettext("Every feature flags "
+                                   "pool already has all supported features "
+                                   "enabled.\n"));
+                       } else {
+                               (void) printf(gettext("All pools are already "
+                                   "formatted with version %llu or higher.\n"),
+                                   (u_longlong_t) cb.cb_version);
                        }
                }
+       } else if (argc == 0) {
+               cb.cb_first = B_TRUE;
+               ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb);
+               assert(ret == 0);
+
+               if (cb.cb_first) {
+                       (void) printf(gettext("All pools are formatted "
+                           "using feature flags.\n\n"));
+               } else {
+                       (void) printf(gettext("\nUse 'zpool upgrade -v' "
+                           "for a list of available legacy versions.\n"));
+               }
 
-               if (ret == 0) {
-                       if (notfound)
-                               (void) printf(gettext("All pools are formatted "
-                                   "using this version.\n"));
-                       else if (!cb.cb_all)
-                               (void) printf(gettext("Use 'zpool upgrade -v' "
-                                   "for a list of available versions and "
-                                   "their associated\nfeatures.\n"));
+               cb.cb_first = B_TRUE;
+               ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb);
+               assert(ret == 0);
+
+               if (cb.cb_first) {
+                       (void) printf(gettext("Every feature flags pool has "
+                           "all supported features enabled.\n"));
+               } else {
+                       (void) printf(gettext("\n"));
                }
        } else {
                ret = for_each_pool(argc, argv, B_FALSE, NULL,
@@ -4968,6 +5373,7 @@ zpool_do_events_next(ev_opts_t *opts)
                        zpool_do_events_nvprint(nvl, 8);
                        printf(gettext("\n"));
                }
+               (void) fflush(stdout);
 
                nvlist_free(nvl);
        }
@@ -5063,8 +5469,8 @@ get_callback(zpool_handle_t *zhp, void *data)
                                    NULL, NULL);
                        }
                } else {
-                       if (zpool_get_prop(zhp, pl->pl_prop, value,
-                           sizeof (value), &srctype) != 0)
+                       if (zpool_get_prop_literal(zhp, pl->pl_prop, value,
+                           sizeof (value), &srctype, cbp->cb_literal) != 0)
                                continue;
 
                        zprop_print_one_property(zpool_get_name(zhp), cbp,
@@ -5080,9 +5486,26 @@ zpool_do_get(int argc, char **argv)
 {
        zprop_get_cbdata_t cb = { 0 };
        zprop_list_t fake_name = { 0 };
-       int ret;
+       int c, ret;
 
-       if (argc < 2) {
+       /* check options */
+       while ((c = getopt(argc, argv, "p")) != -1) {
+               switch (c) {
+               case 'p':
+                       cb.cb_literal = B_TRUE;
+                       break;
+
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 1) {
                (void) fprintf(stderr, gettext("missing property "
                    "argument\n"));
                usage(B_FALSE);
@@ -5096,7 +5519,7 @@ zpool_do_get(int argc, char **argv)
        cb.cb_columns[3] = GET_COL_SOURCE;
        cb.cb_type = ZFS_TYPE_POOL;
 
-       if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist,
+       if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist,
            ZFS_TYPE_POOL) != 0)
                usage(B_FALSE);
 
@@ -5107,7 +5530,7 @@ zpool_do_get(int argc, char **argv)
                cb.cb_proplist = &fake_name;
        }
 
-       ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
+       ret = for_each_pool(argc - 1, argv + 1, B_TRUE, &cb.cb_proplist,
            get_callback, &cb);
 
        if (cb.cb_proplist == &fake_name)