|
124 | 124 | #include <stdio.h>
|
125 | 125 | #include <stdlib.h>
|
126 | 126 | #include <unistd.h>
|
| 127 | +#include <getopt.h> |
127 | 128 | #include <signal.h>
|
128 | 129 | #include <umem.h>
|
129 | 130 | #include <ctype.h>
|
@@ -192,30 +193,58 @@ typedef struct ztest_shared_opts {
|
192 | 193 | char zo_gvars[ZO_GVARS_MAX_COUNT][ZO_GVARS_MAX_ARGLEN];
|
193 | 194 | } ztest_shared_opts_t;
|
194 | 195 |
|
| 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 | + |
195 | 224 | 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, |
198 | 227 | .zo_alt_ztest = { '\0' },
|
199 | 228 | .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, |
205 | 234 | .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, |
213 | 242 | .zo_verbose = 0,
|
214 | 243 | .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, |
219 | 248 | .zo_special_vdevs = ZTEST_VDEV_CLASS_RND,
|
220 | 249 | .zo_gvars_count = 0,
|
221 | 250 | };
|
@@ -684,68 +713,154 @@ nicenumtoull(const char *buf)
|
684 | 713 | return (val);
|
685 | 714 | }
|
686 | 715 |
|
| 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 | + |
687 | 795 | 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) |
689 | 822 | {
|
690 |
| - const ztest_shared_opts_t *zo = &ztest_opts_defaults; |
| 823 | + int count = sizeof (option_table) / sizeof (option_table[0]); |
691 | 824 |
|
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]; |
694 | 836 | FILE *fp = requested ? stdout : stderr;
|
695 | 837 |
|
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 | + } |
749 | 864 | exit(requested ? 0 : 1);
|
750 | 865 | }
|
751 | 866 |
|
@@ -817,8 +932,10 @@ process_options(int argc, char **argv)
|
817 | 932 |
|
818 | 933 | bcopy(&ztest_opts_defaults, zo, sizeof (*zo));
|
819 | 934 |
|
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) { |
822 | 939 | value = 0;
|
823 | 940 | switch (opt) {
|
824 | 941 | case 'v':
|
@@ -953,6 +1070,8 @@ process_options(int argc, char **argv)
|
953 | 1070 | }
|
954 | 1071 | }
|
955 | 1072 |
|
| 1073 | + fini_options(); |
| 1074 | + |
956 | 1075 | /* When raid choice is 'random' add a draid pool 50% of the time */
|
957 | 1076 | if (strcmp(raid_kind, "random") == 0) {
|
958 | 1077 | (void) strlcpy(raid_kind, (ztest_random(2) == 0) ?
|
|
0 commit comments