mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 10:37:35 +03:00
Illumos #1948: zpool list should show more detailed pool info
Reviewed by: Adam Leventhal <ahl@delphix.com> Reviewed by: Matt Ahrens <matt@delphix.com> Reviewed by: Eric Schrock <eric.schrock@delphix.com> Reviewed by: Richard Lowe <richlowe@richlowe.net> Reviewed by: Albert Lee <trisk@nexenta.com> Reviewed by: Dan McDonald <danmcd@nexenta.com> Reviewed by: Garrett D'Amore <garrett@damore.org> Approved by: Eric Schrock <eric.schrock@delphix.com> References: https://www.illumos.org/issues/1948 Ported by: Martin Matuska <martin@matuska.org> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #685
This commit is contained in:
committed by
Brian Behlendorf
parent
95fd8c9a7f
commit
1bd201e70d
+207
-35
@@ -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->cb_proplist, cbp->cb_scripted);
|
||||
print_pool(zhp, cbp);
|
||||
if (!cbp->cb_verbose)
|
||||
return (0);
|
||||
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user