summaryrefslogtreecommitdiffstats
path: root/cmd/zpool/zpool_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/zpool/zpool_main.c')
-rw-r--r--cmd/zpool/zpool_main.c242
1 files changed, 207 insertions, 35 deletions
diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c
index cf8d5ed60..56617323f 100644
--- a/cmd/zpool/zpool_main.c
+++ b/cmd/zpool/zpool_main.c
@@ -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 by Delphix. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright (c) 2012 by Frederik Wessels. All rights reserved.
*/
@@ -43,6 +43,7 @@
#include <priv.h>
#include <pwd.h>
#include <zone.h>
+#include <zfs_prop.h>
#include <sys/fs/zfs.h>
#include <sys/stat.h>
#include <sys/fm/util.h>
@@ -68,6 +69,7 @@ static int zpool_do_status(int, char **);
static int zpool_do_online(int, char **);
static int zpool_do_offline(int, char **);
static int zpool_do_clear(int, char **);
+static int zpool_do_reopen(int, char **);
static int zpool_do_reguid(int, char **);
@@ -131,7 +133,8 @@ typedef enum {
HELP_GET,
HELP_SET,
HELP_SPLIT,
- HELP_REGUID
+ HELP_REGUID,
+ HELP_REOPEN
} zpool_help_t;
@@ -164,6 +167,7 @@ static zpool_command_t command_table[] = {
{ "online", zpool_do_online, HELP_ONLINE },
{ "offline", zpool_do_offline, HELP_OFFLINE },
{ "clear", zpool_do_clear, HELP_CLEAR },
+ { "reopen", zpool_do_reopen, HELP_REOPEN },
{ NULL },
{ "attach", zpool_do_attach, HELP_ATTACH },
{ "detach", zpool_do_detach, HELP_DETACH },
@@ -238,6 +242,8 @@ get_usage(zpool_help_t idx) {
"[new-device]\n"));
case HELP_REMOVE:
return (gettext("\tremove <pool> <device> ...\n"));
+ case HELP_REOPEN:
+ return (""); /* Undocumented command */
case HELP_SCRUB:
return (gettext("\tscrub [-s] <pool> ...\n"));
case HELP_STATUS:
@@ -2018,10 +2024,10 @@ error:
}
typedef struct iostat_cbdata {
- zpool_list_t *cb_list;
- int cb_verbose;
- int cb_iteration;
+ boolean_t cb_verbose;
int cb_namewidth;
+ int cb_iteration;
+ zpool_list_t *cb_list;
} iostat_cbdata_t;
static void
@@ -2518,8 +2524,9 @@ zpool_do_iostat(int argc, char **argv)
}
typedef struct list_cbdata {
+ boolean_t cb_verbose;
+ int cb_namewidth;
boolean_t cb_scripted;
- boolean_t cb_first;
zprop_list_t *cb_proplist;
} list_cbdata_t;
@@ -2527,16 +2534,27 @@ typedef struct list_cbdata {
* Given a list of columns to display, output appropriate headers for each one.
*/
static void
-print_header(zprop_list_t *pl)
+print_header(list_cbdata_t *cb)
{
+ zprop_list_t *pl = cb->cb_proplist;
const char *header;
boolean_t first = B_TRUE;
boolean_t right_justify;
+ size_t width = 0;
for (; pl != NULL; pl = pl->pl_next) {
if (pl->pl_prop == ZPROP_INVAL)
continue;
+ width = pl->pl_width;
+ if (first && cb->cb_verbose) {
+ /*
+ * Reset the width to accommodate the verbose listing
+ * of devices.
+ */
+ width = cb->cb_namewidth;
+ }
+
if (!first)
(void) printf(" ");
else
@@ -2548,9 +2566,9 @@ print_header(zprop_list_t *pl)
if (pl->pl_next == NULL && !right_justify)
(void) printf("%s", header);
else if (right_justify)
- (void) printf("%*s", (int)pl->pl_width, header);
+ (void) printf("%*s", (int)width, header);
else
- (void) printf("%-*s", (int)pl->pl_width, header);
+ (void) printf("%-*s", (int)width, header);
}
(void) printf("\n");
@@ -2561,17 +2579,28 @@ print_header(zprop_list_t *pl)
* to the described layout.
*/
static void
-print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
+print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
{
+ zprop_list_t *pl = cb->cb_proplist;
boolean_t first = B_TRUE;
char property[ZPOOL_MAXPROPLEN];
char *propstr;
boolean_t right_justify;
- int width;
+ size_t width;
for (; pl != NULL; pl = pl->pl_next) {
+
+ width = pl->pl_width;
+ if (first && cb->cb_verbose) {
+ /*
+ * Reset the width to accommodate the verbose listing
+ * of devices.
+ */
+ width = cb->cb_namewidth;
+ }
+
if (!first) {
- if (scripted)
+ if (cb->cb_scripted)
(void) printf("\t");
else
(void) printf(" ");
@@ -2581,7 +2610,10 @@ print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
right_justify = B_FALSE;
if (pl->pl_prop != ZPROP_INVAL) {
- if (zpool_get_prop(zhp, pl->pl_prop, property,
+ if (pl->pl_prop == ZPOOL_PROP_EXPANDSZ &&
+ zpool_get_prop_int(zhp, pl->pl_prop, NULL) == 0)
+ propstr = "-";
+ else if (zpool_get_prop(zhp, pl->pl_prop, property,
sizeof (property), NULL) != 0)
propstr = "-";
else
@@ -2592,24 +2624,118 @@ print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
propstr = "-";
}
- width = pl->pl_width;
/*
* If this is being called in scripted mode, or if this is the
* last column and it is left-justified, don't include a width
* format specifier.
*/
- if (scripted || (pl->pl_next == NULL && !right_justify))
+ if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
(void) printf("%s", propstr);
else if (right_justify)
- (void) printf("%*s", width, propstr);
+ (void) printf("%*s", (int)width, propstr);
else
- (void) printf("%-*s", width, propstr);
+ (void) printf("%-*s", (int)width, propstr);
}
(void) printf("\n");
}
+static void
+print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted)
+{
+ char propval[64];
+ boolean_t fixed;
+ size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
+
+ zfs_nicenum(value, propval, sizeof (propval));
+
+ if (prop == ZPOOL_PROP_EXPANDSZ && value == 0)
+ (void) strlcpy(propval, "-", sizeof (propval));
+
+ if (scripted)
+ (void) printf("\t%s", propval);
+ else
+ (void) printf(" %*s", (int)width, propval);
+}
+
+void
+print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
+ list_cbdata_t *cb, int depth)
+{
+ nvlist_t **child;
+ vdev_stat_t *vs;
+ uint_t c, children;
+ char *vname;
+ boolean_t scripted = cb->cb_scripted;
+
+ verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &c) == 0);
+
+ if (name != NULL) {
+ if (scripted)
+ (void) printf("\t%s", name);
+ else if (strlen(name) + depth > cb->cb_namewidth)
+ (void) printf("%*s%s", depth, "", name);
+ else
+ (void) printf("%*s%s%*s", depth, "", name,
+ (int)(cb->cb_namewidth - strlen(name) - depth), "");
+
+ /* only toplevel vdevs have capacity stats */
+ if (vs->vs_space == 0) {
+ if (scripted)
+ (void) printf("\t-\t-\t-");
+ else
+ (void) printf(" - - -");
+ } else {
+ print_one_column(ZPOOL_PROP_SIZE, vs->vs_space,
+ scripted);
+ print_one_column(ZPOOL_PROP_CAPACITY, vs->vs_alloc,
+ scripted);
+ print_one_column(ZPOOL_PROP_FREE,
+ vs->vs_space - vs->vs_alloc, scripted);
+ }
+ print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize,
+ scripted);
+ (void) printf("\n");
+ }
+
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+ &child, &children) != 0)
+ return;
+
+ for (c = 0; c < children; c++) {
+ uint64_t ishole = B_FALSE;
+
+ if (nvlist_lookup_uint64(child[c],
+ ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
+ continue;
+
+ vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
+ print_list_stats(zhp, vname, child[c], cb, depth + 2);
+ free(vname);
+ }
+
+ /*
+ * Include level 2 ARC devices in iostat output
+ */
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+ &child, &children) != 0)
+ return;
+
+ if (children > 0) {
+ (void) printf("%-*s - - - - - "
+ "-\n", cb->cb_namewidth, "cache");
+ for (c = 0; c < children; c++) {
+ vname = zpool_vdev_name(g_zfs, zhp, child[c],
+ B_FALSE);
+ print_list_stats(zhp, vname, child[c], cb, depth + 2);
+ free(vname);
+ }
+ }
+}
+
+
/*
* Generic callback function to list a pool.
*/
@@ -2617,14 +2743,18 @@ int
list_callback(zpool_handle_t *zhp, void *data)
{
list_cbdata_t *cbp = data;
+ nvlist_t *config;
+ nvlist_t *nvroot;
- if (cbp->cb_first) {
- if (!cbp->cb_scripted)
- print_header(cbp->cb_proplist);
- cbp->cb_first = B_FALSE;
- }
+ config = zpool_get_config(zhp, NULL);
+
+ print_pool(zhp, cbp);
+ if (!cbp->cb_verbose)
+ return (0);
- print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+ print_list_stats(zhp, NULL, nvroot, cbp, 0);
return (0);
}
@@ -2648,12 +2778,15 @@ zpool_do_list(int argc, char **argv)
int ret;
list_cbdata_t cb = { 0 };
static char default_props[] =
- "name,size,allocated,free,capacity,dedupratio,health,altroot";
+ "name,size,allocated,free,capacity,dedupratio,"
+ "health,altroot";
char *props = default_props;
unsigned long interval = 0, count = 0;
+ zpool_list_t *list;
+ boolean_t first = B_TRUE;
/* check options */
- while ((c = getopt(argc, argv, ":Ho:T:")) != -1) {
+ while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) {
switch (c) {
case 'H':
cb.cb_scripted = B_TRUE;
@@ -2664,6 +2797,9 @@ zpool_do_list(int argc, char **argv)
case 'T':
get_timestamp_arg(*optarg);
break;
+ case 'v':
+ cb.cb_verbose = B_TRUE;
+ break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt);
@@ -2684,23 +2820,29 @@ zpool_do_list(int argc, char **argv)
if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
usage(B_FALSE);
- cb.cb_first = B_TRUE;
+ if ((list = pool_list_get(argc, argv, &cb.cb_proplist, &ret)) == NULL)
+ return (1);
+
+ if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
+ (void) printf(gettext("no pools available\n"));
+ zprop_free_list(cb.cb_proplist);
+ return (0);
+ }
for (;;) {
+ pool_list_update(list);
+
+ if (pool_list_count(list) == 0)
+ break;
if (timestamp_fmt != NODATE)
print_timestamp(timestamp_fmt);
- ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
- list_callback, &cb);
-
- if (argc == 0 && cb.cb_first)
- (void) fprintf(stderr, gettext("no pools available\n"));
- else if (argc && cb.cb_first) {
- /* cannot open the given pool */
- zprop_free_list(cb.cb_proplist);
- return (1);
+ if (!cb.cb_scripted && (first || cb.cb_verbose)) {
+ print_header(&cb);
+ first = B_FALSE;
}
+ ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
if (interval == 0)
break;
@@ -3293,6 +3435,36 @@ 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 ret = 0;
+ zpool_handle_t *zhp;
+ char *pool;
+
+ argc--;
+ argv++;
+
+ if (argc != 1)
+ return (2);
+
+ pool = argv[0];
+ if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
+ return (1);
+
+ ret = zpool_reopen(zhp);
+ zpool_close(zhp);
+ return (ret);
+}
+
typedef struct scrub_cbdata {
int cb_type;
int cb_argc;