[LTP] [PATCH v3] kernel/fs/fsnotify-stress: fsnotify stress test
Cyril Hrubis
chrubis@suse.cz
Wed Mar 9 11:38:12 CET 2022
Hi!
> This is a stress tests that exercises fanotify and inotify interfaces
> while IO going on. It ignores some failures of syscalls to let the
> stress go on. If the kernel does not panic or hang after a certain
> period of time of testing, test pass.
>
> Signed-off-by: Murphy Zhou <jencce.kernel@gmail.com>
> ---
> v3:
> remove fs_racer.sh part.
>
> runtest/fs | 2 +
> testcases/kernel/fs/fsnotify-stress/Makefile | 13 +
> .../fs/fsnotify-stress/fsnotify-stress.c | 654 ++++++++++++++++++
> 3 files changed, 669 insertions(+)
> create mode 100644 testcases/kernel/fs/fsnotify-stress/Makefile
> create mode 100644 testcases/kernel/fs/fsnotify-stress/fsnotify-stress.c
>
> diff --git a/runtest/fs b/runtest/fs
> index 1d753e0dd..beb43aae4 100644
> --- a/runtest/fs
> +++ b/runtest/fs
> @@ -87,3 +87,5 @@ binfmt_misc01 binfmt_misc01.sh
> binfmt_misc02 binfmt_misc02.sh
>
> squashfs01 squashfs01
> +
> +fsnotify-stress fsnotify-stress
> diff --git a/testcases/kernel/fs/fsnotify-stress/Makefile b/testcases/kernel/fs/fsnotify-stress/Makefile
> new file mode 100644
> index 000000000..cf4a28e42
> --- /dev/null
> +++ b/testcases/kernel/fs/fsnotify-stress/Makefile
> @@ -0,0 +1,13 @@
> +#
> +# kernel/fs/fs-notify testcases Makefile.
> +#
> +
> +top_srcdir ?= ../../../..
> +
> +include $(top_srcdir)/include/mk/testcases.mk
> +
> +INSTALL_TARGETS := fsnotify-stress
> +
> +MAKE_TARGETS := fsnotify-stress
I do not think that we have to set these two variables at all, the test
source should be compiled and installed automatically.
> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/fs/fsnotify-stress/fsnotify-stress.c b/testcases/kernel/fs/fsnotify-stress/fsnotify-stress.c
> new file mode 100644
> index 000000000..8297cad25
> --- /dev/null
> +++ b/testcases/kernel/fs/fsnotify-stress/fsnotify-stress.c
> @@ -0,0 +1,654 @@
> +// SPDX-License-Identifier: GPL-2.0
The default license for new code should be GPL-2.0-or-later, but if you
think that the code should be strictly GPL-2.0 it's your choice.
> +/*
> + * This is an irregular stress test for Linux kernel fanotify/inotify
> + * interfaces. It calls thoese interfaces with possible best coverage
> + * arguments, in a loop. It ignores some return values in the loop to
> + * let the stress going on. At the same time, it initiates IO traffics
> + * by calling IO syscalls.
> + *
> + * If kernel does no panic or hang after the test, test pass.
> + *
> + * It detected a leak in fsnotify code which was fixed by Amir through
> + * this Linux commit:
> + * 4396a731 fsnotify: fix sb_connectors leak
> + *
> + * Author: Murphy Zhou <jencce.kernel@gmail.com>
> + *
> + */
Please convert this into the docparse format. We do parse special types
of comments during LTP build to render html documentation for the
testsuite. These comments start with:
/*\
* [Description]
*
And are formatted in asciidoc.
> +#define _GNU_SOURCE /* Needed to get O_LARGEFILE definition */
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <limits.h>
> +#include <poll.h>
> +#include <sys/fanotify.h>
> +#include <sys/inotify.h>
> +#include <sys/time.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +#include "tst_test.h"
> +#include "../../syscalls/fanotify/fanotify.h"
> +#include "../../syscalls/inotify/inotify.h"
> +
> +static int fd0;
> +static char *str_timeout;
> +static int arg_timeout = 60;
> +
> +#define TESTDIR "testdir"
> +#define TESTFILE "testdir/file"
> +
> +static void cleanup(void)
> +{
> + if (fd0 > 0) {
> + SAFE_CLOSE(fd0);
> + SAFE_UNLINK(TESTFILE);
> + }
> + SAFE_RMDIR(TESTDIR);
The files and directories will be removed automatically at the end of
the test, all that has to be done here is to close the file descriptor.
> +}
> +
> +static void setup(void)
> +{
> + if (tst_parse_int(str_timeout, &arg_timeout, 1, INT_MAX))
> + tst_brk(TBROK, "Invalid timeout '%s'", str_timeout);
> + SAFE_MKDIR(TESTDIR, 0777);
> + fd0 = SAFE_OPEN(TESTFILE, O_CREAT|O_RDWR, 0666);
> +}
> +
> +static void fanotify_flushes(char *fn, unsigned int timeout)
> +{
> + int fd, ret;
> + struct timeval ts;
> + struct timeval te;
> +
> + /* Create the file descriptor for accessing the fanotify API */
> + fd = SAFE_FANOTIFY_INIT(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> + O_RDONLY | O_LARGEFILE);
> +
> + ret = gettimeofday(&ts, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
First of all using gettimeofday() for any time measurement is wrong, as
the system wall clock is not monotonic and may jump at any time.
Secondly we do have a system in place to run tests for a certain amount
of time already. All you have to do is:
while (tst_timeout_remaining() > 10) {
/* do the work here */
}
And then set the .timeout in the tst_test structure to a some sane
default value. No need to reinvent the wheel.
> + /* Loop marking all kinds of events and flush */
This comment comments obvious fact, please do not add comments like
these.
> + while (1) {
> + /* As a stress test, we ignore the return values here to
> + * proceed with the stress.
> + */
> + fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
> + FAN_ACCESS | FAN_MODIFY | FAN_OPEN_PERM | FAN_CLOSE |
> + FAN_OPEN | FAN_ACCESS_PERM | FAN_ONDIR |
> + FAN_EVENT_ON_CHILD, -1, fn);
> +
> + fanotify_mark(fd, FAN_MARK_FLUSH | FAN_MARK_MOUNT,
> + 0, -1, fn);
> +
> + fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
> + FAN_ACCESS | FAN_MODIFY | FAN_OPEN_PERM | FAN_CLOSE |
> + FAN_OPEN | FAN_ACCESS_PERM | FAN_ONDIR |
> + FAN_EVENT_ON_CHILD, -1, fn);
> +
> + fanotify_mark(fd, FAN_MARK_FLUSH, 0, -1, fn);
> +
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + }
> +
> + close(fd);
> + exit(EXIT_SUCCESS);
> +}
> +
> +static void fanotify_inits(char *fn, unsigned int timeout)
> +{
> + int fd, ret;
> + struct timeval ts;
> + struct timeval te;
> +
> + ret = gettimeofday(&ts, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> +
> + while (1) {
> + /* As a stress test, we ignore the return values here to
> + * proceed with the stress.
> + */
> + fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT |
> + FAN_NONBLOCK, O_RDONLY | O_LARGEFILE);
> + fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
> + FAN_ACCESS | FAN_MODIFY | FAN_OPEN_PERM |
> + FAN_CLOSE | FAN_OPEN | FAN_ACCESS_PERM |
> + FAN_ONDIR | FAN_EVENT_ON_CHILD, -1, fn);
> + close(fd);
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + }
> + exit(EXIT_SUCCESS);
> +}
> +
> +static void add_mark(int fd, uint64_t mask, char *path)
> +{
> + fanotify_mark(fd, FAN_MARK_ADD, mask, -1, path);
> +}
> +
> +static void remove_mark(int fd, uint64_t mask, char *path)
> +{
> + fanotify_mark(fd, FAN_MARK_REMOVE, mask, -1, path);
> +}
> +
> +static void fanotify_marks(char *fn, unsigned int timeout)
> +{
> + int fd, ret;
> + struct timeval ts;
> + struct timeval te;
> +
> + /* Create the file descriptor for accessing the fanotify API */
> + fd = SAFE_FANOTIFY_INIT(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> + O_RDONLY | O_LARGEFILE);
> + ret = gettimeofday(&ts, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + /* Loop marking all kinds of events */
> + while (1) {
> + add_mark(fd, FAN_ACCESS, fn);
> + remove_mark(fd, FAN_ACCESS, fn);
> + add_mark(fd, FAN_MODIFY, fn);
> + remove_mark(fd, FAN_MODIFY, fn);
> + add_mark(fd, FAN_OPEN_PERM, fn);
> + remove_mark(fd, FAN_OPEN_PERM, fn);
> + add_mark(fd, FAN_CLOSE, fn);
> + remove_mark(fd, FAN_CLOSE, fn);
> + add_mark(fd, FAN_OPEN, fn);
> + remove_mark(fd, FAN_OPEN, fn);
> + add_mark(fd, FAN_ACCESS_PERM, fn);
> + remove_mark(fd, FAN_ACCESS_PERM, fn);
> + add_mark(fd, FAN_ONDIR, fn);
> + remove_mark(fd, FAN_ONDIR, fn);
> + add_mark(fd, FAN_EVENT_ON_CHILD, fn);
> + remove_mark(fd, FAN_EVENT_ON_CHILD, fn);
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + }
> + close(fd);
> + exit(EXIT_SUCCESS);
> +}
> +
> +/* Read all available fanotify events from the file descriptor 'fd' */
> +static void fa_handle_events(int fd)
> +{
> + const struct fanotify_event_metadata *metadata;
> + struct fanotify_event_metadata buf[200];
> + ssize_t len;
> + struct fanotify_response response;
> +
> + /* Loop while events can be read from fanotify file descriptor */
> + for (;;) {
> + /* Read some events */
> + len = read(fd, (void *) &buf, sizeof(buf));
> + if (len == -1 && errno != EAGAIN)
> + tst_brk(TBROK | TERRNO, "fanotify read events failed");
> + /* Check if end of available data reached */
> + if (len <= 0)
> + break;
> + /* Point to the first event in the buffer */
> + metadata = buf;
> + /* Loop over all events in the buffer */
> + while (FAN_EVENT_OK(metadata, len)) {
> + if (metadata->vers != FANOTIFY_METADATA_VERSION) {
> + tst_brk(TBROK | TERRNO,
> + "Mismatch of fanotify metadata version.\n");
> + }
> + /* metadata->fd contains either FAN_NOFD, indicating a
> + * queue overflow, or a file descriptor (a nonnegative
> + * integer). Here, we simply ignore queue overflow.
> + */
> + if (metadata->fd >= 0) {
> + /* Handle open permission event */
> + if (metadata->mask & FAN_OPEN_PERM) {
> + /* Allow file to be opened */
> + response.fd = metadata->fd;
> + response.response = FAN_ALLOW;
> + write(fd, &response,
> + sizeof(struct fanotify_response));
> + }
> +
> + /* Handle access permission event */
> + if (metadata->mask & FAN_ACCESS_PERM) {
> + /* Allow file to be accessed */
> + response.fd = metadata->fd;
> + response.response = FAN_ALLOW;
> + write(fd, &response,
> + sizeof(struct fanotify_response));
> + }
> + /* Ignore read/write access events */
> + /* Close the file descriptor of the event */
> + close(metadata->fd);
> + }
> + /* Advance to next event */
> + metadata = FAN_EVENT_NEXT(metadata, len);
> + }
> + }
> +}
> +
> +/* This is from fanotify(7) man page example */
> +static void fanotify_watch(char *fn, unsigned int timeout)
> +{
> + int fd, poll_num, ret, ecnt = 0;
> + nfds_t nfds;
> + struct pollfd fds[2];
> + struct timeval ts;
> + struct timeval te;
> +
> + /* Create the file descriptor for accessing the fanotify API */
> + fd = SAFE_FANOTIFY_INIT(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> + O_RDONLY | O_LARGEFILE);
> + /* Mark the mount for:
> + * - permission events before opening files
> + * - notification events after closing a write-enabled file descriptor
> + */
> + SAFE_FANOTIFY_MARK(fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
> + FAN_ACCESS | FAN_MODIFY | FAN_OPEN_PERM |
> + FAN_CLOSE | FAN_OPEN | FAN_ACCESS_PERM |
> + FAN_ONDIR | FAN_EVENT_ON_CHILD, -1, "/");
> +
> + /* Prepare for polling */
> + nfds = 1;
> + /* Fanotify input */
> + fds[0].fd = fd;
> + fds[0].events = POLLIN;
> +
> + ret = gettimeofday(&ts, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> +
> + /* This is the loop to wait for incoming events */
> + while (1) {
> + poll_num = poll(fds, nfds, timeout/2);
> + if (poll_num == -1)
> + tst_brk(TBROK | TERRNO, "fanotify watch poll failed");
> + if (poll_num > 0) {
> + if (fds[0].revents & POLLIN) {
> + /* Fanotify events are available */
> + fa_handle_events(fd);
> + ecnt++;
> + }
> + }
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + }
> + tst_printf("Got %d fanotify events\n", ecnt);
> + tst_flush();
> + exit(EXIT_SUCCESS);
> +}
> +
> +static void freadfiles(char *fn, unsigned int timeout)
> +{
> + int ret;
> + char buf[BUFSIZ];
> + FILE *f;
> + struct timeval ts;
> + struct timeval te;
> +
> + ret = gettimeofday(&ts, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> +
> + memset(buf, 1, BUFSIZ);
> + while (1) {
> + f = fopen(fn, "r+");
> + if (f == NULL) {
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + continue;
> + }
> + ret = fread(buf, sizeof(char), BUFSIZ, f);
> + usleep(1);
> + fclose(f);
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + }
> +}
> +
> +static void fwritefiles(char *fn, unsigned int timeout)
> +{
> + int ret;
> + char buf[BUFSIZ];
> + FILE *f;
> + struct timeval ts;
> + struct timeval te;
> +
> + ret = gettimeofday(&ts, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> +
> + memset(buf, 1, BUFSIZ);
> + while (1) {
> + f = fopen(fn, "w+");
> + if (f == NULL) {
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + continue;
> + }
> + fwrite(buf, sizeof(char), BUFSIZ, f);
> + usleep(1);
> + fclose(f);
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + }
> +}
> +
> +static void readfiles(char *fn, unsigned int timeout)
> +{
> + int fd, ret;
> + char buf[BUFSIZ];
> + struct timeval ts;
> + struct timeval te;
> +
> + ret = gettimeofday(&ts, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> +
> + memset(buf, 1, BUFSIZ);
> + while (1) {
> + fd = open(fn, O_RDONLY);
> + if (fd == -1) {
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + continue;
> + }
> + ret = read(fd, buf, BUFSIZ);
> + usleep(1);
> + close(fd);
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + }
> +}
> +
> +static void writefiles(char *fn, unsigned int timeout)
> +{
> + int ret, fd;
> + char buf[BUFSIZ];
> + struct timeval ts;
> + struct timeval te;
> +
> + ret = gettimeofday(&ts, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> +
> + memset(buf, 1, BUFSIZ);
> + while (1) {
> + fd = open(fn, O_RDWR);
> + if (fd == -1) {
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + continue;
> + }
> + ret = write(fd, buf, BUFSIZ);
> + usleep(1);
> + close(fd);
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + }
> +}
> +
> +static void inotify_add_rm(char *fn, unsigned int timeout)
> +{
> + int notify_fd;
> + int wd, ret;
> + struct timeval ts;
> + struct timeval te;
> +
> + notify_fd = SAFE_MYINOTIFY_INIT1(IN_CLOEXEC);
> +
> + ret = gettimeofday(&ts, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> +
> + while (1) {
> + wd = inotify_add_watch(notify_fd, fn,
> + IN_ACCESS | IN_ATTRIB | IN_CLOSE_WRITE |
> + IN_CLOSE_NOWRITE | IN_CREATE | IN_DELETE |
> + IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF |
> + IN_MOVED_FROM | IN_MOVED_TO | IN_OPEN);
> +
> + inotify_rm_watch(notify_fd, wd);
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + }
> + close(notify_fd);
> +}
> +
> +static void inotify_inits(char *fn, unsigned int timeout)
> +{
> + int notify_fd, ret;
> + struct timeval ts;
> + struct timeval te;
> +
> + ret = gettimeofday(&ts, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> +
> + while (1) {
> + notify_fd = inotify_init1(IN_CLOEXEC);
> + close(notify_fd);
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + }
> +}
> +
> +static void inotify_add_rm_watches(char *fn, unsigned int timeout)
> +{
> + int ret, fd, wd;
> + struct timeval ts;
> + struct timeval te;
> +
> + fd = SAFE_MYINOTIFY_INIT();
> +
> + ret = gettimeofday(&ts, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> +
> + while (1) {
> + wd = inotify_add_watch(fd, fn, IN_MODIFY);
> + inotify_rm_watch(fd, wd);
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + }
> + close(fd);
> +}
> +
> +static void i_handle_events(int fd)
> +{
> + char buf[4096]
> + __attribute__((aligned(__alignof__(struct inotify_event))));
> + ssize_t len;
> +
> + /* Loop while events can be read from inotify file descriptor. */
> + for (;;) {
> + len = read(fd, buf, sizeof(buf));
> + if (len == -1 && errno != EAGAIN)
> + tst_brk(TBROK | TERRNO, "inotify read event failed");
> + /* If the nonblocking read() found no events to read, then
> + * it returns -1 with errno set to EAGAIN. In that case,
> + * we exit the loop.
> + */
> + if (len <= 0)
> + break;
> + }
> +}
> +
> +static void inotify_watch(char *fn, unsigned int timeout)
> +{
> + int fd, poll_num, wd, ret, ecnt = 0;
> + nfds_t nfds;
> + struct pollfd fds[2];
> + struct timeval ts;
> + struct timeval te;
> +
> + /* Create the file descriptor for accessing the inotify API. */
> + fd = SAFE_MYINOTIFY_INIT1(IN_NONBLOCK);
> +
> + /* Mark directories for events
> + * - file was opened
> + * - file was closed
> + */
> + wd = SAFE_MYINOTIFY_ADD_WATCH(fd, fn, IN_OPEN | IN_CLOSE);
> +
> + /* Prepare for polling. */
> + nfds = 2;
> + fds[0].fd = STDIN_FILENO; /* Console input */
> + fds[0].events = POLLIN;
> + fds[1].fd = fd; /* Inotify input */
> + fds[1].events = POLLIN;
> +
> + ret = gettimeofday(&ts, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> +
> + /* Wait for events and/or terminal input. */
> + while (1) {
> + poll_num = poll(fds, nfds, timeout/2);
> + if (poll_num == -1)
> + tst_brk(TBROK | TERRNO, "inotify watch poll failed");
> + if (poll_num > 0) {
> + if (fds[1].revents & POLLIN) {
> + /* Inotify events are available. */
> + i_handle_events(fd);
> + ecnt++;
> + }
> + }
> + ret = gettimeofday(&te, NULL);
> + if (ret == -1)
> + tst_brk(TBROK | TERRNO, "gettimeofday failed");
> + if (te.tv_sec - ts.tv_sec > timeout)
> + break;
> + }
> +
> + inotify_rm_watch(fd, wd);
> + close(fd);
> + tst_printf("Got %d inotify events\n", ecnt);
> + tst_flush();
> + exit(EXIT_SUCCESS);
> +}
> +
> +struct tcase {
> + char *desc;
> + void (*func_test)(char *fn, unsigned int timeout);
> + int ondir; /* run stress on directory */
> + int onfile; /* run stress on file */
> +};
> +static struct tcase tcases[] = {
> + {"fanotify_flush stress", fanotify_flushes, 1, 1},
> + {"fanotify_init stress", fanotify_inits, 1, 1},
> + {"fanotify_mark stress", fanotify_marks, 1, 1},
> + {"fanotify watching stress", fanotify_watch, 1, 0},
> + {"fread stress", freadfiles, 0, 1},
> + {"fwrite stress", fwritefiles, 0, 1},
> + {"inotify add rm stress", inotify_add_rm, 1, 1},
> + {"inotify init stress", inotify_inits, 1, 1},
> + {"inotify add rm watch stress", inotify_add_rm_watches, 1, 1},
> + {"inotify watching stress", inotify_watch, 1, 0},
> + {"read stress", readfiles, 0, 1},
> + {"write stress", writefiles, 0, 1}
> +};
> +
> +static void run(void)
> +{
> + int tcnt = ARRAY_SIZE(tcases);
> + int i = 0;
> + const struct tst_clone_args args = {
> + .exit_signal = SIGCHLD,
> + };
> +
> + setup();
The setup and cleanup has to be passed via the tst_test structure and
shouldn't be called from the run() function at all.
> + tst_printf("Starting %d stresses\n", tcnt);
This should be tst_res(TINFO, ...);
> + tst_flush();
The SAFE_CLONE() does flush the buffers before it calls the clone()
syscall, there is no need to flush anything in the test itself.
> + while (i < tcnt) {
> + if (tcases[i].ondir && !SAFE_CLONE(&args)) {
> + tst_printf("Starting %s on dir\n", tcases[i].desc);
> + tst_flush();
Here as well.
> + tcases[i].func_test(TESTDIR, arg_timeout);
> + tst_printf("Ending %s on dir\n", tcases[i].desc);
> + tst_flush();
> + exit(EXIT_SUCCESS);
Some of the func_test() calls exit(EXIT_SUCCESS) at the end, in these
casese these messages will not be printed at all.
> + }
> + if (tcases[i].onfile && !SAFE_CLONE(&args)) {
> + tst_printf("Starting %s on file\n", tcases[i].desc);
> + tst_flush();
Here as well.
> + tcases[i].func_test(TESTFILE, arg_timeout);
> + tst_printf("Ending %s on file\n", tcases[i].desc);
> + tst_flush();
> + exit(EXIT_SUCCESS);
And here as well.
> + }
> + i++;
> + }
> + tst_reap_children();
> + cleanup();
> + tst_res(TPASS, "No panic or hang, test pass!");
> +}
> +
> +static struct tst_test test = {
> + .tcnt = 1,
> + .forks_child = 1,
> + .needs_root = 1,
> + .needs_tmpdir = 1,
> + .needs_cmds = 0,
> + .needs_cgroup_ver = 0,
> + .needs_cgroup_ctrls = 0,
Please do not set anything to 0 here, that is the default value for any
uninitialized variables. Unfortunatelly gcc is buggy and prints warnings
for nearly all tst_test initializations in the LTP tree, there is an
upstream gcc bug for that that haven't been worked on for quite some
time now. But that is not a reason to work around compiler bugs here.
> + .test = run,
> + .options = (struct tst_option[]) {
> + {"t:", &str_timeout, "Seconds for tiemout (default 60)"},
> + {}
> + },
> + .tags = (const struct tst_tag[]) {
> + {"linux-git", "4396a731 "},
> + {},
> + },
> +};
> --
> 2.27.0
>
--
Cyril Hrubis
chrubis@suse.cz
More information about the ltp
mailing list