1 /*****************************************************************************\
2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2007 The Regents of the University of California.
4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://github.com/behlendorf/spl/>.
11 * The SPL is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * You should have received a copy of the GNU General Public License along
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting LAyer Tests (SPLAT) User Space Interface.
25 \*****************************************************************************/
35 #include <sys/ioctl.h>
37 #include <sys/types.h>
43 static const char shortOpts[] = "hvlat:xc";
44 static const struct option longOpts[] = {
45 { "help", no_argument, 0, 'h' },
46 { "verbose", no_argument, 0, 'v' },
47 { "list", no_argument, 0, 'l' },
48 { "all", no_argument, 0, 'a' },
49 { "test", required_argument, 0, 't' },
50 { "exit", no_argument, 0, 'x' },
51 { "nocolor", no_argument, 0, 'c' },
55 #define VERSION_SIZE 64
57 static List subsystems; /* Subsystem/tests */
58 static int splatctl_fd; /* Control file descriptor */
59 static char splat_version[VERSION_SIZE]; /* Kernel version string */
60 static char *splat_buffer = NULL; /* Scratch space area */
61 static int splat_buffer_size = 0; /* Scratch space size */
64 static void test_list(List, int);
65 static int dev_clear(void);
66 static void subsystem_fini(subsystem_t *);
67 static void test_fini(test_t *);
70 static int usage(void) {
71 fprintf(stderr, "usage: splat [hvla] [-t <subsystem:<tests>>]\n");
73 " --help -h This help\n"
74 " --verbose -v Increase verbosity\n"
75 " --list -l List all tests in all subsystems\n"
76 " --all -a Run all tests in all subsystems\n"
77 " --test -t <sub:test> Run 'test' in subsystem 'sub'\n"
78 " --exit -x Exit on first test error\n"
79 " --nocolor -c Do not colorize output\n");
82 " splat -t kmem:all # Runs all kmem tests\n"
83 " splat -t taskq:0x201 # Run taskq test 0x201\n");
88 static subsystem_t *subsystem_init(splat_user_t *desc)
92 sub = (subsystem_t *)malloc(sizeof(*sub));
96 memcpy(&sub->sub_desc, desc, sizeof(*desc));
98 sub->sub_tests = list_create((ListDelF)test_fini);
99 if (sub->sub_tests == NULL) {
107 static void subsystem_fini(subsystem_t *sub)
113 static int subsystem_setup(void)
116 int i, rc, size, cfg_size;
120 /* Aquire the number of registered subsystems */
121 cfg_size = sizeof(*cfg);
122 cfg = (splat_cfg_t *)malloc(cfg_size);
126 memset(cfg, 0, cfg_size);
127 cfg->cfg_magic = SPLAT_CFG_MAGIC;
128 cfg->cfg_cmd = SPLAT_CFG_SUBSYSTEM_COUNT;
130 rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
132 fprintf(stderr, "Ioctl() error 0x%lx / %d: %d\n",
133 (unsigned long)SPLAT_CFG, cfg->cfg_cmd, errno);
141 /* Based on the newly acquired number of subsystems allocate
142 * memory to get the descriptive information for them all. */
143 cfg_size = sizeof(*cfg) + size * sizeof(splat_user_t);
144 cfg = (splat_cfg_t *)malloc(cfg_size);
148 memset(cfg, 0, cfg_size);
149 cfg->cfg_magic = SPLAT_CFG_MAGIC;
150 cfg->cfg_cmd = SPLAT_CFG_SUBSYSTEM_LIST;
151 cfg->cfg_data.splat_subsystems.size = size;
153 rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
155 fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
156 (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
161 /* Add the new subsystems in to the global list */
163 for (i = 0; i < size; i++) {
164 desc = &(cfg->cfg_data.splat_subsystems.descs[i]);
166 sub = subsystem_init(desc);
168 fprintf(stderr, "Error initializing subsystem: %s\n",
174 list_append(subsystems, sub);
181 static void subsystem_list(List l, int indent)
187 "------------------------------ "
188 "Available SPLAT Tests "
189 "------------------------------\n");
191 i = list_iterator_create(l);
193 while ((sub = list_next(i))) {
194 fprintf(stdout, "%*s0x%0*x %-*s ---- %s ----\n",
197 SPLAT_NAME_SIZE + 7, sub->sub_desc.name,
199 test_list(sub->sub_tests, indent + 7);
202 list_iterator_destroy(i);
205 static test_t *test_init(subsystem_t *sub, splat_user_t *desc)
209 test = (test_t *)malloc(sizeof(*test));
213 test->test_sub = sub;
214 memcpy(&test->test_desc, desc, sizeof(*desc));
219 static void test_fini(test_t *test)
221 assert(test != NULL);
225 static int test_setup(subsystem_t *sub)
232 /* Aquire the number of registered tests for the give subsystem */
233 cfg = (splat_cfg_t *)malloc(sizeof(*cfg));
237 memset(cfg, 0, sizeof(*cfg));
238 cfg->cfg_magic = SPLAT_CFG_MAGIC;
239 cfg->cfg_cmd = SPLAT_CFG_TEST_COUNT;
240 cfg->cfg_arg1 = sub->sub_desc.id; /* Subsystem of interest */
242 rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
244 fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
245 (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
253 /* Based on the newly aquired number of tests allocate enough
254 * memory to get the descriptive information for them all. */
255 cfg = (splat_cfg_t *)malloc(sizeof(*cfg) + size*sizeof(splat_user_t));
259 memset(cfg, 0, sizeof(*cfg) + size * sizeof(splat_user_t));
260 cfg->cfg_magic = SPLAT_CFG_MAGIC;
261 cfg->cfg_cmd = SPLAT_CFG_TEST_LIST;
262 cfg->cfg_arg1 = sub->sub_desc.id; /* Subsystem of interest */
263 cfg->cfg_data.splat_tests.size = size;
265 rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
267 fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
268 (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
273 /* Add the new tests in to the relevant subsystems */
275 for (i = 0; i < size; i++) {
276 desc = &(cfg->cfg_data.splat_tests.descs[i]);
278 test = test_init(sub, desc);
280 fprintf(stderr, "Error initializing test: %s\n",
286 list_append(sub->sub_tests, test);
293 static test_t *test_copy(test_t *test)
295 return test_init(test->test_sub, &test->test_desc);
298 static void test_list(List l, int indent)
303 i = list_iterator_create(l);
305 while ((test = list_next(i)))
306 fprintf(stdout, "%*s0x%0*x %-*s %s\n",
307 indent, "", 04, test->test_desc.id,
308 SPLAT_NAME_SIZE, test->test_desc.name,
309 test->test_desc.desc);
311 list_iterator_destroy(i);
314 static test_t *test_find(char *sub_str, char *test_str)
319 __u32 sub_num, test_num;
322 * No error checking here because it may not be a number, it's
323 * perfectly OK for it to be a string. Since we're just using
324 * it for comparison purposes this is all very safe.
326 sub_num = strtoul(sub_str, NULL, 0);
327 test_num = strtoul(test_str, NULL, 0);
329 si = list_iterator_create(subsystems);
331 while ((sub = list_next(si))) {
333 if (strncmp(sub->sub_desc.name, sub_str, SPLAT_NAME_SIZE) &&
334 sub->sub_desc.id != sub_num)
337 ti = list_iterator_create(sub->sub_tests);
339 while ((test = list_next(ti))) {
341 if (!strncmp(test->test_desc.name, test_str,
342 SPLAT_NAME_SIZE) || test->test_desc.id==test_num) {
343 list_iterator_destroy(ti);
344 list_iterator_destroy(si);
349 list_iterator_destroy(ti);
352 list_iterator_destroy(si);
357 static int test_add(cmd_args_t *args, test_t *test)
361 tmp = test_copy(test);
365 list_append(args->args_tests, tmp);
369 static int test_add_all(cmd_args_t *args)
376 si = list_iterator_create(subsystems);
378 while ((sub = list_next(si))) {
379 ti = list_iterator_create(sub->sub_tests);
381 while ((test = list_next(ti))) {
382 if ((rc = test_add(args, test))) {
383 list_iterator_destroy(ti);
384 list_iterator_destroy(si);
389 list_iterator_destroy(ti);
392 list_iterator_destroy(si);
397 static int test_run(cmd_args_t *args, test_t *test)
399 subsystem_t *sub = test->test_sub;
405 cmd_size = sizeof(*cmd);
406 cmd = (splat_cmd_t *)malloc(cmd_size);
410 memset(cmd, 0, cmd_size);
411 cmd->cmd_magic = SPLAT_CMD_MAGIC;
412 cmd->cmd_subsystem = sub->sub_desc.id;
413 cmd->cmd_test = test->test_desc.id;
414 cmd->cmd_data_size = 0; /* Unused feature */
416 fprintf(stdout, "%*s:%-*s ",
417 SPLAT_NAME_SIZE, sub->sub_desc.name,
418 SPLAT_NAME_SIZE, test->test_desc.name);
420 rc = ioctl(splatctl_fd, SPLAT_CMD, cmd);
421 if (args->args_do_color) {
422 fprintf(stdout, "%s %s\n", rc ?
423 COLOR_RED "Fail" COLOR_RESET :
424 COLOR_GREEN "Pass" COLOR_RESET,
425 rc ? strerror(errno) : "");
427 fprintf(stdout, "%s %s\n", rc ?
429 rc ? strerror(errno) : "");
434 if (args->args_verbose) {
435 if ((rc = read(splatctl_fd, splat_buffer,
436 splat_buffer_size - 1)) < 0) {
437 fprintf(stdout, "Error reading results: %d\n", rc);
439 fprintf(stdout, "\n%s\n", splat_buffer);
447 static int tests_run(cmd_args_t *args)
454 "------------------------------ "
455 "Running SPLAT Tests "
456 "------------------------------\n");
458 i = list_iterator_create(args->args_tests);
460 while ((test = list_next(i))) {
461 rc = test_run(args, test);
462 if (rc && args->args_exit_on_error) {
463 list_iterator_destroy(i);
468 list_iterator_destroy(i);
472 static int args_parse_test(cmd_args_t *args, char *str)
477 char *sub_str, *test_str;
478 int sub_num, test_num;
479 int sub_all = 0, test_all = 0;
482 test_str = strchr(str, ':');
483 if (test_str == NULL) {
484 fprintf(stderr, "Test must be of the "
485 "form <subsystem:test>\n");
491 test_str = test_str + 1;
493 sub_num = strtol(sub_str, NULL, 0);
494 test_num = strtol(test_str, NULL, 0);
496 if (!strncasecmp(sub_str, "all", strlen(sub_str)) || (sub_num == -1))
499 if (!strncasecmp(test_str,"all",strlen(test_str)) || (test_num == -1))
502 si = list_iterator_create(subsystems);
506 /* Add all tests from all subsystems */
507 while ((s = list_next(si))) {
508 ti = list_iterator_create(s->sub_tests);
509 while ((t = list_next(ti))) {
510 if ((rc = test_add(args, t))) {
511 list_iterator_destroy(ti);
515 list_iterator_destroy(ti);
518 /* Add a specific test from all subsystems */
519 while ((s = list_next(si))) {
520 if ((t=test_find(s->sub_desc.name,test_str))) {
521 if ((rc = test_add(args, t)))
529 fprintf(stderr, "No tests '%s:%s' could be "
530 "found\n", sub_str, test_str);
534 /* Add all tests from a specific subsystem */
535 while ((s = list_next(si))) {
536 if (strncasecmp(sub_str, s->sub_desc.name,
540 ti = list_iterator_create(s->sub_tests);
541 while ((t = list_next(ti))) {
542 if ((rc = test_add(args, t))) {
543 list_iterator_destroy(ti);
547 list_iterator_destroy(ti);
550 /* Add a specific test from a specific subsystem */
551 if ((t = test_find(sub_str, test_str))) {
552 if ((rc = test_add(args, t)))
555 fprintf(stderr, "Test '%s:%s' could not be "
556 "found\n", sub_str, test_str);
562 list_iterator_destroy(si);
567 list_iterator_destroy(si);
569 fprintf(stderr, "Test '%s:%s' not added to run list: %d\n",
570 sub_str, test_str, rc);
575 static void args_fini(cmd_args_t *args)
577 assert(args != NULL);
579 if (args->args_tests != NULL)
580 list_destroy(args->args_tests);
586 args_init(int argc, char **argv)
593 return (cmd_args_t *) NULL;
596 /* Configure and populate the args structures */
597 args = malloc(sizeof(*args));
601 memset(args, 0, sizeof(*args));
602 args->args_verbose = 0;
603 args->args_do_list = 0;
604 args->args_do_all = 0;
605 args->args_do_color = 1;
606 args->args_exit_on_error = 0;
607 args->args_tests = list_create((ListDelF)test_fini);
608 if (args->args_tests == NULL) {
613 while ((c = getopt_long(argc, argv, shortOpts, longOpts, NULL)) != -1){
615 case 'v': args->args_verbose++; break;
616 case 'l': args->args_do_list = 1; break;
617 case 'a': args->args_do_all = 1; break;
618 case 'c': args->args_do_color = 0; break;
619 case 'x': args->args_exit_on_error = 1; break;
621 if (args->args_do_all) {
622 fprintf(stderr, "Option -t <subsystem:test> is "
623 "useless when used with -a\n");
628 rc = args_parse_test(args, argv[optind - 1]);
640 fprintf(stderr, "Unknown option '%s'\n",
655 memset(&cfg, 0, sizeof(cfg));
656 cfg.cfg_magic = SPLAT_CFG_MAGIC;
657 cfg.cfg_cmd = SPLAT_CFG_BUFFER_CLEAR;
660 rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
662 fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
663 (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
665 lseek(splatctl_fd, 0, SEEK_SET);
676 memset(&cfg, 0, sizeof(cfg));
677 cfg.cfg_magic = SPLAT_CFG_MAGIC;
678 cfg.cfg_cmd = SPLAT_CFG_BUFFER_SIZE;
681 rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
683 fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
684 (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
697 if (splatctl_fd != -1) {
698 if (close(splatctl_fd) == -1) {
699 fprintf(stderr, "Unable to close %s: %d\n",
712 splatctl_fd = open(SPLAT_DEV, O_RDONLY);
713 if (splatctl_fd == -1) {
714 fprintf(stderr, "Unable to open %s: %d\n"
715 "Is the splat module loaded?\n", SPLAT_DEV, errno);
720 /* Determine kernel module version string */
721 memset(splat_version, 0, VERSION_SIZE);
722 if ((rc = read(splatctl_fd, splat_version, VERSION_SIZE - 1)) == -1)
725 if ((rc = dev_clear()))
728 if ((rc = dev_size(0)) < 0)
731 splat_buffer_size = rc;
732 splat_buffer = (char *)malloc(splat_buffer_size);
733 if (splat_buffer == NULL) {
738 memset(splat_buffer, 0, splat_buffer_size);
740 /* Determine available subsystems */
741 if ((rc = subsystem_setup()) != 0)
744 /* Determine available tests for all subsystems */
745 i = list_iterator_create(subsystems);
747 while ((sub = list_next(i))) {
748 if ((rc = test_setup(sub)) != 0) {
749 list_iterator_destroy(i);
754 list_iterator_destroy(i);
758 if (splatctl_fd != -1) {
759 if (close(splatctl_fd) == -1) {
760 fprintf(stderr, "Unable to close %s: %d\n",
773 /* Allocate the subsystem list */
774 subsystems = list_create((ListDelF)subsystem_fini);
775 if (subsystems == NULL)
784 list_destroy(subsystems);
789 main(int argc, char **argv)
791 cmd_args_t *args = NULL;
798 /* Device specific init */
799 if ((rc = dev_init()))
802 /* Argument init and parsing */
803 if ((args = args_init(argc, argv)) == NULL) {
808 /* Generic kernel version string */
809 if (args->args_verbose)
810 fprintf(stdout, "%s", splat_version);
812 /* Print the available test list and exit */
813 if (args->args_do_list) {
814 subsystem_list(subsystems, 0);
818 /* Add all available test to the list of tests to run */
819 if (args->args_do_all) {
820 if ((rc = test_add_all(args)))
824 /* Run all the requested tests */
825 if ((rc = tests_run(args)))