]> git.proxmox.com Git - mirror_spl.git/commitdiff
Add a script to display SPL slab cache statistics
authorBoris Protopopov <boris.protopopov@actifio.com>
Tue, 30 Jun 2015 21:47:15 +0000 (17:47 -0400)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 2 Dec 2015 22:08:08 +0000 (14:08 -0800)
Useful when looking for the info on ZFS/SPL related memory consumption.

Signed-off-by: Boris Protopopov <boris.protopopov@actifio.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #460

cmd/Makefile.am
cmd/splat.c [deleted file]
cmd/splat.h [deleted file]
cmd/splat/Makefile.am [new file with mode: 0644]
cmd/splat/splat.c [new file with mode: 0644]
cmd/splat/splat.h [new file with mode: 0644]
cmd/splslab/Makefile.am [new file with mode: 0644]
cmd/splslab/splslab.py [new file with mode: 0755]
configure.ac
rpm/generic/spl.spec.in

index 01afdcf2566d504ac3e9bcc169daed0792fdcd70..63a3c76f9754dc293006e9d37c8687c07801b7eb 100644 (file)
@@ -1,11 +1 @@
-include $(top_srcdir)/config/Rules.am
-
-DEFAULT_INCLUDES += \
-       -I$(top_srcdir)/lib
-
-sbin_PROGRAMS = splat
-
-splat_SOURCES = splat.c
-splat_LDFLAGS = $(top_builddir)/lib/libcommon.la
-
-EXTRA_DIST = splat.h
+SUBDIRS = splat splslab
diff --git a/cmd/splat.c b/cmd/splat.c
deleted file mode 100644 (file)
index 9296239..0000000
+++ /dev/null
@@ -1,836 +0,0 @@
-/*****************************************************************************\
- *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
- *  Copyright (C) 2007 The Regents of the University of California.
- *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
- *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
- *  UCRL-CODE-235197
- *
- *  This file is part of the SPL, Solaris Porting Layer.
- *  For details, see <http://zfsonlinux.org/>.
- *
- *  The SPL is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the
- *  Free Software Foundation; either version 2 of the License, or (at your
- *  option) any later version.
- *
- *  The SPL is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
- *****************************************************************************
- *  Solaris Porting LAyer Tests (SPLAT) User Space Interface.
-\*****************************************************************************/
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <getopt.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include "splat.h"
-
-#undef ioctl
-
-static const char shortOpts[] = "hvlat:xc";
-static const struct option longOpts[] = {
-       { "help",            no_argument,       0, 'h' },
-       { "verbose",         no_argument,       0, 'v' },
-       { "list",            no_argument,       0, 'l' },
-       { "all",             no_argument,       0, 'a' },
-       { "test",            required_argument, 0, 't' },
-       { "exit",            no_argument,       0, 'x' },
-       { "nocolor",         no_argument,       0, 'c' },
-       { 0,                 0,                 0, 0   }
-};
-
-#define VERSION_SIZE   64
-
-static List subsystems;                                /* Subsystem/tests */
-static int splatctl_fd;                                /* Control file descriptor */
-static char splat_version[VERSION_SIZE];       /* Kernel version string */
-static char *splat_buffer = NULL;              /* Scratch space area */
-static int splat_buffer_size = 0;              /* Scratch space size */
-
-
-static void test_list(List, int);
-static int dev_clear(void);
-static void subsystem_fini(subsystem_t *);
-static void test_fini(test_t *);
-
-
-static int usage(void) {
-       fprintf(stderr, "usage: splat [hvla] [-t <subsystem:<tests>>]\n");
-       fprintf(stderr,
-       "  --help      -h               This help\n"
-       "  --verbose   -v               Increase verbosity\n"
-       "  --list      -l               List all tests in all subsystems\n"
-       "  --all       -a               Run all tests in all subsystems\n"
-       "  --test      -t <sub:test>    Run 'test' in subsystem 'sub'\n"
-       "  --exit      -x               Exit on first test error\n"
-       "  --nocolor   -c               Do not colorize output\n");
-       fprintf(stderr, "\n"
-       "Examples:\n"
-       "  splat -t kmem:all     # Runs all kmem tests\n"
-       "  splat -t taskq:0x201  # Run taskq test 0x201\n");
-
-       return 0;
-}
-
-static subsystem_t *subsystem_init(splat_user_t *desc)
-{
-       subsystem_t *sub;
-
-       sub = (subsystem_t *)malloc(sizeof(*sub));
-       if (sub == NULL)
-               return NULL;
-
-       memcpy(&sub->sub_desc, desc, sizeof(*desc));
-
-       sub->sub_tests = list_create((ListDelF)test_fini);
-       if (sub->sub_tests == NULL) {
-               free(sub);
-               return NULL;
-       }
-
-       return sub;
-}
-
-static void subsystem_fini(subsystem_t *sub)
-{
-       assert(sub != NULL);
-       free(sub);
-}
-
-static int subsystem_setup(void)
-{
-       splat_cfg_t *cfg;
-       int i, rc, size, cfg_size;
-       subsystem_t *sub;
-       splat_user_t *desc;
-
-       /* Aquire the number of registered subsystems */
-       cfg_size = sizeof(*cfg);
-       cfg = (splat_cfg_t *)malloc(cfg_size);
-       if (cfg == NULL)
-               return -ENOMEM;
-
-       memset(cfg, 0, cfg_size);
-       cfg->cfg_magic = SPLAT_CFG_MAGIC;
-        cfg->cfg_cmd   = SPLAT_CFG_SUBSYSTEM_COUNT;
-
-       rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
-       if (rc) {
-               fprintf(stderr, "Ioctl() error 0x%lx / %d: %d\n",
-                       (unsigned long)SPLAT_CFG, cfg->cfg_cmd, errno);
-               free(cfg);
-               return rc;
-       }
-
-       size = cfg->cfg_rc1;
-       free(cfg);
-
-       /* Based on the newly acquired number of subsystems allocate
-        * memory to get the descriptive information for them all. */
-       cfg_size = sizeof(*cfg) + size * sizeof(splat_user_t);
-       cfg = (splat_cfg_t *)malloc(cfg_size);
-       if (cfg == NULL)
-               return -ENOMEM;
-
-       memset(cfg, 0, cfg_size);
-       cfg->cfg_magic = SPLAT_CFG_MAGIC;
-       cfg->cfg_cmd   = SPLAT_CFG_SUBSYSTEM_LIST;
-       cfg->cfg_data.splat_subsystems.size = size;
-
-       rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
-       if (rc) {
-               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
-                       (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
-               free(cfg);
-               return rc;
-       }
-
-       /* Add the new subsystems in to the global list */
-       size = cfg->cfg_rc1;
-       for (i = 0; i < size; i++) {
-               desc = &(cfg->cfg_data.splat_subsystems.descs[i]);
-
-               sub = subsystem_init(desc);
-               if (sub == NULL) {
-                       fprintf(stderr, "Error initializing subsystem: %s\n",
-                               desc->name);
-                       free(cfg);
-                       return -ENOMEM;
-               }
-
-               list_append(subsystems, sub);
-       }
-
-       free(cfg);
-       return 0;
-}
-
-static void subsystem_list(List l, int indent)
-{
-       ListIterator i;
-       subsystem_t *sub;
-
-       fprintf(stdout,
-               "------------------------------ "
-               "Available SPLAT Tests "
-               "------------------------------\n");
-
-       i = list_iterator_create(l);
-
-       while ((sub = list_next(i))) {
-               fprintf(stdout, "%*s0x%0*x %-*s ---- %s ----\n",
-                       indent, "",
-                       4, sub->sub_desc.id,
-                       SPLAT_NAME_SIZE + 7, sub->sub_desc.name,
-                       sub->sub_desc.desc);
-               test_list(sub->sub_tests, indent + 7);
-       }
-
-       list_iterator_destroy(i);
-}
-
-static test_t *test_init(subsystem_t *sub, splat_user_t *desc)
-{
-       test_t *test;
-
-       test = (test_t *)malloc(sizeof(*test));
-       if (test == NULL)
-               return NULL;
-
-       test->test_sub = sub;
-       memcpy(&test->test_desc, desc, sizeof(*desc));
-
-       return test;
-}
-
-static void test_fini(test_t *test)
-{
-       assert(test != NULL);
-       free(test);
-}
-
-static int test_setup(subsystem_t *sub)
-{
-       splat_cfg_t *cfg;
-       int i, rc, size;
-       test_t *test;
-       splat_user_t *desc;
-
-       /* Aquire the number of registered tests for the give subsystem */
-       cfg = (splat_cfg_t *)malloc(sizeof(*cfg));
-       if (cfg == NULL)
-               return -ENOMEM;
-
-       memset(cfg, 0, sizeof(*cfg));
-       cfg->cfg_magic = SPLAT_CFG_MAGIC;
-        cfg->cfg_cmd   = SPLAT_CFG_TEST_COUNT;
-       cfg->cfg_arg1  = sub->sub_desc.id; /* Subsystem of interest */
-
-       rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
-       if (rc) {
-               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
-                       (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
-               free(cfg);
-               return rc;
-       }
-
-       size = cfg->cfg_rc1;
-       free(cfg);
-
-       /* Based on the newly aquired number of tests allocate enough
-        * memory to get the descriptive information for them all. */
-       cfg = (splat_cfg_t *)malloc(sizeof(*cfg) + size*sizeof(splat_user_t));
-       if (cfg == NULL)
-               return -ENOMEM;
-
-       memset(cfg, 0, sizeof(*cfg) + size * sizeof(splat_user_t));
-       cfg->cfg_magic = SPLAT_CFG_MAGIC;
-       cfg->cfg_cmd   = SPLAT_CFG_TEST_LIST;
-       cfg->cfg_arg1  = sub->sub_desc.id; /* Subsystem of interest */
-       cfg->cfg_data.splat_tests.size = size;
-
-       rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
-       if (rc) {
-               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
-                       (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
-               free(cfg);
-               return rc;
-       }
-
-       /* Add the new tests in to the relevant subsystems */
-       size = cfg->cfg_rc1;
-       for (i = 0; i < size; i++) {
-               desc = &(cfg->cfg_data.splat_tests.descs[i]);
-
-               test = test_init(sub, desc);
-               if (test == NULL) {
-                       fprintf(stderr, "Error initializing test: %s\n",
-                               desc->name);
-                       free(cfg);
-                       return -ENOMEM;
-               }
-
-               list_append(sub->sub_tests, test);
-       }
-
-       free(cfg);
-       return 0;
-}
-
-static test_t *test_copy(test_t *test)
-{
-       return test_init(test->test_sub, &test->test_desc);
-}
-
-static void test_list(List l, int indent)
-{
-       ListIterator i;
-       test_t *test;
-
-       i = list_iterator_create(l);
-
-       while ((test = list_next(i)))
-               fprintf(stdout, "%*s0x%0*x %-*s %s\n",
-                       indent, "", 04, test->test_desc.id,
-                       SPLAT_NAME_SIZE, test->test_desc.name,
-                       test->test_desc.desc);
-
-       list_iterator_destroy(i);
-}
-
-static test_t *test_find(char *sub_str, char *test_str)
-{
-       ListIterator si, ti;
-       subsystem_t *sub;
-       test_t *test;
-       __u32 sub_num, test_num;
-
-       /*
-        * No error checking here because it may not be a number, it's
-        * perfectly OK for it to be a string.  Since we're just using
-        * it for comparison purposes this is all very safe.
-        */
-       sub_num = strtoul(sub_str, NULL, 0);
-       test_num = strtoul(test_str, NULL, 0);
-
-        si = list_iterator_create(subsystems);
-
-        while ((sub = list_next(si))) {
-
-               if (strncmp(sub->sub_desc.name, sub_str, SPLAT_NAME_SIZE) &&
-                   sub->sub_desc.id != sub_num)
-                       continue;
-
-               ti = list_iterator_create(sub->sub_tests);
-
-               while ((test = list_next(ti))) {
-
-                       if (!strncmp(test->test_desc.name, test_str,
-                           SPLAT_NAME_SIZE) || test->test_desc.id==test_num) {
-                               list_iterator_destroy(ti);
-                               list_iterator_destroy(si);
-                               return test;
-                       }
-               }
-
-               list_iterator_destroy(ti);
-        }
-
-        list_iterator_destroy(si);
-
-       return NULL;
-}
-
-static int test_add(cmd_args_t *args, test_t *test)
-{
-       test_t *tmp;
-
-       tmp = test_copy(test);
-       if (tmp == NULL)
-               return -ENOMEM;
-
-       list_append(args->args_tests, tmp);
-       return 0;
-}
-
-static int test_add_all(cmd_args_t *args)
-{
-       ListIterator si, ti;
-       subsystem_t *sub;
-       test_t *test;
-       int rc;
-
-        si = list_iterator_create(subsystems);
-
-        while ((sub = list_next(si))) {
-               ti = list_iterator_create(sub->sub_tests);
-
-               while ((test = list_next(ti))) {
-                       if ((rc = test_add(args, test))) {
-                               list_iterator_destroy(ti);
-                               list_iterator_destroy(si);
-                               return rc;
-                       }
-               }
-
-               list_iterator_destroy(ti);
-        }
-
-        list_iterator_destroy(si);
-
-       return 0;
-}
-
-static int test_run(cmd_args_t *args, test_t *test)
-{
-       subsystem_t *sub = test->test_sub;
-       splat_cmd_t *cmd;
-       int rc, cmd_size;
-
-       dev_clear();
-
-       cmd_size = sizeof(*cmd);
-       cmd = (splat_cmd_t *)malloc(cmd_size);
-       if (cmd == NULL)
-               return -ENOMEM;
-
-       memset(cmd, 0, cmd_size);
-       cmd->cmd_magic = SPLAT_CMD_MAGIC;
-        cmd->cmd_subsystem = sub->sub_desc.id;
-       cmd->cmd_test = test->test_desc.id;
-       cmd->cmd_data_size = 0; /* Unused feature */
-
-       fprintf(stdout, "%*s:%-*s ",
-               SPLAT_NAME_SIZE, sub->sub_desc.name,
-               SPLAT_NAME_SIZE, test->test_desc.name);
-       fflush(stdout);
-       rc = ioctl(splatctl_fd, SPLAT_CMD, cmd);
-       if (args->args_do_color) {
-               fprintf(stdout, "%s  %s\n", rc ?
-                       COLOR_RED "Fail" COLOR_RESET :
-                       COLOR_GREEN "Pass" COLOR_RESET,
-                       rc ? strerror(errno) : "");
-       } else {
-               fprintf(stdout, "%s  %s\n", rc ?
-                       "Fail" : "Pass",
-                       rc ? strerror(errno) : "");
-       }
-       fflush(stdout);
-       free(cmd);
-
-       if ((args->args_verbose == 1 && rc) ||
-           (args->args_verbose >= 2)) {
-               if ((rc = read(splatctl_fd, splat_buffer,
-                              splat_buffer_size - 1)) < 0) {
-                       fprintf(stdout, "Error reading results: %d\n", rc);
-               } else {
-                       fprintf(stdout, "\n%s\n", splat_buffer);
-                       fflush(stdout);
-               }
-       }
-
-       return rc;
-}
-
-static int tests_run(cmd_args_t *args)
-{
-        ListIterator i;
-       test_t *test;
-       int rc;
-
-       fprintf(stdout,
-               "------------------------------ "
-               "Running SPLAT Tests "
-               "------------------------------\n");
-
-       i = list_iterator_create(args->args_tests);
-
-       while ((test = list_next(i))) {
-               rc = test_run(args, test);
-               if (rc && args->args_exit_on_error) {
-                       list_iterator_destroy(i);
-                       return rc;
-               }
-       }
-
-       list_iterator_destroy(i);
-       return 0;
-}
-
-static int args_parse_test(cmd_args_t *args, char *str)
-{
-        ListIterator si, ti;
-       subsystem_t *s;
-       test_t *t;
-       char *sub_str, *test_str;
-       int sub_num, test_num;
-       int sub_all = 0, test_all = 0;
-       int rc, flag = 0;
-
-       test_str = strchr(str, ':');
-       if (test_str == NULL) {
-               fprintf(stderr, "Test must be of the "
-                       "form <subsystem:test>\n");
-               return -EINVAL;
-       }
-
-       sub_str = str;
-       test_str[0] = '\0';
-       test_str = test_str + 1;
-
-       sub_num = strtol(sub_str, NULL, 0);
-       test_num = strtol(test_str, NULL, 0);
-
-       if (!strncasecmp(sub_str, "all", strlen(sub_str)) || (sub_num == -1))
-               sub_all = 1;
-
-       if (!strncasecmp(test_str,"all",strlen(test_str)) || (test_num == -1))
-               test_all = 1;
-
-       si = list_iterator_create(subsystems);
-
-       if (sub_all) {
-               if (test_all) {
-                       /* Add all tests from all subsystems */
-                       while ((s = list_next(si))) {
-                               ti = list_iterator_create(s->sub_tests);
-                               while ((t = list_next(ti))) {
-                                       if ((rc = test_add(args, t))) {
-                                               list_iterator_destroy(ti);
-                                               goto error_run;
-                                       }
-                               }
-                               list_iterator_destroy(ti);
-                       }
-               } else {
-                       /* Add a specific test from all subsystems */
-                       while ((s = list_next(si))) {
-                               if ((t=test_find(s->sub_desc.name,test_str))) {
-                                       if ((rc = test_add(args, t)))
-                                               goto error_run;
-
-                                       flag = 1;
-                               }
-                       }
-
-                       if (!flag)
-                               fprintf(stderr, "No tests '%s:%s' could be "
-                                       "found\n", sub_str, test_str);
-               }
-       } else {
-               if (test_all) {
-                       /* Add all tests from a specific subsystem */
-                       while ((s = list_next(si))) {
-                               if (strncasecmp(sub_str, s->sub_desc.name,
-                                   strlen(sub_str)))
-                                       continue;
-
-                               ti = list_iterator_create(s->sub_tests);
-                               while ((t = list_next(ti))) {
-                                       if ((rc = test_add(args, t))) {
-                                               list_iterator_destroy(ti);
-                                               goto error_run;
-                                       }
-                               }
-                               list_iterator_destroy(ti);
-                       }
-               } else {
-                       /* Add a specific test from a specific subsystem */
-                       if ((t = test_find(sub_str, test_str))) {
-                               if ((rc = test_add(args, t)))
-                                       goto error_run;
-                       } else {
-                               fprintf(stderr, "Test '%s:%s' could not be "
-                                       "found\n", sub_str, test_str);
-                               return -EINVAL;
-                       }
-               }
-       }
-
-       list_iterator_destroy(si);
-
-       return 0;
-
-error_run:
-       list_iterator_destroy(si);
-
-       fprintf(stderr, "Test '%s:%s' not added to run list: %d\n",
-               sub_str, test_str, rc);
-
-       return rc;
-}
-
-static void args_fini(cmd_args_t *args)
-{
-       assert(args != NULL);
-
-       if (args->args_tests != NULL)
-               list_destroy(args->args_tests);
-
-       free(args);
-}
-
-static cmd_args_t *
-args_init(int argc, char **argv)
-{
-       cmd_args_t *args;
-       int c, rc;
-
-       if (argc == 1) {
-               usage();
-               return (cmd_args_t *) NULL;
-       }
-
-       /* Configure and populate the args structures */
-       args = malloc(sizeof(*args));
-       if (args == NULL)
-               return NULL;
-
-       memset(args, 0, sizeof(*args));
-       args->args_verbose = 0;
-       args->args_do_list = 0;
-       args->args_do_all  = 0;
-       args->args_do_color = 1;
-       args->args_exit_on_error = 0;
-       args->args_tests = list_create((ListDelF)test_fini);
-       if (args->args_tests == NULL) {
-               args_fini(args);
-               return NULL;
-       }
-
-       while ((c = getopt_long(argc, argv, shortOpts, longOpts, NULL)) != -1){
-               switch (c) {
-               case 'v':  args->args_verbose++;                        break;
-               case 'l':  args->args_do_list = 1;                      break;
-               case 'a':  args->args_do_all = 1;                       break;
-               case 'c':  args->args_do_color = 0;                     break;
-               case 'x':  args->args_exit_on_error = 1;                break;
-               case 't':
-                       if (args->args_do_all) {
-                               fprintf(stderr, "Option -t <subsystem:test> is "
-                                       "useless when used with -a\n");
-                               args_fini(args);
-                               return NULL;
-                       }
-
-                       rc = args_parse_test(args, argv[optind - 1]);
-                       if (rc) {
-                               args_fini(args);
-                               return NULL;
-                       }
-                       break;
-               case 'h':
-               case '?':
-                       usage();
-                       args_fini(args);
-                       return NULL;
-               default:
-                       fprintf(stderr, "Unknown option '%s'\n",
-                               argv[optind - 1]);
-                       break;
-               }
-       }
-
-       return args;
-}
-
-static int
-dev_clear(void)
-{
-       splat_cfg_t cfg;
-       int rc;
-
-       memset(&cfg, 0, sizeof(cfg));
-       cfg.cfg_magic = SPLAT_CFG_MAGIC;
-        cfg.cfg_cmd   = SPLAT_CFG_BUFFER_CLEAR;
-       cfg.cfg_arg1  = 0;
-
-       rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
-       if (rc)
-               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
-                       (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
-
-       lseek(splatctl_fd, 0, SEEK_SET);
-
-       return rc;
-}
-
-static int
-dev_size(int size)
-{
-       splat_cfg_t cfg;
-       int rc;
-
-       memset(&cfg, 0, sizeof(cfg));
-       cfg.cfg_magic = SPLAT_CFG_MAGIC;
-        cfg.cfg_cmd   = SPLAT_CFG_BUFFER_SIZE;
-       cfg.cfg_arg1  = size;
-
-       rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
-       if (rc) {
-               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
-                       (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
-               return rc;
-       }
-
-       return cfg.cfg_rc1;
-}
-
-static void
-dev_fini(void)
-{
-       if (splat_buffer)
-               free(splat_buffer);
-
-       if (splatctl_fd != -1) {
-               if (close(splatctl_fd) == -1) {
-                       fprintf(stderr, "Unable to close %s: %d\n",
-                               SPLAT_DEV, errno);
-               }
-       }
-}
-
-static int
-dev_init(void)
-{
-       ListIterator i;
-       subsystem_t *sub;
-       int rc;
-
-       splatctl_fd = open(SPLAT_DEV, O_RDONLY);
-       if (splatctl_fd == -1) {
-               fprintf(stderr, "Unable to open %s: %d\n"
-                       "Is the splat module loaded?\n", SPLAT_DEV, errno);
-               rc = errno;
-               goto error;
-       }
-
-       /* Determine kernel module version string */
-       memset(splat_version, 0, VERSION_SIZE);
-       if ((rc = read(splatctl_fd, splat_version, VERSION_SIZE - 1)) == -1)
-               goto error;
-
-       if ((rc = dev_clear()))
-               goto error;
-
-       if ((rc = dev_size(0)) < 0)
-               goto error;
-
-       splat_buffer_size = rc;
-       splat_buffer = (char *)malloc(splat_buffer_size);
-       if (splat_buffer == NULL) {
-               rc = -ENOMEM;
-               goto error;
-       }
-
-       memset(splat_buffer, 0, splat_buffer_size);
-
-       /* Determine available subsystems */
-       if ((rc = subsystem_setup()) != 0)
-               goto error;
-
-       /* Determine available tests for all subsystems */
-       i = list_iterator_create(subsystems);
-
-       while ((sub = list_next(i))) {
-               if ((rc = test_setup(sub)) != 0) {
-                       list_iterator_destroy(i);
-                       goto error;
-               }
-       }
-
-       list_iterator_destroy(i);
-       return 0;
-
-error:
-       if (splatctl_fd != -1) {
-               if (close(splatctl_fd) == -1) {
-                       fprintf(stderr, "Unable to close %s: %d\n",
-                               SPLAT_DEV, errno);
-               }
-       }
-
-       return rc;
-}
-
-int
-init(void)
-{
-       int rc = 0;
-
-       /* Allocate the subsystem list */
-       subsystems = list_create((ListDelF)subsystem_fini);
-       if (subsystems == NULL)
-               rc = ENOMEM;
-
-       return rc;
-}
-
-void
-fini(void)
-{
-       list_destroy(subsystems);
-}
-
-
-int
-main(int argc, char **argv)
-{
-       cmd_args_t *args = NULL;
-       int rc = 0;
-
-       /* General init */
-       if ((rc = init()))
-               return rc;
-
-       /* Device specific init */
-       if ((rc = dev_init()))
-               goto out;
-
-       /* Argument init and parsing */
-       if ((args = args_init(argc, argv)) == NULL) {
-               rc = -1;
-               goto out;
-       }
-
-       /* Generic kernel version string */
-       if (args->args_verbose)
-               fprintf(stdout, "%s", splat_version);
-
-       /* Print the available test list and exit */
-       if (args->args_do_list) {
-               subsystem_list(subsystems, 0);
-               goto out;
-       }
-
-       /* Add all available test to the list of tests to run */
-       if (args->args_do_all) {
-               if ((rc = test_add_all(args)))
-                       goto out;
-       }
-
-       /* Run all the requested tests */
-       if ((rc = tests_run(args)))
-               goto out;
-
-out:
-       if (args != NULL)
-               args_fini(args);
-
-       dev_fini();
-       fini();
-       return rc;
-}
diff --git a/cmd/splat.h b/cmd/splat.h
deleted file mode 100644 (file)
index 5b838af..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*****************************************************************************\
- *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
- *  Copyright (C) 2007 The Regents of the University of California.
- *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
- *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
- *  UCRL-CODE-235197
- *
- *  This file is part of the SPL, Solaris Porting Layer.
- *  For details, see <http://zfsonlinux.org/>.
- *
- *  The SPL is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the
- *  Free Software Foundation; either version 2 of the License, or (at your
- *  option) any later version.
- *
- *  The SPL is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
-\*****************************************************************************/
-
-#ifndef _SPLAT_H
-#define _SPLAT_H
-
-#include "list.h"
-#include "../include/splat-ctl.h"
-
-#define DEV_NAME                       "/dev/splatctl"
-#define COLOR_BLACK                    "\033[0;30m"
-#define COLOR_DK_GRAY                  "\033[1;30m"
-#define COLOR_BLUE                     "\033[0;34m"
-#define COLOR_LT_BLUE                  "\033[1;34m"
-#define COLOR_GREEN                    "\033[0;32m"
-#define COLOR_LT_GREEN                 "\033[1;32m"
-#define COLOR_CYAN                     "\033[0;36m"
-#define COLOR_LT_CYAN                  "\033[1;36m"
-#define COLOR_RED                      "\033[0;31m"
-#define COLOR_LT_RED                   "\033[1;31m"
-#define COLOR_PURPLE                   "\033[0;35m"
-#define COLOR_LT_PURPLE                        "\033[1;35m"
-#define COLOR_BROWN                    "\033[0;33m"
-#define COLOR_YELLOW                   "\033[1;33m"
-#define COLOR_LT_GRAY                  "\033[0;37m"
-#define COLOR_WHITE                    "\033[1;37m"
-#define COLOR_RESET                    "\033[0m"
-
-typedef struct subsystem {
-       splat_user_t sub_desc;          /* Subsystem description */
-       List sub_tests;                 /* Assocated subsystem tests list */
-} subsystem_t;
-
-typedef struct test {
-       splat_user_t test_desc;         /* Test description */
-       subsystem_t *test_sub;          /* Parent subsystem */
-} test_t;
-
-typedef struct cmd_args {
-       int args_verbose;               /* Verbose flag */
-       int args_do_list;               /* Display all tests flag */
-       int args_do_all;                /* Run all tests flag */
-       int args_do_color;              /* Colorize output */
-       int args_exit_on_error;         /* Exit on first error flag */
-       List args_tests;                /* Requested subsystems/tests */
-} cmd_args_t;
-
-#endif /* _SPLAT_H */
-
diff --git a/cmd/splat/Makefile.am b/cmd/splat/Makefile.am
new file mode 100644 (file)
index 0000000..01afdcf
--- /dev/null
@@ -0,0 +1,11 @@
+include $(top_srcdir)/config/Rules.am
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/lib
+
+sbin_PROGRAMS = splat
+
+splat_SOURCES = splat.c
+splat_LDFLAGS = $(top_builddir)/lib/libcommon.la
+
+EXTRA_DIST = splat.h
diff --git a/cmd/splat/splat.c b/cmd/splat/splat.c
new file mode 100644 (file)
index 0000000..9296239
--- /dev/null
@@ -0,0 +1,836 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  The SPL is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting LAyer Tests (SPLAT) User Space Interface.
+\*****************************************************************************/
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "splat.h"
+
+#undef ioctl
+
+static const char shortOpts[] = "hvlat:xc";
+static const struct option longOpts[] = {
+       { "help",            no_argument,       0, 'h' },
+       { "verbose",         no_argument,       0, 'v' },
+       { "list",            no_argument,       0, 'l' },
+       { "all",             no_argument,       0, 'a' },
+       { "test",            required_argument, 0, 't' },
+       { "exit",            no_argument,       0, 'x' },
+       { "nocolor",         no_argument,       0, 'c' },
+       { 0,                 0,                 0, 0   }
+};
+
+#define VERSION_SIZE   64
+
+static List subsystems;                                /* Subsystem/tests */
+static int splatctl_fd;                                /* Control file descriptor */
+static char splat_version[VERSION_SIZE];       /* Kernel version string */
+static char *splat_buffer = NULL;              /* Scratch space area */
+static int splat_buffer_size = 0;              /* Scratch space size */
+
+
+static void test_list(List, int);
+static int dev_clear(void);
+static void subsystem_fini(subsystem_t *);
+static void test_fini(test_t *);
+
+
+static int usage(void) {
+       fprintf(stderr, "usage: splat [hvla] [-t <subsystem:<tests>>]\n");
+       fprintf(stderr,
+       "  --help      -h               This help\n"
+       "  --verbose   -v               Increase verbosity\n"
+       "  --list      -l               List all tests in all subsystems\n"
+       "  --all       -a               Run all tests in all subsystems\n"
+       "  --test      -t <sub:test>    Run 'test' in subsystem 'sub'\n"
+       "  --exit      -x               Exit on first test error\n"
+       "  --nocolor   -c               Do not colorize output\n");
+       fprintf(stderr, "\n"
+       "Examples:\n"
+       "  splat -t kmem:all     # Runs all kmem tests\n"
+       "  splat -t taskq:0x201  # Run taskq test 0x201\n");
+
+       return 0;
+}
+
+static subsystem_t *subsystem_init(splat_user_t *desc)
+{
+       subsystem_t *sub;
+
+       sub = (subsystem_t *)malloc(sizeof(*sub));
+       if (sub == NULL)
+               return NULL;
+
+       memcpy(&sub->sub_desc, desc, sizeof(*desc));
+
+       sub->sub_tests = list_create((ListDelF)test_fini);
+       if (sub->sub_tests == NULL) {
+               free(sub);
+               return NULL;
+       }
+
+       return sub;
+}
+
+static void subsystem_fini(subsystem_t *sub)
+{
+       assert(sub != NULL);
+       free(sub);
+}
+
+static int subsystem_setup(void)
+{
+       splat_cfg_t *cfg;
+       int i, rc, size, cfg_size;
+       subsystem_t *sub;
+       splat_user_t *desc;
+
+       /* Aquire the number of registered subsystems */
+       cfg_size = sizeof(*cfg);
+       cfg = (splat_cfg_t *)malloc(cfg_size);
+       if (cfg == NULL)
+               return -ENOMEM;
+
+       memset(cfg, 0, cfg_size);
+       cfg->cfg_magic = SPLAT_CFG_MAGIC;
+        cfg->cfg_cmd   = SPLAT_CFG_SUBSYSTEM_COUNT;
+
+       rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
+       if (rc) {
+               fprintf(stderr, "Ioctl() error 0x%lx / %d: %d\n",
+                       (unsigned long)SPLAT_CFG, cfg->cfg_cmd, errno);
+               free(cfg);
+               return rc;
+       }
+
+       size = cfg->cfg_rc1;
+       free(cfg);
+
+       /* Based on the newly acquired number of subsystems allocate
+        * memory to get the descriptive information for them all. */
+       cfg_size = sizeof(*cfg) + size * sizeof(splat_user_t);
+       cfg = (splat_cfg_t *)malloc(cfg_size);
+       if (cfg == NULL)
+               return -ENOMEM;
+
+       memset(cfg, 0, cfg_size);
+       cfg->cfg_magic = SPLAT_CFG_MAGIC;
+       cfg->cfg_cmd   = SPLAT_CFG_SUBSYSTEM_LIST;
+       cfg->cfg_data.splat_subsystems.size = size;
+
+       rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
+       if (rc) {
+               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
+                       (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
+               free(cfg);
+               return rc;
+       }
+
+       /* Add the new subsystems in to the global list */
+       size = cfg->cfg_rc1;
+       for (i = 0; i < size; i++) {
+               desc = &(cfg->cfg_data.splat_subsystems.descs[i]);
+
+               sub = subsystem_init(desc);
+               if (sub == NULL) {
+                       fprintf(stderr, "Error initializing subsystem: %s\n",
+                               desc->name);
+                       free(cfg);
+                       return -ENOMEM;
+               }
+
+               list_append(subsystems, sub);
+       }
+
+       free(cfg);
+       return 0;
+}
+
+static void subsystem_list(List l, int indent)
+{
+       ListIterator i;
+       subsystem_t *sub;
+
+       fprintf(stdout,
+               "------------------------------ "
+               "Available SPLAT Tests "
+               "------------------------------\n");
+
+       i = list_iterator_create(l);
+
+       while ((sub = list_next(i))) {
+               fprintf(stdout, "%*s0x%0*x %-*s ---- %s ----\n",
+                       indent, "",
+                       4, sub->sub_desc.id,
+                       SPLAT_NAME_SIZE + 7, sub->sub_desc.name,
+                       sub->sub_desc.desc);
+               test_list(sub->sub_tests, indent + 7);
+       }
+
+       list_iterator_destroy(i);
+}
+
+static test_t *test_init(subsystem_t *sub, splat_user_t *desc)
+{
+       test_t *test;
+
+       test = (test_t *)malloc(sizeof(*test));
+       if (test == NULL)
+               return NULL;
+
+       test->test_sub = sub;
+       memcpy(&test->test_desc, desc, sizeof(*desc));
+
+       return test;
+}
+
+static void test_fini(test_t *test)
+{
+       assert(test != NULL);
+       free(test);
+}
+
+static int test_setup(subsystem_t *sub)
+{
+       splat_cfg_t *cfg;
+       int i, rc, size;
+       test_t *test;
+       splat_user_t *desc;
+
+       /* Aquire the number of registered tests for the give subsystem */
+       cfg = (splat_cfg_t *)malloc(sizeof(*cfg));
+       if (cfg == NULL)
+               return -ENOMEM;
+
+       memset(cfg, 0, sizeof(*cfg));
+       cfg->cfg_magic = SPLAT_CFG_MAGIC;
+        cfg->cfg_cmd   = SPLAT_CFG_TEST_COUNT;
+       cfg->cfg_arg1  = sub->sub_desc.id; /* Subsystem of interest */
+
+       rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
+       if (rc) {
+               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
+                       (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
+               free(cfg);
+               return rc;
+       }
+
+       size = cfg->cfg_rc1;
+       free(cfg);
+
+       /* Based on the newly aquired number of tests allocate enough
+        * memory to get the descriptive information for them all. */
+       cfg = (splat_cfg_t *)malloc(sizeof(*cfg) + size*sizeof(splat_user_t));
+       if (cfg == NULL)
+               return -ENOMEM;
+
+       memset(cfg, 0, sizeof(*cfg) + size * sizeof(splat_user_t));
+       cfg->cfg_magic = SPLAT_CFG_MAGIC;
+       cfg->cfg_cmd   = SPLAT_CFG_TEST_LIST;
+       cfg->cfg_arg1  = sub->sub_desc.id; /* Subsystem of interest */
+       cfg->cfg_data.splat_tests.size = size;
+
+       rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
+       if (rc) {
+               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
+                       (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
+               free(cfg);
+               return rc;
+       }
+
+       /* Add the new tests in to the relevant subsystems */
+       size = cfg->cfg_rc1;
+       for (i = 0; i < size; i++) {
+               desc = &(cfg->cfg_data.splat_tests.descs[i]);
+
+               test = test_init(sub, desc);
+               if (test == NULL) {
+                       fprintf(stderr, "Error initializing test: %s\n",
+                               desc->name);
+                       free(cfg);
+                       return -ENOMEM;
+               }
+
+               list_append(sub->sub_tests, test);
+       }
+
+       free(cfg);
+       return 0;
+}
+
+static test_t *test_copy(test_t *test)
+{
+       return test_init(test->test_sub, &test->test_desc);
+}
+
+static void test_list(List l, int indent)
+{
+       ListIterator i;
+       test_t *test;
+
+       i = list_iterator_create(l);
+
+       while ((test = list_next(i)))
+               fprintf(stdout, "%*s0x%0*x %-*s %s\n",
+                       indent, "", 04, test->test_desc.id,
+                       SPLAT_NAME_SIZE, test->test_desc.name,
+                       test->test_desc.desc);
+
+       list_iterator_destroy(i);
+}
+
+static test_t *test_find(char *sub_str, char *test_str)
+{
+       ListIterator si, ti;
+       subsystem_t *sub;
+       test_t *test;
+       __u32 sub_num, test_num;
+
+       /*
+        * No error checking here because it may not be a number, it's
+        * perfectly OK for it to be a string.  Since we're just using
+        * it for comparison purposes this is all very safe.
+        */
+       sub_num = strtoul(sub_str, NULL, 0);
+       test_num = strtoul(test_str, NULL, 0);
+
+        si = list_iterator_create(subsystems);
+
+        while ((sub = list_next(si))) {
+
+               if (strncmp(sub->sub_desc.name, sub_str, SPLAT_NAME_SIZE) &&
+                   sub->sub_desc.id != sub_num)
+                       continue;
+
+               ti = list_iterator_create(sub->sub_tests);
+
+               while ((test = list_next(ti))) {
+
+                       if (!strncmp(test->test_desc.name, test_str,
+                           SPLAT_NAME_SIZE) || test->test_desc.id==test_num) {
+                               list_iterator_destroy(ti);
+                               list_iterator_destroy(si);
+                               return test;
+                       }
+               }
+
+               list_iterator_destroy(ti);
+        }
+
+        list_iterator_destroy(si);
+
+       return NULL;
+}
+
+static int test_add(cmd_args_t *args, test_t *test)
+{
+       test_t *tmp;
+
+       tmp = test_copy(test);
+       if (tmp == NULL)
+               return -ENOMEM;
+
+       list_append(args->args_tests, tmp);
+       return 0;
+}
+
+static int test_add_all(cmd_args_t *args)
+{
+       ListIterator si, ti;
+       subsystem_t *sub;
+       test_t *test;
+       int rc;
+
+        si = list_iterator_create(subsystems);
+
+        while ((sub = list_next(si))) {
+               ti = list_iterator_create(sub->sub_tests);
+
+               while ((test = list_next(ti))) {
+                       if ((rc = test_add(args, test))) {
+                               list_iterator_destroy(ti);
+                               list_iterator_destroy(si);
+                               return rc;
+                       }
+               }
+
+               list_iterator_destroy(ti);
+        }
+
+        list_iterator_destroy(si);
+
+       return 0;
+}
+
+static int test_run(cmd_args_t *args, test_t *test)
+{
+       subsystem_t *sub = test->test_sub;
+       splat_cmd_t *cmd;
+       int rc, cmd_size;
+
+       dev_clear();
+
+       cmd_size = sizeof(*cmd);
+       cmd = (splat_cmd_t *)malloc(cmd_size);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       memset(cmd, 0, cmd_size);
+       cmd->cmd_magic = SPLAT_CMD_MAGIC;
+        cmd->cmd_subsystem = sub->sub_desc.id;
+       cmd->cmd_test = test->test_desc.id;
+       cmd->cmd_data_size = 0; /* Unused feature */
+
+       fprintf(stdout, "%*s:%-*s ",
+               SPLAT_NAME_SIZE, sub->sub_desc.name,
+               SPLAT_NAME_SIZE, test->test_desc.name);
+       fflush(stdout);
+       rc = ioctl(splatctl_fd, SPLAT_CMD, cmd);
+       if (args->args_do_color) {
+               fprintf(stdout, "%s  %s\n", rc ?
+                       COLOR_RED "Fail" COLOR_RESET :
+                       COLOR_GREEN "Pass" COLOR_RESET,
+                       rc ? strerror(errno) : "");
+       } else {
+               fprintf(stdout, "%s  %s\n", rc ?
+                       "Fail" : "Pass",
+                       rc ? strerror(errno) : "");
+       }
+       fflush(stdout);
+       free(cmd);
+
+       if ((args->args_verbose == 1 && rc) ||
+           (args->args_verbose >= 2)) {
+               if ((rc = read(splatctl_fd, splat_buffer,
+                              splat_buffer_size - 1)) < 0) {
+                       fprintf(stdout, "Error reading results: %d\n", rc);
+               } else {
+                       fprintf(stdout, "\n%s\n", splat_buffer);
+                       fflush(stdout);
+               }
+       }
+
+       return rc;
+}
+
+static int tests_run(cmd_args_t *args)
+{
+        ListIterator i;
+       test_t *test;
+       int rc;
+
+       fprintf(stdout,
+               "------------------------------ "
+               "Running SPLAT Tests "
+               "------------------------------\n");
+
+       i = list_iterator_create(args->args_tests);
+
+       while ((test = list_next(i))) {
+               rc = test_run(args, test);
+               if (rc && args->args_exit_on_error) {
+                       list_iterator_destroy(i);
+                       return rc;
+               }
+       }
+
+       list_iterator_destroy(i);
+       return 0;
+}
+
+static int args_parse_test(cmd_args_t *args, char *str)
+{
+        ListIterator si, ti;
+       subsystem_t *s;
+       test_t *t;
+       char *sub_str, *test_str;
+       int sub_num, test_num;
+       int sub_all = 0, test_all = 0;
+       int rc, flag = 0;
+
+       test_str = strchr(str, ':');
+       if (test_str == NULL) {
+               fprintf(stderr, "Test must be of the "
+                       "form <subsystem:test>\n");
+               return -EINVAL;
+       }
+
+       sub_str = str;
+       test_str[0] = '\0';
+       test_str = test_str + 1;
+
+       sub_num = strtol(sub_str, NULL, 0);
+       test_num = strtol(test_str, NULL, 0);
+
+       if (!strncasecmp(sub_str, "all", strlen(sub_str)) || (sub_num == -1))
+               sub_all = 1;
+
+       if (!strncasecmp(test_str,"all",strlen(test_str)) || (test_num == -1))
+               test_all = 1;
+
+       si = list_iterator_create(subsystems);
+
+       if (sub_all) {
+               if (test_all) {
+                       /* Add all tests from all subsystems */
+                       while ((s = list_next(si))) {
+                               ti = list_iterator_create(s->sub_tests);
+                               while ((t = list_next(ti))) {
+                                       if ((rc = test_add(args, t))) {
+                                               list_iterator_destroy(ti);
+                                               goto error_run;
+                                       }
+                               }
+                               list_iterator_destroy(ti);
+                       }
+               } else {
+                       /* Add a specific test from all subsystems */
+                       while ((s = list_next(si))) {
+                               if ((t=test_find(s->sub_desc.name,test_str))) {
+                                       if ((rc = test_add(args, t)))
+                                               goto error_run;
+
+                                       flag = 1;
+                               }
+                       }
+
+                       if (!flag)
+                               fprintf(stderr, "No tests '%s:%s' could be "
+                                       "found\n", sub_str, test_str);
+               }
+       } else {
+               if (test_all) {
+                       /* Add all tests from a specific subsystem */
+                       while ((s = list_next(si))) {
+                               if (strncasecmp(sub_str, s->sub_desc.name,
+                                   strlen(sub_str)))
+                                       continue;
+
+                               ti = list_iterator_create(s->sub_tests);
+                               while ((t = list_next(ti))) {
+                                       if ((rc = test_add(args, t))) {
+                                               list_iterator_destroy(ti);
+                                               goto error_run;
+                                       }
+                               }
+                               list_iterator_destroy(ti);
+                       }
+               } else {
+                       /* Add a specific test from a specific subsystem */
+                       if ((t = test_find(sub_str, test_str))) {
+                               if ((rc = test_add(args, t)))
+                                       goto error_run;
+                       } else {
+                               fprintf(stderr, "Test '%s:%s' could not be "
+                                       "found\n", sub_str, test_str);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       list_iterator_destroy(si);
+
+       return 0;
+
+error_run:
+       list_iterator_destroy(si);
+
+       fprintf(stderr, "Test '%s:%s' not added to run list: %d\n",
+               sub_str, test_str, rc);
+
+       return rc;
+}
+
+static void args_fini(cmd_args_t *args)
+{
+       assert(args != NULL);
+
+       if (args->args_tests != NULL)
+               list_destroy(args->args_tests);
+
+       free(args);
+}
+
+static cmd_args_t *
+args_init(int argc, char **argv)
+{
+       cmd_args_t *args;
+       int c, rc;
+
+       if (argc == 1) {
+               usage();
+               return (cmd_args_t *) NULL;
+       }
+
+       /* Configure and populate the args structures */
+       args = malloc(sizeof(*args));
+       if (args == NULL)
+               return NULL;
+
+       memset(args, 0, sizeof(*args));
+       args->args_verbose = 0;
+       args->args_do_list = 0;
+       args->args_do_all  = 0;
+       args->args_do_color = 1;
+       args->args_exit_on_error = 0;
+       args->args_tests = list_create((ListDelF)test_fini);
+       if (args->args_tests == NULL) {
+               args_fini(args);
+               return NULL;
+       }
+
+       while ((c = getopt_long(argc, argv, shortOpts, longOpts, NULL)) != -1){
+               switch (c) {
+               case 'v':  args->args_verbose++;                        break;
+               case 'l':  args->args_do_list = 1;                      break;
+               case 'a':  args->args_do_all = 1;                       break;
+               case 'c':  args->args_do_color = 0;                     break;
+               case 'x':  args->args_exit_on_error = 1;                break;
+               case 't':
+                       if (args->args_do_all) {
+                               fprintf(stderr, "Option -t <subsystem:test> is "
+                                       "useless when used with -a\n");
+                               args_fini(args);
+                               return NULL;
+                       }
+
+                       rc = args_parse_test(args, argv[optind - 1]);
+                       if (rc) {
+                               args_fini(args);
+                               return NULL;
+                       }
+                       break;
+               case 'h':
+               case '?':
+                       usage();
+                       args_fini(args);
+                       return NULL;
+               default:
+                       fprintf(stderr, "Unknown option '%s'\n",
+                               argv[optind - 1]);
+                       break;
+               }
+       }
+
+       return args;
+}
+
+static int
+dev_clear(void)
+{
+       splat_cfg_t cfg;
+       int rc;
+
+       memset(&cfg, 0, sizeof(cfg));
+       cfg.cfg_magic = SPLAT_CFG_MAGIC;
+        cfg.cfg_cmd   = SPLAT_CFG_BUFFER_CLEAR;
+       cfg.cfg_arg1  = 0;
+
+       rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
+       if (rc)
+               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
+                       (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
+
+       lseek(splatctl_fd, 0, SEEK_SET);
+
+       return rc;
+}
+
+static int
+dev_size(int size)
+{
+       splat_cfg_t cfg;
+       int rc;
+
+       memset(&cfg, 0, sizeof(cfg));
+       cfg.cfg_magic = SPLAT_CFG_MAGIC;
+        cfg.cfg_cmd   = SPLAT_CFG_BUFFER_SIZE;
+       cfg.cfg_arg1  = size;
+
+       rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
+       if (rc) {
+               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
+                       (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
+               return rc;
+       }
+
+       return cfg.cfg_rc1;
+}
+
+static void
+dev_fini(void)
+{
+       if (splat_buffer)
+               free(splat_buffer);
+
+       if (splatctl_fd != -1) {
+               if (close(splatctl_fd) == -1) {
+                       fprintf(stderr, "Unable to close %s: %d\n",
+                               SPLAT_DEV, errno);
+               }
+       }
+}
+
+static int
+dev_init(void)
+{
+       ListIterator i;
+       subsystem_t *sub;
+       int rc;
+
+       splatctl_fd = open(SPLAT_DEV, O_RDONLY);
+       if (splatctl_fd == -1) {
+               fprintf(stderr, "Unable to open %s: %d\n"
+                       "Is the splat module loaded?\n", SPLAT_DEV, errno);
+               rc = errno;
+               goto error;
+       }
+
+       /* Determine kernel module version string */
+       memset(splat_version, 0, VERSION_SIZE);
+       if ((rc = read(splatctl_fd, splat_version, VERSION_SIZE - 1)) == -1)
+               goto error;
+
+       if ((rc = dev_clear()))
+               goto error;
+
+       if ((rc = dev_size(0)) < 0)
+               goto error;
+
+       splat_buffer_size = rc;
+       splat_buffer = (char *)malloc(splat_buffer_size);
+       if (splat_buffer == NULL) {
+               rc = -ENOMEM;
+               goto error;
+       }
+
+       memset(splat_buffer, 0, splat_buffer_size);
+
+       /* Determine available subsystems */
+       if ((rc = subsystem_setup()) != 0)
+               goto error;
+
+       /* Determine available tests for all subsystems */
+       i = list_iterator_create(subsystems);
+
+       while ((sub = list_next(i))) {
+               if ((rc = test_setup(sub)) != 0) {
+                       list_iterator_destroy(i);
+                       goto error;
+               }
+       }
+
+       list_iterator_destroy(i);
+       return 0;
+
+error:
+       if (splatctl_fd != -1) {
+               if (close(splatctl_fd) == -1) {
+                       fprintf(stderr, "Unable to close %s: %d\n",
+                               SPLAT_DEV, errno);
+               }
+       }
+
+       return rc;
+}
+
+int
+init(void)
+{
+       int rc = 0;
+
+       /* Allocate the subsystem list */
+       subsystems = list_create((ListDelF)subsystem_fini);
+       if (subsystems == NULL)
+               rc = ENOMEM;
+
+       return rc;
+}
+
+void
+fini(void)
+{
+       list_destroy(subsystems);
+}
+
+
+int
+main(int argc, char **argv)
+{
+       cmd_args_t *args = NULL;
+       int rc = 0;
+
+       /* General init */
+       if ((rc = init()))
+               return rc;
+
+       /* Device specific init */
+       if ((rc = dev_init()))
+               goto out;
+
+       /* Argument init and parsing */
+       if ((args = args_init(argc, argv)) == NULL) {
+               rc = -1;
+               goto out;
+       }
+
+       /* Generic kernel version string */
+       if (args->args_verbose)
+               fprintf(stdout, "%s", splat_version);
+
+       /* Print the available test list and exit */
+       if (args->args_do_list) {
+               subsystem_list(subsystems, 0);
+               goto out;
+       }
+
+       /* Add all available test to the list of tests to run */
+       if (args->args_do_all) {
+               if ((rc = test_add_all(args)))
+                       goto out;
+       }
+
+       /* Run all the requested tests */
+       if ((rc = tests_run(args)))
+               goto out;
+
+out:
+       if (args != NULL)
+               args_fini(args);
+
+       dev_fini();
+       fini();
+       return rc;
+}
diff --git a/cmd/splat/splat.h b/cmd/splat/splat.h
new file mode 100644 (file)
index 0000000..5b838af
--- /dev/null
@@ -0,0 +1,70 @@
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  UCRL-CODE-235197
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  The SPL is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPLAT_H
+#define _SPLAT_H
+
+#include "list.h"
+#include "../include/splat-ctl.h"
+
+#define DEV_NAME                       "/dev/splatctl"
+#define COLOR_BLACK                    "\033[0;30m"
+#define COLOR_DK_GRAY                  "\033[1;30m"
+#define COLOR_BLUE                     "\033[0;34m"
+#define COLOR_LT_BLUE                  "\033[1;34m"
+#define COLOR_GREEN                    "\033[0;32m"
+#define COLOR_LT_GREEN                 "\033[1;32m"
+#define COLOR_CYAN                     "\033[0;36m"
+#define COLOR_LT_CYAN                  "\033[1;36m"
+#define COLOR_RED                      "\033[0;31m"
+#define COLOR_LT_RED                   "\033[1;31m"
+#define COLOR_PURPLE                   "\033[0;35m"
+#define COLOR_LT_PURPLE                        "\033[1;35m"
+#define COLOR_BROWN                    "\033[0;33m"
+#define COLOR_YELLOW                   "\033[1;33m"
+#define COLOR_LT_GRAY                  "\033[0;37m"
+#define COLOR_WHITE                    "\033[1;37m"
+#define COLOR_RESET                    "\033[0m"
+
+typedef struct subsystem {
+       splat_user_t sub_desc;          /* Subsystem description */
+       List sub_tests;                 /* Assocated subsystem tests list */
+} subsystem_t;
+
+typedef struct test {
+       splat_user_t test_desc;         /* Test description */
+       subsystem_t *test_sub;          /* Parent subsystem */
+} test_t;
+
+typedef struct cmd_args {
+       int args_verbose;               /* Verbose flag */
+       int args_do_list;               /* Display all tests flag */
+       int args_do_all;                /* Run all tests flag */
+       int args_do_color;              /* Colorize output */
+       int args_exit_on_error;         /* Exit on first error flag */
+       List args_tests;                /* Requested subsystems/tests */
+} cmd_args_t;
+
+#endif /* _SPLAT_H */
+
diff --git a/cmd/splslab/Makefile.am b/cmd/splslab/Makefile.am
new file mode 100644 (file)
index 0000000..b18d52d
--- /dev/null
@@ -0,0 +1,2 @@
+bin_SCRIPTS = splslab.py
+EXTRA_DIST = $(bin_SCRIPTS)
diff --git a/cmd/splslab/splslab.py b/cmd/splslab/splslab.py
new file mode 100755 (executable)
index 0000000..160fb27
--- /dev/null
@@ -0,0 +1,202 @@
+#!/usr/bin/python
+
+import sys
+import time
+import getopt
+import re
+import signal
+from collections import defaultdict
+
+class Stat:
+    # flag definitions based on the kmem.h
+    NOTOUCH = 1
+    NODEBUG = 2
+    KMEM = 32
+    VMEM = 64
+    SLAB = 128
+    OFFSLAB = 256
+    NOEMERGENCY = 512
+    DEADLOCKED = 16384
+    GROWING = 32768
+    REAPING = 65536
+    DESTROY = 131072
+
+    fdefs = {
+        NOTOUCH : "NTCH",
+        NODEBUG : "NDBG", 
+        KMEM : "KMEM",
+        VMEM : "VMEM",
+        SLAB : "SLAB",
+        OFFSLAB : "OFSL",
+        NOEMERGENCY : "NEMG",
+        DEADLOCKED : "DDLK",
+        GROWING : "GROW",
+        REAPING : "REAP",
+        DESTROY : "DSTR"
+        }
+
+    def __init__(self, name, flags, size, alloc, slabsize, objsize):
+        self._name = name
+        self._flags = self.f2str(flags)
+        self._size = size
+        self._alloc = alloc
+        self._slabsize = slabsize
+        self._objsize = objsize
+
+    def f2str(self, flags):
+        fstring = ''
+        for k in Stat.fdefs.keys():
+            if flags & k:
+                fstring = fstring + Stat.fdefs[k] + '|'
+
+        fstring = fstring[:-1]
+        return fstring
+
+class CumulativeStat:
+    def __init__(self, skey="a"):
+        self._size = 0
+        self._alloc = 0
+        self._pct = 0
+        self._skey = skey
+        self._regexp = \
+            re.compile('(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+');
+        self._stats = defaultdict(list)
+
+    # Add another stat to the dictionary and re-calculate the totals
+    def add(self, s):
+        key = 0
+        if self._skey == "a":
+            key = s._alloc
+        else:
+            key = s._size
+        self._stats[key].append(s)
+        self._size = self._size + s._size
+        self._alloc = self._alloc + s._alloc
+        if self._size:
+            self._pct = self._alloc * 100 / self._size
+        else:
+            self._pct = 0
+
+    # Parse the slab info in the procfs
+    # Calculate cumulative stats
+    def slab_update(self):
+        k = [line.strip() for line in open('/proc/spl/kmem/slab')]
+
+        if not k:
+            sys.stderr.write("No SPL slab stats found\n")
+            sys.exit(1)
+
+        del k[0:2]
+
+        for s in k:
+            if not s:
+                continue
+            m = self._regexp.match(s)
+            if m:
+                self.add(Stat(m.group(1), int(m.group(2),16), int(m.group(3)),
+                            int(m.group(4)), int(m.group(5)), int(m.group(6))))
+            else:
+                sys.stderr.write("Error: unexpected input format\n" % s)
+                exit(-1)
+
+    def show_header(self):
+        sys.stdout.write("\n%25s %20s %15s %15s %15s %15s\n\n" % \
+            ("cache name", "flags", "size", "alloc", "slabsize", "objsize"))
+
+    # Show up to the number of 'rows' of output sorted in descending order
+    # by the key specified earlier; if rows == 0, all rows are shown
+    def show(self, rows):
+        self.show_header()
+        i = 1
+        done = False
+        for k in reversed(sorted(self._stats.keys())):
+            for s in self._stats[k]:
+                sys.stdout.write("%25s %20s %15d %15d %15d %15d\n" % \
+                                     (s._name, s._flags, s._size, s._alloc, \
+                                          s._slabsize, s._objsize))
+                i = i + 1
+                if rows != 0 and i > rows:
+                    done = True
+                    break
+            if done:
+                break
+        sys.stdout.write("%25s %36d %15d (%d%%)\n\n" % \
+            ("Totals:", self._size, self._alloc, self._pct))
+
+def usage():
+    cmd = "Usage: splslab.py [-n|--num-rows] number [-s|--sort-by] " + \
+        "[interval] [count]";
+    sys.stderr.write("%s\n" % cmd)
+    sys.stderr.write("\t-h : print help\n")
+    sys.stderr.write("\t-n : --num-rows N : limit output to N top " +
+                     "largest slabs (default: all)\n")
+    sys.stderr.write("\t-s : --sort-by key : sort output in descending " +
+                     "order by total size (s)\n\t\tor allocated size (a) " +
+                     "(default: a)\n")
+    sys.stderr.write("\tinterval : repeat every interval seconds\n")
+    sys.stderr.write("\tcount : output statistics count times and exit\n")
+    
+
+def main():
+
+    rows = 0
+    count = 0
+    skey = "a"
+    interval = 1
+
+    signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+    try:
+        opts, args = getopt.getopt(
+            sys.argv[1:],
+            "n:s:h",
+            [
+                "num-rows",
+                "sort-by",
+                "help"
+            ]
+        )
+    except getopt.error as e:
+        sys.stderr.write("Error: %s\n" % e.msg)
+        usage()
+        exit(-1)
+
+    i = 1
+    for opt, arg in opts:
+        if opt in ('-n', '--num-rows'):
+            rows = int(arg)
+            i = i + 2
+        elif opt in ('-s', '--sort-by'):
+            if arg != "s" and arg != "a":
+                sys.stderr.write("Error: invalid sorting key \"%s\"\n" % arg)
+                usage()
+                exit(-1)
+            skey = arg
+            i = i + 2
+        elif opt in ('-h', '--help'):
+            usage()
+            exit(0)
+        else:
+            break
+
+    args = sys.argv[i:]
+
+    interval = int(args[0]) if len(args) else interval
+    count = int(args[1]) if len(args) > 1 else count
+
+    i = 0
+    while True:
+        cs = CumulativeStat(skey)
+        cs.slab_update()
+        cs.show(rows)
+
+        i = i + 1
+        if count and i >= count:
+            break
+
+        time.sleep(interval)
+
+    return 0
+
+if __name__ == '__main__':
+    main()
index efeb243cba692f6b5fc751de65259378fb81b512..70735ce2cf42deee7fa40c4fb3828c70df18fa9d 100644 (file)
@@ -54,6 +54,8 @@ AC_CONFIG_FILES([
        man/man5/Makefile
        lib/Makefile
        cmd/Makefile
+       cmd/splat/Makefile
+       cmd/splslab/Makefile
        module/Makefile
        module/spl/Makefile
        module/splat/Makefile
index 48eafe67086ff83d14309e306affb3ae1e6b13c4..43bbd98f4903201e0346ba6ccb9c6f698c58d929 100644 (file)
@@ -33,6 +33,7 @@ make install DESTDIR=%{?buildroot}
 
 %files
 %doc AUTHORS COPYING DISCLAIMER
+%{_bindir}/*
 %{_sbindir}/*
 %{_mandir}/man1/*
 %{_mandir}/man5/*