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://zfsonlinux.org/>.
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
== 1 && rc
) ||
435 (args
->args_verbose
>= 2)) {
436 if ((rc
= read(splatctl_fd
, splat_buffer
,
437 splat_buffer_size
- 1)) < 0) {
438 fprintf(stdout
, "Error reading results: %d\n", rc
);
440 fprintf(stdout
, "\n%s\n", splat_buffer
);
448 static int tests_run(cmd_args_t
*args
)
455 "------------------------------ "
456 "Running SPLAT Tests "
457 "------------------------------\n");
459 i
= list_iterator_create(args
->args_tests
);
461 while ((test
= list_next(i
))) {
462 rc
= test_run(args
, test
);
463 if (rc
&& args
->args_exit_on_error
) {
464 list_iterator_destroy(i
);
469 list_iterator_destroy(i
);
473 static int args_parse_test(cmd_args_t
*args
, char *str
)
478 char *sub_str
, *test_str
;
479 int sub_num
, test_num
;
480 int sub_all
= 0, test_all
= 0;
483 test_str
= strchr(str
, ':');
484 if (test_str
== NULL
) {
485 fprintf(stderr
, "Test must be of the "
486 "form <subsystem:test>\n");
492 test_str
= test_str
+ 1;
494 sub_num
= strtol(sub_str
, NULL
, 0);
495 test_num
= strtol(test_str
, NULL
, 0);
497 if (!strncasecmp(sub_str
, "all", strlen(sub_str
)) || (sub_num
== -1))
500 if (!strncasecmp(test_str
,"all",strlen(test_str
)) || (test_num
== -1))
503 si
= list_iterator_create(subsystems
);
507 /* Add all tests from all subsystems */
508 while ((s
= list_next(si
))) {
509 ti
= list_iterator_create(s
->sub_tests
);
510 while ((t
= list_next(ti
))) {
511 if ((rc
= test_add(args
, t
))) {
512 list_iterator_destroy(ti
);
516 list_iterator_destroy(ti
);
519 /* Add a specific test from all subsystems */
520 while ((s
= list_next(si
))) {
521 if ((t
=test_find(s
->sub_desc
.name
,test_str
))) {
522 if ((rc
= test_add(args
, t
)))
530 fprintf(stderr
, "No tests '%s:%s' could be "
531 "found\n", sub_str
, test_str
);
535 /* Add all tests from a specific subsystem */
536 while ((s
= list_next(si
))) {
537 if (strncasecmp(sub_str
, s
->sub_desc
.name
,
541 ti
= list_iterator_create(s
->sub_tests
);
542 while ((t
= list_next(ti
))) {
543 if ((rc
= test_add(args
, t
))) {
544 list_iterator_destroy(ti
);
548 list_iterator_destroy(ti
);
551 /* Add a specific test from a specific subsystem */
552 if ((t
= test_find(sub_str
, test_str
))) {
553 if ((rc
= test_add(args
, t
)))
556 fprintf(stderr
, "Test '%s:%s' could not be "
557 "found\n", sub_str
, test_str
);
563 list_iterator_destroy(si
);
568 list_iterator_destroy(si
);
570 fprintf(stderr
, "Test '%s:%s' not added to run list: %d\n",
571 sub_str
, test_str
, rc
);
576 static void args_fini(cmd_args_t
*args
)
578 assert(args
!= NULL
);
580 if (args
->args_tests
!= NULL
)
581 list_destroy(args
->args_tests
);
587 args_init(int argc
, char **argv
)
594 return (cmd_args_t
*) NULL
;
597 /* Configure and populate the args structures */
598 args
= malloc(sizeof(*args
));
602 memset(args
, 0, sizeof(*args
));
603 args
->args_verbose
= 0;
604 args
->args_do_list
= 0;
605 args
->args_do_all
= 0;
606 args
->args_do_color
= 1;
607 args
->args_exit_on_error
= 0;
608 args
->args_tests
= list_create((ListDelF
)test_fini
);
609 if (args
->args_tests
== NULL
) {
614 while ((c
= getopt_long(argc
, argv
, shortOpts
, longOpts
, NULL
)) != -1){
616 case 'v': args
->args_verbose
++; break;
617 case 'l': args
->args_do_list
= 1; break;
618 case 'a': args
->args_do_all
= 1; break;
619 case 'c': args
->args_do_color
= 0; break;
620 case 'x': args
->args_exit_on_error
= 1; break;
622 if (args
->args_do_all
) {
623 fprintf(stderr
, "Option -t <subsystem:test> is "
624 "useless when used with -a\n");
629 rc
= args_parse_test(args
, argv
[optind
- 1]);
641 fprintf(stderr
, "Unknown option '%s'\n",
656 memset(&cfg
, 0, sizeof(cfg
));
657 cfg
.cfg_magic
= SPLAT_CFG_MAGIC
;
658 cfg
.cfg_cmd
= SPLAT_CFG_BUFFER_CLEAR
;
661 rc
= ioctl(splatctl_fd
, SPLAT_CFG
, &cfg
);
663 fprintf(stderr
, "Ioctl() error %lu / %d: %d\n",
664 (unsigned long) SPLAT_CFG
, cfg
.cfg_cmd
, errno
);
666 lseek(splatctl_fd
, 0, SEEK_SET
);
677 memset(&cfg
, 0, sizeof(cfg
));
678 cfg
.cfg_magic
= SPLAT_CFG_MAGIC
;
679 cfg
.cfg_cmd
= SPLAT_CFG_BUFFER_SIZE
;
682 rc
= ioctl(splatctl_fd
, SPLAT_CFG
, &cfg
);
684 fprintf(stderr
, "Ioctl() error %lu / %d: %d\n",
685 (unsigned long) SPLAT_CFG
, cfg
.cfg_cmd
, errno
);
698 if (splatctl_fd
!= -1) {
699 if (close(splatctl_fd
) == -1) {
700 fprintf(stderr
, "Unable to close %s: %d\n",
713 splatctl_fd
= open(SPLAT_DEV
, O_RDONLY
);
714 if (splatctl_fd
== -1) {
715 fprintf(stderr
, "Unable to open %s: %d\n"
716 "Is the splat module loaded?\n", SPLAT_DEV
, errno
);
721 /* Determine kernel module version string */
722 memset(splat_version
, 0, VERSION_SIZE
);
723 if ((rc
= read(splatctl_fd
, splat_version
, VERSION_SIZE
- 1)) == -1)
726 if ((rc
= dev_clear()))
729 if ((rc
= dev_size(0)) < 0)
732 splat_buffer_size
= rc
;
733 splat_buffer
= (char *)malloc(splat_buffer_size
);
734 if (splat_buffer
== NULL
) {
739 memset(splat_buffer
, 0, splat_buffer_size
);
741 /* Determine available subsystems */
742 if ((rc
= subsystem_setup()) != 0)
745 /* Determine available tests for all subsystems */
746 i
= list_iterator_create(subsystems
);
748 while ((sub
= list_next(i
))) {
749 if ((rc
= test_setup(sub
)) != 0) {
750 list_iterator_destroy(i
);
755 list_iterator_destroy(i
);
759 if (splatctl_fd
!= -1) {
760 if (close(splatctl_fd
) == -1) {
761 fprintf(stderr
, "Unable to close %s: %d\n",
774 /* Allocate the subsystem list */
775 subsystems
= list_create((ListDelF
)subsystem_fini
);
776 if (subsystems
== NULL
)
785 list_destroy(subsystems
);
790 main(int argc
, char **argv
)
792 cmd_args_t
*args
= NULL
;
799 /* Device specific init */
800 if ((rc
= dev_init()))
803 /* Argument init and parsing */
804 if ((args
= args_init(argc
, argv
)) == NULL
) {
809 /* Generic kernel version string */
810 if (args
->args_verbose
)
811 fprintf(stdout
, "%s", splat_version
);
813 /* Print the available test list and exit */
814 if (args
->args_do_list
) {
815 subsystem_list(subsystems
, 0);
819 /* Add all available test to the list of tests to run */
820 if (args
->args_do_all
) {
821 if ((rc
= test_add_all(args
)))
825 /* Run all the requested tests */
826 if ((rc
= tests_run(args
)))