summaryrefslogtreecommitdiffstats
path: root/cddl
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2016-03-08 17:27:13 +0000
committermav <mav@FreeBSD.org>2016-03-08 17:27:13 +0000
commitdca4cd64ea6b1e8db72455a81d48e7d323aead09 (patch)
treeab2cbe27e549c0cd687ffbc5934c61ae84ad67e1 /cddl
parent58b4e76bc94229690f082e7a67646f0a7583c89e (diff)
downloadFreeBSD-src-dca4cd64ea6b1e8db72455a81d48e7d323aead09.zip
FreeBSD-src-dca4cd64ea6b1e8db72455a81d48e7d323aead09.tar.gz
MFV r296505: 6531 Provide mechanism to artificially limit disk performance
Reviewed by: Paul Dagnelie <pcd@delphix.com> Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Approved by: Dan McDonald <danmcd@omniti.com> Author: Prakash Surya <prakash.surya@delphix.com> illumos/illumos-gate@97e81309571898df9fdd94aab1216dfcf23e060b
Diffstat (limited to 'cddl')
-rw-r--r--cddl/contrib/opensolaris/cmd/zinject/zinject.c111
1 files changed, 108 insertions, 3 deletions
diff --git a/cddl/contrib/opensolaris/cmd/zinject/zinject.c b/cddl/contrib/opensolaris/cmd/zinject/zinject.c
index ddcdb1f..bf42bc4 100644
--- a/cddl/contrib/opensolaris/cmd/zinject/zinject.c
+++ b/cddl/contrib/opensolaris/cmd/zinject/zinject.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
*/
/*
@@ -229,21 +229,57 @@ usage(void)
"\t\tall records if 'all' is specificed.\n"
"\n"
"\tzinject -p <function name> pool\n"
+ "\n"
"\t\tInject a panic fault at the specified function. Only \n"
"\t\tfunctions which call spa_vdev_config_exit(), or \n"
"\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"
+ "\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"
"\n"
"\tzinject -d device -A <degrade|fault> pool\n"
+ "\n"
"\t\tPerform a specific action on a particular device\n"
"\n"
+ "\tzinject -d device -D latency:lanes pool\n"
+ "\n"
+ "\t\tAdd an artificial delay to IO requests on a particular\n"
+ "\t\tdevice, such that the requests take a minimum of 'latency'\n"
+ "\t\tmilliseconds to complete. Each delay has an associated\n"
+ "\t\tnumber of 'lanes' which defines the number of concurrent\n"
+ "\t\tIO requests that can be processed.\n"
+ "\n"
+ "\t\tFor example, with a single lane delay of 10 ms (-D 10:1),\n"
+ "\t\tthe device will only be able to service a single IO request\n"
+ "\t\tat a time with each request taking 10 ms to complete. So,\n"
+ "\t\tif only a single request is submitted every 10 ms, the\n"
+ "\t\taverage latency will be 10 ms; but if more than one request\n"
+ "\t\tis submitted every 10 ms, the average latency will be more\n"
+ "\t\tthan 10 ms.\n"
+ "\n"
+ "\t\tSimilarly, if a delay of 10 ms is specified to have two\n"
+ "\t\tlanes (-D 10:2), then the device will be able to service\n"
+ "\t\ttwo requests at a time, each with a minimum latency of\n"
+ "\t\t10 ms. So, if two requests are submitted every 10 ms, then\n"
+ "\t\tthe average latency will be 10 ms; but if more than two\n"
+ "\t\trequests are submitted every 10 ms, the average latency\n"
+ "\t\twill be more than 10 ms.\n"
+ "\n"
+ "\t\tAlso note, these delays are additive. So two invocations\n"
+ "\t\tof '-D 10:1', is roughly equivalent to a single invocation\n"
+ "\t\tof '-D 10:2'. This also means, one can specify multiple\n"
+ "\t\tlanes with differing target latencies. For example, an\n"
+ "\t\tinvocation of '-D 10:1' followed by '-D 25:2' will\n"
+ "\t\tcreate 3 lanes on the device; one lane with a latency\n"
+ "\t\tof 10 ms and two lanes with a 25 ms latency.\n"
+ "\n"
"\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
+ "\n"
"\t\tCause the pool to stop writing blocks yet not\n"
"\t\treport errors for a duration. Simulates buggy hardware\n"
"\t\tthat fails to honor cache flush requests.\n"
@@ -357,6 +393,9 @@ print_device_handler(int id, const char *pool, zinject_record_t *record,
if (record->zi_guid == 0 || record->zi_func[0] != '\0')
return (0);
+ if (record->zi_cmd == ZINJECT_DELAY_IO)
+ return (0);
+
if (*count == 0) {
(void) printf("%3s %-15s %s\n", "ID", "POOL", "GUID");
(void) printf("--- --------------- ----------------\n");
@@ -371,6 +410,35 @@ print_device_handler(int id, const char *pool, zinject_record_t *record,
}
static int
+print_delay_handler(int id, const char *pool, zinject_record_t *record,
+ void *data)
+{
+ int *count = data;
+
+ if (record->zi_guid == 0 || record->zi_func[0] != '\0')
+ return (0);
+
+ if (record->zi_cmd != ZINJECT_DELAY_IO)
+ return (0);
+
+ if (*count == 0) {
+ (void) printf("%3s %-15s %-15s %-15s %s\n",
+ "ID", "POOL", "DELAY (ms)", "LANES", "GUID");
+ (void) printf("--- --------------- --------------- "
+ "--------------- ----------------\n");
+ }
+
+ *count += 1;
+
+ (void) printf("%3d %-15s %-15llu %-15llu %llx\n", id, pool,
+ (u_longlong_t)NSEC2MSEC(record->zi_timer),
+ (u_longlong_t)record->zi_nlanes,
+ (u_longlong_t)record->zi_guid);
+
+ return (0);
+}
+
+static int
print_panic_handler(int id, const char *pool, zinject_record_t *record,
void *data)
{
@@ -407,6 +475,13 @@ print_all_handlers(void)
count = 0;
}
+ (void) iter_handlers(print_delay_handler, &count);
+ if (count > 0) {
+ total += count;
+ (void) printf("\n");
+ count = 0;
+ }
+
(void) iter_handlers(print_data_handler, &count);
if (count > 0) {
total += count;
@@ -549,6 +624,35 @@ perform_action(const char *pool, zinject_record_t *record, int cmd)
return (1);
}
+static int
+parse_delay(char *str, uint64_t *delay, uint64_t *nlanes)
+{
+ unsigned long scan_delay;
+ unsigned long scan_nlanes;
+
+ if (sscanf(str, "%lu:%lu", &scan_delay, &scan_nlanes) != 2)
+ return (1);
+
+ /*
+ * We explicitly disallow a delay of zero here, because we key
+ * off this value being non-zero in translate_device(), to
+ * determine if the fault is a ZINJECT_DELAY_IO fault or not.
+ */
+ if (scan_delay == 0)
+ return (1);
+
+ /*
+ * The units for the CLI delay parameter is milliseconds, but
+ * the data passed to the kernel is interpreted as nanoseconds.
+ * Thus we scale the milliseconds to nanoseconds here, and this
+ * nanosecond value is used to pass the delay to the kernel.
+ */
+ *delay = MSEC2NSEC(scan_delay);
+ *nlanes = scan_nlanes;
+
+ return (0);
+}
+
int
main(int argc, char **argv)
{
@@ -632,8 +736,9 @@ main(int argc, char **argv)
device = optarg;
break;
case 'D':
- record.zi_timer = strtoull(optarg, &end, 10);
- if (errno != 0 || *end != '\0') {
+ ret = parse_delay(optarg, &record.zi_timer,
+ &record.zi_nlanes);
+ if (ret != 0) {
(void) fprintf(stderr, "invalid i/o delay "
"value: '%s'\n", optarg);
usage();
OpenPOWER on IntegriCloud