Skip to content

Commit 45516b4

Browse files
authored
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 <[email protected]> Reviewed-by: John Kennedy <[email protected]> Signed-off-by: Manoj Joseph <[email protected]> Closes #12117
1 parent 5d59178 commit 45516b4

File tree

2 files changed

+247
-108
lines changed

2 files changed

+247
-108
lines changed

cmd/ztest/ztest.c

Lines changed: 196 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
#include <stdio.h>
125125
#include <stdlib.h>
126126
#include <unistd.h>
127+
#include <getopt.h>
127128
#include <signal.h>
128129
#include <umem.h>
129130
#include <ctype.h>
@@ -192,30 +193,58 @@ typedef struct ztest_shared_opts {
192193
char zo_gvars[ZO_GVARS_MAX_COUNT][ZO_GVARS_MAX_ARGLEN];
193194
} ztest_shared_opts_t;
194195

196+
/* Default values for command line options. */
197+
#define DEFAULT_POOL "ztest"
198+
#define DEFAULT_VDEV_DIR "/tmp"
199+
#define DEFAULT_VDEV_COUNT 5
200+
#define DEFAULT_VDEV_SIZE (SPA_MINDEVSIZE * 4) /* 256m default size */
201+
#define DEFAULT_VDEV_SIZE_STR "256M"
202+
#define DEFAULT_ASHIFT SPA_MINBLOCKSHIFT
203+
#define DEFAULT_MIRRORS 2
204+
#define DEFAULT_RAID_CHILDREN 4
205+
#define DEFAULT_RAID_PARITY 1
206+
#define DEFAULT_DRAID_DATA 4
207+
#define DEFAULT_DRAID_SPARES 1
208+
#define DEFAULT_DATASETS_COUNT 7
209+
#define DEFAULT_THREADS 23
210+
#define DEFAULT_RUN_TIME 300 /* 300 seconds */
211+
#define DEFAULT_RUN_TIME_STR "300 sec"
212+
#define DEFAULT_PASS_TIME 60 /* 60 seconds */
213+
#define DEFAULT_PASS_TIME_STR "60 sec"
214+
#define DEFAULT_KILL_RATE 70 /* 70% kill rate */
215+
#define DEFAULT_KILLRATE_STR "70%"
216+
#define DEFAULT_INITS 1
217+
#define DEFAULT_MAX_LOOPS 50 /* 5 minutes */
218+
#define DEFAULT_FORCE_GANGING (64 << 10)
219+
#define DEFAULT_FORCE_GANGING_STR "64K"
220+
221+
/* Simplifying assumption: -1 is not a valid default. */
222+
#define NO_DEFAULT -1
223+
195224
static const ztest_shared_opts_t ztest_opts_defaults = {
196-
.zo_pool = "ztest",
197-
.zo_dir = "/tmp",
225+
.zo_pool = DEFAULT_POOL,
226+
.zo_dir = DEFAULT_VDEV_DIR,
198227
.zo_alt_ztest = { '\0' },
199228
.zo_alt_libpath = { '\0' },
200-
.zo_vdevs = 5,
201-
.zo_ashift = SPA_MINBLOCKSHIFT,
202-
.zo_mirrors = 2,
203-
.zo_raid_children = 4,
204-
.zo_raid_parity = 1,
229+
.zo_vdevs = DEFAULT_VDEV_COUNT,
230+
.zo_ashift = DEFAULT_ASHIFT,
231+
.zo_mirrors = DEFAULT_MIRRORS,
232+
.zo_raid_children = DEFAULT_RAID_CHILDREN,
233+
.zo_raid_parity = DEFAULT_RAID_PARITY,
205234
.zo_raid_type = VDEV_TYPE_RAIDZ,
206-
.zo_vdev_size = SPA_MINDEVSIZE * 4, /* 256m default size */
207-
.zo_draid_data = 4, /* data drives */
208-
.zo_draid_spares = 1, /* distributed spares */
209-
.zo_datasets = 7,
210-
.zo_threads = 23,
211-
.zo_passtime = 60, /* 60 seconds */
212-
.zo_killrate = 70, /* 70% kill rate */
235+
.zo_vdev_size = DEFAULT_VDEV_SIZE,
236+
.zo_draid_data = DEFAULT_DRAID_DATA, /* data drives */
237+
.zo_draid_spares = DEFAULT_DRAID_SPARES, /* distributed spares */
238+
.zo_datasets = DEFAULT_DATASETS_COUNT,
239+
.zo_threads = DEFAULT_THREADS,
240+
.zo_passtime = DEFAULT_PASS_TIME,
241+
.zo_killrate = DEFAULT_KILL_RATE,
213242
.zo_verbose = 0,
214243
.zo_mmp_test = 0,
215-
.zo_init = 1,
216-
.zo_time = 300, /* 5 minutes */
217-
.zo_maxloops = 50, /* max loops during spa_freeze() */
218-
.zo_metaslab_force_ganging = 64 << 10,
244+
.zo_init = DEFAULT_INITS,
245+
.zo_time = DEFAULT_RUN_TIME,
246+
.zo_maxloops = DEFAULT_MAX_LOOPS, /* max loops during spa_freeze() */
247+
.zo_metaslab_force_ganging = DEFAULT_FORCE_GANGING,
219248
.zo_special_vdevs = ZTEST_VDEV_CLASS_RND,
220249
.zo_gvars_count = 0,
221250
};
@@ -684,68 +713,154 @@ nicenumtoull(const char *buf)
684713
return (val);
685714
}
686715

716+
typedef struct ztest_option {
717+
const char short_opt;
718+
const char *long_opt;
719+
const char *long_opt_param;
720+
const char *comment;
721+
unsigned int default_int;
722+
char *default_str;
723+
} ztest_option_t;
724+
725+
/*
726+
* The following option_table is used for generating the usage info as well as
727+
* the long and short option information for calling getopt_long().
728+
*/
729+
static ztest_option_t option_table[] = {
730+
{ 'v', "vdevs", "INTEGER", "Number of vdevs", DEFAULT_VDEV_COUNT,
731+
NULL},
732+
{ 's', "vdev-size", "INTEGER", "Size of each vdev",
733+
NO_DEFAULT, DEFAULT_VDEV_SIZE_STR},
734+
{ 'a', "alignment-shift", "INTEGER",
735+
"Alignment shift; use 0 for random", DEFAULT_ASHIFT, NULL},
736+
{ 'm', "mirror-copies", "INTEGER", "Number of mirror copies",
737+
DEFAULT_MIRRORS, NULL},
738+
{ 'r', "raid-disks", "INTEGER", "Number of raidz/draid disks",
739+
DEFAULT_RAID_CHILDREN, NULL},
740+
{ 'R', "raid-parity", "INTEGER", "Raid parity",
741+
DEFAULT_RAID_PARITY, NULL},
742+
{ 'K', "raid-kind", "raidz|draid|random", "Raid kind",
743+
NO_DEFAULT, "random"},
744+
{ 'D', "draid-data", "INTEGER", "Number of draid data drives",
745+
DEFAULT_DRAID_DATA, NULL},
746+
{ 'S', "draid-spares", "INTEGER", "Number of draid spares",
747+
DEFAULT_DRAID_SPARES, NULL},
748+
{ 'd', "datasets", "INTEGER", "Number of datasets",
749+
DEFAULT_DATASETS_COUNT, NULL},
750+
{ 't', "threads", "INTEGER", "Number of ztest threads",
751+
DEFAULT_THREADS, NULL},
752+
{ 'g', "gang-block-threshold", "INTEGER",
753+
"Metaslab gang block threshold",
754+
NO_DEFAULT, DEFAULT_FORCE_GANGING_STR},
755+
{ 'i', "init-count", "INTEGER", "Number of times to initialize pool",
756+
DEFAULT_INITS, NULL},
757+
{ 'k', "kill-percentage", "INTEGER", "Kill percentage",
758+
NO_DEFAULT, DEFAULT_KILLRATE_STR},
759+
{ 'p', "pool-name", "STRING", "Pool name",
760+
NO_DEFAULT, DEFAULT_POOL},
761+
{ 'f', "vdev-file-directory", "PATH", "File directory for vdev files",
762+
NO_DEFAULT, DEFAULT_VDEV_DIR},
763+
{ 'M', "multi-host", NULL,
764+
"Multi-host; simulate pool imported on remote host",
765+
NO_DEFAULT, NULL},
766+
{ 'E', "use-existing-pool", NULL,
767+
"Use existing pool instead of creating new one", NO_DEFAULT, NULL},
768+
{ 'T', "run-time", "INTEGER", "Total run time",
769+
NO_DEFAULT, DEFAULT_RUN_TIME_STR},
770+
{ 'P', "pass-time", "INTEGER", "Time per pass",
771+
NO_DEFAULT, DEFAULT_PASS_TIME_STR},
772+
{ 'F', "freeze-loops", "INTEGER", "Max loops in spa_freeze()",
773+
DEFAULT_MAX_LOOPS, NULL},
774+
{ 'B', "alt-ztest", "PATH", "Alternate ztest path",
775+
NO_DEFAULT, NULL},
776+
{ 'C', "vdev-class-state", "on|off|random", "vdev class state",
777+
NO_DEFAULT, "random"},
778+
{ 'o', "option", "\"OPTION=INTEGER\"",
779+
"Set global variable to an unsigned 32-bit integer value",
780+
NO_DEFAULT, NULL},
781+
{ 'G', "dump-debug-msg", NULL,
782+
"Dump zfs_dbgmsg buffer before exiting due to an error",
783+
NO_DEFAULT, NULL},
784+
{ 'V', "verbose", NULL,
785+
"Verbose (use multiple times for ever more verbosity)",
786+
NO_DEFAULT, NULL},
787+
{ 'h', "help", NULL, "Show this help",
788+
NO_DEFAULT, NULL},
789+
{0, 0, 0, 0, 0, 0}
790+
};
791+
792+
static struct option *long_opts = NULL;
793+
static char *short_opts = NULL;
794+
687795
static void
688-
usage(boolean_t requested)
796+
init_options(void)
797+
{
798+
ASSERT3P(long_opts, ==, NULL);
799+
ASSERT3P(short_opts, ==, NULL);
800+
801+
int count = sizeof (option_table) / sizeof (option_table[0]);
802+
long_opts = umem_alloc(sizeof (struct option) * count, UMEM_NOFAIL);
803+
804+
short_opts = umem_alloc(sizeof (char) * 2 * count, UMEM_NOFAIL);
805+
int short_opt_index = 0;
806+
807+
for (int i = 0; i < count; i++) {
808+
long_opts[i].val = option_table[i].short_opt;
809+
long_opts[i].name = option_table[i].long_opt;
810+
long_opts[i].has_arg = option_table[i].long_opt_param != NULL
811+
? required_argument : no_argument;
812+
long_opts[i].flag = NULL;
813+
short_opts[short_opt_index++] = option_table[i].short_opt;
814+
if (option_table[i].long_opt_param != NULL) {
815+
short_opts[short_opt_index++] = ':';
816+
}
817+
}
818+
}
819+
820+
static void
821+
fini_options(void)
689822
{
690-
const ztest_shared_opts_t *zo = &ztest_opts_defaults;
823+
int count = sizeof (option_table) / sizeof (option_table[0]);
691824

692-
char nice_vdev_size[NN_NUMBUF_SZ];
693-
char nice_force_ganging[NN_NUMBUF_SZ];
825+
umem_free(long_opts, sizeof (struct option) * count);
826+
umem_free(short_opts, sizeof (char) * 2 * count);
827+
828+
long_opts = NULL;
829+
short_opts = NULL;
830+
}
831+
832+
static void
833+
usage(boolean_t requested)
834+
{
835+
char option[80];
694836
FILE *fp = requested ? stdout : stderr;
695837

696-
nicenum(zo->zo_vdev_size, nice_vdev_size, sizeof (nice_vdev_size));
697-
nicenum(zo->zo_metaslab_force_ganging, nice_force_ganging,
698-
sizeof (nice_force_ganging));
699-
700-
(void) fprintf(fp, "Usage: %s\n"
701-
"\t[-v vdevs (default: %llu)]\n"
702-
"\t[-s size_of_each_vdev (default: %s)]\n"
703-
"\t[-a alignment_shift (default: %d)] use 0 for random\n"
704-
"\t[-m mirror_copies (default: %d)]\n"
705-
"\t[-r raidz_disks / draid_disks (default: %d)]\n"
706-
"\t[-R raid_parity (default: %d)]\n"
707-
"\t[-K raid_kind (default: random)] raidz|draid|random\n"
708-
"\t[-D draid_data (default: %d)] in config\n"
709-
"\t[-S draid_spares (default: %d)]\n"
710-
"\t[-d datasets (default: %d)]\n"
711-
"\t[-t threads (default: %d)]\n"
712-
"\t[-g gang_block_threshold (default: %s)]\n"
713-
"\t[-i init_count (default: %d)] initialize pool i times\n"
714-
"\t[-k kill_percentage (default: %llu%%)]\n"
715-
"\t[-p pool_name (default: %s)]\n"
716-
"\t[-f dir (default: %s)] file directory for vdev files\n"
717-
"\t[-M] Multi-host simulate pool imported on remote host\n"
718-
"\t[-V] verbose (use multiple times for ever more blather)\n"
719-
"\t[-E] use existing pool instead of creating new one\n"
720-
"\t[-T time (default: %llu sec)] total run time\n"
721-
"\t[-F freezeloops (default: %llu)] max loops in spa_freeze()\n"
722-
"\t[-P passtime (default: %llu sec)] time per pass\n"
723-
"\t[-B alt_ztest (default: <none>)] alternate ztest path\n"
724-
"\t[-C vdev class state (default: random)] special=on|off|random\n"
725-
"\t[-o variable=value] ... set global variable to an unsigned\n"
726-
"\t 32-bit integer value\n"
727-
"\t[-G dump zfs_dbgmsg buffer before exiting due to an error\n"
728-
"\t[-h] (print help)\n"
729-
"",
730-
zo->zo_pool,
731-
(u_longlong_t)zo->zo_vdevs, /* -v */
732-
nice_vdev_size, /* -s */
733-
zo->zo_ashift, /* -a */
734-
zo->zo_mirrors, /* -m */
735-
zo->zo_raid_children, /* -r */
736-
zo->zo_raid_parity, /* -R */
737-
zo->zo_draid_data, /* -D */
738-
zo->zo_draid_spares, /* -S */
739-
zo->zo_datasets, /* -d */
740-
zo->zo_threads, /* -t */
741-
nice_force_ganging, /* -g */
742-
zo->zo_init, /* -i */
743-
(u_longlong_t)zo->zo_killrate, /* -k */
744-
zo->zo_pool, /* -p */
745-
zo->zo_dir, /* -f */
746-
(u_longlong_t)zo->zo_time, /* -T */
747-
(u_longlong_t)zo->zo_maxloops, /* -F */
748-
(u_longlong_t)zo->zo_passtime);
838+
(void) fprintf(fp, "Usage: %s [OPTIONS...]\n", DEFAULT_POOL);
839+
for (int i = 0; option_table[i].short_opt != 0; i++) {
840+
if (option_table[i].long_opt_param != NULL) {
841+
(void) sprintf(option, " -%c --%s=%s",
842+
option_table[i].short_opt,
843+
option_table[i].long_opt,
844+
option_table[i].long_opt_param);
845+
} else {
846+
(void) sprintf(option, " -%c --%s",
847+
option_table[i].short_opt,
848+
option_table[i].long_opt);
849+
}
850+
(void) fprintf(fp, " %-40s%s", option,
851+
option_table[i].comment);
852+
853+
if (option_table[i].long_opt_param != NULL) {
854+
if (option_table[i].default_str != NULL) {
855+
(void) fprintf(fp, " (default: %s)",
856+
option_table[i].default_str);
857+
} else if (option_table[i].default_int != NO_DEFAULT) {
858+
(void) fprintf(fp, " (default: %u)",
859+
option_table[i].default_int);
860+
}
861+
}
862+
(void) fprintf(fp, "\n");
863+
}
749864
exit(requested ? 0 : 1);
750865
}
751866

@@ -817,8 +932,10 @@ process_options(int argc, char **argv)
817932

818933
bcopy(&ztest_opts_defaults, zo, sizeof (*zo));
819934

820-
while ((opt = getopt(argc, argv,
821-
"v:s:a:m:r:R:K:D:S:d:t:g:i:k:p:f:MVET:P:hF:B:C:o:G")) != EOF) {
935+
init_options();
936+
937+
while ((opt = getopt_long(argc, argv, short_opts, long_opts,
938+
NULL)) != EOF) {
822939
value = 0;
823940
switch (opt) {
824941
case 'v':
@@ -953,6 +1070,8 @@ process_options(int argc, char **argv)
9531070
}
9541071
}
9551072

1073+
fini_options();
1074+
9561075
/* When raid choice is 'random' add a draid pool 50% of the time */
9571076
if (strcmp(raid_kind, "random") == 0) {
9581077
(void) strlcpy(raid_kind, (ztest_random(2) == 0) ?

0 commit comments

Comments
 (0)