aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/zinject
diff options
context:
space:
mode:
authorDon Brady <[email protected]>2017-06-16 18:21:11 -0600
committerBrian Behlendorf <[email protected]>2017-06-16 17:21:11 -0700
commit0241e491a08ffa471a08ceaa0b0943999d775cbe (patch)
tree17f07ce2cf37c4f19155dba12851c8eab519c8a1 /cmd/zinject
parent05a5357a6c63b8c83062c1b295ee98d14f8e85aa (diff)
Inject zinject(8) a percentage amount of dev errs
In the original form of device error injection, it was an all or nothing situation. To help simulate intermittent error conditions, you can now specify a real number percentage value. This is also very useful for our ZFS fault diagnosis testing and for injecting intermittent errors during load testing. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Don Brady <[email protected]> Closes #6227
Diffstat (limited to 'cmd/zinject')
-rw-r--r--cmd/zinject/zinject.c48
1 files changed, 38 insertions, 10 deletions
diff --git a/cmd/zinject/zinject.c b/cmd/zinject/zinject.c
index 604554e71..ccd3534d0 100644
--- a/cmd/zinject/zinject.c
+++ b/cmd/zinject/zinject.c
@@ -21,6 +21,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.
*/
/*
@@ -124,7 +125,7 @@
* cache.
*
* The '-f' flag controls the frequency of errors injected, expressed as a
- * integer percentage between 1 and 100. The default is 100.
+ * real number percentage between 0.0001 and 100. The default is 100.
*
* The this form is responsible for actually injecting the handler into the
* framework. It takes the arguments described above, translates them to the
@@ -230,11 +231,13 @@ usage(void)
"\t\tspa_vdev_exit() will trigger a panic.\n"
"\n"
"\tzinject -d device [-e errno] [-L <nvlist|uber|pad1|pad2>] [-F]\n"
- "\t [-T <read|write|free|claim|all> pool\n"
+ "\t [-T <read|write|free|claim|all>] [-f frequency] pool\n"
"\t\tInject a fault into a particular device or the device's\n"
"\t\tlabel. Label injection can either be 'nvlist', 'uber',\n "
"\t\t'pad1', or 'pad2'.\n"
"\t\t'errno' can be 'nxio' (the default), 'io', or 'dtl'.\n"
+ "\t\t'frequency' is a value between 0.0001 and 100.0 that limits\n"
+ "\t\tdevice error injection to a percentage of the IOs.\n"
"\n"
"\tzinject -d device -A <degrade|fault> -D <delay secs> pool\n"
"\t\tPerform a specific action on a particular device.\n"
@@ -305,7 +308,7 @@ usage(void)
"\t\t-u\tUnload the associated pool. Can be specified with only\n"
"\t\t\ta pool object.\n"
"\t\t-f\tOnly inject errors a fraction of the time. Expressed as\n"
- "\t\t\ta percentage between 1 and 100.\n"
+ "\t\t\ta percentage between 0.0001 and 100.\n"
"\n"
"\t-t data\t\tInject an error into the plain file contents of a\n"
"\t\t\tfile. The object must be specified as a complete path\n"
@@ -645,6 +648,27 @@ parse_delay(char *str, uint64_t *delay, uint64_t *nlanes)
return (0);
}
+static int
+parse_frequency(const char *str, uint32_t *percent)
+{
+ double val;
+ char *post;
+
+ val = strtod(str, &post);
+ if (post == NULL || *post != '\0')
+ return (EINVAL);
+
+ /* valid range is [0.0001, 100.0] */
+ val /= 100.0f;
+ if (val < 0.000001f || val > 1.0f)
+ return (ERANGE);
+
+ /* convert to an integer for use by kernel */
+ *percent = ((uint32_t)(val * ZI_PERCENTAGE_MAX));
+
+ return (0);
+}
+
int
main(int argc, char **argv)
{
@@ -760,10 +784,12 @@ main(int argc, char **argv)
}
break;
case 'f':
- record.zi_freq = atoi(optarg);
- if (record.zi_freq < 1 || record.zi_freq > 100) {
- (void) fprintf(stderr, "frequency range must "
- "be in the range (0, 100]\n");
+ ret = parse_frequency(optarg, &record.zi_freq);
+ if (ret != 0) {
+ (void) fprintf(stderr, "%sfrequency value must "
+ "be in the range [0.0001, 100.0]\n",
+ ret == EINVAL ? "invalid value: " :
+ ret == ERANGE ? "out of range: " : "");
libzfs_fini(g_zfs);
return (1);
}
@@ -898,7 +924,8 @@ main(int argc, char **argv)
* '-c' is invalid with any other options.
*/
if (raw != NULL || range != NULL || type != TYPE_INVAL ||
- level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
+ level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED ||
+ record.zi_freq > 0) {
(void) fprintf(stderr, "cancel (-c) incompatible with "
"any other options\n");
usage();
@@ -972,7 +999,8 @@ main(int argc, char **argv)
} else if (raw != NULL) {
if (range != NULL || type != TYPE_INVAL || level != 0 ||
- record.zi_cmd != ZINJECT_UNINITIALIZED) {
+ record.zi_cmd != ZINJECT_UNINITIALIZED ||
+ record.zi_freq > 0) {
(void) fprintf(stderr, "raw (-b) format with "
"any other options\n");
usage();
@@ -1007,7 +1035,7 @@ main(int argc, char **argv)
error = EIO;
} else if (record.zi_cmd == ZINJECT_PANIC) {
if (raw != NULL || range != NULL || type != TYPE_INVAL ||
- level != 0 || device != NULL) {
+ level != 0 || device != NULL || record.zi_freq > 0) {
(void) fprintf(stderr, "panic (-p) incompatible with "
"other options\n");
usage();