Skip to content

Commit b07f519

Browse files
committed
Add "zpool status -vv"
Specifying the verbose flag twice will display a list of all corrupt sectors within each corrupt file, as opposed to just the name of the file. Signed-off-by: Alan Somers <[email protected]> Sponsored by: ConnectWise
1 parent 6b3333d commit b07f519

File tree

6 files changed

+102
-26
lines changed

6 files changed

+102
-26
lines changed

cmd/zpool/zpool_main.c

Lines changed: 72 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2590,7 +2590,7 @@ typedef struct status_cbdata {
25902590
int cb_name_flags;
25912591
int cb_namewidth;
25922592
boolean_t cb_allpools;
2593-
boolean_t cb_verbose;
2593+
int cb_verbosity;
25942594
boolean_t cb_literal;
25952595
boolean_t cb_explain;
25962596
boolean_t cb_first;
@@ -3322,7 +3322,7 @@ print_class_vdevs(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
33223322
nvlist_t **child;
33233323
boolean_t printed = B_FALSE;
33243324

3325-
assert(zhp != NULL || !cb->cb_verbose);
3325+
assert(zhp != NULL || cb->cb_verbosity == 0);
33263326

33273327
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
33283328
&children) != 0)
@@ -9478,7 +9478,7 @@ class_vdevs_nvlist(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
94789478
if (!cb->cb_flat_vdevs)
94799479
class_obj = fnvlist_alloc();
94809480

9481-
assert(zhp != NULL || !cb->cb_verbose);
9481+
assert(zhp != NULL || cb->cb_verbosity == 0);
94829482

94839483
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
94849484
&children) != 0)
@@ -9586,26 +9586,38 @@ static void
95869586
errors_nvlist(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *item)
95879587
{
95889588
uint64_t nerr;
9589+
int verbosity = cb->cb_verbosity;
95899590
nvlist_t *config = zpool_get_config(zhp, NULL);
95909591
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
95919592
&nerr) == 0) {
95929593
nice_num_str_nvlist(item, ZPOOL_CONFIG_ERRCOUNT, nerr,
95939594
cb->cb_literal, cb->cb_json_as_int, ZFS_NICENUM_1024);
9594-
if (nerr != 0 && cb->cb_verbose) {
9595+
if (nerr != 0 && cb->cb_verbosity > 0) {
95959596
nvlist_t *nverrlist = NULL;
9596-
if (zpool_get_errlog(zhp, &nverrlist) == 0) {
9597+
if (zpool_get_errlog(zhp, &nverrlist, verbosity) == 0) {
95979598
int i = 0;
95989599
int count = 0;
95999600
size_t len = MAXPATHLEN * 2;
96009601
nvpair_t *elem = NULL;
9602+
char **errl = NULL, *pathbuf = NULL;
9603+
nvlist_t **errnvl = NULL;
96019604

96029605
for (nvpair_t *pair =
96039606
nvlist_next_nvpair(nverrlist, NULL);
96049607
pair != NULL;
96059608
pair = nvlist_next_nvpair(nverrlist, pair))
96069609
count++;
9607-
char **errl = (char **)malloc(
9608-
count * sizeof (char *));
9610+
if (cb->cb_verbosity < 2)
9611+
errl = calloc(count, sizeof (char *));
9612+
else {
9613+
pathbuf = safe_malloc(len);
9614+
errnvl = calloc(count,
9615+
sizeof (nvlist_t *));
9616+
}
9617+
if (errl == NULL && errnvl == NULL) {
9618+
perror("calloc");
9619+
exit(1);
9620+
}
96099621

96109622
while ((elem = nvlist_next_nvpair(nverrlist,
96119623
elem)) != NULL) {
@@ -9618,16 +9630,46 @@ errors_nvlist(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *item)
96189630
ZPOOL_ERR_DATASET, &dsobj) == 0);
96199631
verify(nvlist_lookup_uint64(nv,
96209632
ZPOOL_ERR_OBJECT, &obj) == 0);
9621-
errl[i] = safe_malloc(len);
9622-
zpool_obj_to_path(zhp, dsobj, obj,
9623-
errl[i++], len);
9633+
if (cb->cb_verbosity < 2) {
9634+
errl[i] = safe_malloc(len);
9635+
zpool_obj_to_path(zhp, dsobj,
9636+
obj, errl[i++], len);
9637+
} else {
9638+
uint64_t lvl, blkid;
9639+
9640+
errnvl[i] = fnvlist_alloc();
9641+
lvl = fnvlist_lookup_uint64(nv,
9642+
ZPOOL_ERR_LEVEL);
9643+
blkid = fnvlist_lookup_uint64(
9644+
nv, ZPOOL_ERR_BLKID);
9645+
zpool_obj_to_path(zhp, dsobj,
9646+
obj, pathbuf, len);
9647+
fnvlist_add_string(errnvl[i],
9648+
"path", pathbuf);
9649+
fnvlist_add_uint64(errnvl[i],
9650+
"level", lvl);
9651+
fnvlist_add_uint64(errnvl[i++],
9652+
"record", blkid);
9653+
}
96249654
}
96259655
nvlist_free(nverrlist);
9626-
fnvlist_add_string_array(item, "errlist",
9627-
(const char **)errl, count);
9628-
for (int i = 0; i < count; ++i)
9629-
free(errl[i]);
9630-
free(errl);
9656+
if (cb->cb_verbosity < 2) {
9657+
fnvlist_add_string_array(item,
9658+
"errlist", (const char **)errl,
9659+
count);
9660+
for (int i = 0; i < count; ++i)
9661+
free(errl[i]);
9662+
free(errl);
9663+
} else {
9664+
fnvlist_add_nvlist_array(item,
9665+
"errlist",
9666+
(const nvlist_t **)errnvl,
9667+
count);
9668+
for (int i = 0; i < count; ++i)
9669+
free(errnvl[i]);
9670+
free(errnvl);
9671+
free(pathbuf);
9672+
}
96319673
} else
96329674
fnvlist_add_string(item, "errlist",
96339675
strerror(errno));
@@ -10304,14 +10346,14 @@ print_checkpoint_status(pool_checkpoint_stat_t *pcs)
1030410346
}
1030510347

1030610348
static void
10307-
print_error_log(zpool_handle_t *zhp)
10349+
print_error_log(zpool_handle_t *zhp, int verbosity)
1030810350
{
1030910351
nvlist_t *nverrlist = NULL;
1031010352
nvpair_t *elem;
1031110353
char *pathname;
1031210354
size_t len = MAXPATHLEN * 2;
1031310355

10314-
if (zpool_get_errlog(zhp, &nverrlist) != 0)
10356+
if (zpool_get_errlog(zhp, &nverrlist, verbosity) != 0)
1031510357
return;
1031610358

1031710359
(void) printf("errors: Permanent errors have been "
@@ -10329,7 +10371,16 @@ print_error_log(zpool_handle_t *zhp)
1032910371
verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
1033010372
&obj) == 0);
1033110373
zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
10332-
(void) printf("%7s %s\n", "", pathname);
10374+
if (verbosity > 1) {
10375+
uint64_t level, blkid;
10376+
10377+
blkid = fnvlist_lookup_uint64(nv, ZPOOL_ERR_BLKID);
10378+
level = fnvlist_lookup_uint64(nv, ZPOOL_ERR_LEVEL);
10379+
(void) printf("%7s %s L%lu record %lu\n", "", pathname,
10380+
level, blkid);
10381+
} else {
10382+
(void) printf("%7s %s\n", "", pathname);
10383+
}
1033310384
}
1033410385
free(pathname);
1033510386
nvlist_free(nverrlist);
@@ -11027,14 +11078,14 @@ status_callback(zpool_handle_t *zhp, void *data)
1102711078
if (nerr == 0) {
1102811079
(void) printf(gettext(
1102911080
"errors: No known data errors\n"));
11030-
} else if (!cbp->cb_verbose) {
11081+
} else if (0 == cbp->cb_verbosity) {
1103111082
color_start(ANSI_RED);
1103211083
(void) printf(gettext("errors: %llu data "
1103311084
"errors, use '-v' for a list\n"),
1103411085
(u_longlong_t)nerr);
1103511086
color_end();
1103611087
} else {
11037-
print_error_log(zhp);
11088+
print_error_log(zhp, cbp->cb_verbosity);
1103811089
}
1103911090
}
1104011091

@@ -11161,7 +11212,7 @@ zpool_do_status(int argc, char **argv)
1116111212
get_timestamp_arg(*optarg);
1116211213
break;
1116311214
case 'v':
11164-
cb.cb_verbose = B_TRUE;
11215+
cb.cb_verbosity++;
1116511216
break;
1116611217
case 'j':
1116711218
cb.cb_json = B_TRUE;

include/libzfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ _LIBZFS_H zpool_status_t zpool_import_status(nvlist_t *, const char **,
479479
_LIBZFS_H nvlist_t *zpool_get_config(zpool_handle_t *, nvlist_t **);
480480
_LIBZFS_H nvlist_t *zpool_get_features(zpool_handle_t *);
481481
_LIBZFS_H int zpool_refresh_stats(zpool_handle_t *, boolean_t *);
482-
_LIBZFS_H int zpool_get_errlog(zpool_handle_t *, nvlist_t **);
482+
_LIBZFS_H int zpool_get_errlog(zpool_handle_t *, nvlist_t **, int);
483483
_LIBZFS_H void zpool_add_propname(zpool_handle_t *, const char *);
484484

485485
/*

include/sys/fs/zfs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,8 @@ typedef enum {
17231723
#define ZPOOL_ERR_LIST "error list"
17241724
#define ZPOOL_ERR_DATASET "dataset"
17251725
#define ZPOOL_ERR_OBJECT "object"
1726+
#define ZPOOL_ERR_LEVEL "level"
1727+
#define ZPOOL_ERR_BLKID "blkid"
17261728

17271729
#define HIS_MAX_RECORD_LEN (MAXPATHLEN + MAXPATHLEN + 1)
17281730

lib/libzfs/libzfs.abi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7103,6 +7103,7 @@
71037103
<function-decl name='zpool_get_errlog' mangled-name='zpool_get_errlog' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_get_errlog'>
71047104
<parameter type-id='4c81de99' name='zhp'/>
71057105
<parameter type-id='857bb57e' name='nverrlistp'/>
7106+
<parameter type-id='95e97e5e' name='verbosity'/>
71067107
<return type-id='95e97e5e'/>
71077108
</function-decl>
71087109
<function-decl name='zpool_upgrade' mangled-name='zpool_upgrade' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_upgrade'>

lib/libzfs/libzfs_pool.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4618,7 +4618,7 @@ zpool_add_propname(zpool_handle_t *zhp, const char *propname)
46184618
* caller.
46194619
*/
46204620
int
4621-
zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
4621+
zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp, int verbosity)
46224622
{
46234623
zfs_cmd_t zc = {"\0"};
46244624
libzfs_handle_t *hdl = zhp->zpool_hdl;
@@ -4674,8 +4674,16 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
46744674
for (uint64_t i = 0; i < zblen; i++) {
46754675
nvlist_t *nv;
46764676

4677-
/* ignoring zb_blkid and zb_level for now */
4677+
/* filter out duplicate records */
46784678
if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset &&
4679+
zb[i-1].zb_object == zb[i].zb_object &&
4680+
zb[i-1].zb_level == zb[i].zb_level &&
4681+
zb[i-1].zb_blkid == zb[i].zb_blkid)
4682+
continue;
4683+
4684+
/* filter out duplicate files */
4685+
if (verbosity < 2 && i > 0 &&
4686+
zb[i-1].zb_objset == zb[i].zb_objset &&
46794687
zb[i-1].zb_object == zb[i].zb_object)
46804688
continue;
46814689

@@ -4691,6 +4699,18 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
46914699
nvlist_free(nv);
46924700
goto nomem;
46934701
}
4702+
if (verbosity > 1) {
4703+
if (nvlist_add_uint64(nv, ZPOOL_ERR_LEVEL,
4704+
zb[i].zb_level) != 0) {
4705+
nvlist_free(nv);
4706+
goto nomem;
4707+
}
4708+
if (nvlist_add_uint64(nv, ZPOOL_ERR_BLKID,
4709+
zb[i].zb_blkid) != 0) {
4710+
nvlist_free(nv);
4711+
goto nomem;
4712+
}
4713+
}
46944714
if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) {
46954715
nvlist_free(nv);
46964716
goto nomem;

man/man8/zpool-status.8

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
.\" Copyright 2017 Nexenta Systems, Inc.
2828
.\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
2929
.\"
30-
.Dd February 14, 2024
30+
.Dd July 1, 2025
3131
.Dt ZPOOL-STATUS 8
3232
.Os
3333
.
@@ -156,7 +156,9 @@ See
156156
Display vdev TRIM status.
157157
.It Fl v
158158
Displays verbose data error information, printing out a complete list of all
159-
data errors since the last complete pool scrub.
159+
files containing data errors since the last complete pool scrub.
160+
Specified twice, prints out the complete list of all corrupt records within
161+
each corrupt file.
160162
If the head_errlog feature is enabled and files containing errors have been
161163
removed then the respective filenames will not be reported in subsequent runs
162164
of this command.

0 commit comments

Comments
 (0)