summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2020-05-06 11:28:46 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2020-05-06 11:28:46 +0000
commitb2ab2331a3517ced2ba3f7089d9977314b5802f6 (patch)
treed8b93660db3373c6d506e04cbcde2ef4965b11eb
parente28caa620b96c1b08f8b4ca6a99cb350839dfd02 (diff)
parentb853d39ade4a504f3447f996dbf5dd985f0236bc (diff)
downloadillumos-joyent-release-20200507.tar.gz
[illumos-gate merge]release-20200507
commit b853d39ade4a504f3447f996dbf5dd985f0236bc 12684 Inject zinject a percentage amount of dev errs
-rw-r--r--usr/src/cmd/zinject/zinject.c40
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h5
-rw-r--r--usr/src/uts/common/fs/zfs/zio_inject.c36
3 files changed, 70 insertions, 11 deletions
diff --git a/usr/src/cmd/zinject/zinject.c b/usr/src/cmd/zinject/zinject.c
index 16e659ca6f..6ab78ad46b 100644
--- a/usr/src/cmd/zinject/zinject.c
+++ b/usr/src/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
@@ -231,12 +232,14 @@ 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"
"\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> pool\n"
"\n"
@@ -313,7 +316,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"
@@ -657,6 +660,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);
+}
+
/*
* This function converts a string specifier for DVAs into a bit mask.
* The dva's provided by the user should be 0 indexed and separated by
@@ -834,10 +858,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: " : "");
return (1);
}
break;
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h b/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
index 9947bedf54..60d4d6805f 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
@@ -24,6 +24,7 @@
* Copyright (c) 2012, 2017 by Delphix. All rights reserved.
* Copyright 2016 RackTop Systems.
* Copyright (c) 2014 Integros [integros.com]
+ * Copyright (c) 2017, Intel Corporation.
*/
#ifndef _SYS_ZFS_IOCTL_H
@@ -389,6 +390,10 @@ typedef struct zinject_record {
#define ZI_NO_DVA (-1)
+/* scaled frequency ranges */
+#define ZI_PERCENTAGE_MIN 4294UL
+#define ZI_PERCENTAGE_MAX UINT32_MAX
+
typedef enum zinject_type {
ZINJECT_UNINITIALIZED,
ZINJECT_DATA_FAULT,
diff --git a/usr/src/uts/common/fs/zfs/zio_inject.c b/usr/src/uts/common/fs/zfs/zio_inject.c
index a65721d175..e332da9672 100644
--- a/usr/src/uts/common/fs/zfs/zio_inject.c
+++ b/usr/src/uts/common/fs/zfs/zio_inject.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.
*/
/*
@@ -100,6 +101,26 @@ static kmutex_t inject_delay_mtx;
static int inject_next_id = 1;
/*
+ * Test if the requested frequency was triggered
+ */
+static boolean_t
+freq_triggered(uint32_t frequency)
+{
+ /*
+ * zero implies always (100%)
+ */
+ if (frequency == 0)
+ return (B_TRUE);
+
+ /*
+ * Note: we still handle legacy (unscaled) frequecy values
+ */
+ uint32_t maximum = (frequency <= 100) ? 100 : ZI_PERCENTAGE_MAX;
+
+ return (spa_get_random(maximum) < frequency);
+}
+
+/*
* Returns true if the given record matches the I/O in progress.
*/
static boolean_t
@@ -114,8 +135,7 @@ zio_match_handler(zbookmark_phys_t *zb, uint64_t type, int dva,
record->zi_object == DMU_META_DNODE_OBJECT) {
if (record->zi_type == DMU_OT_NONE ||
type == record->zi_type)
- return (record->zi_freq == 0 ||
- spa_get_random(100) < record->zi_freq);
+ return (freq_triggered(record->zi_freq));
else
return (B_FALSE);
}
@@ -130,8 +150,7 @@ zio_match_handler(zbookmark_phys_t *zb, uint64_t type, int dva,
zb->zb_blkid <= record->zi_end &&
(record->zi_dvas == 0 || (record->zi_dvas & (1ULL << dva))) &&
error == record->zi_error) {
- return (record->zi_freq == 0 ||
- spa_get_random(100) < record->zi_freq);
+ return (freq_triggered(record->zi_freq));
}
return (B_FALSE);
@@ -360,6 +379,12 @@ zio_handle_device_injection(vdev_t *vd, zio_t *zio, int error)
if (handler->zi_record.zi_error == error) {
/*
+ * limit error injection if requested
+ */
+ if (!freq_triggered(handler->zi_record.zi_freq))
+ continue;
+
+ /*
* For a failed open, pretend like the device
* has gone away.
*/
@@ -527,6 +552,9 @@ zio_handle_io_delay(zio_t *zio)
if (handler->zi_record.zi_cmd != ZINJECT_DELAY_IO)
continue;
+ if (!freq_triggered(handler->zi_record.zi_freq))
+ continue;
+
if (vd->vdev_guid != handler->zi_record.zi_guid)
continue;