Rebase master to b117
[zfs.git] / cmd / zpool / zpool_main.c
index 1bca45c..c8a33df 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -376,12 +376,11 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props,
                }
                normnm = zpool_prop_to_name(prop);
        } else {
-               if ((fprop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
-                       (void) fprintf(stderr, gettext("property '%s' is "
-                           "not a valid file system property\n"), propname);
-                       return (2);
+               if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
+                       normnm = zfs_prop_to_name(fprop);
+               } else {
+                       normnm = propname;
                }
-               normnm = zfs_prop_to_name(fprop);
        }
 
        if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
@@ -979,14 +978,189 @@ max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
        return (max);
 }
 
+typedef struct spare_cbdata {
+       uint64_t        cb_guid;
+       zpool_handle_t  *cb_zhp;
+} spare_cbdata_t;
+
+static boolean_t
+find_vdev(nvlist_t *nv, uint64_t search)
+{
+       uint64_t guid;
+       nvlist_t **child;
+       uint_t c, children;
+
+       if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
+           search == guid)
+               return (B_TRUE);
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) == 0) {
+               for (c = 0; c < children; c++)
+                       if (find_vdev(child[c], search))
+                               return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+static int
+find_spare(zpool_handle_t *zhp, void *data)
+{
+       spare_cbdata_t *cbp = data;
+       nvlist_t *config, *nvroot;
+
+       config = zpool_get_config(zhp, NULL);
+       verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+
+       if (find_vdev(nvroot, cbp->cb_guid)) {
+               cbp->cb_zhp = zhp;
+               return (1);
+       }
+
+       zpool_close(zhp);
+       return (0);
+}
+
+/*
+ * Print out configuration state as requested by status_callback.
+ */
+void
+print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
+    int namewidth, int depth, boolean_t isspare)
+{
+       nvlist_t **child;
+       uint_t c, children;
+       vdev_stat_t *vs;
+       char rbuf[6], wbuf[6], cbuf[6], repaired[7];
+       char *vname;
+       uint64_t notpresent;
+       spare_cbdata_t cb;
+       char *state;
+
+       verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
+           (uint64_t **)&vs, &c) == 0);
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0)
+               children = 0;
+
+       state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
+       if (isspare) {
+               /*
+                * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
+                * online drives.
+                */
+               if (vs->vs_aux == VDEV_AUX_SPARED)
+                       state = "INUSE";
+               else if (vs->vs_state == VDEV_STATE_HEALTHY)
+                       state = "AVAIL";
+       }
+
+       (void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
+           name, state);
+
+       if (!isspare) {
+               zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
+               zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
+               zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
+               (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
+       }
+
+       if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
+           &notpresent) == 0) {
+               char *path;
+               verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
+               (void) printf("  was %s", path);
+       } else if (vs->vs_aux != 0) {
+               (void) printf("  ");
+
+               switch (vs->vs_aux) {
+               case VDEV_AUX_OPEN_FAILED:
+                       (void) printf(gettext("cannot open"));
+                       break;
+
+               case VDEV_AUX_BAD_GUID_SUM:
+                       (void) printf(gettext("missing device"));
+                       break;
+
+               case VDEV_AUX_NO_REPLICAS:
+                       (void) printf(gettext("insufficient replicas"));
+                       break;
+
+               case VDEV_AUX_VERSION_NEWER:
+                       (void) printf(gettext("newer version"));
+                       break;
+
+               case VDEV_AUX_SPARED:
+                       verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
+                           &cb.cb_guid) == 0);
+                       if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
+                               if (strcmp(zpool_get_name(cb.cb_zhp),
+                                   zpool_get_name(zhp)) == 0)
+                                       (void) printf(gettext("currently in "
+                                           "use"));
+                               else
+                                       (void) printf(gettext("in use by "
+                                           "pool '%s'"),
+                                           zpool_get_name(cb.cb_zhp));
+                               zpool_close(cb.cb_zhp);
+                       } else {
+                               (void) printf(gettext("currently in use"));
+                       }
+                       break;
+
+               case VDEV_AUX_ERR_EXCEEDED:
+                       (void) printf(gettext("too many errors"));
+                       break;
+
+               case VDEV_AUX_IO_FAILURE:
+                       (void) printf(gettext("experienced I/O failures"));
+                       break;
+
+               case VDEV_AUX_BAD_LOG:
+                       (void) printf(gettext("bad intent log"));
+                       break;
+
+               default:
+                       (void) printf(gettext("corrupted data"));
+                       break;
+               }
+       } else if (vs->vs_scrub_repaired != 0 && children == 0) {
+               /*
+                * Report bytes resilvered/repaired on leaf devices.
+                */
+               zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
+               (void) printf(gettext("  %s %s"), repaired,
+                   (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
+                   "resilvered" : "repaired");
+       }
+
+       (void) printf("\n");
+
+       for (c = 0; c < children; c++) {
+               uint64_t is_log = B_FALSE;
+
+               /* Don't print logs here */
+               (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+                   &is_log);
+               if (is_log)
+                       continue;
+               vname = zpool_vdev_name(g_zfs, zhp, child[c]);
+               print_status_config(zhp, vname, child[c],
+                   namewidth, depth + 2, isspare);
+               free(vname);
+       }
+}
+
 
 /*
  * Print the configuration of an exported pool.  Iterate over all vdevs in the
  * pool, printing out the name and status for each one.
  */
 void
-print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
-    boolean_t print_logs)
+print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
 {
        nvlist_t **child;
        uint_t c, children;
@@ -1043,12 +1217,11 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
 
                (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
                    &is_log);
-               if ((is_log && !print_logs) || (!is_log && print_logs))
+               if (is_log)
                        continue;
 
                vname = zpool_vdev_name(g_zfs, NULL, child[c]);
-               print_import_config(vname, child[c],
-                   namewidth, depth + 2, B_FALSE);
+               print_import_config(vname, child[c], namewidth, depth + 2);
                free(vname);
        }
 
@@ -1074,6 +1247,43 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
 }
 
 /*
+ * Print log vdevs.
+ * Logs are recorded as top level vdevs in the main pool child array
+ * but with "is_log" set to 1. We use either print_status_config() or
+ * print_import_config() to print the top level logs then any log
+ * children (eg mirrored slogs) are printed recursively - which
+ * works because only the top level vdev is marked "is_log"
+ */
+static void
+print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
+{
+       uint_t c, children;
+       nvlist_t **child;
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
+           &children) != 0)
+               return;
+
+       (void) printf(gettext("\tlogs\n"));
+
+       for (c = 0; c < children; c++) {
+               uint64_t is_log = B_FALSE;
+               char *name;
+
+               (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+                   &is_log);
+               if (!is_log)
+                       continue;
+               name = zpool_vdev_name(g_zfs, zhp, child[c]);
+               if (verbose)
+                       print_status_config(zhp, name, child[c], namewidth,
+                           2, B_FALSE);
+               else
+                       print_import_config(name, child[c], namewidth, 2);
+               free(name);
+       }
+}
+/*
  * Display the status for the given pool.
  */
 static void
@@ -1241,11 +1451,9 @@ show_import(nvlist_t *config)
        if (namewidth < 10)
                namewidth = 10;
 
-       print_import_config(name, nvroot, namewidth, 0, B_FALSE);
-       if (num_logs(nvroot) > 0) {
-               (void) printf(gettext("\tlogs\n"));
-               print_import_config(name, nvroot, namewidth, 0, B_TRUE);
-       }
+       print_import_config(name, nvroot, namewidth, 0);
+       if (num_logs(nvroot) > 0)
+               print_logs(NULL, nvroot, namewidth, B_FALSE);
 
        if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
                (void) printf(gettext("\n\tAdditional devices are known to "
@@ -1323,7 +1531,8 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
 
        verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL);
 
-       if (zpool_enable_datasets(zhp, mntopts, 0) != 0) {
+       if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
+           zpool_enable_datasets(zhp, mntopts, 0) != 0) {
                zpool_close(zhp);
                return (1);
        }
@@ -2426,10 +2635,14 @@ zpool_do_online(int argc, char **argv)
        zpool_handle_t *zhp;
        int ret = 0;
        vdev_state_t newstate;
+       int flags = 0;
 
        /* check options */
-       while ((c = getopt(argc, argv, "t")) != -1) {
+       while ((c = getopt(argc, argv, "et")) != -1) {
                switch (c) {
+               case 'e':
+                       flags |= ZFS_ONLINE_EXPAND;
+                       break;
                case 't':
                case '?':
                        (void) fprintf(stderr, gettext("invalid option '%c'\n"),
@@ -2457,7 +2670,7 @@ zpool_do_online(int argc, char **argv)
                return (1);
 
        for (i = 1; i < argc; i++) {
-               if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
+               if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
                        if (newstate != VDEV_STATE_HEALTHY) {
                                (void) printf(gettext("warning: device '%s' "
                                    "onlined, but remains in faulted state\n"),
@@ -2714,181 +2927,6 @@ print_scrub_status(nvlist_t *nvroot)
            (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
 }
 
-typedef struct spare_cbdata {
-       uint64_t        cb_guid;
-       zpool_handle_t  *cb_zhp;
-} spare_cbdata_t;
-
-static boolean_t
-find_vdev(nvlist_t *nv, uint64_t search)
-{
-       uint64_t guid;
-       nvlist_t **child;
-       uint_t c, children;
-
-       if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
-           search == guid)
-               return (B_TRUE);
-
-       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
-           &child, &children) == 0) {
-               for (c = 0; c < children; c++)
-                       if (find_vdev(child[c], search))
-                               return (B_TRUE);
-       }
-
-       return (B_FALSE);
-}
-
-static int
-find_spare(zpool_handle_t *zhp, void *data)
-{
-       spare_cbdata_t *cbp = data;
-       nvlist_t *config, *nvroot;
-
-       config = zpool_get_config(zhp, NULL);
-       verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
-           &nvroot) == 0);
-
-       if (find_vdev(nvroot, cbp->cb_guid)) {
-               cbp->cb_zhp = zhp;
-               return (1);
-       }
-
-       zpool_close(zhp);
-       return (0);
-}
-
-/*
- * Print out configuration state as requested by status_callback.
- */
-void
-print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
-    int namewidth, int depth, boolean_t isspare, boolean_t print_logs)
-{
-       nvlist_t **child;
-       uint_t c, children;
-       vdev_stat_t *vs;
-       char rbuf[6], wbuf[6], cbuf[6], repaired[7];
-       char *vname;
-       uint64_t notpresent;
-       spare_cbdata_t cb;
-       char *state;
-
-       verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
-           (uint64_t **)&vs, &c) == 0);
-
-       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
-           &child, &children) != 0)
-               children = 0;
-
-       state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
-       if (isspare) {
-               /*
-                * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
-                * online drives.
-                */
-               if (vs->vs_aux == VDEV_AUX_SPARED)
-                       state = "INUSE";
-               else if (vs->vs_state == VDEV_STATE_HEALTHY)
-                       state = "AVAIL";
-       }
-
-       (void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
-           name, state);
-
-       if (!isspare) {
-               zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
-               zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
-               zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
-               (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
-       }
-
-       if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
-           &notpresent) == 0) {
-               char *path;
-               verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
-               (void) printf("  was %s", path);
-       } else if (vs->vs_aux != 0) {
-               (void) printf("  ");
-
-               switch (vs->vs_aux) {
-               case VDEV_AUX_OPEN_FAILED:
-                       (void) printf(gettext("cannot open"));
-                       break;
-
-               case VDEV_AUX_BAD_GUID_SUM:
-                       (void) printf(gettext("missing device"));
-                       break;
-
-               case VDEV_AUX_NO_REPLICAS:
-                       (void) printf(gettext("insufficient replicas"));
-                       break;
-
-               case VDEV_AUX_VERSION_NEWER:
-                       (void) printf(gettext("newer version"));
-                       break;
-
-               case VDEV_AUX_SPARED:
-                       verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
-                           &cb.cb_guid) == 0);
-                       if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
-                               if (strcmp(zpool_get_name(cb.cb_zhp),
-                                   zpool_get_name(zhp)) == 0)
-                                       (void) printf(gettext("currently in "
-                                           "use"));
-                               else
-                                       (void) printf(gettext("in use by "
-                                           "pool '%s'"),
-                                           zpool_get_name(cb.cb_zhp));
-                               zpool_close(cb.cb_zhp);
-                       } else {
-                               (void) printf(gettext("currently in use"));
-                       }
-                       break;
-
-               case VDEV_AUX_ERR_EXCEEDED:
-                       (void) printf(gettext("too many errors"));
-                       break;
-
-               case VDEV_AUX_IO_FAILURE:
-                       (void) printf(gettext("experienced I/O failures"));
-                       break;
-
-               case VDEV_AUX_BAD_LOG:
-                       (void) printf(gettext("bad intent log"));
-                       break;
-
-               default:
-                       (void) printf(gettext("corrupted data"));
-                       break;
-               }
-       } else if (vs->vs_scrub_repaired != 0 && children == 0) {
-               /*
-                * Report bytes resilvered/repaired on leaf devices.
-                */
-               zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
-               (void) printf(gettext("  %s %s"), repaired,
-                   (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
-                   "resilvered" : "repaired");
-       }
-
-       (void) printf("\n");
-
-       for (c = 0; c < children; c++) {
-               uint64_t is_log = B_FALSE;
-
-               (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
-                   &is_log);
-               if ((is_log && !print_logs) || (!is_log && print_logs))
-                       continue;
-               vname = zpool_vdev_name(g_zfs, zhp, child[c]);
-               print_status_config(zhp, vname, child[c],
-                   namewidth, depth + 2, isspare, B_FALSE);
-               free(vname);
-       }
-}
-
 static void
 print_error_log(zpool_handle_t *zhp)
 {
@@ -2939,7 +2977,7 @@ print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
        for (i = 0; i < nspares; i++) {
                name = zpool_vdev_name(g_zfs, zhp, spares[i]);
                print_status_config(zhp, name, spares[i],
-                   namewidth, 2, B_TRUE, B_FALSE);
+                   namewidth, 2, B_TRUE);
                free(name);
        }
 }
@@ -2959,7 +2997,7 @@ print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
        for (i = 0; i < nl2cache; i++) {
                name = zpool_vdev_name(g_zfs, zhp, l2cache[i]);
                print_status_config(zhp, name, l2cache[i],
-                   namewidth, 2, B_FALSE, B_FALSE);
+                   namewidth, 2, B_FALSE);
                free(name);
        }
 }
@@ -3189,11 +3227,10 @@ status_callback(zpool_handle_t *zhp, void *data)
                (void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
                    "NAME", "STATE", "READ", "WRITE", "CKSUM");
                print_status_config(zhp, zpool_get_name(zhp), nvroot,
-                   namewidth, 0, B_FALSE, B_FALSE);
-               if (num_logs(nvroot) > 0)
-                       print_status_config(zhp, "logs", nvroot, namewidth, 0,
-                           B_FALSE, B_TRUE);
+                   namewidth, 0, B_FALSE);
 
+               if (num_logs(nvroot) > 0)
+                       print_logs(zhp, nvroot, namewidth, B_TRUE);
                if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
                    &l2cache, &nl2cache) == 0)
                        print_l2cache(zhp, l2cache, nl2cache, namewidth);
@@ -3417,7 +3454,7 @@ zpool_do_upgrade(int argc, char **argv)
 
 
        /* check options */
-       while ((c = getopt(argc, argv, "avV:")) != -1) {
+       while ((c = getopt(argc, argv, ":avV:")) != -1) {
                switch (c) {
                case 'a':
                        cb.cb_all = B_TRUE;
@@ -3434,6 +3471,11 @@ zpool_do_upgrade(int argc, char **argv)
                                usage(B_FALSE);
                        }
                        break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing argument for "
+                           "'%c' option\n"), optopt);
+                       usage(B_FALSE);
+                       break;
                case '?':
                        (void) fprintf(stderr, gettext("invalid option '%c'\n"),
                            optopt);
@@ -3494,8 +3536,9 @@ zpool_do_upgrade(int argc, char **argv)
                (void) printf(gettext(" 11  Improved scrub performance\n"));
                (void) printf(gettext(" 12  Snapshot properties\n"));
                (void) printf(gettext(" 13  snapused property\n"));
-               (void) printf(gettext(" 14  passthrough-x aclinherit "
-                   "support\n"));
+               (void) printf(gettext(" 14  passthrough-x aclinherit\n"));
+               (void) printf(gettext(" 15  user/group space accounting\n"));
+               (void) printf(gettext(" 16  stmf property support\n"));
                (void) printf(gettext("For more information on a particular "
                    "version, including supported releases, see:\n\n"));
                (void) printf("http://www.opensolaris.org/os/community/zfs/"