Skip to content

Commit 072ab34

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 Signed-off-by: Alan Somers <[email protected]>
1 parent eacf618 commit 072ab34

File tree

5 files changed

+100
-26
lines changed

5 files changed

+100
-26
lines changed

cmd/zpool/zpool_main.c

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2596,7 +2596,7 @@ typedef struct status_cbdata {
25962596
int cb_name_flags;
25972597
int cb_namewidth;
25982598
boolean_t cb_allpools;
2599-
boolean_t cb_verbose;
2599+
int cb_verbosity;
26002600
boolean_t cb_literal;
26012601
boolean_t cb_explain;
26022602
boolean_t cb_first;
@@ -3328,7 +3328,7 @@ print_class_vdevs(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
33283328
nvlist_t **child;
33293329
boolean_t printed = B_FALSE;
33303330

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

33333333
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
33343334
&children) != 0)
@@ -9407,7 +9407,7 @@ class_vdevs_nvlist(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
94079407
if (!cb->cb_flat_vdevs)
94089408
class_obj = fnvlist_alloc();
94099409

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

94129412
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
94139413
&children) != 0)
@@ -9515,26 +9515,35 @@ static void
95159515
errors_nvlist(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *item)
95169516
{
95179517
uint64_t nerr;
9518+
int verbosity = cb->cb_verbosity;
95189519
nvlist_t *config = zpool_get_config(zhp, NULL);
95199520
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
95209521
&nerr) == 0) {
95219522
nice_num_str_nvlist(item, ZPOOL_CONFIG_ERRCOUNT, nerr,
95229523
cb->cb_literal, cb->cb_json_as_int, ZFS_NICENUM_1024);
9523-
if (nerr != 0 && cb->cb_verbose) {
9524+
if (nerr != 0 && cb->cb_verbosity > 0) {
95249525
nvlist_t *nverrlist = NULL;
9525-
if (zpool_get_errlog(zhp, &nverrlist) == 0) {
9526+
if (zpool_get_errlog(zhp, &nverrlist, verbosity) == 0) {
95269527
int i = 0;
95279528
int count = 0;
95289529
size_t len = MAXPATHLEN * 2;
95299530
nvpair_t *elem = NULL;
9531+
char **errl, *pathbuf = NULL;
9532+
nvlist_t **errnvl;
95309533

95319534
for (nvpair_t *pair =
95329535
nvlist_next_nvpair(nverrlist, NULL);
95339536
pair != NULL;
95349537
pair = nvlist_next_nvpair(nverrlist, pair))
95359538
count++;
9536-
char **errl = (char **)malloc(
9537-
count * sizeof (char *));
9539+
if (cb->cb_verbosity < 2)
9540+
errl = (char **)malloc(
9541+
count * sizeof (char *));
9542+
else {
9543+
pathbuf = safe_malloc(len);
9544+
errnvl = calloc(count,
9545+
sizeof (nvlist_t *));
9546+
}
95389547

95399548
while ((elem = nvlist_next_nvpair(nverrlist,
95409549
elem)) != NULL) {
@@ -9547,16 +9556,46 @@ errors_nvlist(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *item)
95479556
ZPOOL_ERR_DATASET, &dsobj) == 0);
95489557
verify(nvlist_lookup_uint64(nv,
95499558
ZPOOL_ERR_OBJECT, &obj) == 0);
9550-
errl[i] = safe_malloc(len);
9551-
zpool_obj_to_path(zhp, dsobj, obj,
9552-
errl[i++], len);
9559+
if (cb->cb_verbosity < 2) {
9560+
errl[i] = safe_malloc(len);
9561+
zpool_obj_to_path(zhp, dsobj,
9562+
obj, errl[i++], len);
9563+
} else {
9564+
uint64_t lvl, blkid;
9565+
9566+
errnvl[i] = fnvlist_alloc();
9567+
lvl = fnvlist_lookup_uint64(nv,
9568+
ZPOOL_ERR_LEVEL);
9569+
blkid = fnvlist_lookup_uint64(
9570+
nv, ZPOOL_ERR_BLKID);
9571+
zpool_obj_to_path(zhp, dsobj,
9572+
obj, pathbuf, len);
9573+
fnvlist_add_string(errnvl[i],
9574+
"path", pathbuf);
9575+
fnvlist_add_uint64(errnvl[i],
9576+
"level", lvl);
9577+
fnvlist_add_uint64(errnvl[i++],
9578+
"record", blkid);
9579+
}
95539580
}
95549581
nvlist_free(nverrlist);
9555-
fnvlist_add_string_array(item, "errlist",
9556-
(const char **)errl, count);
9557-
for (int i = 0; i < count; ++i)
9558-
free(errl[i]);
9559-
free(errl);
9582+
if (cb->cb_verbosity < 2) {
9583+
fnvlist_add_string_array(item,
9584+
"errlist", (const char **)errl,
9585+
count);
9586+
for (int i = 0; i < count; ++i)
9587+
free(errl[i]);
9588+
free(errl);
9589+
} else {
9590+
fnvlist_add_nvlist_array(item,
9591+
"errlist",
9592+
(const nvlist_t **)errnvl,
9593+
count);
9594+
for (int i = 0; i < count; ++i)
9595+
free(errnvl[i]);
9596+
free(errnvl);
9597+
free(pathbuf);
9598+
}
95609599
} else
95619600
fnvlist_add_string(item, "errlist",
95629601
strerror(errno));
@@ -10233,14 +10272,14 @@ print_checkpoint_status(pool_checkpoint_stat_t *pcs)
1023310272
}
1023410273

1023510274
static void
10236-
print_error_log(zpool_handle_t *zhp)
10275+
print_error_log(zpool_handle_t *zhp, int verbosity)
1023710276
{
1023810277
nvlist_t *nverrlist = NULL;
1023910278
nvpair_t *elem;
1024010279
char *pathname;
1024110280
size_t len = MAXPATHLEN * 2;
1024210281

10243-
if (zpool_get_errlog(zhp, &nverrlist) != 0)
10282+
if (zpool_get_errlog(zhp, &nverrlist, verbosity) != 0)
1024410283
return;
1024510284

1024610285
(void) printf("errors: Permanent errors have been "
@@ -10258,7 +10297,18 @@ print_error_log(zpool_handle_t *zhp)
1025810297
verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
1025910298
&obj) == 0);
1026010299
zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
10261-
(void) printf("%7s %s\n", "", pathname);
10300+
if (verbosity > 1) {
10301+
uint64_t level, blkid;
10302+
10303+
verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_BLKID,
10304+
&blkid) == 0);
10305+
verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_LEVEL,
10306+
&level) == 0);
10307+
(void) printf("%7s %s L%lu record %lu\n", "", pathname,
10308+
level, blkid);
10309+
} else {
10310+
(void) printf("%7s %s\n", "", pathname);
10311+
}
1026210312
}
1026310313
free(pathname);
1026410314
nvlist_free(nverrlist);
@@ -10957,14 +11007,14 @@ status_callback(zpool_handle_t *zhp, void *data)
1095711007
if (nerr == 0) {
1095811008
(void) printf(gettext(
1095911009
"errors: No known data errors\n"));
10960-
} else if (!cbp->cb_verbose) {
11010+
} else if (0 == cbp->cb_verbosity) {
1096111011
color_start(ANSI_RED);
1096211012
(void) printf(gettext("errors: %llu data "
1096311013
"errors, use '-v' for a list\n"),
1096411014
(u_longlong_t)nerr);
1096511015
color_end();
1096611016
} else {
10967-
print_error_log(zhp);
11017+
print_error_log(zhp, cbp->cb_verbosity);
1096811018
}
1096911019
}
1097011020

@@ -11091,7 +11141,7 @@ zpool_do_status(int argc, char **argv)
1109111141
get_timestamp_arg(*optarg);
1109211142
break;
1109311143
case 'v':
11094-
cb.cb_verbose = B_TRUE;
11144+
cb.cb_verbosity++;
1109511145
break;
1109611146
case 'j':
1109711147
cb.cb_json = B_TRUE;

include/libzfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ _LIBZFS_H zpool_status_t zpool_import_status(nvlist_t *, const char **,
464464
_LIBZFS_H nvlist_t *zpool_get_config(zpool_handle_t *, nvlist_t **);
465465
_LIBZFS_H nvlist_t *zpool_get_features(zpool_handle_t *);
466466
_LIBZFS_H int zpool_refresh_stats(zpool_handle_t *, boolean_t *);
467-
_LIBZFS_H int zpool_get_errlog(zpool_handle_t *, nvlist_t **);
467+
_LIBZFS_H int zpool_get_errlog(zpool_handle_t *, nvlist_t **, int);
468468
_LIBZFS_H void zpool_add_propname(zpool_handle_t *, const char *);
469469

470470
/*

include/sys/fs/zfs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,8 @@ typedef enum {
17201720
#define ZPOOL_ERR_LIST "error list"
17211721
#define ZPOOL_ERR_DATASET "dataset"
17221722
#define ZPOOL_ERR_OBJECT "object"
1723+
#define ZPOOL_ERR_LEVEL "level"
1724+
#define ZPOOL_ERR_BLKID "blkid"
17231725

17241726
#define HIS_MAX_RECORD_LEN (MAXPATHLEN + MAXPATHLEN + 1)
17251727

lib/libzfs/libzfs_pool.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4567,7 +4567,7 @@ zpool_add_propname(zpool_handle_t *zhp, const char *propname)
45674567
* caller.
45684568
*/
45694569
int
4570-
zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
4570+
zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp, int verbosity)
45714571
{
45724572
zfs_cmd_t zc = {"\0"};
45734573
libzfs_handle_t *hdl = zhp->zpool_hdl;
@@ -4623,8 +4623,16 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
46234623
for (uint64_t i = 0; i < zblen; i++) {
46244624
nvlist_t *nv;
46254625

4626-
/* ignoring zb_blkid and zb_level for now */
4626+
/* filter out duplicate records */
46274627
if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset &&
4628+
zb[i-1].zb_object == zb[i].zb_object &&
4629+
zb[i-1].zb_level == zb[i].zb_level &&
4630+
zb[i-1].zb_blkid == zb[i].zb_blkid)
4631+
continue;
4632+
4633+
/* filter out duplicate files */
4634+
if (verbosity < 2 && i > 0 &&
4635+
zb[i-1].zb_objset == zb[i].zb_objset &&
46284636
zb[i-1].zb_object == zb[i].zb_object)
46294637
continue;
46304638

@@ -4640,6 +4648,18 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
46404648
nvlist_free(nv);
46414649
goto nomem;
46424650
}
4651+
if (verbosity > 1) {
4652+
if (nvlist_add_uint64(nv, ZPOOL_ERR_LEVEL,
4653+
zb[i].zb_level) != 0) {
4654+
nvlist_free(nv);
4655+
goto nomem;
4656+
}
4657+
if (nvlist_add_uint64(nv, ZPOOL_ERR_BLKID,
4658+
zb[i].zb_blkid) != 0) {
4659+
nvlist_free(nv);
4660+
goto nomem;
4661+
}
4662+
}
46434663
if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) {
46444664
nvlist_free(nv);
46454665
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)