zinject: show more device fault fields

Once there's a few different kinds injected, its pretty hard to see them
otherwise.

So, lets show IO type, error type and frequency fields in the table too.

Since we now have to convert from error code to pretty string, refactor
the error names into a table and add lookup functions.

Sponsored-by: Klara, Inc.
Sponsored-by: Wasabi Technology, Inc.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Brian Atkinson <batkinson@lanl.gov>
Reviewed-by: Tino Reichardt <milky-zfs@mcmilk.de>
Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
Closes #15953
This commit is contained in:
Rob Norris 2024-03-01 10:38:41 +11:00 committed by Brian Behlendorf
parent ca678bc0bc
commit fa480fe5ba
1 changed files with 52 additions and 21 deletions

View File

@ -22,6 +22,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
* Copyright (c) 2017, Intel Corporation.
* Copyright (c) 2024, Klara Inc.
*/
/*
@ -208,6 +209,37 @@ type_to_name(uint64_t type)
}
}
struct errstr {
int err;
const char *str;
};
static const struct errstr errstrtable[] = {
{ EIO, "io" },
{ ECKSUM, "checksum" },
{ EINVAL, "decompress" },
{ EACCES, "decrypt" },
{ ENXIO, "nxio" },
{ ECHILD, "dtl" },
{ EILSEQ, "corrupt" },
{ 0, NULL },
};
static int
str_to_err(const char *str)
{
for (int i = 0; errstrtable[i].str != NULL; i++)
if (strcasecmp(errstrtable[i].str, str) == 0)
return (errstrtable[i].err);
return (-1);
}
static const char *
err_to_str(int err)
{
for (int i = 0; errstrtable[i].str != NULL; i++)
if (errstrtable[i].err == err)
return (errstrtable[i].str);
return ("[unknown]");
}
/*
* Print usage message.
@ -392,6 +424,10 @@ static int
print_device_handler(int id, const char *pool, zinject_record_t *record,
void *data)
{
static const char *iotypestr[] = {
"null", "read", "write", "free", "claim", "ioctl", "trim", "all",
};
int *count = data;
if (record->zi_guid == 0 || record->zi_func[0] != '\0')
@ -401,14 +437,21 @@ print_device_handler(int id, const char *pool, zinject_record_t *record,
return (0);
if (*count == 0) {
(void) printf("%3s %-15s %s\n", "ID", "POOL", "GUID");
(void) printf("--- --------------- ----------------\n");
(void) printf("%3s %-15s %-16s %-5s %-10s %-9s\n",
"ID", "POOL", "GUID", "TYPE", "ERROR", "FREQ");
(void) printf(
"--- --------------- ---------------- "
"----- ---------- ---------\n");
}
*count += 1;
(void) printf("%3d %-15s %llx\n", id, pool,
(u_longlong_t)record->zi_guid);
double freq = record->zi_freq == 0 ? 100.0f :
(((double)record->zi_freq) / ZI_PERCENTAGE_MAX) * 100.0f;
(void) printf("%3d %-15s %llx %-5s %-10s %8.4f%%\n", id, pool,
(u_longlong_t)record->zi_guid, iotypestr[record->zi_iotype],
err_to_str(record->zi_error), freq);
return (0);
}
@ -842,24 +885,12 @@ main(int argc, char **argv)
}
break;
case 'e':
if (strcasecmp(optarg, "io") == 0) {
error = EIO;
} else if (strcasecmp(optarg, "checksum") == 0) {
error = ECKSUM;
} else if (strcasecmp(optarg, "decompress") == 0) {
error = EINVAL;
} else if (strcasecmp(optarg, "decrypt") == 0) {
error = EACCES;
} else if (strcasecmp(optarg, "nxio") == 0) {
error = ENXIO;
} else if (strcasecmp(optarg, "dtl") == 0) {
error = ECHILD;
} else if (strcasecmp(optarg, "corrupt") == 0) {
error = EILSEQ;
} else {
error = str_to_err(optarg);
if (error < 0) {
(void) fprintf(stderr, "invalid error type "
"'%s': must be 'io', 'checksum' or "
"'nxio'\n", optarg);
"'%s': must be one of: io decompress "
"decrypt nxio dtl corrupt\n",
optarg);
usage();
libzfs_fini(g_zfs);
return (1);