aboutsummaryrefslogtreecommitdiffstats
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/ztest/ztest.c273
1 files changed, 196 insertions, 77 deletions
diff --git a/cmd/ztest/ztest.c b/cmd/ztest/ztest.c
index 24197d27b..73694b0b3 100644
--- a/cmd/ztest/ztest.c
+++ b/cmd/ztest/ztest.c
@@ -124,6 +124,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <getopt.h>
#include <signal.h>
#include <umem.h>
#include <ctype.h>
@@ -192,30 +193,58 @@ typedef struct ztest_shared_opts {
char zo_gvars[ZO_GVARS_MAX_COUNT][ZO_GVARS_MAX_ARGLEN];
} ztest_shared_opts_t;
+/* Default values for command line options. */
+#define DEFAULT_POOL "ztest"
+#define DEFAULT_VDEV_DIR "/tmp"
+#define DEFAULT_VDEV_COUNT 5
+#define DEFAULT_VDEV_SIZE (SPA_MINDEVSIZE * 4) /* 256m default size */
+#define DEFAULT_VDEV_SIZE_STR "256M"
+#define DEFAULT_ASHIFT SPA_MINBLOCKSHIFT
+#define DEFAULT_MIRRORS 2
+#define DEFAULT_RAID_CHILDREN 4
+#define DEFAULT_RAID_PARITY 1
+#define DEFAULT_DRAID_DATA 4
+#define DEFAULT_DRAID_SPARES 1
+#define DEFAULT_DATASETS_COUNT 7
+#define DEFAULT_THREADS 23
+#define DEFAULT_RUN_TIME 300 /* 300 seconds */
+#define DEFAULT_RUN_TIME_STR "300 sec"
+#define DEFAULT_PASS_TIME 60 /* 60 seconds */
+#define DEFAULT_PASS_TIME_STR "60 sec"
+#define DEFAULT_KILL_RATE 70 /* 70% kill rate */
+#define DEFAULT_KILLRATE_STR "70%"
+#define DEFAULT_INITS 1
+#define DEFAULT_MAX_LOOPS 50 /* 5 minutes */
+#define DEFAULT_FORCE_GANGING (64 << 10)
+#define DEFAULT_FORCE_GANGING_STR "64K"
+
+/* Simplifying assumption: -1 is not a valid default. */
+#define NO_DEFAULT -1
+
static const ztest_shared_opts_t ztest_opts_defaults = {
- .zo_pool = "ztest",
- .zo_dir = "/tmp",
+ .zo_pool = DEFAULT_POOL,
+ .zo_dir = DEFAULT_VDEV_DIR,
.zo_alt_ztest = { '\0' },
.zo_alt_libpath = { '\0' },
- .zo_vdevs = 5,
- .zo_ashift = SPA_MINBLOCKSHIFT,
- .zo_mirrors = 2,
- .zo_raid_children = 4,
- .zo_raid_parity = 1,
+ .zo_vdevs = DEFAULT_VDEV_COUNT,
+ .zo_ashift = DEFAULT_ASHIFT,
+ .zo_mirrors = DEFAULT_MIRRORS,
+ .zo_raid_children = DEFAULT_RAID_CHILDREN,
+ .zo_raid_parity = DEFAULT_RAID_PARITY,
.zo_raid_type = VDEV_TYPE_RAIDZ,
- .zo_vdev_size = SPA_MINDEVSIZE * 4, /* 256m default size */
- .zo_draid_data = 4, /* data drives */
- .zo_draid_spares = 1, /* distributed spares */
- .zo_datasets = 7,
- .zo_threads = 23,
- .zo_passtime = 60, /* 60 seconds */
- .zo_killrate = 70, /* 70% kill rate */
+ .zo_vdev_size = DEFAULT_VDEV_SIZE,
+ .zo_draid_data = DEFAULT_DRAID_DATA, /* data drives */
+ .zo_draid_spares = DEFAULT_DRAID_SPARES, /* distributed spares */
+ .zo_datasets = DEFAULT_DATASETS_COUNT,
+ .zo_threads = DEFAULT_THREADS,
+ .zo_passtime = DEFAULT_PASS_TIME,
+ .zo_killrate = DEFAULT_KILL_RATE,
.zo_verbose = 0,
.zo_mmp_test = 0,
- .zo_init = 1,
- .zo_time = 300, /* 5 minutes */
- .zo_maxloops = 50, /* max loops during spa_freeze() */
- .zo_metaslab_force_ganging = 64 << 10,
+ .zo_init = DEFAULT_INITS,
+ .zo_time = DEFAULT_RUN_TIME,
+ .zo_maxloops = DEFAULT_MAX_LOOPS, /* max loops during spa_freeze() */
+ .zo_metaslab_force_ganging = DEFAULT_FORCE_GANGING,
.zo_special_vdevs = ZTEST_VDEV_CLASS_RND,
.zo_gvars_count = 0,
};
@@ -684,68 +713,154 @@ nicenumtoull(const char *buf)
return (val);
}
+typedef struct ztest_option {
+ const char short_opt;
+ const char *long_opt;
+ const char *long_opt_param;
+ const char *comment;
+ unsigned int default_int;
+ char *default_str;
+} ztest_option_t;
+
+/*
+ * The following option_table is used for generating the usage info as well as
+ * the long and short option information for calling getopt_long().
+ */
+static ztest_option_t option_table[] = {
+ { 'v', "vdevs", "INTEGER", "Number of vdevs", DEFAULT_VDEV_COUNT,
+ NULL},
+ { 's', "vdev-size", "INTEGER", "Size of each vdev",
+ NO_DEFAULT, DEFAULT_VDEV_SIZE_STR},
+ { 'a', "alignment-shift", "INTEGER",
+ "Alignment shift; use 0 for random", DEFAULT_ASHIFT, NULL},
+ { 'm', "mirror-copies", "INTEGER", "Number of mirror copies",
+ DEFAULT_MIRRORS, NULL},
+ { 'r', "raid-disks", "INTEGER", "Number of raidz/draid disks",
+ DEFAULT_RAID_CHILDREN, NULL},
+ { 'R', "raid-parity", "INTEGER", "Raid parity",
+ DEFAULT_RAID_PARITY, NULL},
+ { 'K', "raid-kind", "raidz|draid|random", "Raid kind",
+ NO_DEFAULT, "random"},
+ { 'D', "draid-data", "INTEGER", "Number of draid data drives",
+ DEFAULT_DRAID_DATA, NULL},
+ { 'S', "draid-spares", "INTEGER", "Number of draid spares",
+ DEFAULT_DRAID_SPARES, NULL},
+ { 'd', "datasets", "INTEGER", "Number of datasets",
+ DEFAULT_DATASETS_COUNT, NULL},
+ { 't', "threads", "INTEGER", "Number of ztest threads",
+ DEFAULT_THREADS, NULL},
+ { 'g', "gang-block-threshold", "INTEGER",
+ "Metaslab gang block threshold",
+ NO_DEFAULT, DEFAULT_FORCE_GANGING_STR},
+ { 'i', "init-count", "INTEGER", "Number of times to initialize pool",
+ DEFAULT_INITS, NULL},
+ { 'k', "kill-percentage", "INTEGER", "Kill percentage",
+ NO_DEFAULT, DEFAULT_KILLRATE_STR},
+ { 'p', "pool-name", "STRING", "Pool name",
+ NO_DEFAULT, DEFAULT_POOL},
+ { 'f', "vdev-file-directory", "PATH", "File directory for vdev files",
+ NO_DEFAULT, DEFAULT_VDEV_DIR},
+ { 'M', "multi-host", NULL,
+ "Multi-host; simulate pool imported on remote host",
+ NO_DEFAULT, NULL},
+ { 'E', "use-existing-pool", NULL,
+ "Use existing pool instead of creating new one", NO_DEFAULT, NULL},
+ { 'T', "run-time", "INTEGER", "Total run time",
+ NO_DEFAULT, DEFAULT_RUN_TIME_STR},
+ { 'P', "pass-time", "INTEGER", "Time per pass",
+ NO_DEFAULT, DEFAULT_PASS_TIME_STR},
+ { 'F', "freeze-loops", "INTEGER", "Max loops in spa_freeze()",
+ DEFAULT_MAX_LOOPS, NULL},
+ { 'B', "alt-ztest", "PATH", "Alternate ztest path",
+ NO_DEFAULT, NULL},
+ { 'C', "vdev-class-state", "on|off|random", "vdev class state",
+ NO_DEFAULT, "random"},
+ { 'o', "option", "\"OPTION=INTEGER\"",
+ "Set global variable to an unsigned 32-bit integer value",
+ NO_DEFAULT, NULL},
+ { 'G', "dump-debug-msg", NULL,
+ "Dump zfs_dbgmsg buffer before exiting due to an error",
+ NO_DEFAULT, NULL},
+ { 'V', "verbose", NULL,
+ "Verbose (use multiple times for ever more verbosity)",
+ NO_DEFAULT, NULL},
+ { 'h', "help", NULL, "Show this help",
+ NO_DEFAULT, NULL},
+ {0, 0, 0, 0, 0, 0}
+};
+
+static struct option *long_opts = NULL;
+static char *short_opts = NULL;
+
static void
-usage(boolean_t requested)
+init_options(void)
+{
+ ASSERT3P(long_opts, ==, NULL);
+ ASSERT3P(short_opts, ==, NULL);
+
+ int count = sizeof (option_table) / sizeof (option_table[0]);
+ long_opts = umem_alloc(sizeof (struct option) * count, UMEM_NOFAIL);
+
+ short_opts = umem_alloc(sizeof (char) * 2 * count, UMEM_NOFAIL);
+ int short_opt_index = 0;
+
+ for (int i = 0; i < count; i++) {
+ long_opts[i].val = option_table[i].short_opt;
+ long_opts[i].name = option_table[i].long_opt;
+ long_opts[i].has_arg = option_table[i].long_opt_param != NULL
+ ? required_argument : no_argument;
+ long_opts[i].flag = NULL;
+ short_opts[short_opt_index++] = option_table[i].short_opt;
+ if (option_table[i].long_opt_param != NULL) {
+ short_opts[short_opt_index++] = ':';
+ }
+ }
+}
+
+static void
+fini_options(void)
{
- const ztest_shared_opts_t *zo = &ztest_opts_defaults;
+ int count = sizeof (option_table) / sizeof (option_table[0]);
- char nice_vdev_size[NN_NUMBUF_SZ];
- char nice_force_ganging[NN_NUMBUF_SZ];
+ umem_free(long_opts, sizeof (struct option) * count);
+ umem_free(short_opts, sizeof (char) * 2 * count);
+
+ long_opts = NULL;
+ short_opts = NULL;
+}
+
+static void
+usage(boolean_t requested)
+{
+ char option[80];
FILE *fp = requested ? stdout : stderr;
- nicenum(zo->zo_vdev_size, nice_vdev_size, sizeof (nice_vdev_size));
- nicenum(zo->zo_metaslab_force_ganging, nice_force_ganging,
- sizeof (nice_force_ganging));
-
- (void) fprintf(fp, "Usage: %s\n"
- "\t[-v vdevs (default: %llu)]\n"
- "\t[-s size_of_each_vdev (default: %s)]\n"
- "\t[-a alignment_shift (default: %d)] use 0 for random\n"
- "\t[-m mirror_copies (default: %d)]\n"
- "\t[-r raidz_disks / draid_disks (default: %d)]\n"
- "\t[-R raid_parity (default: %d)]\n"
- "\t[-K raid_kind (default: random)] raidz|draid|random\n"
- "\t[-D draid_data (default: %d)] in config\n"
- "\t[-S draid_spares (default: %d)]\n"
- "\t[-d datasets (default: %d)]\n"
- "\t[-t threads (default: %d)]\n"
- "\t[-g gang_block_threshold (default: %s)]\n"
- "\t[-i init_count (default: %d)] initialize pool i times\n"
- "\t[-k kill_percentage (default: %llu%%)]\n"
- "\t[-p pool_name (default: %s)]\n"
- "\t[-f dir (default: %s)] file directory for vdev files\n"
- "\t[-M] Multi-host simulate pool imported on remote host\n"
- "\t[-V] verbose (use multiple times for ever more blather)\n"
- "\t[-E] use existing pool instead of creating new one\n"
- "\t[-T time (default: %llu sec)] total run time\n"
- "\t[-F freezeloops (default: %llu)] max loops in spa_freeze()\n"
- "\t[-P passtime (default: %llu sec)] time per pass\n"
- "\t[-B alt_ztest (default: <none>)] alternate ztest path\n"
- "\t[-C vdev class state (default: random)] special=on|off|random\n"
- "\t[-o variable=value] ... set global variable to an unsigned\n"
- "\t 32-bit integer value\n"
- "\t[-G dump zfs_dbgmsg buffer before exiting due to an error\n"
- "\t[-h] (print help)\n"
- "",
- zo->zo_pool,
- (u_longlong_t)zo->zo_vdevs, /* -v */
- nice_vdev_size, /* -s */
- zo->zo_ashift, /* -a */
- zo->zo_mirrors, /* -m */
- zo->zo_raid_children, /* -r */
- zo->zo_raid_parity, /* -R */
- zo->zo_draid_data, /* -D */
- zo->zo_draid_spares, /* -S */
- zo->zo_datasets, /* -d */
- zo->zo_threads, /* -t */
- nice_force_ganging, /* -g */
- zo->zo_init, /* -i */
- (u_longlong_t)zo->zo_killrate, /* -k */
- zo->zo_pool, /* -p */
- zo->zo_dir, /* -f */
- (u_longlong_t)zo->zo_time, /* -T */
- (u_longlong_t)zo->zo_maxloops, /* -F */
- (u_longlong_t)zo->zo_passtime);
+ (void) fprintf(fp, "Usage: %s [OPTIONS...]\n", DEFAULT_POOL);
+ for (int i = 0; option_table[i].short_opt != 0; i++) {
+ if (option_table[i].long_opt_param != NULL) {
+ (void) sprintf(option, " -%c --%s=%s",
+ option_table[i].short_opt,
+ option_table[i].long_opt,
+ option_table[i].long_opt_param);
+ } else {
+ (void) sprintf(option, " -%c --%s",
+ option_table[i].short_opt,
+ option_table[i].long_opt);
+ }
+ (void) fprintf(fp, " %-40s%s", option,
+ option_table[i].comment);
+
+ if (option_table[i].long_opt_param != NULL) {
+ if (option_table[i].default_str != NULL) {
+ (void) fprintf(fp, " (default: %s)",
+ option_table[i].default_str);
+ } else if (option_table[i].default_int != NO_DEFAULT) {
+ (void) fprintf(fp, " (default: %u)",
+ option_table[i].default_int);
+ }
+ }
+ (void) fprintf(fp, "\n");
+ }
exit(requested ? 0 : 1);
}
@@ -817,8 +932,10 @@ process_options(int argc, char **argv)
bcopy(&ztest_opts_defaults, zo, sizeof (*zo));
- while ((opt = getopt(argc, argv,
- "v:s:a:m:r:R:K:D:S:d:t:g:i:k:p:f:MVET:P:hF:B:C:o:G")) != EOF) {
+ init_options();
+
+ while ((opt = getopt_long(argc, argv, short_opts, long_opts,
+ NULL)) != EOF) {
value = 0;
switch (opt) {
case 'v':
@@ -953,6 +1070,8 @@ process_options(int argc, char **argv)
}
}
+ fini_options();
+
/* When raid choice is 'random' add a draid pool 50% of the time */
if (strcmp(raid_kind, "random") == 0) {
(void) strlcpy(raid_kind, (ztest_random(2) == 0) ?