long options for ztest

This change introduces long options for ztest. It builds the usage
message as well as the long_options array from a single table. It also
adds #defines for the default values.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: John Kennedy <john.kennedy@delphix.com>
Signed-off-by: Manoj Joseph <manoj.joseph@delphix.com>
Closes #12117
This commit is contained in:
Manoj Joseph 2021-05-28 15:06:07 -07:00 committed by Brian Behlendorf
parent eb9d335009
commit c3c65e3cfb
2 changed files with 246 additions and 107 deletions

View File

@ -124,6 +124,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <getopt.h>
#include <signal.h> #include <signal.h>
#include <umem.h> #include <umem.h>
#include <ctype.h> #include <ctype.h>
@ -192,30 +193,58 @@ typedef struct ztest_shared_opts {
char zo_gvars[ZO_GVARS_MAX_COUNT][ZO_GVARS_MAX_ARGLEN]; char zo_gvars[ZO_GVARS_MAX_COUNT][ZO_GVARS_MAX_ARGLEN];
} ztest_shared_opts_t; } 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 = { static const ztest_shared_opts_t ztest_opts_defaults = {
.zo_pool = "ztest", .zo_pool = DEFAULT_POOL,
.zo_dir = "/tmp", .zo_dir = DEFAULT_VDEV_DIR,
.zo_alt_ztest = { '\0' }, .zo_alt_ztest = { '\0' },
.zo_alt_libpath = { '\0' }, .zo_alt_libpath = { '\0' },
.zo_vdevs = 5, .zo_vdevs = DEFAULT_VDEV_COUNT,
.zo_ashift = SPA_MINBLOCKSHIFT, .zo_ashift = DEFAULT_ASHIFT,
.zo_mirrors = 2, .zo_mirrors = DEFAULT_MIRRORS,
.zo_raid_children = 4, .zo_raid_children = DEFAULT_RAID_CHILDREN,
.zo_raid_parity = 1, .zo_raid_parity = DEFAULT_RAID_PARITY,
.zo_raid_type = VDEV_TYPE_RAIDZ, .zo_raid_type = VDEV_TYPE_RAIDZ,
.zo_vdev_size = SPA_MINDEVSIZE * 4, /* 256m default size */ .zo_vdev_size = DEFAULT_VDEV_SIZE,
.zo_draid_data = 4, /* data drives */ .zo_draid_data = DEFAULT_DRAID_DATA, /* data drives */
.zo_draid_spares = 1, /* distributed spares */ .zo_draid_spares = DEFAULT_DRAID_SPARES, /* distributed spares */
.zo_datasets = 7, .zo_datasets = DEFAULT_DATASETS_COUNT,
.zo_threads = 23, .zo_threads = DEFAULT_THREADS,
.zo_passtime = 60, /* 60 seconds */ .zo_passtime = DEFAULT_PASS_TIME,
.zo_killrate = 70, /* 70% kill rate */ .zo_killrate = DEFAULT_KILL_RATE,
.zo_verbose = 0, .zo_verbose = 0,
.zo_mmp_test = 0, .zo_mmp_test = 0,
.zo_init = 1, .zo_init = DEFAULT_INITS,
.zo_time = 300, /* 5 minutes */ .zo_time = DEFAULT_RUN_TIME,
.zo_maxloops = 50, /* max loops during spa_freeze() */ .zo_maxloops = DEFAULT_MAX_LOOPS, /* max loops during spa_freeze() */
.zo_metaslab_force_ganging = 64 << 10, .zo_metaslab_force_ganging = DEFAULT_FORCE_GANGING,
.zo_special_vdevs = ZTEST_VDEV_CLASS_RND, .zo_special_vdevs = ZTEST_VDEV_CLASS_RND,
.zo_gvars_count = 0, .zo_gvars_count = 0,
}; };
@ -684,68 +713,154 @@ nicenumtoull(const char *buf)
return (val); 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
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)
{
int count = sizeof (option_table) / sizeof (option_table[0]);
umem_free(long_opts, sizeof (struct option) * count);
umem_free(short_opts, sizeof (char) * 2 * count);
long_opts = NULL;
short_opts = NULL;
}
static void static void
usage(boolean_t requested) usage(boolean_t requested)
{ {
const ztest_shared_opts_t *zo = &ztest_opts_defaults; char option[80];
char nice_vdev_size[NN_NUMBUF_SZ];
char nice_force_ganging[NN_NUMBUF_SZ];
FILE *fp = requested ? stdout : stderr; FILE *fp = requested ? stdout : stderr;
nicenum(zo->zo_vdev_size, nice_vdev_size, sizeof (nice_vdev_size)); (void) fprintf(fp, "Usage: %s [OPTIONS...]\n", DEFAULT_POOL);
nicenum(zo->zo_metaslab_force_ganging, nice_force_ganging, for (int i = 0; option_table[i].short_opt != 0; i++) {
sizeof (nice_force_ganging)); 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);
(void) fprintf(fp, "Usage: %s\n" if (option_table[i].long_opt_param != NULL) {
"\t[-v vdevs (default: %llu)]\n" if (option_table[i].default_str != NULL) {
"\t[-s size_of_each_vdev (default: %s)]\n" (void) fprintf(fp, " (default: %s)",
"\t[-a alignment_shift (default: %d)] use 0 for random\n" option_table[i].default_str);
"\t[-m mirror_copies (default: %d)]\n" } else if (option_table[i].default_int != NO_DEFAULT) {
"\t[-r raidz_disks / draid_disks (default: %d)]\n" (void) fprintf(fp, " (default: %u)",
"\t[-R raid_parity (default: %d)]\n" option_table[i].default_int);
"\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" (void) fprintf(fp, "\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);
exit(requested ? 0 : 1); exit(requested ? 0 : 1);
} }
@ -817,8 +932,10 @@ process_options(int argc, char **argv)
bcopy(&ztest_opts_defaults, zo, sizeof (*zo)); bcopy(&ztest_opts_defaults, zo, sizeof (*zo));
while ((opt = getopt(argc, argv, init_options();
"v:s:a:m:r:R:K:D:S:d:t:g:i:k:p:f:MVET:P:hF:B:C:o:G")) != EOF) {
while ((opt = getopt_long(argc, argv, short_opts, long_opts,
NULL)) != EOF) {
value = 0; value = 0;
switch (opt) { switch (opt) {
case 'v': 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 */ /* When raid choice is 'random' add a draid pool 50% of the time */
if (strcmp(raid_kind, "random") == 0) { if (strcmp(raid_kind, "random") == 0) {
(void) strlcpy(raid_kind, (ztest_random(2) == 0) ? (void) strlcpy(raid_kind, (ztest_random(2) == 0) ?

View File

@ -63,93 +63,113 @@ can re-use these files in your next \fBztest\fR run by using the -E
option. option.
.SH OPTIONS .SH OPTIONS
.HP .HP
.BI "\-?" "" .BR "\-h, -?, --help"
.IP .IP
Print a help summary. Print a help summary.
.HP .HP
.BI "\-v" " vdevs" " (default: 5) .BR "\-v, --vdevs=" " (default: 5)
.IP .IP
Number of vdevs. Number of vdevs.
.HP .HP
.BI "\-s" " size_of_each_vdev" " (default: 64M)" .BR "\-s, --vdev-size=" " (default: 64M)"
.IP .IP
Size of each vdev. Size of each vdev.
.HP .HP
.BI "\-a" " alignment_shift" " (default: 9) (use 0 for random)" .BR "\-a, --alignment-shift=" " (default: 9) (use 0 for random)"
.IP .IP
Used alignment in test. Alignment shift used in test.
.HP .HP
.BI "\-m" " mirror_copies" " (default: 2)" .BR "\-m, --mirror-copies=" " (default: 2)"
.IP .IP
Number of mirror copies. Number of mirror copies.
.HP .HP
.BI "\-r" " raidz_disks / draid_disks" " (default: 4 / 16)" .BR "\-r, --raid-disks=" " (default: 4 for raidz/ 16 for draid)"
.IP .IP
Number of raidz disks. Number of raidz/draid disks.
.HP .HP
.BI "\-R" " raid_parity" " (default: 1)" .BR "\-R, --raid-parity=" " (default: 1)"
.IP .IP
Raid parity (raidz & draid). Raid parity (raidz & draid).
.HP .HP
.BI "\-K" " raid_kind" " (default: 'random') raidz|draid|random" .BR "\-K, --raid-kind=" " (default: 'random') raidz|draid|random"
.IP .IP
The kind of RAID config to use. With 'random' the kind alternates between raidz and draid. The kind of RAID config to use. With 'random' the kind alternates between raidz and draid.
.HP .HP
.BI "\-D" " draid_data" " (default: 4)" .BR "\-D, --draid-data=" " (default: 4)"
.IP .IP
Number of data disks in a dRAID redundancy group. Number of data disks in a dRAID redundancy group.
.HP .HP
.BI "\-S" " draid_spares" " (default: 1)" .BR "\-S, --draid-spares=" " (default: 1)"
.IP .IP
Number of dRAID distributed spare disks. Number of dRAID distributed spare disks.
.HP .HP
.BI "\-C" " vdev_class_state" " (default: random)" .BR "\-d, --datasets=" " (default: 7)"
.IP
The vdev allocation class state: special=on|off|random.
.HP
.BI "\-d" " datasets" " (default: 7)"
.IP .IP
Number of datasets. Number of datasets.
.HP .HP
.BI "\-t" " threads" " (default: 23)" .BR "\-t, --threads=" " (default: 23)"
.IP .IP
Number of threads. Number of threads.
.HP .HP
.BI "\-g" " gang_block_threshold" " (default: 32K)" .BR "\-g, --gang-block-threshold=" " (default: 32K)"
.IP .IP
Gang block threshold. Gang block threshold.
.HP .HP
.BI "\-i" " initialize_pool_i_times" " (default: 1)" .BR "\-i, --init-count=" " (default: 1)"
.IP .IP
Number of pool initialisations. Number of pool initializations.
.HP .HP
.BI "\-k" " kill_percentage" " (default: 70%)" .BR "\-k, --kill-percentage=" " (default: 70%)"
.IP .IP
Kill percentage. Kill percentage.
.HP .HP
.BI "\-p" " pool_name" " (default: ztest)" .BR "\-p, --pool-name=" " (default: ztest)"
.IP .IP
Pool name. Pool name.
.HP .HP
.BI "\-V(erbose)" .BR "\-f, --vdev-file-directory=" " (default: /tmp)"
.IP .IP
Verbose (use multiple times for ever more blather). File directory for vdev files.
.HP .HP
.BI "\-E(xisting)" .BR "\-M, --multi-host"
.IP
Multi-host; simulate pool imported on remote host.
.HP
.BR "\-E, --use-existing-pool"
.IP .IP
Use existing pool (use existing pool instead of creating new one). Use existing pool (use existing pool instead of creating new one).
.HP .HP
.BI "\-T" " time" " (default: 300 sec)" .BR "\-T, --run-time=" " (default: 300 sec)"
.IP .IP
Total test run time. Total test run time.
.HP .HP
.BI "\-z" " zil_failure_rate" " (default: fail every 2^5 allocs) .BR "\-P, --pass-time=" " (default: 60 sec)"
.IP .IP
Injected failure rate. Time per pass.
.HP .HP
.BI "\-G" .BR "\-F, --freeze-loops=" " (default: 50)"
.IP .IP
Dump zfs_dbgmsg buffer before exiting. Max loops in spa_freeze().
.HP
.BR "\-B, --alt-ztest="
.IP
Alternate ztest path.
.HP
.BR "\-C, --vdev-class-state=on|off|random" " (default: random)"
.IP
The vdev allocation class state.
.HP
.BR "\-o, --option="
.IP
Set global variable to an unsigned 32-bit integer value.
.HP
.BR "\-G, --dump-debug"
.IP
Dump zfs_dbgmsg buffer before exiting due to an error.
.HP
.BR "\-V, --verbose"
.IP
Verbose (use multiple times for ever more verbosity).
.SH "EXAMPLES" .SH "EXAMPLES"
.LP .LP
To override /tmp as your location for block files, you can use the -f To override /tmp as your location for block files, you can use the -f