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 int sub_num
, test_num
;
321 /* No error checking here because it may not be a number, it's
322 * perfectly OK for it to be a string. Since we're just using
323 * it for comparison purposes this is all very safe.
325 sub_num
= strtol(sub_str
, NULL
, 0);
326 test_num
= strtol(test_str
, NULL
, 0);
328 si
= list_iterator_create(subsystems
);
330 while ((sub
= list_next(si
))) {
332 if (strncmp(sub
->sub_desc
.name
, sub_str
, SPLAT_NAME_SIZE
) &&
333 sub
->sub_desc
.id
!= sub_num
)
336 ti
= list_iterator_create(sub
->sub_tests
);
338 while ((test
= list_next(ti
))) {
340 if (!strncmp(test
->test_desc
.name
, test_str
,
341 SPLAT_NAME_SIZE
) || test
->test_desc
.id
==test_num
) {
342 list_iterator_destroy(ti
);
343 list_iterator_destroy(si
);
348 list_iterator_destroy(ti
);
351 list_iterator_destroy(si
);
356 static int test_add(cmd_args_t
*args
, test_t
*test
)
360 tmp
= test_copy(test
);
364 list_append(args
->args_tests
, tmp
);
368 static int test_add_all(cmd_args_t
*args
)
375 si
= list_iterator_create(subsystems
);
377 while ((sub
= list_next(si
))) {
378 ti
= list_iterator_create(sub
->sub_tests
);
380 while ((test
= list_next(ti
))) {
381 if ((rc
= test_add(args
, test
))) {
382 list_iterator_destroy(ti
);
383 list_iterator_destroy(si
);
388 list_iterator_destroy(ti
);
391 list_iterator_destroy(si
);
396 static int test_run(cmd_args_t
*args
, test_t
*test
)
398 subsystem_t
*sub
= test
->test_sub
;
404 cmd_size
= sizeof(*cmd
);
405 cmd
= (splat_cmd_t
*)malloc(cmd_size
);
409 memset(cmd
, 0, cmd_size
);
410 cmd
->cmd_magic
= SPLAT_CMD_MAGIC
;
411 cmd
->cmd_subsystem
= sub
->sub_desc
.id
;
412 cmd
->cmd_test
= test
->test_desc
.id
;
413 cmd
->cmd_data_size
= 0; /* Unused feature */
415 fprintf(stdout
, "%*s:%-*s ",
416 SPLAT_NAME_SIZE
, sub
->sub_desc
.name
,
417 SPLAT_NAME_SIZE
, test
->test_desc
.name
);
419 rc
= ioctl(splatctl_fd
, SPLAT_CMD
, cmd
);
420 if (args
->args_do_color
) {
421 fprintf(stdout
, "%s %s\n", rc
?
422 COLOR_RED
"Fail" COLOR_RESET
:
423 COLOR_GREEN
"Pass" COLOR_RESET
,
424 rc
? strerror(errno
) : "");
426 fprintf(stdout
, "%s %s\n", rc
?
428 rc
? strerror(errno
) : "");
433 if (args
->args_verbose
) {
434 if ((rc
= read(splatctl_fd
, splat_buffer
,
435 splat_buffer_size
- 1)) < 0) {
436 fprintf(stdout
, "Error reading results: %d\n", rc
);
438 fprintf(stdout
, "\n%s\n", splat_buffer
);
446 static int tests_run(cmd_args_t
*args
)
453 "------------------------------ "
454 "Running SPLAT Tests "
455 "------------------------------\n");
457 i
= list_iterator_create(args
->args_tests
);
459 while ((test
= list_next(i
))) {
460 rc
= test_run(args
, test
);
461 if (rc
&& args
->args_exit_on_error
) {
462 list_iterator_destroy(i
);
467 list_iterator_destroy(i
);
471 static int args_parse_test(cmd_args_t
*args
, char *str
)
476 char *sub_str
, *test_str
;
477 int sub_num
, test_num
;
478 int sub_all
= 0, test_all
= 0;
481 test_str
= strchr(str
, ':');
482 if (test_str
== NULL
) {
483 fprintf(stderr
, "Test must be of the "
484 "form <subsystem:test>\n");
490 test_str
= test_str
+ 1;
492 sub_num
= strtol(sub_str
, NULL
, 0);
493 test_num
= strtol(test_str
, NULL
, 0);
495 if (!strncasecmp(sub_str
, "all", strlen(sub_str
)) || (sub_num
== -1))
498 if (!strncasecmp(test_str
,"all",strlen(test_str
)) || (test_num
== -1))
501 si
= list_iterator_create(subsystems
);
505 /* Add all tests from all subsystems */
506 while ((s
= list_next(si
))) {
507 ti
= list_iterator_create(s
->sub_tests
);
508 while ((t
= list_next(ti
))) {
509 if ((rc
= test_add(args
, t
))) {
510 list_iterator_destroy(ti
);
514 list_iterator_destroy(ti
);
517 /* Add a specific test from all subsystems */
518 while ((s
= list_next(si
))) {
519 if ((t
=test_find(s
->sub_desc
.name
,test_str
))) {
520 if ((rc
= test_add(args
, t
)))
528 fprintf(stderr
, "No tests '%s:%s' could be "
529 "found\n", sub_str
, test_str
);
533 /* Add all tests from a specific subsystem */
534 while ((s
= list_next(si
))) {
535 if (strncasecmp(sub_str
, s
->sub_desc
.name
,
539 ti
= list_iterator_create(s
->sub_tests
);
540 while ((t
= list_next(ti
))) {
541 if ((rc
= test_add(args
, t
))) {
542 list_iterator_destroy(ti
);
546 list_iterator_destroy(ti
);
549 /* Add a specific test from a specific subsystem */
550 if ((t
= test_find(sub_str
, test_str
))) {
551 if ((rc
= test_add(args
, t
)))
554 fprintf(stderr
, "Test '%s:%s' could not be "
555 "found\n", sub_str
, test_str
);
561 list_iterator_destroy(si
);
566 list_iterator_destroy(si
);
568 fprintf(stderr
, "Test '%s:%s' not added to run list: %d\n",
569 sub_str
, test_str
, rc
);
574 static void args_fini(cmd_args_t
*args
)
576 assert(args
!= NULL
);
578 if (args
->args_tests
!= NULL
)
579 list_destroy(args
->args_tests
);
585 args_init(int argc
, char **argv
)
592 return (cmd_args_t
*) NULL
;
595 /* Configure and populate the args structures */
596 args
= malloc(sizeof(*args
));
600 memset(args
, 0, sizeof(*args
));
601 args
->args_verbose
= 0;
602 args
->args_do_list
= 0;
603 args
->args_do_all
= 0;
604 args
->args_do_color
= 1;
605 args
->args_exit_on_error
= 0;
606 args
->args_tests
= list_create((ListDelF
)test_fini
);
607 if (args
->args_tests
== NULL
) {
612 while ((c
= getopt_long(argc
, argv
, shortOpts
, longOpts
, NULL
)) != -1){
614 case 'v': args
->args_verbose
++; break;
615 case 'l': args
->args_do_list
= 1; break;
616 case 'a': args
->args_do_all
= 1; break;
617 case 'c': args
->args_do_color
= 0; break;
618 case 'x': args
->args_exit_on_error
= 1; break;
620 if (args
->args_do_all
) {
621 fprintf(stderr
, "Option -t <subsystem:test> is "
622 "useless when used with -a\n");
627 rc
= args_parse_test(args
, argv
[optind
- 1]);
639 fprintf(stderr
, "Unknown option '%s'\n",
654 memset(&cfg
, 0, sizeof(cfg
));
655 cfg
.cfg_magic
= SPLAT_CFG_MAGIC
;
656 cfg
.cfg_cmd
= SPLAT_CFG_BUFFER_CLEAR
;
659 rc
= ioctl(splatctl_fd
, SPLAT_CFG
, &cfg
);
661 fprintf(stderr
, "Ioctl() error %lu / %d: %d\n",
662 (unsigned long) SPLAT_CFG
, cfg
.cfg_cmd
, errno
);
664 lseek(splatctl_fd
, 0, SEEK_SET
);
675 memset(&cfg
, 0, sizeof(cfg
));
676 cfg
.cfg_magic
= SPLAT_CFG_MAGIC
;
677 cfg
.cfg_cmd
= SPLAT_CFG_BUFFER_SIZE
;
680 rc
= ioctl(splatctl_fd
, SPLAT_CFG
, &cfg
);
682 fprintf(stderr
, "Ioctl() error %lu / %d: %d\n",
683 (unsigned long) SPLAT_CFG
, cfg
.cfg_cmd
, errno
);
696 if (splatctl_fd
!= -1) {
697 if (close(splatctl_fd
) == -1) {
698 fprintf(stderr
, "Unable to close %s: %d\n",
711 splatctl_fd
= open(SPLAT_DEV
, O_RDONLY
);
712 if (splatctl_fd
== -1) {
713 fprintf(stderr
, "Unable to open %s: %d\n"
714 "Is the splat module loaded?\n", SPLAT_DEV
, errno
);
719 /* Determine kernel module version string */
720 memset(splat_version
, 0, VERSION_SIZE
);
721 if ((rc
= read(splatctl_fd
, splat_version
, VERSION_SIZE
- 1)) == -1)
724 if ((rc
= dev_clear()))
727 if ((rc
= dev_size(0)) < 0)
730 splat_buffer_size
= rc
;
731 splat_buffer
= (char *)malloc(splat_buffer_size
);
732 if (splat_buffer
== NULL
) {
737 memset(splat_buffer
, 0, splat_buffer_size
);
739 /* Determine available subsystems */
740 if ((rc
= subsystem_setup()) != 0)
743 /* Determine available tests for all subsystems */
744 i
= list_iterator_create(subsystems
);
746 while ((sub
= list_next(i
))) {
747 if ((rc
= test_setup(sub
)) != 0) {
748 list_iterator_destroy(i
);
753 list_iterator_destroy(i
);
757 if (splatctl_fd
!= -1) {
758 if (close(splatctl_fd
) == -1) {
759 fprintf(stderr
, "Unable to close %s: %d\n",
772 /* Allocate the subsystem list */
773 subsystems
= list_create((ListDelF
)subsystem_fini
);
774 if (subsystems
== NULL
)
783 list_destroy(subsystems
);
788 main(int argc
, char **argv
)
790 cmd_args_t
*args
= NULL
;
797 /* Device specific init */
798 if ((rc
= dev_init()))
801 /* Argument init and parsing */
802 if ((args
= args_init(argc
, argv
)) == NULL
) {
807 /* Generic kernel version string */
808 if (args
->args_verbose
)
809 fprintf(stdout
, "%s", splat_version
);
811 /* Print the available test list and exit */
812 if (args
->args_do_list
) {
813 subsystem_list(subsystems
, 0);
817 /* Add all available test to the list of tests to run */
818 if (args
->args_do_all
) {
819 if ((rc
= test_add_all(args
)))
823 /* Run all the requested tests */
824 if ((rc
= tests_run(args
)))