diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/ztest/ztest.c | 273 |
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) ? |