On 10/19/2015 10:50 AM, Paul Osmialowski wrote:
> This patch adds selftests framework and four test scenarios for kmsg.
> 
> The framework shape and code was inspired by similar selftests framework
> for kdbus.
> 
> Signed-off-by: Paul Osmialowski <p.osmialo...@samsung.com>
> ---
>  samples/kmsg/kmsg-api.h                            |  44 +++
>  tools/testing/selftests/Makefile                   |   1 +
>  tools/testing/selftests/kmsg/.gitignore            |   1 +
>  tools/testing/selftests/kmsg/Makefile              |  30 ++
>  tools/testing/selftests/kmsg/kmsg-test.c           | 329 
> +++++++++++++++++++++
>  tools/testing/selftests/kmsg/kmsg-test.h           |  34 +++
>  tools/testing/selftests/kmsg/test-buffer-add-del.c |  76 +++++
>  .../kmsg/test-buffer-add-write-read-del.c          | 161 ++++++++++
>  .../kmsg/test-buffer-buf-multithreaded-torture.c   | 199 +++++++++++++
>  .../selftests/kmsg/test-buffer-buf-torture.c       | 139 +++++++++
>  10 files changed, 1014 insertions(+)
>  create mode 100644 samples/kmsg/kmsg-api.h
>  create mode 100644 tools/testing/selftests/kmsg/.gitignore
>  create mode 100644 tools/testing/selftests/kmsg/Makefile
>  create mode 100644 tools/testing/selftests/kmsg/kmsg-test.c
>  create mode 100644 tools/testing/selftests/kmsg/kmsg-test.h
>  create mode 100644 tools/testing/selftests/kmsg/test-buffer-add-del.c
>  create mode 100644 
> tools/testing/selftests/kmsg/test-buffer-add-write-read-del.c
>  create mode 100644 
> tools/testing/selftests/kmsg/test-buffer-buf-multithreaded-torture.c
>  create mode 100644 tools/testing/selftests/kmsg/test-buffer-buf-torture.c
> 
> diff --git a/samples/kmsg/kmsg-api.h b/samples/kmsg/kmsg-api.h
> new file mode 100644
> index 0000000..9004acd
> --- /dev/null
> +++ b/samples/kmsg/kmsg-api.h
> @@ -0,0 +1,44 @@
> +#ifndef KMSG_API_H
> +#define KMSG_API_H
> +
> +#include <stdint.h>
> +#include <errno.h>
> +#include <sys/ioctl.h>
> +#include <linux/kmsg_ioctl.h>
> +
> +static inline int kmsg_cmd_buffer_add(int fd, struct kmsg_cmd_buffer_add 
> *cmd)
> +{
> +     int ret = ioctl(fd, KMSG_CMD_BUFFER_ADD, cmd);
> +
> +     return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
> +}
> +
> +static inline int kmsg_cmd_buffer_del(int fd, int *minor)
> +{
> +     int ret = ioctl(fd, KMSG_CMD_BUFFER_DEL, minor);
> +
> +     return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
> +}
> +
> +static inline int kmsg_cmd_get_buf_size(int fd, uint32_t *size)
> +{
> +     int ret = ioctl(fd, KMSG_CMD_GET_BUF_SIZE, size);
> +
> +     return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
> +}
> +
> +static inline int kmsg_cmd_get_read_size_max(int fd, uint32_t *max_size)
> +{
> +     int ret = ioctl(fd, KMSG_CMD_GET_READ_SIZE_MAX, max_size);
> +
> +     return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
> +}
> +
> +static inline int kmsg_cmd_clear(int fd)
> +{
> +     int ret = ioctl(fd, KMSG_CMD_CLEAR);
> +
> +     return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0;
> +}
> +
> +#endif /* KMSG_API_H */
> diff --git a/tools/testing/selftests/Makefile 
> b/tools/testing/selftests/Makefile
> index bf4ece6..b7bdf58 100644
> --- a/tools/testing/selftests/Makefile
> +++ b/tools/testing/selftests/Makefile
> @@ -7,6 +7,7 @@ TARGETS += ftrace
>  TARGETS += futex
>  TARGETS += kcmp
>  TARGETS += kdbus

Doesn't look like this patch is based on linux-kselftest next
or Linus's latest. Please base your work on either one of the
above. Please make sure "make kselftest" from top level Makefile
doesn't break.

> +TARGETS += kmsg
>  TARGETS += lib
>  TARGETS += membarrier
>  TARGETS += memfd
> diff --git a/tools/testing/selftests/kmsg/.gitignore 
> b/tools/testing/selftests/kmsg/.gitignore
> new file mode 100644
> index 0000000..687d517
> --- /dev/null
> +++ b/tools/testing/selftests/kmsg/.gitignore
> @@ -0,0 +1 @@
> +kmsg-test
> diff --git a/tools/testing/selftests/kmsg/Makefile 
> b/tools/testing/selftests/kmsg/Makefile
> new file mode 100644
> index 0000000..b4ba892
> --- /dev/null
> +++ b/tools/testing/selftests/kmsg/Makefile
> @@ -0,0 +1,30 @@
> +CFLAGS += -I../../../../usr/include/
> +CFLAGS += -I../../../../samples/kmsg/
> +CFLAGS += -I../../../../include/uapi/
> +CFLAGS += -std=gnu99 -Wall
> +CFLAGS += -DKBUILD_MODNAME=\"kmsg\" -D_GNU_SOURCE
> +CFLAGS += -pthread
> +LDLIBS += -pthread
> +
> +OBJS= \
> +     kmsg-test.o                             \
> +     test-buffer-add-del.o                   \
> +     test-buffer-add-write-read-del.o        \
> +     test-buffer-buf-torture.o               \
> +     test-buffer-buf-multithreaded-torture.o
> +
> +all: kmsg-test
> +
> +include ../lib.mk
> +
> +%.o: %.c kmsg-test.h
> +     $(CC) $(CFLAGS) -c $< -o $@
> +
> +kmsg-test: $(OBJS)
> +     $(CC) $(CFLAGS) $^ $(LDLIBS) -o $@
> +
> +run_tests:
> +     ./kmsg-test --tap

What does --tap do? Is this a longform option?
I don't see it in usage()

> +
> +clean:
> +     rm -f *.o kmsg-test
> diff --git a/tools/testing/selftests/kmsg/kmsg-test.c 
> b/tools/testing/selftests/kmsg/kmsg-test.c
> new file mode 100644
> index 0000000..4f17b73
> --- /dev/null
> +++ b/tools/testing/selftests/kmsg/kmsg-test.c
> @@ -0,0 +1,329 @@
> +#include <stddef.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <time.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <getopt.h>
> +#include <sys/types.h>
> +#include <sys/wait.h>
> +#include <sys/stat.h>
> +
> +#include "kmsg-test.h"
> +
> +struct kmsg_test {
> +     const char      *name;
> +     const char      *desc;
> +     int (*func)(const struct kmsg_test_args *args);
> +};
> +
> +static const struct kmsg_test tests[] = {
> +     {
> +             .name   = "buffer-add-del",
> +             .desc   = "create and delete kmsg devices",
> +             .func   = kmsg_test_buffer_add_del,
> +     }, {
> +             .name   = "buffer-add-write-read-del",
> +             .desc   = "create w/r and del kmsg device",
> +             .func   = kmsg_test_buffer_add_write_read_del,
> +     }, {
> +             .name   = "buffer-buf-torture",
> +             .desc   = "fill more than whole buffer can hold",
> +             .func   = kmsg_test_buffer_buf_torture,
> +     }, {
> +             .name   = "buffer-buf-multitheaded-torture",
> +             .desc   = "fill from many threads",
> +             .func   = kmsg_test_buffer_buf_multithreaded_torture,
> +     },
> +};
> +
> +#define N_TESTS ARRAY_SIZE(tests)
> +
> +FILE *kmsg_get_device(int minor, const char *mode)
> +{
> +     char path[80] = "";
> +     dev_t dev = makedev(1, minor);
> +
> +     if (minor < 0) {
> +             printf("Invalid minor number %d\n", minor);
> +             return NULL;
> +     }
> +
> +     snprintf(path, sizeof(path), "/tmp/kmsg-%d", minor);
> +
> +     if (access(path, F_OK) < 0) {
> +             if (mknod(path, S_IFCHR | 0600, dev)) {
> +                     printf("Cannot create device %s with minor %d\n",
> +                                                             path, minor);
> +                     return NULL;
> +             }
> +     }
> +
> +     if (access(path, F_OK) < 0) {
> +             printf("Cannot access device %s\n", path);
> +             return NULL;
> +     }
> +
> +     return fopen(path, mode);
> +}
> +
> +int kmsg_drop_device(int minor)
> +{
> +     char path[80] = "";
> +
> +     if (minor < 0) {
> +             printf("Invalid minor number %d\n", minor);
> +             return -1;
> +     }
> +
> +     snprintf(path, sizeof(path), "/tmp/kmsg-%d", minor);
> +
> +     return unlink(path);
> +}
> +
> +static void usage(const char *argv0)
> +{
> +     unsigned int i, j;
> +
> +     printf("Usage: %s [options]\n"
> +            "Options:\n"
> +            "\t-x, --loop            Run in a loop\n"
> +            "\t-f, --fork            Fork before running a test\n"
> +            "\t-h, --help            Print this help\n"
> +            "\t-t, --test <test-id>  Run one specific test only\n"
> +            "\t-w, --wait <secs>     Wait <secs> before actually starting 
> test\n"
> +            "\n", argv0);
> +
> +     printf("By default, all test are run once, and a summary is printed.\n"
> +            "Available tests for --test:\n\n");
> +
> +     for (i = 0; i < N_TESTS; i++) {
> +             const struct kmsg_test *t = tests + i;
> +
> +             printf("\t%s", t->name);
> +
> +             for (j = 0; j < 24 - strlen(t->name); j++)
> +                     printf(" ");
> +
> +             printf("Test %s\n", t->desc);
> +     }
> +
> +     printf("\n");
> +     printf("Note that some tests may, if run specifically by --test, ");
> +     printf("behave differently, and not terminate by themselves.\n");
> +
> +     exit(EXIT_FAILURE);
> +}
> +
> +static void print_test_result(int ret)
> +{
> +     switch (ret) {
> +     case TEST_OK:
> +             printf("OK");
> +             break;
> +     case TEST_SKIP:
> +             printf("SKIPPED");
> +             break;
> +     case TEST_ERR:
> +             printf("ERROR");
> +             break;
> +     }
> +}
> +
> +static int test_run(const struct kmsg_test *t,
> +                 const struct kmsg_test_args *kmsg_args,
> +                 int wait)
> +{
> +     int ret;
> +
> +     if (wait > 0) {
> +             printf("Sleeping %d seconds before running test ...\n", wait);
> +             sleep(wait);
> +     }
> +
> +     ret = t->func(kmsg_args);
> +     return ret;
> +}
> +
> +static int test_run_forked(const struct kmsg_test *t,
> +                        const struct kmsg_test_args *kmsg_args,
> +                        int wait)
> +{
> +     int ret;
> +     pid_t pid;
> +
> +     pid = fork();
> +     if (pid < 0) {
> +             return TEST_ERR;
> +     } else if (pid == 0) {
> +             ret = test_run(t, kmsg_args, wait);
> +             _exit(ret);
> +     }
> +
> +     pid = waitpid(pid, &ret, 0);
> +     if (pid <= 0)
> +             return TEST_ERR;
> +     else if (!WIFEXITED(ret))
> +             return TEST_ERR;
> +     else
> +             return WEXITSTATUS(ret);
> +}
> +
> +static int start_all_tests(const struct kmsg_test_args *kmsg_args)
> +{
> +     int ret;
> +     unsigned int fail_cnt = 0;
> +     unsigned int skip_cnt = 0;
> +     unsigned int ok_cnt = 0;
> +     unsigned int i, n;
> +     const struct kmsg_test *t;
> +
> +     for (i = 0; i < N_TESTS; i++) {
> +             t = tests + i;
> +
> +             printf("Testing %s (%s) ", t->desc, t->name);
> +             for (n = 0; n < 60 - strlen(t->desc) - strlen(t->name); n++)
> +                     printf(".");
> +             printf(" ");
> +
> +             ret = test_run_forked(t, kmsg_args, 0);
> +             switch (ret) {
> +             case TEST_OK:
> +                     ok_cnt++;
> +                     break;
> +             case TEST_SKIP:
> +                     skip_cnt++;
> +                     break;
> +             case TEST_ERR:
> +                     fail_cnt++;
> +                     break;
> +             }
> +
> +             print_test_result(ret);
> +             printf("\n");
> +     }
> +
> +     printf("\nSUMMARY: %u tests passed, %u skipped, %u failed\n",
> +                                         ok_cnt, skip_cnt, fail_cnt);
> +
> +     return fail_cnt > 0 ? TEST_ERR : TEST_OK;
> +}
> +
> +static int start_one_test(const struct kmsg_test_args *kmsg_args)
> +{
> +     int i, ret;
> +     bool test_found = false;
> +     const struct kmsg_test *t;
> +
> +     for (i = 0; i < N_TESTS; i++) {
> +             t = tests + i;
> +
> +             if (strcmp(t->name, kmsg_args->test))
> +                     continue;
> +
> +             do {
> +                     test_found = true;
> +                     if (kmsg_args->fork)
> +                             ret = test_run_forked(t, kmsg_args,
> +                                                   kmsg_args->wait);
> +                     else
> +                             ret = test_run(t, kmsg_args,
> +                                            kmsg_args->wait);
> +
> +                     printf("Testing %s: ", t->desc);
> +                     print_test_result(ret);
> +                     printf("\n");
> +
> +                     if (ret != TEST_OK)
> +                             break;
> +             } while (kmsg_args->loop);
> +
> +             return ret;
> +     }
> +
> +     if (!test_found) {
> +             printf("Unknown test-id '%s'\n", kmsg_args->test);
> +             return TEST_ERR;
> +     }
> +
> +     return TEST_OK;
> +}
> +
> +static int start_tests(const struct kmsg_test_args *kmsg_args)
> +{
> +     int ret = 0;
> +
> +     if (kmsg_args->test) {
> +             ret = start_one_test(kmsg_args);
> +     } else  {
> +             do {
> +                     ret = start_all_tests(kmsg_args);
> +                     if (ret != TEST_OK)
> +                             break;
> +             } while (kmsg_args->loop);
> +     }
> +
> +     return ret;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +     int t, ret = 0;
> +     struct kmsg_test_args *kmsg_args;
> +     char *exec = basename(argv[0]);
> +
> +     kmsg_args = malloc(sizeof(*kmsg_args));
> +     if (!kmsg_args) {
> +             printf("unable to malloc() kmsg_args\n");
> +             return EXIT_FAILURE;
> +     }
> +
> +     memset(kmsg_args, 0, sizeof(*kmsg_args));
> +
> +     static const struct option options[] = {
> +             { "loop",       no_argument,            NULL, 'x' },
> +             { "help",       no_argument,            NULL, 'h' },
> +             { "test",       required_argument,      NULL, 't' },
> +             { "wait",       required_argument,      NULL, 'w' },
> +             { "fork",       no_argument,            NULL, 'f' },
> +             {}
> +     };
> +
> +     if (strcmp(exec, "kmsg-test") != 0)
> +             kmsg_args->test = exec;
> +
> +     while ((t = getopt_long(argc, argv, "hxfm:r:t:b:w:a",
> +                                             options, NULL)) >= 0) {
> +             switch (t) {
> +             case 'x':
> +                     kmsg_args->loop = 1;
> +                     break;
> +
> +             case 't':
> +                     kmsg_args->test = optarg;
> +                     break;
> +
> +             case 'w':
> +                     kmsg_args->wait = strtol(optarg, NULL, 10);
> +                     break;
> +
> +             case 'f':
> +                     kmsg_args->fork = 1;
> +                     break;
> +
> +             default:
> +             case 'h':
> +                     usage(argv[0]);
> +             }
> +     }
> +
> +     ret = start_tests(kmsg_args);
> +     if (ret == TEST_ERR)
> +             return EXIT_FAILURE;
> +
> +     free(kmsg_args);
> +
> +     return 0;
> +}
> diff --git a/tools/testing/selftests/kmsg/kmsg-test.h 
> b/tools/testing/selftests/kmsg/kmsg-test.h
> new file mode 100644
> index 0000000..b9ce896
> --- /dev/null
> +++ b/tools/testing/selftests/kmsg/kmsg-test.h
> @@ -0,0 +1,34 @@
> +#ifndef _KMSG_TEST_H_
> +#define _KMSG_TEST_H_
> +
> +#include <stdio.h>
> +
> +#define DEV_KMSG "/dev/kmsg"
> +
> +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
> +
> +#define KMSG_REQUESTED_BUF_SIZE (1024 * 256)
> +
> +enum {
> +     TEST_OK,
> +     TEST_SKIP,
> +     TEST_ERR,
> +};
> +
> +struct kmsg_test_args {
> +     int loop;
> +     int wait;
> +     int fork;
> +     const char *test;
> +};
> +
> +FILE *kmsg_get_device(int minor, const char *mode);
> +int kmsg_drop_device(int minor);
> +
> +int kmsg_test_buffer_add_del(const struct kmsg_test_args *args);
> +int kmsg_test_buffer_add_write_read_del(const struct kmsg_test_args *args);
> +int kmsg_test_buffer_buf_torture(const struct kmsg_test_args *args);
> +int kmsg_test_buffer_buf_multithreaded_torture(
> +                                     const struct kmsg_test_args *args);
> +
> +#endif /* _KMSG_TEST_H_ */
> diff --git a/tools/testing/selftests/kmsg/test-buffer-add-del.c 
> b/tools/testing/selftests/kmsg/test-buffer-add-del.c
> new file mode 100644
> index 0000000..22b69ac
> --- /dev/null
> +++ b/tools/testing/selftests/kmsg/test-buffer-add-del.c
> @@ -0,0 +1,76 @@
> +#include <stddef.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <kmsg-api.h>
> +
> +#include "kmsg-test.h"
> +
> +int kmsg_test_buffer_add_del(const struct kmsg_test_args *args)
> +{
> +     int i;
> +     int fd = open(DEV_KMSG, O_RDWR);
> +     struct kmsg_cmd_buffer_add cmd = { 0 };
> +     int minors[] = { -1, -1, -1, -1 };
> +     FILE *fds[ARRAY_SIZE(minors)];
> +     int retval = TEST_OK;
> +     uint32_t size;
> +
> +     if (fd < 0) {
> +             printf("Failed: cannot open %s\n", DEV_KMSG);
> +             return TEST_ERR;
> +     }
> +
> +     for (i = 0; i < ARRAY_SIZE(minors); i++) {
> +             fds[i] = NULL;
> +             cmd.size = KMSG_REQUESTED_BUF_SIZE;
> +             cmd.mode = 0662;
> +             if (kmsg_cmd_buffer_add(fd, &cmd)) {
> +                     printf("Failed to add buffer\n");
> +                     goto error;
> +             }
> +             if (cmd.minor < 0) {
> +                     printf("Minor number < 0\n");
> +                     goto error;
> +             }
> +             minors[i] = cmd.minor;
> +             fds[i] = kmsg_get_device(minors[i], "r");
> +             if (!fds[i]) {
> +                     printf("Cannot get device %d\n", i);
> +                     goto error;
> +             }
> +             size = 0;
> +             if (kmsg_cmd_get_buf_size(fileno(fds[i]), &size)) {
> +                     printf("Cannot get buf size on defice %d\n", i);
> +                     goto error;
> +             }
> +             if (size != KMSG_REQUESTED_BUF_SIZE) {
> +                     printf("Invalid buf size on device %d\n", i);
> +                     goto error;
> +             }
> +     }
> +
> +     goto cleanup;
> +
> +error:
> +     retval = TEST_ERR;
> +
> +cleanup:
> +     for (i = 0; i < ARRAY_SIZE(minors); i++) {
> +             if (minors[i] < 0)
> +                     continue;
> +             if (fds[i])
> +                     fclose(fds[i]);
> +             if (kmsg_drop_device(minors[i])) {
> +                     printf("Failed to delete device file %d\n", i);
> +                     retval = TEST_ERR;
> +             }
> +             if (kmsg_cmd_buffer_del(fd, &minors[i])) {
> +                     printf("Failed to delete buffer %d\n", i);
> +                     retval = TEST_ERR;
> +             }
> +     }
> +     close(fd);
> +     return retval;
> +}
> diff --git a/tools/testing/selftests/kmsg/test-buffer-add-write-read-del.c 
> b/tools/testing/selftests/kmsg/test-buffer-add-write-read-del.c
> new file mode 100644
> index 0000000..ab4223f
> --- /dev/null
> +++ b/tools/testing/selftests/kmsg/test-buffer-add-write-read-del.c
> @@ -0,0 +1,161 @@
> +#include <stddef.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <kmsg-api.h>
> +
> +#include "kmsg-test.h"
> +
> +static const char *message(char *buff, size_t size, int i, int j)
> +{
> +     snprintf(buff, size, "Test message (%d, %d)", i, j);
> +     return buff;
> +}
> +
> +int kmsg_test_buffer_add_write_read_del(const struct kmsg_test_args *args)
> +{
> +     int i, j;
> +     int fd = open(DEV_KMSG, O_RDWR);
> +     struct kmsg_cmd_buffer_add cmd = { 0 };
> +     int minors[] = { -1, -1, -1, -1 };
> +     FILE *fds[ARRAY_SIZE(minors)];
> +     FILE *log[ARRAY_SIZE(minors)];
> +     int logfd;
> +     int retval = TEST_OK;
> +     uint32_t size;
> +     char txt[80] = "";
> +     char *buff = NULL;
> +     const char *msg;
> +     char *msgend;
> +
> +     if (fd < 0) {
> +             printf("Failed: cannot open %s\n", DEV_KMSG);
> +             return TEST_ERR;
> +     }
> +
> +     for (i = 0; i < ARRAY_SIZE(minors); i++) {
> +             fds[i] = NULL;
> +             log[i] = NULL;
> +             cmd.size = KMSG_REQUESTED_BUF_SIZE;
> +             cmd.mode = 0662;
> +             if (kmsg_cmd_buffer_add(fd, &cmd)) {
> +                     printf("Failed to add buffer\n");
> +                     goto error;
> +             }
> +             if (cmd.minor < 0) {
> +                     printf("Minor number < 0\n");
> +                     goto error;
> +             }
> +             minors[i] = cmd.minor;
> +
> +             fds[i] = kmsg_get_device(minors[i], "w");
> +             if (!fds[i]) {
> +                     printf("Cannot get device %d for write\n", i);
> +                     goto error;
> +             }
> +             size = 0;
> +             if (kmsg_cmd_get_buf_size(fileno(fds[i]), &size)) {
> +                     printf("Cannot get buf size on defice %d\n", i);
> +                     goto error;
> +             }
> +             if (size != KMSG_REQUESTED_BUF_SIZE) {
> +                     printf("Invalid buf size on device %d\n", i);
> +                     goto error;
> +             }
> +             log[i] = kmsg_get_device(minors[i], "r");
> +             if (!log[i]) {
> +                     printf("Cannot get device %d for read\n", i);
> +                     goto error;
> +             }
> +             size = 0;
> +             if (kmsg_cmd_get_buf_size(fileno(log[i]), &size)) {
> +                     printf("Cannot get buf size on defice %d\n", i);
> +                     goto error;
> +             }
> +             if (size != KMSG_REQUESTED_BUF_SIZE) {
> +                     printf("Invalid buf size on device %d\n", i);
> +                     goto error;
> +             }
> +
> +             for (j = 0; j <= i; j++) {
> +                     if (kmsg_cmd_clear(fileno(fds[j]))) {
> +                             printf("Cannot clear buffer on device %d\n", j);
> +                             goto error;
> +                     }
> +                     fprintf(fds[j], "%s\n", message(txt, ARRAY_SIZE(txt),
> +                                                                     i, j));
> +                     fflush(fds[j]);
> +             }
> +
> +             for (j = 0; j <= i; j++) {
> +                     logfd = fileno(log[j]);
> +                     size = 0;
> +                     if (kmsg_cmd_get_read_size_max(logfd, &size)) {
> +                             printf("Cannot get buf size on device %d\n", j);
> +                             goto error;
> +                     }
> +                     if (!size) {
> +                             printf("Expected non-zero buf size on %d\n", j);
> +                             goto error;
> +                     }
> +                     buff = malloc(size);
> +                     if (!buff) {
> +                             printf("Out of memory\n");
> +                             goto error;
> +                     }
> +                     if (read(logfd, buff, size) <= 0) {
> +                             printf("Could not read from buffer %d\n", j);
> +                             goto error;
> +                     }
> +                     msg = strchr(buff, ';');
> +                     msgend = strchr(buff, '\n');
> +                     if ((!msg) || (!msgend)) {
> +                             printf("Could not read stored log on %d\n", j);
> +                             goto error;
> +                     }
> +                     msg++;
> +                     *msgend = 0;
> +                     if (strcmp(msg, message(txt, ARRAY_SIZE(txt), i, j))) {
> +                             printf("Messages do not match on %d\n", j);
> +                             goto error;
> +                     }
> +                     free(buff);
> +                     buff = NULL;
> +             }
> +     }
> +
> +     goto cleanup;
> +
> +error:
> +     retval = TEST_ERR;
> +
> +cleanup:
> +     for (i = 0; i < ARRAY_SIZE(minors); i++) {
> +             if (minors[i] < 0)
> +                     continue;
> +             if (fds[i])
> +                     fclose(fds[i]);
> +             if (log[i]) {
> +                     if (kmsg_cmd_clear(fileno(log[i]))) {
> +                             printf("Failed to clear device %d\n", i);
> +                             retval = TEST_ERR;
> +                     }
> +                     fclose(log[i]);
> +             }
> +             if (kmsg_drop_device(minors[i])) {
> +                     printf("Failed to delete device file %d\n", i);
> +                     retval = TEST_ERR;
> +             }
> +             if (kmsg_cmd_buffer_del(fd, &minors[i])) {
> +                     printf("Failed to delete buffer %d\n", i);
> +                     retval = TEST_ERR;
> +             }
> +     }
> +     close(fd);
> +     if (buff)
> +             free(buff);
> +     return retval;
> +}
> diff --git 
> a/tools/testing/selftests/kmsg/test-buffer-buf-multithreaded-torture.c 
> b/tools/testing/selftests/kmsg/test-buffer-buf-multithreaded-torture.c
> new file mode 100644
> index 0000000..5510b13
> --- /dev/null
> +++ b/tools/testing/selftests/kmsg/test-buffer-buf-multithreaded-torture.c
> @@ -0,0 +1,199 @@
> +#include <stddef.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <pthread.h>
> +#include <kmsg-api.h>
> +
> +#include "kmsg-test.h"
> +
> +#define SOME_BUFF_SIZE 4096
> +#define THREADS_PER_DEVICE 10
> +
> +static bool ok = true;
> +static bool nok = !true;
> +
> +static void *kmsg_test_thread_func(void *data)
> +{
> +     char buff[SOME_BUFF_SIZE];
> +     int minor = *((int *)data);
> +     FILE *f = kmsg_get_device(minor, "w");
> +     int fd;
> +     void *retval = &ok;
> +     int iter;
> +     ssize_t s;
> +     uint32_t size, done;
> +     uint32_t max_size;
> +
> +     memset(buff, 'A', ARRAY_SIZE(buff));
> +     buff[ARRAY_SIZE(buff) - 1] = 0;
> +
> +     if (!f) {
> +             printf("Cannot get device for write\n");
> +             return &nok;
> +     }
> +     fd = fileno(f);
> +
> +     size = 0;
> +     if (kmsg_cmd_get_buf_size(fd, &size)) {
> +             printf("Cannot get buf size\n");
> +             goto error;
> +     }
> +     if (size != KMSG_REQUESTED_BUF_SIZE) {
> +             printf("Invalid buf size\n");
> +             goto error;
> +     }
> +
> +     if (kmsg_cmd_clear(fd)) {
> +             printf("Cannot clear buffer\n");
> +             goto error;
> +     }
> +
> +     iter = 0;
> +     while (done < (KMSG_REQUESTED_BUF_SIZE * 2)) {
> +             s = write(fd, buff, ARRAY_SIZE(buff));
> +             if (s < 0) {
> +                     printf("Cannot write iteration %d\n", iter);
> +                     goto error;
> +             }
> +             done += s;
> +
> +             max_size = 0;
> +             if (kmsg_cmd_get_read_size_max(fd, &max_size)) {
> +                     printf("Cannot get max_size\n");
> +                     goto error;
> +             }
> +             if (!max_size) {
> +                     printf("Expected non-zero max_size\n");
> +                     goto error;
> +             }
> +
> +             iter++;
> +     }
> +
> +     goto cleanup;
> +
> +error:
> +     retval = &nok;
> +
> +cleanup:
> +     fclose(f);
> +
> +     return retval;
> +}
> +
> +int kmsg_test_buffer_buf_multithreaded_torture(
> +                                     const struct kmsg_test_args *args)
> +{
> +     int i, j;
> +     int fd = open(DEV_KMSG, O_RDWR);
> +     struct kmsg_cmd_buffer_add cmd = { 0 };
> +     int minors[] = { -1, -1, -1, -1 };
> +     FILE *log[ARRAY_SIZE(minors)];
> +     int retval = TEST_OK;
> +     pthread_t threads[ARRAY_SIZE(minors)][THREADS_PER_DEVICE];
> +     bool started[ARRAY_SIZE(minors)][THREADS_PER_DEVICE];
> +     uint32_t size;
> +     uint32_t max_size;
> +     void *retptr;
> +
> +     for (i = 0; i < ARRAY_SIZE(minors); i++)
> +             for (j = 0; j < THREADS_PER_DEVICE; j++)
> +                     started[i][j] = false;
> +
> +     if (fd < 0) {
> +             printf("Failed: cannot open %s\n", DEV_KMSG);
> +             return TEST_ERR;
> +     }
> +
> +     for (i = 0; i < ARRAY_SIZE(minors); i++) {
> +             log[i] = NULL;
> +             cmd.size = KMSG_REQUESTED_BUF_SIZE;
> +             cmd.mode = 0662;
> +             if (kmsg_cmd_buffer_add(fd, &cmd)) {
> +                     printf("Failed to add buffer\n");
> +                     goto error;
> +             }
> +             if (cmd.minor < 0) {
> +                     printf("Minor number < 0\n");
> +                     goto error;
> +             }
> +             minors[i] = cmd.minor;
> +
> +             log[i] = kmsg_get_device(minors[i], "r");
> +             if (!log[i]) {
> +                     printf("Cannot get device %d for read\n", i);
> +                     goto error;
> +             }
> +             size = 0;
> +             if (kmsg_cmd_get_buf_size(fileno(log[i]), &size)) {
> +                     printf("Cannot get buf size on defice %d\n", i);
> +                     goto error;
> +             }
> +             if (size != KMSG_REQUESTED_BUF_SIZE) {
> +                     printf("Invalid buf size on device %d\n", i);
> +                     goto error;
> +             }
> +
> +             for (j = 0; j < THREADS_PER_DEVICE; j++) {
> +                     if (pthread_create(&threads[i][j], NULL,
> +                                       kmsg_test_thread_func, &minors[i])) {
> +                             printf("Cannot create thread %d for dev %d\n",
> +                                                                     j, i);
> +                             goto error;
> +                     }
> +                     started[i][j] = true;
> +             }
> +     }
> +
> +     goto cleanup;
> +
> +error:
> +     retval = TEST_ERR;
> +
> +cleanup:
> +     for (i = 0; i < ARRAY_SIZE(minors); i++) {
> +             for (j = 0; j < THREADS_PER_DEVICE; j++)
> +                     if (started[i][j]) {
> +                             if (pthread_join(threads[i][j], &retptr)) {
> +                                     printf("pthread_join() failed %d:%d\n",
> +                                                                     i, j);
> +                                     retval = TEST_ERR;
> +                             }
> +                             if (!(*((bool *)retptr)))
> +                                     retval = TEST_ERR;
> +                     }
> +             if (minors[i] < 0)
> +                     continue;
> +             if (log[i]) {
> +                     max_size = 0;
> +                     if (kmsg_cmd_get_read_size_max(fileno(log[i]),
> +                                                             &max_size)) {
> +                             printf("Cannot get max_size\n");
> +                             retval = TEST_ERR;
> +                     }
> +                     if (!max_size) {
> +                             printf("Expected non-zero max_size\n");
> +                             retval = TEST_ERR;
> +                     }
> +                     if (kmsg_cmd_clear(fileno(log[i]))) {
> +                             printf("Failed to clear device %d\n", i);
> +                             retval = TEST_ERR;
> +                     }
> +                     fclose(log[i]);
> +             }
> +             if (kmsg_drop_device(minors[i])) {
> +                     printf("Failed to delete device file %d\n", i);
> +                     retval = TEST_ERR;
> +             }
> +             if (kmsg_cmd_buffer_del(fd, &minors[i])) {
> +                     printf("Failed to delete buffer %d\n", i);
> +                     retval = TEST_ERR;
> +             }
> +     }
> +     close(fd);
> +     return retval;
> +}
> diff --git a/tools/testing/selftests/kmsg/test-buffer-buf-torture.c 
> b/tools/testing/selftests/kmsg/test-buffer-buf-torture.c
> new file mode 100644
> index 0000000..700a2fa
> --- /dev/null
> +++ b/tools/testing/selftests/kmsg/test-buffer-buf-torture.c
> @@ -0,0 +1,139 @@
> +#include <stddef.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <kmsg-api.h>
> +
> +#include "kmsg-test.h"
> +
> +#define SOME_BUFF_SIZE 4096
> +
> +int kmsg_test_buffer_buf_torture(const struct kmsg_test_args *args)
> +{
> +     int i, iter;
> +     int fd = open(DEV_KMSG, O_RDWR);
> +     struct kmsg_cmd_buffer_add cmd = { 0 };
> +     int minors[] = { -1, -1, -1, -1 };
> +     FILE *fds[ARRAY_SIZE(minors)];
> +     FILE *log[ARRAY_SIZE(minors)];
> +     int retval = TEST_OK;
> +     char buff[SOME_BUFF_SIZE];
> +     ssize_t s;
> +     int logfd;
> +     uint32_t size, done;
> +     uint32_t max_size;
> +
> +     memset(buff, 'A', ARRAY_SIZE(buff));
> +     buff[ARRAY_SIZE(buff) - 1] = 0;
> +
> +     if (fd < 0) {
> +             printf("Failed: cannot open %s\n", DEV_KMSG);
> +             return TEST_ERR;
> +     }
> +
> +     for (i = 0; i < ARRAY_SIZE(minors); i++) {
> +             fds[i] = NULL;
> +             log[i] = NULL;
> +             cmd.size = KMSG_REQUESTED_BUF_SIZE;
> +             cmd.mode = 0662;
> +             if (kmsg_cmd_buffer_add(fd, &cmd)) {
> +                     printf("Failed to add buffer\n");
> +                     goto error;
> +             }
> +             if (cmd.minor < 0) {
> +                     printf("Minor number < 0\n");
> +                     goto error;
> +             }
> +             minors[i] = cmd.minor;
> +
> +             fds[i] = kmsg_get_device(minors[i], "w");
> +             if (!fds[i]) {
> +                     printf("Cannot get device %d for write\n", i);
> +                     goto error;
> +             }
> +             size = 0;
> +             if (kmsg_cmd_get_buf_size(fileno(fds[i]), &size)) {
> +                     printf("Cannot get buf size on defice %d\n", i);
> +                     goto error;
> +             }
> +             if (size != KMSG_REQUESTED_BUF_SIZE) {
> +                     printf("Invalid buf size on device %d\n", i);
> +                     goto error;
> +             }
> +             log[i] = kmsg_get_device(minors[i], "r");
> +             if (!log[i]) {
> +                     printf("Cannot get device %d for read\n", i);
> +                     goto error;
> +             }
> +             size = 0;
> +             if (kmsg_cmd_get_buf_size(fileno(log[i]), &size)) {
> +                     printf("Cannot get buf size on defice %d\n", i);
> +                     goto error;
> +             }
> +             if (size != KMSG_REQUESTED_BUF_SIZE) {
> +                     printf("Invalid buf size on device %d\n", i);
> +                     goto error;
> +             }
> +
> +             logfd = fileno(fds[i]);
> +             if (kmsg_cmd_clear(logfd)) {
> +                     printf("Cannot clear buffer on device %d\n", i);
> +                     goto error;
> +             }
> +
> +             iter = 0;
> +             while (done < (KMSG_REQUESTED_BUF_SIZE * 2)) {
> +                     s = write(logfd, buff, ARRAY_SIZE(buff));
> +                     if (s < 0) {
> +                             printf("Cannot write %d to device %d, %s\n",
> +                                                 iter, i, strerror(errno));
> +                             goto error;
> +                     }
> +                     done += s;
> +
> +                     max_size = 0;
> +                     if (kmsg_cmd_get_read_size_max(logfd, &max_size)) {
> +                             printf("Cannot get max_size on device %d\n", i);
> +                             goto error;
> +                     }
> +                     if (!max_size) {
> +                             printf("Expected non-zero max_size on %d\n", i);
> +                             goto error;
> +                     }
> +
> +                     iter++;
> +             }
> +     }
> +
> +     goto cleanup;
> +
> +error:
> +     retval = TEST_ERR;
> +
> +cleanup:
> +     for (i = 0; i < ARRAY_SIZE(minors); i++) {
> +             if (minors[i] < 0)
> +                     continue;
> +             if (fds[i])
> +                     fclose(fds[i]);
> +             if (log[i]) {
> +                     if (kmsg_cmd_clear(fileno(log[i]))) {
> +                             printf("Failed to clear device %d\n", i);
> +                             retval = TEST_ERR;
> +                     }
> +                     fclose(log[i]);
> +             }
> +             if (kmsg_drop_device(minors[i])) {
> +                     printf("Failed to delete device file %d\n", i);
> +                     retval = TEST_ERR;
> +             }
> +             if (kmsg_cmd_buffer_del(fd, &minors[i])) {
> +                     printf("Failed to delete buffer %d\n", i);
> +                     retval = TEST_ERR;
> +             }
> +     }
> +     close(fd);
> +     return retval;
> +}
> 


-- 
Shuah Khan
Sr. Linux Kernel Developer
Open Source Innovation Group
Samsung Research America (Silicon Valley)
shua...@osg.samsung.com | (970) 217-8978
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to