diff mbox series

[1/2] kernel/fs/fs-notify: fsnotify stress tests

Message ID 20220125024718.jszwoussimqk6trf@xzhoux.usersys.redhat.com
State Changes Requested
Headers show
Series [1/2] kernel/fs/fs-notify: fsnotify stress tests | expand

Commit Message

Murphy Zhou Jan. 25, 2022, 2:47 a.m. UTC
Exercise fsnotify and inotify interfaces while IO going on.

Signed-off-by: Murphy Zhou <jencce.kernel@gmail.com>
---
 testcases/kernel/fs/fs-notify/Makefile        |  18 ++
 .../fs/fs-notify/fanotify_flush_stress.c      |  52 ++++
 .../fs/fs-notify/fanotify_init_stress.c       |  32 +++
 .../fs/fs-notify/fanotify_mark_stress.c       |  58 +++++
 .../kernel/fs/fs-notify/fanotify_watch.c      | 244 ++++++++++++++++++
 testcases/kernel/fs/fs-notify/freadfile.c     |  27 ++
 .../kernel/fs/fs-notify/fsnotify-stress.sh    |  64 +++++
 testcases/kernel/fs/fs-notify/fwritefile.c    |  27 ++
 .../fs/fs-notify/inotify_add_rm_stress.c      |  36 +++
 .../kernel/fs/fs-notify/inotify_init_stress.c |  22 ++
 .../fs/fs-notify/inotify_inmodify_stress.c    |  17 ++
 testcases/kernel/fs/fs-notify/inotify_watch.c |  98 +++++++
 testcases/kernel/fs/fs-notify/readfile.c      |  28 ++
 testcases/kernel/fs/fs-notify/rw_files.sh     |  90 +++++++
 testcases/kernel/fs/fs-notify/writefile.c     |  28 ++
 15 files changed, 841 insertions(+)
 create mode 100644 testcases/kernel/fs/fs-notify/Makefile
 create mode 100644 testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
 create mode 100644 testcases/kernel/fs/fs-notify/fanotify_init_stress.c
 create mode 100644 testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
 create mode 100644 testcases/kernel/fs/fs-notify/fanotify_watch.c
 create mode 100644 testcases/kernel/fs/fs-notify/freadfile.c
 create mode 100755 testcases/kernel/fs/fs-notify/fsnotify-stress.sh
 create mode 100644 testcases/kernel/fs/fs-notify/fwritefile.c
 create mode 100644 testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c
 create mode 100644 testcases/kernel/fs/fs-notify/inotify_init_stress.c
 create mode 100644 testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c
 create mode 100644 testcases/kernel/fs/fs-notify/inotify_watch.c
 create mode 100644 testcases/kernel/fs/fs-notify/readfile.c
 create mode 100755 testcases/kernel/fs/fs-notify/rw_files.sh
 create mode 100644 testcases/kernel/fs/fs-notify/writefile.c

Comments

Amir Goldstein Jan. 25, 2022, 7:29 a.m. UTC | #1
On Tue, Jan 25, 2022 at 4:47 AM Murphy Zhou <jencce.kernel@gmail.com> wrote:
>
> Exercise fsnotify and inotify interfaces while IO going on.

Hi Murphy,

It's worth documenting in main test script that this test
was created as a regression test for commit
4396a73115fc fsnotify: fix sb_connectors leak

Can you elaborate a bit more about the expectation from this test.
I do not see any error checking in the main script.
Is any perror supposed to fail the test?
Is its purpose to catch kernel dmesg splats of all sorts?

In your original post you wrote that bug makes the test hang:
https://lore.kernel.org/linux-fsdevel/20210907063338.ycaw6wvhzrfsfdlp@xzhoux.usersys.redhat.com/

If that is the case, better mention this to the LTP maintainers.

Thanks,
Amir.




>
> Signed-off-by: Murphy Zhou <jencce.kernel@gmail.com>
> ---
>  testcases/kernel/fs/fs-notify/Makefile        |  18 ++
>  .../fs/fs-notify/fanotify_flush_stress.c      |  52 ++++
>  .../fs/fs-notify/fanotify_init_stress.c       |  32 +++
>  .../fs/fs-notify/fanotify_mark_stress.c       |  58 +++++
>  .../kernel/fs/fs-notify/fanotify_watch.c      | 244 ++++++++++++++++++
>  testcases/kernel/fs/fs-notify/freadfile.c     |  27 ++
>  .../kernel/fs/fs-notify/fsnotify-stress.sh    |  64 +++++
>  testcases/kernel/fs/fs-notify/fwritefile.c    |  27 ++
>  .../fs/fs-notify/inotify_add_rm_stress.c      |  36 +++
>  .../kernel/fs/fs-notify/inotify_init_stress.c |  22 ++
>  .../fs/fs-notify/inotify_inmodify_stress.c    |  17 ++
>  testcases/kernel/fs/fs-notify/inotify_watch.c |  98 +++++++
>  testcases/kernel/fs/fs-notify/readfile.c      |  28 ++
>  testcases/kernel/fs/fs-notify/rw_files.sh     |  90 +++++++
>  testcases/kernel/fs/fs-notify/writefile.c     |  28 ++
>  15 files changed, 841 insertions(+)
>  create mode 100644 testcases/kernel/fs/fs-notify/Makefile
>  create mode 100644 testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
>  create mode 100644 testcases/kernel/fs/fs-notify/fanotify_init_stress.c
>  create mode 100644 testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
>  create mode 100644 testcases/kernel/fs/fs-notify/fanotify_watch.c
>  create mode 100644 testcases/kernel/fs/fs-notify/freadfile.c
>  create mode 100755 testcases/kernel/fs/fs-notify/fsnotify-stress.sh
>  create mode 100644 testcases/kernel/fs/fs-notify/fwritefile.c
>  create mode 100644 testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c
>  create mode 100644 testcases/kernel/fs/fs-notify/inotify_init_stress.c
>  create mode 100644 testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c
>  create mode 100644 testcases/kernel/fs/fs-notify/inotify_watch.c
>  create mode 100644 testcases/kernel/fs/fs-notify/readfile.c
>  create mode 100755 testcases/kernel/fs/fs-notify/rw_files.sh
>  create mode 100644 testcases/kernel/fs/fs-notify/writefile.c
>
> diff --git a/testcases/kernel/fs/fs-notify/Makefile b/testcases/kernel/fs/fs-notify/Makefile
> new file mode 100644
> index 000000000..328783942
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/Makefile
> @@ -0,0 +1,18 @@
> +#
> +#    kernel/fs/fs-notify testcases Makefile.
> +#
> +
> +top_srcdir                     ?= ../../../..
> +
> +include $(top_srcdir)/include/mk/testcases.mk
> +
> +BINARIES:=fanotify_flush_stress fanotify_init_stress \
> +fanotify_mark_stress fanotify_watch inotify_watch \
> +inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress\
> +writefile freadfile fwritefile readfile
> +
> +INSTALL_TARGETS                        := fsnotify-stress.sh $(BINARIES) rw_files.sh
> +
> +MAKE_TARGETS                   := $(BINARIES)
> +
> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> new file mode 100644
> index 000000000..493acfb56
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> @@ -0,0 +1,52 @@
> +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <limits.h>
> +#include <poll.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/fanotify.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +int main(int argc, char *argv[])
> +{
> +       char buf;
> +       int fd;
> +
> +       /* Create the file descriptor for accessing the fanotify API */
> +       fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> +                                          O_RDONLY | O_LARGEFILE);
> +       if (fd == -1) {
> +               perror("fanotify_init");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       /* Loop marking all kinds of events and flush */
> +       while (1) {
> +
> +               if (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, argv[1]) == -1)
> +
> +                       perror("fanotify_mark add");
> +
> +               if (fanotify_mark(fd, FAN_MARK_FLUSH | FAN_MARK_MOUNT,
> +                                               0, -1, argv[1]) == -1)
> +                       perror("fanotify_mark flush mount");
> +
> +               if (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, argv[1]) == -1)
> +
> +                       perror("fanotify_mark add");
> +
> +               if (fanotify_mark(fd, FAN_MARK_FLUSH, 0, -1, argv[1]) == -1)
> +                       perror("fanotify_mark flush");
> +       }
> +
> +       close(fd);
> +       exit(EXIT_SUCCESS);
> +}
> diff --git a/testcases/kernel/fs/fs-notify/fanotify_init_stress.c b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> new file mode 100644
> index 000000000..d11924b57
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> @@ -0,0 +1,32 @@
> +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> +#include <errno.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <sys/fanotify.h>
> +
> +int main(int argc, char *argv[])
> +{
> +       char buf;
> +       int fd;
> +       while (1) {
> +
> +               /* Create the file descriptor for accessing the fanotify API */
> +               fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT |
> +                               FAN_NONBLOCK, O_RDONLY | O_LARGEFILE);
> +               if (fd == -1)
> +                       perror("fanotify_init");
> +
> +               if (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,
> +                               argv[1]) == -1)
> +                       perror("fanotify_mark");
> +
> +               close(fd);
> +       }
> +
> +       exit(EXIT_SUCCESS);
> +}
> diff --git a/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> new file mode 100644
> index 000000000..7f648e103
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> @@ -0,0 +1,58 @@
> +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <limits.h>
> +#include <poll.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/fanotify.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +void add_mark(int fd, uint64_t mask, char *path)
> +{
> +       if (fanotify_mark(fd, FAN_MARK_ADD, mask, -1, path) == -1)
> +               perror("fanotify_mark add");
> +}
> +
> +void remove_mark(int fd, uint64_t mask, char *path)
> +{
> +       if (fanotify_mark(fd, FAN_MARK_REMOVE, mask, -1, path) == -1)
> +               perror("fanotify_mark remove");
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +       char buf;
> +       int fd;
> +       /* Create the file descriptor for accessing the fanotify API */
> +       fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> +                                          O_RDONLY | O_LARGEFILE);
> +       if (fd == -1) {
> +               perror("fanotify_init");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       /* Loop marking all kinds of events */
> +       while (1) {
> +               add_mark(fd, FAN_ACCESS, argv[1]);
> +               remove_mark(fd, FAN_ACCESS, argv[1]);
> +               add_mark(fd, FAN_MODIFY, argv[1]);
> +               remove_mark(fd, FAN_MODIFY, argv[1]);
> +               add_mark(fd, FAN_OPEN_PERM, argv[1]);
> +               remove_mark(fd, FAN_OPEN_PERM, argv[1]);
> +               add_mark(fd, FAN_CLOSE, argv[1]);
> +               remove_mark(fd, FAN_CLOSE, argv[1]);
> +               add_mark(fd, FAN_OPEN, argv[1]);
> +               remove_mark(fd, FAN_OPEN, argv[1]);
> +               add_mark(fd, FAN_ACCESS_PERM, argv[1]);
> +               remove_mark(fd, FAN_ACCESS_PERM, argv[1]);
> +               add_mark(fd, FAN_ONDIR, argv[1]);
> +               remove_mark(fd, FAN_ONDIR, argv[1]);
> +               add_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
> +               remove_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
> +       }
> +
> +       close(fd);
> +       exit(EXIT_SUCCESS);
> +}
> diff --git a/testcases/kernel/fs/fs-notify/fanotify_watch.c b/testcases/kernel/fs/fs-notify/fanotify_watch.c
> new file mode 100644
> index 000000000..1028e0e30
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/fanotify_watch.c
> @@ -0,0 +1,244 @@
> +/* Example in man 7 fanotify */
> +
> +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <limits.h>
> +#include <poll.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/fanotify.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +/* get comm for pid from /proc/pid/comm */
> +static char * get_comm_pid(unsigned int pid)
> +{
> +       char * proc_name;
> +       char * comm;
> +       int comm_fd, cnt;
> +
> +       proc_name = (char *)malloc(50);
> +       if (proc_name != NULL)
> +               sprintf(proc_name, "/proc/%u/comm\0", pid);
> +       else
> +               return NULL;
> +
> +       comm = (char *)malloc(50);
> +       if (comm != NULL)
> +               memset(comm, 0, 50);
> +       else
> +               return NULL;
> +
> +       comm_fd = open(proc_name, O_RDONLY);
> +       if (comm_fd != -1) {
> +               cnt = read(comm_fd, comm, 50);
> +               if (cnt != -1) {
> +                       comm[cnt] = '\0';
> +                       close(comm_fd);
> +                       return comm;
> +               }
> +               close(comm_fd);
> +       }
> +
> +       return NULL;
> +}
> +
> +/* Read all available fanotify events from the file descriptor 'fd' */
> +
> +static void handle_events(int fd)
> +{
> +       const struct fanotify_event_metadata *metadata;
> +       struct fanotify_event_metadata buf[200];
> +       ssize_t len;
> +       char path[PATH_MAX];
> +       ssize_t path_len;
> +       char procfd_path[PATH_MAX];
> +       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) {
> +                       perror("read");
> +                       exit(EXIT_FAILURE);
> +               }
> +
> +               /* 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)) {
> +
> +                       /* Check that run-time and compile-time structures match */
> +
> +                       if (metadata->vers != FANOTIFY_METADATA_VERSION) {
> +                               fprintf(stderr,
> +                                   "Mismatch of fanotify metadata version.\n");
> +                               exit(EXIT_FAILURE);
> +                       }
> +
> +                       /* 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) {
> +                                       printf("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) {
> +                                       printf("FAN_ACCESS_PERM: ");
> +
> +                                       /* Allow file to be accessed */
> +                                       response.fd = metadata->fd;
> +                                       response.response = FAN_ALLOW;
> +                                       write(fd, &response,
> +                                           sizeof(struct fanotify_response));
> +                               }
> +
> +                               /* Handle closing of writable file event */
> +                               if (metadata->mask & FAN_CLOSE_WRITE)
> +                                       printf("FAN_CLOSE_WRITE: ");
> +
> +                               /* Handle closing of not writable file event */
> +                               if (metadata->mask & FAN_CLOSE_NOWRITE)
> +                                       printf("FAN_CLOSE_NOWRITE: ");
> +
> +                               /* Handle modify file event */
> +                               if (metadata->mask & FAN_MODIFY)
> +                                       printf("FAN_MODIFY: ");
> +
> +                               /* Handle open event */
> +                               if (metadata->mask & FAN_OPEN)
> +                                       printf("FAN_OPEN: ");
> +
> +                               /* Handle access event */
> +                               if (metadata->mask & FAN_ACCESS)
> +                                       printf("FAN_ACCESS: ");
> +
> +                               /* Handle access event */
> +                               if (metadata->mask & FAN_ONDIR)
> +                                       printf("FAN_ONDIR: ");
> +
> +                               /* Handle access event */
> +                               if (metadata->mask & FAN_EVENT_ON_CHILD)
> +                                       printf("FAN_EVENT_ON_CHILD: ");
> +
> +                               /* Retrieve/print the accessed file path*/
> +                               snprintf(procfd_path, sizeof(procfd_path),
> +                                           "/proc/self/fd/%d", metadata->fd);
> +                               path_len = readlink(procfd_path, path,
> +                                           sizeof(path) - 1);
> +                               if (path_len == -1) {
> +                                       perror("readlink");
> +                                       exit(EXIT_FAILURE);
> +                               }
> +
> +                               path[path_len] = '\0';
> +                               printf("File %s.\t\t Comm %s", path,
> +                                       get_comm_pid(metadata->pid));
> +
> +                               /* Close the file descriptor of the event */
> +
> +                               close(metadata->fd);
> +                       }
> +
> +                       /* Advance to next event */
> +                       metadata = FAN_EVENT_NEXT(metadata, len);
> +               }
> +       }
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +       char buf;
> +       int fd, poll_num;
> +       nfds_t nfds;
> +       struct pollfd fds[2];
> +       FILE *f;
> +#if 0
> +       /* Check mount point is supplied */
> +       if (argc != 2) {
> +               fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
> +               exit(EXIT_FAILURE);
> +       }
> +#endif
> +       printf("%s on %s\n", argv[0], argv[1]);
> +       fflush(stdout);
> +       f = freopen("fanotify.log", "w+", stdout);
> +       if (f == NULL) {
> +               perror("freopen");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       /* Create the file descriptor for accessing the fanotify API */
> +       fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> +                                          O_RDONLY | O_LARGEFILE);
> +       if (fd == -1) {
> +               perror("fanotify_init");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       /* Mark the mount for:
> +          - permission events before opening files
> +          - notification events after closing a write-enabled
> +                file descriptor */
> +       if (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, argv[1]) == -1) {
> +
> +               perror("fanotify_mark");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       /* Prepare for polling */
> +       nfds = 1;
> +
> +       /* Fanotify input */
> +       fds[0].fd = fd;
> +       fds[0].events = POLLIN;
> +
> +       /* This is the loop to wait for incoming events */
> +       printf("Listening for events.\n");
> +       while (1) {
> +               poll_num = poll(fds, nfds, -1);
> +               if (poll_num == -1) {
> +                       if (errno == EINTR)     /* Interrupted by a signal */
> +                               continue;           /* Restart poll() */
> +
> +                       perror("poll");         /* Unexpected error */
> +                       exit(EXIT_FAILURE);
> +               }
> +
> +               if (poll_num > 0) {
> +
> +                       if (fds[0].revents & POLLIN) {
> +
> +                               /* Fanotify events are available */
> +                               handle_events(fd);
> +                       }
> +               }
> +       }
> +
> +       fclose(f);
> +       printf("Listening for events stopped.\n");
> +       exit(EXIT_SUCCESS);
> +}
> diff --git a/testcases/kernel/fs/fs-notify/freadfile.c b/testcases/kernel/fs/fs-notify/freadfile.c
> new file mode 100644
> index 000000000..24bf76bcd
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/freadfile.c
> @@ -0,0 +1,27 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +
> +int main(int argc, char **argv)
> +{
> +       int fd;
> +       char buf[BUFSIZ];
> +       FILE *f;
> +
> +       memset(buf, 1, BUFSIZ);
> +       while(1) {
> +               f = fopen(argv[1], "r+");
> +               if (f == NULL) {
> +                       perror("freadfile fopen");
> +                       exit(EXIT_FAILURE);
> +               }
> +               fread(buf, sizeof(char), BUFSIZ, f);
> +               usleep(1);
> +       }
> +       fclose(f);
> +       return 0;
> +}
> diff --git a/testcases/kernel/fs/fs-notify/fsnotify-stress.sh b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> new file mode 100755
> index 000000000..d6fd5482b
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> @@ -0,0 +1,64 @@
> +#!/bin/bash
> +
> +export TIMEOUT=10
> +
> +STRESSES="fanotify_flush_stress fanotify_init_stress \
> +fanotify_mark_stress fanotify_watch inotify_watch \
> +inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress"
> +IO_OPES="writefile freadfile fwritefile readfile"
> +
> +NR_CPUS=$(grep -c processor /proc/cpuinfo)
> +[ $NR_CPUS -lt 4 ] && NR_CPUS=4
> +
> +function cleanup_processes()
> +{
> +       while ps -eo pid,comm | \
> +               grep -q -E "fanotify|inotify|rw_files|readfile|writefile" ; do
> +               killall rw_files.sh $STRESSES $IO_OPES > /dev/null 2>&1
> +               sleep 1
> +       done
> +}
> +
> +function cleanup()
> +{
> +       sleep 3 # waiting possible unfinished processes
> +       cleanup_processes
> +       rm -f $STRESSES $IO_OPES fanotify.log inotify.log tmp
> +       cd /
> +       sync
> +}
> +
> +function run_stress()
> +{
> +       local i j rcnt=0
> +       echo -e "* CPU count: $NR_CPUS"
> +       echo -e "* TIMEOUT for each subcase: $TIMEOUT"
> +
> +       echo -e "* Starting fsnotify stress on directory and regular file"
> +       touch $TMPDIR/testfile
> +       >tmp
> +       for i in $STRESSES $IO_OPES rw_files.sh; do
> +               for j in $STRESSES ; do
> +                       [ "$i" == "$j" ] && continue
> +                       # skip duplicate combinations
> +                       grep -w $j tmp | grep -qw $i && continue
> +                       echo -e "* Starting $i and $j, rcnt $rcnt"
> +                       ./$i $TMPDIR $TIMEOUT > /dev/null 2>&1 &
> +                       ./$i $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
> +                       ./$j $TMPDIR $TIMEOUT > /dev/null 2>&1 &
> +                       ./$j $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
> +                       sleep $TIMEOUT
> +                       cleanup_processes
> +                       echo -e "$i $j" >> tmp
> +                       ((rcnt++))
> +               done
> +       done
> +}
> +
> +trap "cleanup; exit;" 2
> +
> +echo "***** Starting tests *****"
> +run_stress
> +
> +echo -e "\n***** Cleanup fanotify inotify device *****"
> +cleanup
> diff --git a/testcases/kernel/fs/fs-notify/fwritefile.c b/testcases/kernel/fs/fs-notify/fwritefile.c
> new file mode 100644
> index 000000000..a2956d60b
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/fwritefile.c
> @@ -0,0 +1,27 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +
> +int main(int argc, char **argv)
> +{
> +       int fd;
> +       char buf[BUFSIZ];
> +       FILE *f;
> +
> +       memset(buf, 1, BUFSIZ);
> +       while(1) {
> +               f = fopen(argv[1], "w+");
> +               if (f == NULL) {
> +                       perror("fwritefile fopen");
> +                       exit(EXIT_FAILURE);
> +               }
> +               fwrite(buf, sizeof(char), BUFSIZ, f);
> +               usleep(1);
> +       }
> +       fclose(f);
> +       return 0;
> +}
> diff --git a/testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c b/testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c
> new file mode 100644
> index 000000000..e88fc088e
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c
> @@ -0,0 +1,36 @@
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <dirent.h>
> +#include <stdio.h>
> +#include <sys/inotify.h>
> +
> +int main(int argc, char *argv[])
> +{
> +       int notify_fd;
> +       int wd, ret;
> +
> +       notify_fd = inotify_init1(IN_CLOEXEC);
> +       if (notify_fd == -1) {
> +               perror("inotify_init1");
> +               return -1;
> +       }
> +
> +       while (1) {
> +               wd = inotify_add_watch(notify_fd, argv[1],
> +                       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);
> +               if (wd < 0)
> +                       perror("inotify_add_watch");
> +
> +               ret = inotify_rm_watch(notify_fd, wd);
> +               if (ret < 0)
> +                       perror("inotify_rm_watch");
> +       }
> +       close(notify_fd);
> +       return 0;
> +}
> diff --git a/testcases/kernel/fs/fs-notify/inotify_init_stress.c b/testcases/kernel/fs/fs-notify/inotify_init_stress.c
> new file mode 100644
> index 000000000..62cb7c2e6
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/inotify_init_stress.c
> @@ -0,0 +1,22 @@
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <dirent.h>
> +#include <stdio.h>
> +#include <sys/inotify.h>
> +
> +int main(int argc, char *argv[])
> +{
> +       int notify_fd;
> +       int wd;
> +
> +       while (1) {
> +               notify_fd = inotify_init1(IN_CLOEXEC);
> +               if (notify_fd == -1)
> +                       perror("inotify_init1");
> +               close(notify_fd);
> +       }
> +       return 0;
> +}
> diff --git a/testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c b/testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c
> new file mode 100644
> index 000000000..546ccb76f
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c
> @@ -0,0 +1,17 @@
> +#include <sys/inotify.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +
> +/*
> + * Calls inotify_rm_watch in a loop.
> + */
> +int main(int argc, char **argv)
> +{
> +       int fd = inotify_init();
> +       while (1) {
> +               int wd = inotify_add_watch(fd, argv[1], IN_MODIFY);
> +               inotify_rm_watch(fd, wd);
> +       }
> +       close(fd);
> +       return 0;
> +}
> diff --git a/testcases/kernel/fs/fs-notify/inotify_watch.c b/testcases/kernel/fs/fs-notify/inotify_watch.c
> new file mode 100644
> index 000000000..b4b908b6b
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/inotify_watch.c
> @@ -0,0 +1,98 @@
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <dirent.h>
> +#include <stdio.h>
> +#include <sys/inotify.h>
> +
> +int main(int argc, char *argv[])
> +{
> +       int notify_fd;
> +       int wd, ret;
> +       char *buf;
> +       FILE *f;
> +
> +       f = freopen("inotify.log", "w+", stdout);
> +       if (f == NULL) {
> +               perror("freopen");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       buf = malloc(sizeof(struct inotify_event) + NAME_MAX + 1);
> +       if (buf == NULL) {
> +               perror("malloc");
> +               return -1;
> +       }
> +
> +       notify_fd = inotify_init1(IN_CLOEXEC);
> +       if (notify_fd == -1) {
> +               perror("inotify_init1");
> +               return -1;
> +       }
> +
> +       wd = inotify_add_watch(notify_fd, argv[1],
> +               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);
> +
> +       if (wd < 0) {
> +               perror("inotify_add_watch");
> +               return -1;
> +       }
> +
> +       while (ret = read(notify_fd, buf, NAME_MAX) != -1) {
> +               struct inotify_event *ip = (struct inotify_event *)buf;
> +               printf("name %s event ", ip->name);
> +               switch (ip->mask) {
> +               case IN_ACCESS:
> +                       printf("access\n");
> +                       break;
> +               case IN_ATTRIB:
> +                       printf("attrib\n");
> +                       break;
> +               case IN_CLOSE_WRITE:
> +                       printf("close write\n");
> +                       break;
> +               case IN_CLOSE_NOWRITE:
> +                       printf("close nowrite\n");
> +                       break;
> +               case IN_CREATE:
> +                       printf("create\n");
> +                       break;
> +               case IN_DELETE:
> +                       printf("delete\n");
> +                       break;
> +               case IN_DELETE_SELF:
> +                       printf("deleteself\n");
> +                       break;
> +               case IN_MODIFY:
> +                       printf("modify\n");
> +                       break;
> +               case IN_MOVE_SELF:
> +                       printf("move self\n");
> +                       break;
> +               case IN_MOVED_FROM:
> +                       printf("move from\n");
> +                       break;
> +               case IN_MOVED_TO:
> +                       printf("move to\n");
> +                       break;
> +               case IN_OPEN:
> +                       printf("open\n");
> +                       break;
> +               default:
> +                       printf("\n");
> +                       break;
> +               };
> +       }
> +
> +       ret = inotify_rm_watch(notify_fd, wd);
> +       if (ret < 0)
> +               perror("inotify_rm_watch");
> +
> +       fclose(f);
> +       close(notify_fd);
> +       return 0;
> +}
> diff --git a/testcases/kernel/fs/fs-notify/readfile.c b/testcases/kernel/fs/fs-notify/readfile.c
> new file mode 100644
> index 000000000..2ab1a3694
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/readfile.c
> @@ -0,0 +1,28 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +
> +int main(int argc, char **argv)
> +{
> +       int fd, ret;
> +       char buf[BUFSIZ];
> +
> +       memset(buf, 1, BUFSIZ);
> +       while (1) {
> +               fd = open(argv[1], O_RDWR);
> +               if (fd == -1) {
> +                       perror("readfile open");
> +                       exit(EXIT_FAILURE);
> +               }
> +               ret = read(fd, buf, BUFSIZ);
> +               if (ret == -1)
> +                       perror("readfile read");
> +               usleep(1);
> +       }
> +       close(fd);
> +       return 0;
> +}
> diff --git a/testcases/kernel/fs/fs-notify/rw_files.sh b/testcases/kernel/fs/fs-notify/rw_files.sh
> new file mode 100755
> index 000000000..bb3387160
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/rw_files.sh
> @@ -0,0 +1,90 @@
> +#!/bin/bash
> +
> +TDIR=$1
> +TIMEO=$2
> +
> +[ -z "$TDIR" ] && TDIR=/tmp/
> +[ -d $TDIR ] || TDIR=/tmp/
> +[ -z "$TIMEO" ] && TIMEO=1m
> +
> +[ ! -d $TDIR ] && exit
> +
> +function add_files()
> +{
> +       local i=0
> +
> +       while true ; do
> +
> +               touch f-$i
> +               ln -s f-$i f-$i-sym
> +               ln f-$i f-$i-hdl
> +
> +               mkdir d-$i
> +
> +               mknod c-$i c 1 2
> +               mknod b-$i b 1 2
> +               mknod p-$i p
> +
> +               ((i++))
> +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> +       done
> +}
> +
> +function mv_files()
> +{
> +       local i=0
> +
> +       while true ; do
> +
> +               mv -f f-$i f-$i-rename
> +               mv -f f-$i-rename f-$i
> +               ((i++))
> +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> +       done
> +}
> +
> +function read_files()
> +{
> +       while true ; do
> +
> +               find .
> +               cat f-*
> +               ls d-*
> +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> +       done
> +}
> +
> +function write_files()
> +{
> +       while true ; do
> +
> +               for j in f-* d-* c-* b-* p-* ; do
> +                       echo 1 > $j
> +                       echo 2 >> $j
> +                       [ -e stoptest ] && { echo $FUNCNAME; exit; }
> +               done
> +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> +       done
> +}
> +
> +function rm_files()
> +{
> +       while true ; do
> +
> +               rm -rf d-* f-* c-* b-* p-*
> +               sleep 3
> +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> +       done
> +}
> +
> +pushd $TDIR > /dev/null 2>&1
> +rm -f stoptest
> +add_files > /dev/null 2>&1 &
> +mv_files > /dev/null 2>&1 &
> +read_files > /dev/null 2>&1 &
> +write_files > /dev/null 2>&1 &
> +rm_files > /dev/null 2>&1 &
> +popd > /dev/null 2>&1
> +
> +sleep $TIMEO
> +touch $TDIR/stoptest
> diff --git a/testcases/kernel/fs/fs-notify/writefile.c b/testcases/kernel/fs/fs-notify/writefile.c
> new file mode 100644
> index 000000000..9025b5d95
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/writefile.c
> @@ -0,0 +1,28 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +
> +int main(int argc, char **argv)
> +{
> +       int fd, ret;
> +       char buf[BUFSIZ];
> +
> +       memset(buf, 1, BUFSIZ);
> +       while (1) {
> +               fd = open(argv[1], O_RDWR);
> +               if (fd == -1) {
> +                       perror("writefile open");
> +                       exit(EXIT_FAILURE);
> +               }
> +               ret = write(fd, buf, BUFSIZ);
> +               if (ret == -1)
> +                       perror("writefile write");
> +               usleep(1);
> +       }
> +       close(fd);
> +       return 0;
> +}
> --
> 2.31.1
>
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
Murphy Zhou Jan. 25, 2022, 8:30 a.m. UTC | #2
Hi Amir,

On Tue, Jan 25, 2022 at 09:29:47AM +0200, Amir Goldstein wrote:
> On Tue, Jan 25, 2022 at 4:47 AM Murphy Zhou <jencce.kernel@gmail.com> wrote:
> >
> > Exercise fsnotify and inotify interfaces while IO going on.
> 
> Hi Murphy,
> 
> It's worth documenting in main test script that this test
> was created as a regression test for commit
> 4396a73115fc fsnotify: fix sb_connectors leak

Ah, the tests were created for the goal of stress test. This leak
was one of the bugs that this test found.

> 
> Can you elaborate a bit more about the expectation from this test.
> I do not see any error checking in the main script.

Sure. Will explain more.

> Is any perror supposed to fail the test?

No.

> Is its purpose to catch kernel dmesg splats of all sorts?

Not needed.

My intend is to use these interfaces insanely a while, if kernel 
does not panic or hang, pass. This test is not checking *notify
function which has already been covered.

> 
> In your original post you wrote that bug makes the test hang:
> https://lore.kernel.org/linux-fsdevel/20210907063338.ycaw6wvhzrfsfdlp@xzhoux.usersys.redhat.com/
> 
> If that is the case, better mention this to the LTP maintainers.

Sure. Thanks for reviewing!

Murphy
> 
> Thanks,
> Amir.
> 
> 
> 
> 
> >
> > Signed-off-by: Murphy Zhou <jencce.kernel@gmail.com>
> > ---
> >  testcases/kernel/fs/fs-notify/Makefile        |  18 ++
> >  .../fs/fs-notify/fanotify_flush_stress.c      |  52 ++++
> >  .../fs/fs-notify/fanotify_init_stress.c       |  32 +++
> >  .../fs/fs-notify/fanotify_mark_stress.c       |  58 +++++
> >  .../kernel/fs/fs-notify/fanotify_watch.c      | 244 ++++++++++++++++++
> >  testcases/kernel/fs/fs-notify/freadfile.c     |  27 ++
> >  .../kernel/fs/fs-notify/fsnotify-stress.sh    |  64 +++++
> >  testcases/kernel/fs/fs-notify/fwritefile.c    |  27 ++
> >  .../fs/fs-notify/inotify_add_rm_stress.c      |  36 +++
> >  .../kernel/fs/fs-notify/inotify_init_stress.c |  22 ++
> >  .../fs/fs-notify/inotify_inmodify_stress.c    |  17 ++
> >  testcases/kernel/fs/fs-notify/inotify_watch.c |  98 +++++++
> >  testcases/kernel/fs/fs-notify/readfile.c      |  28 ++
> >  testcases/kernel/fs/fs-notify/rw_files.sh     |  90 +++++++
> >  testcases/kernel/fs/fs-notify/writefile.c     |  28 ++
> >  15 files changed, 841 insertions(+)
> >  create mode 100644 testcases/kernel/fs/fs-notify/Makefile
> >  create mode 100644 testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> >  create mode 100644 testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> >  create mode 100644 testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> >  create mode 100644 testcases/kernel/fs/fs-notify/fanotify_watch.c
> >  create mode 100644 testcases/kernel/fs/fs-notify/freadfile.c
> >  create mode 100755 testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> >  create mode 100644 testcases/kernel/fs/fs-notify/fwritefile.c
> >  create mode 100644 testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c
> >  create mode 100644 testcases/kernel/fs/fs-notify/inotify_init_stress.c
> >  create mode 100644 testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c
> >  create mode 100644 testcases/kernel/fs/fs-notify/inotify_watch.c
> >  create mode 100644 testcases/kernel/fs/fs-notify/readfile.c
> >  create mode 100755 testcases/kernel/fs/fs-notify/rw_files.sh
> >  create mode 100644 testcases/kernel/fs/fs-notify/writefile.c
> >
> > diff --git a/testcases/kernel/fs/fs-notify/Makefile b/testcases/kernel/fs/fs-notify/Makefile
> > new file mode 100644
> > index 000000000..328783942
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/Makefile
> > @@ -0,0 +1,18 @@
> > +#
> > +#    kernel/fs/fs-notify testcases Makefile.
> > +#
> > +
> > +top_srcdir                     ?= ../../../..
> > +
> > +include $(top_srcdir)/include/mk/testcases.mk
> > +
> > +BINARIES:=fanotify_flush_stress fanotify_init_stress \
> > +fanotify_mark_stress fanotify_watch inotify_watch \
> > +inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress\
> > +writefile freadfile fwritefile readfile
> > +
> > +INSTALL_TARGETS                        := fsnotify-stress.sh $(BINARIES) rw_files.sh
> > +
> > +MAKE_TARGETS                   := $(BINARIES)
> > +
> > +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> > diff --git a/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> > new file mode 100644
> > index 000000000..493acfb56
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> > @@ -0,0 +1,52 @@
> > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <limits.h>
> > +#include <poll.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <sys/fanotify.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +       char buf;
> > +       int fd;
> > +
> > +       /* Create the file descriptor for accessing the fanotify API */
> > +       fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> > +                                          O_RDONLY | O_LARGEFILE);
> > +       if (fd == -1) {
> > +               perror("fanotify_init");
> > +               exit(EXIT_FAILURE);
> > +       }
> > +
> > +       /* Loop marking all kinds of events and flush */
> > +       while (1) {
> > +
> > +               if (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, argv[1]) == -1)
> > +
> > +                       perror("fanotify_mark add");
> > +
> > +               if (fanotify_mark(fd, FAN_MARK_FLUSH | FAN_MARK_MOUNT,
> > +                                               0, -1, argv[1]) == -1)
> > +                       perror("fanotify_mark flush mount");
> > +
> > +               if (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, argv[1]) == -1)
> > +
> > +                       perror("fanotify_mark add");
> > +
> > +               if (fanotify_mark(fd, FAN_MARK_FLUSH, 0, -1, argv[1]) == -1)
> > +                       perror("fanotify_mark flush");
> > +       }
> > +
> > +       close(fd);
> > +       exit(EXIT_SUCCESS);
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/fanotify_init_stress.c b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> > new file mode 100644
> > index 000000000..d11924b57
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> > @@ -0,0 +1,32 @@
> > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > +#include <errno.h>
> > +#include <stdio.h>
> > +#include <unistd.h>
> > +#include <fcntl.h>
> > +#include <stdlib.h>
> > +#include <sys/fanotify.h>
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +       char buf;
> > +       int fd;
> > +       while (1) {
> > +
> > +               /* Create the file descriptor for accessing the fanotify API */
> > +               fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT |
> > +                               FAN_NONBLOCK, O_RDONLY | O_LARGEFILE);
> > +               if (fd == -1)
> > +                       perror("fanotify_init");
> > +
> > +               if (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,
> > +                               argv[1]) == -1)
> > +                       perror("fanotify_mark");
> > +
> > +               close(fd);
> > +       }
> > +
> > +       exit(EXIT_SUCCESS);
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> > new file mode 100644
> > index 000000000..7f648e103
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> > @@ -0,0 +1,58 @@
> > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <limits.h>
> > +#include <poll.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <sys/fanotify.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +
> > +void add_mark(int fd, uint64_t mask, char *path)
> > +{
> > +       if (fanotify_mark(fd, FAN_MARK_ADD, mask, -1, path) == -1)
> > +               perror("fanotify_mark add");
> > +}
> > +
> > +void remove_mark(int fd, uint64_t mask, char *path)
> > +{
> > +       if (fanotify_mark(fd, FAN_MARK_REMOVE, mask, -1, path) == -1)
> > +               perror("fanotify_mark remove");
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +       char buf;
> > +       int fd;
> > +       /* Create the file descriptor for accessing the fanotify API */
> > +       fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> > +                                          O_RDONLY | O_LARGEFILE);
> > +       if (fd == -1) {
> > +               perror("fanotify_init");
> > +               exit(EXIT_FAILURE);
> > +       }
> > +
> > +       /* Loop marking all kinds of events */
> > +       while (1) {
> > +               add_mark(fd, FAN_ACCESS, argv[1]);
> > +               remove_mark(fd, FAN_ACCESS, argv[1]);
> > +               add_mark(fd, FAN_MODIFY, argv[1]);
> > +               remove_mark(fd, FAN_MODIFY, argv[1]);
> > +               add_mark(fd, FAN_OPEN_PERM, argv[1]);
> > +               remove_mark(fd, FAN_OPEN_PERM, argv[1]);
> > +               add_mark(fd, FAN_CLOSE, argv[1]);
> > +               remove_mark(fd, FAN_CLOSE, argv[1]);
> > +               add_mark(fd, FAN_OPEN, argv[1]);
> > +               remove_mark(fd, FAN_OPEN, argv[1]);
> > +               add_mark(fd, FAN_ACCESS_PERM, argv[1]);
> > +               remove_mark(fd, FAN_ACCESS_PERM, argv[1]);
> > +               add_mark(fd, FAN_ONDIR, argv[1]);
> > +               remove_mark(fd, FAN_ONDIR, argv[1]);
> > +               add_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
> > +               remove_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
> > +       }
> > +
> > +       close(fd);
> > +       exit(EXIT_SUCCESS);
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/fanotify_watch.c b/testcases/kernel/fs/fs-notify/fanotify_watch.c
> > new file mode 100644
> > index 000000000..1028e0e30
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fanotify_watch.c
> > @@ -0,0 +1,244 @@
> > +/* Example in man 7 fanotify */
> > +
> > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <limits.h>
> > +#include <poll.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <sys/fanotify.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +
> > +/* get comm for pid from /proc/pid/comm */
> > +static char * get_comm_pid(unsigned int pid)
> > +{
> > +       char * proc_name;
> > +       char * comm;
> > +       int comm_fd, cnt;
> > +
> > +       proc_name = (char *)malloc(50);
> > +       if (proc_name != NULL)
> > +               sprintf(proc_name, "/proc/%u/comm\0", pid);
> > +       else
> > +               return NULL;
> > +
> > +       comm = (char *)malloc(50);
> > +       if (comm != NULL)
> > +               memset(comm, 0, 50);
> > +       else
> > +               return NULL;
> > +
> > +       comm_fd = open(proc_name, O_RDONLY);
> > +       if (comm_fd != -1) {
> > +               cnt = read(comm_fd, comm, 50);
> > +               if (cnt != -1) {
> > +                       comm[cnt] = '\0';
> > +                       close(comm_fd);
> > +                       return comm;
> > +               }
> > +               close(comm_fd);
> > +       }
> > +
> > +       return NULL;
> > +}
> > +
> > +/* Read all available fanotify events from the file descriptor 'fd' */
> > +
> > +static void handle_events(int fd)
> > +{
> > +       const struct fanotify_event_metadata *metadata;
> > +       struct fanotify_event_metadata buf[200];
> > +       ssize_t len;
> > +       char path[PATH_MAX];
> > +       ssize_t path_len;
> > +       char procfd_path[PATH_MAX];
> > +       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) {
> > +                       perror("read");
> > +                       exit(EXIT_FAILURE);
> > +               }
> > +
> > +               /* 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)) {
> > +
> > +                       /* Check that run-time and compile-time structures match */
> > +
> > +                       if (metadata->vers != FANOTIFY_METADATA_VERSION) {
> > +                               fprintf(stderr,
> > +                                   "Mismatch of fanotify metadata version.\n");
> > +                               exit(EXIT_FAILURE);
> > +                       }
> > +
> > +                       /* 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) {
> > +                                       printf("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) {
> > +                                       printf("FAN_ACCESS_PERM: ");
> > +
> > +                                       /* Allow file to be accessed */
> > +                                       response.fd = metadata->fd;
> > +                                       response.response = FAN_ALLOW;
> > +                                       write(fd, &response,
> > +                                           sizeof(struct fanotify_response));
> > +                               }
> > +
> > +                               /* Handle closing of writable file event */
> > +                               if (metadata->mask & FAN_CLOSE_WRITE)
> > +                                       printf("FAN_CLOSE_WRITE: ");
> > +
> > +                               /* Handle closing of not writable file event */
> > +                               if (metadata->mask & FAN_CLOSE_NOWRITE)
> > +                                       printf("FAN_CLOSE_NOWRITE: ");
> > +
> > +                               /* Handle modify file event */
> > +                               if (metadata->mask & FAN_MODIFY)
> > +                                       printf("FAN_MODIFY: ");
> > +
> > +                               /* Handle open event */
> > +                               if (metadata->mask & FAN_OPEN)
> > +                                       printf("FAN_OPEN: ");
> > +
> > +                               /* Handle access event */
> > +                               if (metadata->mask & FAN_ACCESS)
> > +                                       printf("FAN_ACCESS: ");
> > +
> > +                               /* Handle access event */
> > +                               if (metadata->mask & FAN_ONDIR)
> > +                                       printf("FAN_ONDIR: ");
> > +
> > +                               /* Handle access event */
> > +                               if (metadata->mask & FAN_EVENT_ON_CHILD)
> > +                                       printf("FAN_EVENT_ON_CHILD: ");
> > +
> > +                               /* Retrieve/print the accessed file path*/
> > +                               snprintf(procfd_path, sizeof(procfd_path),
> > +                                           "/proc/self/fd/%d", metadata->fd);
> > +                               path_len = readlink(procfd_path, path,
> > +                                           sizeof(path) - 1);
> > +                               if (path_len == -1) {
> > +                                       perror("readlink");
> > +                                       exit(EXIT_FAILURE);
> > +                               }
> > +
> > +                               path[path_len] = '\0';
> > +                               printf("File %s.\t\t Comm %s", path,
> > +                                       get_comm_pid(metadata->pid));
> > +
> > +                               /* Close the file descriptor of the event */
> > +
> > +                               close(metadata->fd);
> > +                       }
> > +
> > +                       /* Advance to next event */
> > +                       metadata = FAN_EVENT_NEXT(metadata, len);
> > +               }
> > +       }
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +       char buf;
> > +       int fd, poll_num;
> > +       nfds_t nfds;
> > +       struct pollfd fds[2];
> > +       FILE *f;
> > +#if 0
> > +       /* Check mount point is supplied */
> > +       if (argc != 2) {
> > +               fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
> > +               exit(EXIT_FAILURE);
> > +       }
> > +#endif
> > +       printf("%s on %s\n", argv[0], argv[1]);
> > +       fflush(stdout);
> > +       f = freopen("fanotify.log", "w+", stdout);
> > +       if (f == NULL) {
> > +               perror("freopen");
> > +               exit(EXIT_FAILURE);
> > +       }
> > +
> > +       /* Create the file descriptor for accessing the fanotify API */
> > +       fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> > +                                          O_RDONLY | O_LARGEFILE);
> > +       if (fd == -1) {
> > +               perror("fanotify_init");
> > +               exit(EXIT_FAILURE);
> > +       }
> > +
> > +       /* Mark the mount for:
> > +          - permission events before opening files
> > +          - notification events after closing a write-enabled
> > +                file descriptor */
> > +       if (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, argv[1]) == -1) {
> > +
> > +               perror("fanotify_mark");
> > +               exit(EXIT_FAILURE);
> > +       }
> > +
> > +       /* Prepare for polling */
> > +       nfds = 1;
> > +
> > +       /* Fanotify input */
> > +       fds[0].fd = fd;
> > +       fds[0].events = POLLIN;
> > +
> > +       /* This is the loop to wait for incoming events */
> > +       printf("Listening for events.\n");
> > +       while (1) {
> > +               poll_num = poll(fds, nfds, -1);
> > +               if (poll_num == -1) {
> > +                       if (errno == EINTR)     /* Interrupted by a signal */
> > +                               continue;           /* Restart poll() */
> > +
> > +                       perror("poll");         /* Unexpected error */
> > +                       exit(EXIT_FAILURE);
> > +               }
> > +
> > +               if (poll_num > 0) {
> > +
> > +                       if (fds[0].revents & POLLIN) {
> > +
> > +                               /* Fanotify events are available */
> > +                               handle_events(fd);
> > +                       }
> > +               }
> > +       }
> > +
> > +       fclose(f);
> > +       printf("Listening for events stopped.\n");
> > +       exit(EXIT_SUCCESS);
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/freadfile.c b/testcases/kernel/fs/fs-notify/freadfile.c
> > new file mode 100644
> > index 000000000..24bf76bcd
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/freadfile.c
> > @@ -0,0 +1,27 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +
> > +int main(int argc, char **argv)
> > +{
> > +       int fd;
> > +       char buf[BUFSIZ];
> > +       FILE *f;
> > +
> > +       memset(buf, 1, BUFSIZ);
> > +       while(1) {
> > +               f = fopen(argv[1], "r+");
> > +               if (f == NULL) {
> > +                       perror("freadfile fopen");
> > +                       exit(EXIT_FAILURE);
> > +               }
> > +               fread(buf, sizeof(char), BUFSIZ, f);
> > +               usleep(1);
> > +       }
> > +       fclose(f);
> > +       return 0;
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/fsnotify-stress.sh b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> > new file mode 100755
> > index 000000000..d6fd5482b
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> > @@ -0,0 +1,64 @@
> > +#!/bin/bash
> > +
> > +export TIMEOUT=10
> > +
> > +STRESSES="fanotify_flush_stress fanotify_init_stress \
> > +fanotify_mark_stress fanotify_watch inotify_watch \
> > +inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress"
> > +IO_OPES="writefile freadfile fwritefile readfile"
> > +
> > +NR_CPUS=$(grep -c processor /proc/cpuinfo)
> > +[ $NR_CPUS -lt 4 ] && NR_CPUS=4
> > +
> > +function cleanup_processes()
> > +{
> > +       while ps -eo pid,comm | \
> > +               grep -q -E "fanotify|inotify|rw_files|readfile|writefile" ; do
> > +               killall rw_files.sh $STRESSES $IO_OPES > /dev/null 2>&1
> > +               sleep 1
> > +       done
> > +}
> > +
> > +function cleanup()
> > +{
> > +       sleep 3 # waiting possible unfinished processes
> > +       cleanup_processes
> > +       rm -f $STRESSES $IO_OPES fanotify.log inotify.log tmp
> > +       cd /
> > +       sync
> > +}
> > +
> > +function run_stress()
> > +{
> > +       local i j rcnt=0
> > +       echo -e "* CPU count: $NR_CPUS"
> > +       echo -e "* TIMEOUT for each subcase: $TIMEOUT"
> > +
> > +       echo -e "* Starting fsnotify stress on directory and regular file"
> > +       touch $TMPDIR/testfile
> > +       >tmp
> > +       for i in $STRESSES $IO_OPES rw_files.sh; do
> > +               for j in $STRESSES ; do
> > +                       [ "$i" == "$j" ] && continue
> > +                       # skip duplicate combinations
> > +                       grep -w $j tmp | grep -qw $i && continue
> > +                       echo -e "* Starting $i and $j, rcnt $rcnt"
> > +                       ./$i $TMPDIR $TIMEOUT > /dev/null 2>&1 &
> > +                       ./$i $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
> > +                       ./$j $TMPDIR $TIMEOUT > /dev/null 2>&1 &
> > +                       ./$j $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
> > +                       sleep $TIMEOUT
> > +                       cleanup_processes
> > +                       echo -e "$i $j" >> tmp
> > +                       ((rcnt++))
> > +               done
> > +       done
> > +}
> > +
> > +trap "cleanup; exit;" 2
> > +
> > +echo "***** Starting tests *****"
> > +run_stress
> > +
> > +echo -e "\n***** Cleanup fanotify inotify device *****"
> > +cleanup
> > diff --git a/testcases/kernel/fs/fs-notify/fwritefile.c b/testcases/kernel/fs/fs-notify/fwritefile.c
> > new file mode 100644
> > index 000000000..a2956d60b
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fwritefile.c
> > @@ -0,0 +1,27 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +
> > +int main(int argc, char **argv)
> > +{
> > +       int fd;
> > +       char buf[BUFSIZ];
> > +       FILE *f;
> > +
> > +       memset(buf, 1, BUFSIZ);
> > +       while(1) {
> > +               f = fopen(argv[1], "w+");
> > +               if (f == NULL) {
> > +                       perror("fwritefile fopen");
> > +                       exit(EXIT_FAILURE);
> > +               }
> > +               fwrite(buf, sizeof(char), BUFSIZ, f);
> > +               usleep(1);
> > +       }
> > +       fclose(f);
> > +       return 0;
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c b/testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c
> > new file mode 100644
> > index 000000000..e88fc088e
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c
> > @@ -0,0 +1,36 @@
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +#include <unistd.h>
> > +#include <stdlib.h>
> > +#include <dirent.h>
> > +#include <stdio.h>
> > +#include <sys/inotify.h>
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +       int notify_fd;
> > +       int wd, ret;
> > +
> > +       notify_fd = inotify_init1(IN_CLOEXEC);
> > +       if (notify_fd == -1) {
> > +               perror("inotify_init1");
> > +               return -1;
> > +       }
> > +
> > +       while (1) {
> > +               wd = inotify_add_watch(notify_fd, argv[1],
> > +                       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);
> > +               if (wd < 0)
> > +                       perror("inotify_add_watch");
> > +
> > +               ret = inotify_rm_watch(notify_fd, wd);
> > +               if (ret < 0)
> > +                       perror("inotify_rm_watch");
> > +       }
> > +       close(notify_fd);
> > +       return 0;
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/inotify_init_stress.c b/testcases/kernel/fs/fs-notify/inotify_init_stress.c
> > new file mode 100644
> > index 000000000..62cb7c2e6
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/inotify_init_stress.c
> > @@ -0,0 +1,22 @@
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +#include <unistd.h>
> > +#include <stdlib.h>
> > +#include <dirent.h>
> > +#include <stdio.h>
> > +#include <sys/inotify.h>
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +       int notify_fd;
> > +       int wd;
> > +
> > +       while (1) {
> > +               notify_fd = inotify_init1(IN_CLOEXEC);
> > +               if (notify_fd == -1)
> > +                       perror("inotify_init1");
> > +               close(notify_fd);
> > +       }
> > +       return 0;
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c b/testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c
> > new file mode 100644
> > index 000000000..546ccb76f
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c
> > @@ -0,0 +1,17 @@
> > +#include <sys/inotify.h>
> > +#include <stdio.h>
> > +#include <unistd.h>
> > +
> > +/*
> > + * Calls inotify_rm_watch in a loop.
> > + */
> > +int main(int argc, char **argv)
> > +{
> > +       int fd = inotify_init();
> > +       while (1) {
> > +               int wd = inotify_add_watch(fd, argv[1], IN_MODIFY);
> > +               inotify_rm_watch(fd, wd);
> > +       }
> > +       close(fd);
> > +       return 0;
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/inotify_watch.c b/testcases/kernel/fs/fs-notify/inotify_watch.c
> > new file mode 100644
> > index 000000000..b4b908b6b
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/inotify_watch.c
> > @@ -0,0 +1,98 @@
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +#include <unistd.h>
> > +#include <stdlib.h>
> > +#include <dirent.h>
> > +#include <stdio.h>
> > +#include <sys/inotify.h>
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +       int notify_fd;
> > +       int wd, ret;
> > +       char *buf;
> > +       FILE *f;
> > +
> > +       f = freopen("inotify.log", "w+", stdout);
> > +       if (f == NULL) {
> > +               perror("freopen");
> > +               exit(EXIT_FAILURE);
> > +       }
> > +
> > +       buf = malloc(sizeof(struct inotify_event) + NAME_MAX + 1);
> > +       if (buf == NULL) {
> > +               perror("malloc");
> > +               return -1;
> > +       }
> > +
> > +       notify_fd = inotify_init1(IN_CLOEXEC);
> > +       if (notify_fd == -1) {
> > +               perror("inotify_init1");
> > +               return -1;
> > +       }
> > +
> > +       wd = inotify_add_watch(notify_fd, argv[1],
> > +               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);
> > +
> > +       if (wd < 0) {
> > +               perror("inotify_add_watch");
> > +               return -1;
> > +       }
> > +
> > +       while (ret = read(notify_fd, buf, NAME_MAX) != -1) {
> > +               struct inotify_event *ip = (struct inotify_event *)buf;
> > +               printf("name %s event ", ip->name);
> > +               switch (ip->mask) {
> > +               case IN_ACCESS:
> > +                       printf("access\n");
> > +                       break;
> > +               case IN_ATTRIB:
> > +                       printf("attrib\n");
> > +                       break;
> > +               case IN_CLOSE_WRITE:
> > +                       printf("close write\n");
> > +                       break;
> > +               case IN_CLOSE_NOWRITE:
> > +                       printf("close nowrite\n");
> > +                       break;
> > +               case IN_CREATE:
> > +                       printf("create\n");
> > +                       break;
> > +               case IN_DELETE:
> > +                       printf("delete\n");
> > +                       break;
> > +               case IN_DELETE_SELF:
> > +                       printf("deleteself\n");
> > +                       break;
> > +               case IN_MODIFY:
> > +                       printf("modify\n");
> > +                       break;
> > +               case IN_MOVE_SELF:
> > +                       printf("move self\n");
> > +                       break;
> > +               case IN_MOVED_FROM:
> > +                       printf("move from\n");
> > +                       break;
> > +               case IN_MOVED_TO:
> > +                       printf("move to\n");
> > +                       break;
> > +               case IN_OPEN:
> > +                       printf("open\n");
> > +                       break;
> > +               default:
> > +                       printf("\n");
> > +                       break;
> > +               };
> > +       }
> > +
> > +       ret = inotify_rm_watch(notify_fd, wd);
> > +       if (ret < 0)
> > +               perror("inotify_rm_watch");
> > +
> > +       fclose(f);
> > +       close(notify_fd);
> > +       return 0;
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/readfile.c b/testcases/kernel/fs/fs-notify/readfile.c
> > new file mode 100644
> > index 000000000..2ab1a3694
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/readfile.c
> > @@ -0,0 +1,28 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +
> > +int main(int argc, char **argv)
> > +{
> > +       int fd, ret;
> > +       char buf[BUFSIZ];
> > +
> > +       memset(buf, 1, BUFSIZ);
> > +       while (1) {
> > +               fd = open(argv[1], O_RDWR);
> > +               if (fd == -1) {
> > +                       perror("readfile open");
> > +                       exit(EXIT_FAILURE);
> > +               }
> > +               ret = read(fd, buf, BUFSIZ);
> > +               if (ret == -1)
> > +                       perror("readfile read");
> > +               usleep(1);
> > +       }
> > +       close(fd);
> > +       return 0;
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/rw_files.sh b/testcases/kernel/fs/fs-notify/rw_files.sh
> > new file mode 100755
> > index 000000000..bb3387160
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/rw_files.sh
> > @@ -0,0 +1,90 @@
> > +#!/bin/bash
> > +
> > +TDIR=$1
> > +TIMEO=$2
> > +
> > +[ -z "$TDIR" ] && TDIR=/tmp/
> > +[ -d $TDIR ] || TDIR=/tmp/
> > +[ -z "$TIMEO" ] && TIMEO=1m
> > +
> > +[ ! -d $TDIR ] && exit
> > +
> > +function add_files()
> > +{
> > +       local i=0
> > +
> > +       while true ; do
> > +
> > +               touch f-$i
> > +               ln -s f-$i f-$i-sym
> > +               ln f-$i f-$i-hdl
> > +
> > +               mkdir d-$i
> > +
> > +               mknod c-$i c 1 2
> > +               mknod b-$i b 1 2
> > +               mknod p-$i p
> > +
> > +               ((i++))
> > +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> > +       done
> > +}
> > +
> > +function mv_files()
> > +{
> > +       local i=0
> > +
> > +       while true ; do
> > +
> > +               mv -f f-$i f-$i-rename
> > +               mv -f f-$i-rename f-$i
> > +               ((i++))
> > +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> > +       done
> > +}
> > +
> > +function read_files()
> > +{
> > +       while true ; do
> > +
> > +               find .
> > +               cat f-*
> > +               ls d-*
> > +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> > +       done
> > +}
> > +
> > +function write_files()
> > +{
> > +       while true ; do
> > +
> > +               for j in f-* d-* c-* b-* p-* ; do
> > +                       echo 1 > $j
> > +                       echo 2 >> $j
> > +                       [ -e stoptest ] && { echo $FUNCNAME; exit; }
> > +               done
> > +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> > +       done
> > +}
> > +
> > +function rm_files()
> > +{
> > +       while true ; do
> > +
> > +               rm -rf d-* f-* c-* b-* p-*
> > +               sleep 3
> > +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> > +       done
> > +}
> > +
> > +pushd $TDIR > /dev/null 2>&1
> > +rm -f stoptest
> > +add_files > /dev/null 2>&1 &
> > +mv_files > /dev/null 2>&1 &
> > +read_files > /dev/null 2>&1 &
> > +write_files > /dev/null 2>&1 &
> > +rm_files > /dev/null 2>&1 &
> > +popd > /dev/null 2>&1
> > +
> > +sleep $TIMEO
> > +touch $TDIR/stoptest
> > diff --git a/testcases/kernel/fs/fs-notify/writefile.c b/testcases/kernel/fs/fs-notify/writefile.c
> > new file mode 100644
> > index 000000000..9025b5d95
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/writefile.c
> > @@ -0,0 +1,28 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +
> > +int main(int argc, char **argv)
> > +{
> > +       int fd, ret;
> > +       char buf[BUFSIZ];
> > +
> > +       memset(buf, 1, BUFSIZ);
> > +       while (1) {
> > +               fd = open(argv[1], O_RDWR);
> > +               if (fd == -1) {
> > +                       perror("writefile open");
> > +                       exit(EXIT_FAILURE);
> > +               }
> > +               ret = write(fd, buf, BUFSIZ);
> > +               if (ret == -1)
> > +                       perror("writefile write");
> > +               usleep(1);
> > +       }
> > +       close(fd);
> > +       return 0;
> > +}
> > --
> > 2.31.1
> >
> >
> > --
> > Mailing list info: https://lists.linux.it/listinfo/ltp
Petr Vorel Jan. 25, 2022, 10:28 a.m. UTC | #3
Hi Murphy, Amir,

Amir, thanks a lot for your review, comments.

> Hi Amir,

> On Tue, Jan 25, 2022 at 09:29:47AM +0200, Amir Goldstein wrote:
> > On Tue, Jan 25, 2022 at 4:47 AM Murphy Zhou <jencce.kernel@gmail.com> wrote:

> > > Exercise fsnotify and inotify interfaces while IO going on.

> > Hi Murphy,

> > It's worth documenting in main test script that this test
> > was created as a regression test for commit
> > 4396a73115fc fsnotify: fix sb_connectors leak

> Ah, the tests were created for the goal of stress test. This leak
> was one of the bugs that this test found.
But still, it can be worth to mention it for affected systems without this bug
(v5.14?).

> > Can you elaborate a bit more about the expectation from this test.
> > I do not see any error checking in the main script.

> Sure. Will explain more.

> > Is any perror supposed to fail the test?

> No.

> > Is its purpose to catch kernel dmesg splats of all sorts?

> Not needed.

> My intend is to use these interfaces insanely a while, if kernel 
> does not panic or hang, pass. This test is not checking *notify
> function which has already been covered.

FYI for hitting a race conditions we have fuzzy sync library, it can reduce
running time a lot specially for two race windows (I see you use 2x infinite loop)
https://github.com/linux-test-project/ltp/wiki/C-Test-API#133-reproducing-race-conditions


> > In your original post you wrote that bug makes the test hang:
> > https://lore.kernel.org/linux-fsdevel/20210907063338.ycaw6wvhzrfsfdlp@xzhoux.usersys.redhat.com/

> > If that is the case, better mention this to the LTP maintainers.
+1, helps to understand the context.


Few general notes for porting reproducer to LTP. Takes time, but the result is
support for wide range of kernel versions and different user space (including
different init systems, test are used also on AOSP).
Maybe quite a lot of new things, thus don't hesitate to ask for help.

1) using C API (tst_test.h) helps to have more compact code
i.e. instead of
fd = open(argv[1], O_RDWR);
	if (fd == -1) {
		perror("writefile open");
		exit(EXIT_FAILURE);
	}
	ret = write(fd, buf, BUFSIZ);
	if (ret == -1)
		perror("writefile write");
	usleep(1);

you can have just 2 lines:

fd = SAFE_OPEN(argv[1], O_RDWR);
SAFE_WRITE(fd, buf, BUFSIZ);

See
https://github.com/linux-test-project/ltp/wiki/C-Test-API

2) shell must be POSIX compliant (some systems use other shells e.g. dash), i.e.
no bashisms (e.g. function, pushd, popd).
And for sure no /bin/bash, but /bin/sh

and use LTP shell API (tst_test.sh)

See
https://github.com/linux-test-project/ltp/wiki/Shell-Test-API

fsnotify-stress.sh looks like a custom runner, please don't reinvent a wheel.
We have in the API support for timeout, temporary directories etc.

Also I'd write only necessary minimum in shell (C is much more portable than
shell, also C does not bring unnecessary userspace dependencies).
C API has many helper, you don't have to write things from scratch.

3) make check
You can use make check in testcases/kernel/fs/fs-notify/ directory to
see common C and shell errors.

Below is the output for current code.

Kind regards,
Petr

CHECK testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
fanotify_flush_stress.c:1: WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
make: [../../../../include/mk/rules.mk:48: check-fanotify_flush_stress] Error 1 (ignored)
CHECK testcases/kernel/fs/fs-notify/fanotify_init_stress.c
fanotify_init_stress.c:1: WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
fanotify_init_stress.c:13: WARNING: Missing a blank line after declarations
make: [../../../../include/mk/rules.mk:48: check-fanotify_init_stress] Error 1 (ignored)
CHECK testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
fanotify_mark_stress.c:1: WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
make: [../../../../include/mk/rules.mk:48: check-fanotify_mark_stress] Error 1 (ignored)
fanotify_mark_stress.c:12:6: warning: Symbol 'add_mark' has no prototype or library ('tst_') prefix. Should it be static?
fanotify_mark_stress.c:18:6: warning: Symbol 'remove_mark' has no prototype or library ('tst_') prefix. Should it be static?
CHECK testcases/kernel/fs/fs-notify/fanotify_watch.c
fanotify_watch.c:1: WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
fanotify_watch.c:15: ERROR: "foo * bar" should be "foo *bar"
fanotify_watch.c:17: ERROR: "foo * bar" should be "foo *bar"
fanotify_watch.c:18: ERROR: "foo * bar" should be "foo *bar"
fanotify_watch.c:60: ERROR: space required before the open parenthesis '('
fanotify_watch.c:88: WARNING: Block comments use * on subsequent lines
fanotify_watch.c:89: WARNING: Block comments use a trailing */ on a separate line
fanotify_watch.c:175: WARNING: Consider removing the code enclosed by this #if 0 and its #endif
fanotify_watch.c:199: WARNING: Block comments use * on subsequent lines
fanotify_watch.c:201: WARNING: Block comments use a trailing */ on a separate line
make: [../../../../include/mk/rules.mk:48: check-fanotify_watch] Error 1 (ignored)
CHECK testcases/kernel/fs/fs-notify/freadfile.c
freadfile.c:1: WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
freadfile.c:16: ERROR: space required before the open parenthesis '('
make: [../../../../include/mk/rules.mk:48: check-freadfile] Error 1 (ignored)
CHECK testcases/kernel/fs/fs-notify/fwritefile.c
fwritefile.c:1: WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
fwritefile.c:16: ERROR: space required before the open parenthesis '('
make: [../../../../include/mk/rules.mk:48: check-fwritefile] Error 1 (ignored)
CHECK testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c
inotify_add_rm_stress.c:1: WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
make: [../../../../include/mk/rules.mk:48: check-inotify_add_rm_stress] Error 1 (ignored)
CHECK testcases/kernel/fs/fs-notify/inotify_init_stress.c
inotify_init_stress.c:1: WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
make: [../../../../include/mk/rules.mk:48: check-inotify_init_stress] Error 1 (ignored)
CHECK testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c
inotify_inmodify_stress.c:1: WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
inotify_inmodify_stress.c:11: WARNING: Missing a blank line after declarations
inotify_inmodify_stress.c:13: WARNING: Missing a blank line after declarations
make: [../../../../include/mk/rules.mk:48: check-inotify_inmodify_stress] Error 1 (ignored)
CHECK testcases/kernel/fs/fs-notify/inotify_watch.c
inotify_watch.c:1: WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
inotify_watch.c:47: WARNING: Missing a blank line after declarations
make: [../../../../include/mk/rules.mk:48: check-inotify_watch] Error 1 (ignored)
CHECK testcases/kernel/fs/fs-notify/readfile.c
readfile.c:1: WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
make: [../../../../include/mk/rules.mk:48: check-readfile] Error 1 (ignored)
CHECK testcases/kernel/fs/fs-notify/writefile.c
writefile.c:1: WARNING: Missing or malformed SPDX-License-Identifier tag in line 1
make: [../../../../include/mk/rules.mk:48: check-writefile] Error 1 (ignored)
CHECK testcases/kernel/fs/fs-notify/fsnotify-stress.sh
possible bashism in fsnotify-stress.sh line 13 ('function' is useless):
function cleanup_processes()
possible bashism in fsnotify-stress.sh line 22 ('function' is useless):
function cleanup()
possible bashism in fsnotify-stress.sh line 31 ('function' is useless):
function run_stress()
possible bashism in fsnotify-stress.sh line 34 (echo -e):
	echo -e "* CPU count: $NR_CPUS"
possible bashism in fsnotify-stress.sh line 35 (echo -e):
	echo -e "* TIMEOUT for each subcase: $TIMEOUT"
possible bashism in fsnotify-stress.sh line 37 (echo -e):
	echo -e "* Starting fsnotify stress on directory and regular file"
possible bashism in fsnotify-stress.sh line 42 (should be 'b = a'):
			[ "$i" == "$j" ] && continue
possible bashism in fsnotify-stress.sh line 45 (echo -e):
			echo -e "* Starting $i and $j, rcnt $rcnt"
possible bashism in fsnotify-stress.sh line 52 (echo -e):
			echo -e "$i $j" >> tmp
possible bashism in fsnotify-stress.sh line 53 ('((' should be '$(('):
			((rcnt++))
possible bashism in fsnotify-stress.sh line 63 (echo -e):
echo -e "\n***** Cleanup fanotify inotify device *****"
make: [../../../../include/mk/rules.mk:58: check-fsnotify-stress.sh] Error 1 (ignored)
CHECK testcases/kernel/fs/fs-notify/rw_files.sh
possible bashism in rw_files.sh line 12 ('function' is useless):
function add_files()
possible bashism in rw_files.sh line 28 ('((' should be '$(('):
		((i++))
possible bashism in rw_files.sh line 29 ($FUNCNAME):
		[ -e stoptest ] && { echo $FUNCNAME; exit; }
possible bashism in rw_files.sh line 33 ('function' is useless):
function mv_files()
possible bashism in rw_files.sh line 41 ('((' should be '$(('):
		((i++))
possible bashism in rw_files.sh line 42 ($FUNCNAME):
		[ -e stoptest ] && { echo $FUNCNAME; exit; }
possible bashism in rw_files.sh line 46 ('function' is useless):
function read_files()
possible bashism in rw_files.sh line 53 ($FUNCNAME):
		[ -e stoptest ] && { echo $FUNCNAME; exit; }
possible bashism in rw_files.sh line 57 ('function' is useless):
function write_files()
possible bashism in rw_files.sh line 64 ($FUNCNAME):
			[ -e stoptest ] && { echo $FUNCNAME; exit; }
possible bashism in rw_files.sh line 66 ($FUNCNAME):
		[ -e stoptest ] && { echo $FUNCNAME; exit; }
possible bashism in rw_files.sh line 70 ('function' is useless):
function rm_files()
possible bashism in rw_files.sh line 76 ($FUNCNAME):
		[ -e stoptest ] && { echo $FUNCNAME; exit; }
possible bashism in rw_files.sh line 80 ((push|pop)d):
pushd $TDIR > /dev/null 2>&1
possible bashism in rw_files.sh line 87 ((push|pop)d):
popd > /dev/null 2>&1
Cyril Hrubis Jan. 25, 2022, 10:56 a.m. UTC | #4
Hi!
> My intend is to use these interfaces insanely a while, if kernel 
> does not panic or hang, pass. This test is not checking *notify
> function which has already been covered.

So looking at the original bug it seems that the end result is a kernel
hang, that sounds like we can adopt the usual approach where LTP tests
that may crash the system print passing message at the end
unconditionally like:

tst_res(TPASS, "Nothing bad happened, probably");

And we have even API for checking kernel taint flags which is used
extensively in CVE tests that can trigger all kinds of undefined
behavior.

> > 
> > In your original post you wrote that bug makes the test hang:
> > https://lore.kernel.org/linux-fsdevel/20210907063338.ycaw6wvhzrfsfdlp@xzhoux.usersys.redhat.com/
> > 
> > If that is the case, better mention this to the LTP maintainers.
> 
> Sure. Thanks for reviewing!
> 
> Murphy
> > 
> > Thanks,
> > Amir.
> > 
> > 
> > 
> > 
> > >
> > > Signed-off-by: Murphy Zhou <jencce.kernel@gmail.com>
> > > ---
> > >  testcases/kernel/fs/fs-notify/Makefile        |  18 ++
> > >  .../fs/fs-notify/fanotify_flush_stress.c      |  52 ++++
> > >  .../fs/fs-notify/fanotify_init_stress.c       |  32 +++
> > >  .../fs/fs-notify/fanotify_mark_stress.c       |  58 +++++
> > >  .../kernel/fs/fs-notify/fanotify_watch.c      | 244 ++++++++++++++++++
> > >  testcases/kernel/fs/fs-notify/freadfile.c     |  27 ++
> > >  .../kernel/fs/fs-notify/fsnotify-stress.sh    |  64 +++++
> > >  testcases/kernel/fs/fs-notify/fwritefile.c    |  27 ++
> > >  .../fs/fs-notify/inotify_add_rm_stress.c      |  36 +++
> > >  .../kernel/fs/fs-notify/inotify_init_stress.c |  22 ++
> > >  .../fs/fs-notify/inotify_inmodify_stress.c    |  17 ++
> > >  testcases/kernel/fs/fs-notify/inotify_watch.c |  98 +++++++
> > >  testcases/kernel/fs/fs-notify/readfile.c      |  28 ++
> > >  testcases/kernel/fs/fs-notify/rw_files.sh     |  90 +++++++
> > >  testcases/kernel/fs/fs-notify/writefile.c     |  28 ++
> > >  15 files changed, 841 insertions(+)
> > >  create mode 100644 testcases/kernel/fs/fs-notify/Makefile
> > >  create mode 100644 testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> > >  create mode 100644 testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> > >  create mode 100644 testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> > >  create mode 100644 testcases/kernel/fs/fs-notify/fanotify_watch.c
> > >  create mode 100644 testcases/kernel/fs/fs-notify/freadfile.c
> > >  create mode 100755 testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> > >  create mode 100644 testcases/kernel/fs/fs-notify/fwritefile.c
> > >  create mode 100644 testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c
> > >  create mode 100644 testcases/kernel/fs/fs-notify/inotify_init_stress.c
> > >  create mode 100644 testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c
> > >  create mode 100644 testcases/kernel/fs/fs-notify/inotify_watch.c
> > >  create mode 100644 testcases/kernel/fs/fs-notify/readfile.c
> > >  create mode 100755 testcases/kernel/fs/fs-notify/rw_files.sh
> > >  create mode 100644 testcases/kernel/fs/fs-notify/writefile.c
> > >
> > > diff --git a/testcases/kernel/fs/fs-notify/Makefile b/testcases/kernel/fs/fs-notify/Makefile
> > > new file mode 100644
> > > index 000000000..328783942
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/Makefile
> > > @@ -0,0 +1,18 @@
> > > +#
> > > +#    kernel/fs/fs-notify testcases Makefile.
> > > +#
> > > +
> > > +top_srcdir                     ?= ../../../..
> > > +
> > > +include $(top_srcdir)/include/mk/testcases.mk
> > > +
> > > +BINARIES:=fanotify_flush_stress fanotify_init_stress \
> > > +fanotify_mark_stress fanotify_watch inotify_watch \
> > > +inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress\
> > > +writefile freadfile fwritefile readfile
> > > +
> > > +INSTALL_TARGETS                        := fsnotify-stress.sh $(BINARIES) rw_files.sh
> > > +
> > > +MAKE_TARGETS                   := $(BINARIES)
> > > +
> > > +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> > > diff --git a/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> > > new file mode 100644
> > > index 000000000..493acfb56
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> > > @@ -0,0 +1,52 @@
> > > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > > +#include <errno.h>
> > > +#include <fcntl.h>
> > > +#include <limits.h>
> > > +#include <poll.h>
> > > +#include <stdio.h>
> > > +#include <stdlib.h>
> > > +#include <sys/fanotify.h>
> > > +#include <unistd.h>
> > > +#include <string.h>
> > > +
> > > +int main(int argc, char *argv[])
> > > +{
> > > +       char buf;
> > > +       int fd;
> > > +
> > > +       /* Create the file descriptor for accessing the fanotify API */
> > > +       fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> > > +                                          O_RDONLY | O_LARGEFILE);
> > > +       if (fd == -1) {
> > > +               perror("fanotify_init");
> > > +               exit(EXIT_FAILURE);
> > > +       }
> > > +
> > > +       /* Loop marking all kinds of events and flush */
> > > +       while (1) {
> > > +
> > > +               if (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, argv[1]) == -1)
> > > +
> > > +                       perror("fanotify_mark add");
> > > +
> > > +               if (fanotify_mark(fd, FAN_MARK_FLUSH | FAN_MARK_MOUNT,
> > > +                                               0, -1, argv[1]) == -1)
> > > +                       perror("fanotify_mark flush mount");
> > > +
> > > +               if (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, argv[1]) == -1)
> > > +
> > > +                       perror("fanotify_mark add");
> > > +
> > > +               if (fanotify_mark(fd, FAN_MARK_FLUSH, 0, -1, argv[1]) == -1)
> > > +                       perror("fanotify_mark flush");
> > > +       }
> > > +
> > > +       close(fd);
> > > +       exit(EXIT_SUCCESS);
> > > +}
> > > diff --git a/testcases/kernel/fs/fs-notify/fanotify_init_stress.c b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> > > new file mode 100644
> > > index 000000000..d11924b57
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> > > @@ -0,0 +1,32 @@
> > > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > > +#include <errno.h>
> > > +#include <stdio.h>
> > > +#include <unistd.h>
> > > +#include <fcntl.h>
> > > +#include <stdlib.h>
> > > +#include <sys/fanotify.h>
> > > +
> > > +int main(int argc, char *argv[])
> > > +{
> > > +       char buf;
> > > +       int fd;
> > > +       while (1) {
> > > +
> > > +               /* Create the file descriptor for accessing the fanotify API */
> > > +               fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT |
> > > +                               FAN_NONBLOCK, O_RDONLY | O_LARGEFILE);
> > > +               if (fd == -1)
> > > +                       perror("fanotify_init");
> > > +
> > > +               if (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,
> > > +                               argv[1]) == -1)
> > > +                       perror("fanotify_mark");
> > > +
> > > +               close(fd);
> > > +       }
> > > +
> > > +       exit(EXIT_SUCCESS);
> > > +}
> > > diff --git a/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> > > new file mode 100644
> > > index 000000000..7f648e103
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> > > @@ -0,0 +1,58 @@
> > > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > > +#include <errno.h>
> > > +#include <fcntl.h>
> > > +#include <limits.h>
> > > +#include <poll.h>
> > > +#include <stdio.h>
> > > +#include <stdlib.h>
> > > +#include <sys/fanotify.h>
> > > +#include <unistd.h>
> > > +#include <string.h>
> > > +
> > > +void add_mark(int fd, uint64_t mask, char *path)
> > > +{
> > > +       if (fanotify_mark(fd, FAN_MARK_ADD, mask, -1, path) == -1)
> > > +               perror("fanotify_mark add");
> > > +}
> > > +
> > > +void remove_mark(int fd, uint64_t mask, char *path)
> > > +{
> > > +       if (fanotify_mark(fd, FAN_MARK_REMOVE, mask, -1, path) == -1)
> > > +               perror("fanotify_mark remove");
> > > +}
> > > +
> > > +int main(int argc, char *argv[])
> > > +{
> > > +       char buf;
> > > +       int fd;
> > > +       /* Create the file descriptor for accessing the fanotify API */
> > > +       fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> > > +                                          O_RDONLY | O_LARGEFILE);
> > > +       if (fd == -1) {
> > > +               perror("fanotify_init");
> > > +               exit(EXIT_FAILURE);
> > > +       }
> > > +
> > > +       /* Loop marking all kinds of events */
> > > +       while (1) {
> > > +               add_mark(fd, FAN_ACCESS, argv[1]);
> > > +               remove_mark(fd, FAN_ACCESS, argv[1]);
> > > +               add_mark(fd, FAN_MODIFY, argv[1]);
> > > +               remove_mark(fd, FAN_MODIFY, argv[1]);
> > > +               add_mark(fd, FAN_OPEN_PERM, argv[1]);
> > > +               remove_mark(fd, FAN_OPEN_PERM, argv[1]);
> > > +               add_mark(fd, FAN_CLOSE, argv[1]);
> > > +               remove_mark(fd, FAN_CLOSE, argv[1]);
> > > +               add_mark(fd, FAN_OPEN, argv[1]);
> > > +               remove_mark(fd, FAN_OPEN, argv[1]);
> > > +               add_mark(fd, FAN_ACCESS_PERM, argv[1]);
> > > +               remove_mark(fd, FAN_ACCESS_PERM, argv[1]);
> > > +               add_mark(fd, FAN_ONDIR, argv[1]);
> > > +               remove_mark(fd, FAN_ONDIR, argv[1]);
> > > +               add_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
> > > +               remove_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
> > > +       }
> > > +
> > > +       close(fd);
> > > +       exit(EXIT_SUCCESS);
> > > +}
> > > diff --git a/testcases/kernel/fs/fs-notify/fanotify_watch.c b/testcases/kernel/fs/fs-notify/fanotify_watch.c
> > > new file mode 100644
> > > index 000000000..1028e0e30
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/fanotify_watch.c
> > > @@ -0,0 +1,244 @@
> > > +/* Example in man 7 fanotify */
> > > +
> > > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > > +#include <errno.h>
> > > +#include <fcntl.h>
> > > +#include <limits.h>
> > > +#include <poll.h>
> > > +#include <stdio.h>
> > > +#include <stdlib.h>
> > > +#include <sys/fanotify.h>
> > > +#include <unistd.h>
> > > +#include <string.h>
> > > +
> > > +/* get comm for pid from /proc/pid/comm */
> > > +static char * get_comm_pid(unsigned int pid)
> > > +{
> > > +       char * proc_name;
> > > +       char * comm;
> > > +       int comm_fd, cnt;
> > > +
> > > +       proc_name = (char *)malloc(50);
> > > +       if (proc_name != NULL)
> > > +               sprintf(proc_name, "/proc/%u/comm\0", pid);
> > > +       else
> > > +               return NULL;
> > > +
> > > +       comm = (char *)malloc(50);
> > > +       if (comm != NULL)
> > > +               memset(comm, 0, 50);
> > > +       else
> > > +               return NULL;
> > > +
> > > +       comm_fd = open(proc_name, O_RDONLY);
> > > +       if (comm_fd != -1) {
> > > +               cnt = read(comm_fd, comm, 50);
> > > +               if (cnt != -1) {
> > > +                       comm[cnt] = '\0';
> > > +                       close(comm_fd);
> > > +                       return comm;
> > > +               }
> > > +               close(comm_fd);
> > > +       }
> > > +
> > > +       return NULL;
> > > +}
> > > +
> > > +/* Read all available fanotify events from the file descriptor 'fd' */
> > > +
> > > +static void handle_events(int fd)
> > > +{
> > > +       const struct fanotify_event_metadata *metadata;
> > > +       struct fanotify_event_metadata buf[200];
> > > +       ssize_t len;
> > > +       char path[PATH_MAX];
> > > +       ssize_t path_len;
> > > +       char procfd_path[PATH_MAX];
> > > +       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) {
> > > +                       perror("read");
> > > +                       exit(EXIT_FAILURE);
> > > +               }
> > > +
> > > +               /* 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)) {
> > > +
> > > +                       /* Check that run-time and compile-time structures match */
> > > +
> > > +                       if (metadata->vers != FANOTIFY_METADATA_VERSION) {
> > > +                               fprintf(stderr,
> > > +                                   "Mismatch of fanotify metadata version.\n");
> > > +                               exit(EXIT_FAILURE);
> > > +                       }
> > > +
> > > +                       /* 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) {
> > > +                                       printf("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) {
> > > +                                       printf("FAN_ACCESS_PERM: ");
> > > +
> > > +                                       /* Allow file to be accessed */
> > > +                                       response.fd = metadata->fd;
> > > +                                       response.response = FAN_ALLOW;
> > > +                                       write(fd, &response,
> > > +                                           sizeof(struct fanotify_response));
> > > +                               }
> > > +
> > > +                               /* Handle closing of writable file event */
> > > +                               if (metadata->mask & FAN_CLOSE_WRITE)
> > > +                                       printf("FAN_CLOSE_WRITE: ");
> > > +
> > > +                               /* Handle closing of not writable file event */
> > > +                               if (metadata->mask & FAN_CLOSE_NOWRITE)
> > > +                                       printf("FAN_CLOSE_NOWRITE: ");
> > > +
> > > +                               /* Handle modify file event */
> > > +                               if (metadata->mask & FAN_MODIFY)
> > > +                                       printf("FAN_MODIFY: ");
> > > +
> > > +                               /* Handle open event */
> > > +                               if (metadata->mask & FAN_OPEN)
> > > +                                       printf("FAN_OPEN: ");
> > > +
> > > +                               /* Handle access event */
> > > +                               if (metadata->mask & FAN_ACCESS)
> > > +                                       printf("FAN_ACCESS: ");
> > > +
> > > +                               /* Handle access event */
> > > +                               if (metadata->mask & FAN_ONDIR)
> > > +                                       printf("FAN_ONDIR: ");
> > > +
> > > +                               /* Handle access event */
> > > +                               if (metadata->mask & FAN_EVENT_ON_CHILD)
> > > +                                       printf("FAN_EVENT_ON_CHILD: ");
> > > +
> > > +                               /* Retrieve/print the accessed file path*/
> > > +                               snprintf(procfd_path, sizeof(procfd_path),
> > > +                                           "/proc/self/fd/%d", metadata->fd);
> > > +                               path_len = readlink(procfd_path, path,
> > > +                                           sizeof(path) - 1);
> > > +                               if (path_len == -1) {
> > > +                                       perror("readlink");
> > > +                                       exit(EXIT_FAILURE);
> > > +                               }
> > > +
> > > +                               path[path_len] = '\0';
> > > +                               printf("File %s.\t\t Comm %s", path,
> > > +                                       get_comm_pid(metadata->pid));
> > > +
> > > +                               /* Close the file descriptor of the event */
> > > +
> > > +                               close(metadata->fd);
> > > +                       }
> > > +
> > > +                       /* Advance to next event */
> > > +                       metadata = FAN_EVENT_NEXT(metadata, len);
> > > +               }
> > > +       }
> > > +}
> > > +
> > > +int main(int argc, char *argv[])
> > > +{
> > > +       char buf;
> > > +       int fd, poll_num;
> > > +       nfds_t nfds;
> > > +       struct pollfd fds[2];
> > > +       FILE *f;
> > > +#if 0
> > > +       /* Check mount point is supplied */
> > > +       if (argc != 2) {
> > > +               fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
> > > +               exit(EXIT_FAILURE);
> > > +       }
> > > +#endif
> > > +       printf("%s on %s\n", argv[0], argv[1]);
> > > +       fflush(stdout);
> > > +       f = freopen("fanotify.log", "w+", stdout);
> > > +       if (f == NULL) {
> > > +               perror("freopen");
> > > +               exit(EXIT_FAILURE);
> > > +       }
> > > +
> > > +       /* Create the file descriptor for accessing the fanotify API */
> > > +       fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> > > +                                          O_RDONLY | O_LARGEFILE);
> > > +       if (fd == -1) {
> > > +               perror("fanotify_init");
> > > +               exit(EXIT_FAILURE);
> > > +       }
> > > +
> > > +       /* Mark the mount for:
> > > +          - permission events before opening files
> > > +          - notification events after closing a write-enabled
> > > +                file descriptor */
> > > +       if (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, argv[1]) == -1) {
> > > +
> > > +               perror("fanotify_mark");
> > > +               exit(EXIT_FAILURE);
> > > +       }
> > > +
> > > +       /* Prepare for polling */
> > > +       nfds = 1;
> > > +
> > > +       /* Fanotify input */
> > > +       fds[0].fd = fd;
> > > +       fds[0].events = POLLIN;
> > > +
> > > +       /* This is the loop to wait for incoming events */
> > > +       printf("Listening for events.\n");
> > > +       while (1) {
> > > +               poll_num = poll(fds, nfds, -1);
> > > +               if (poll_num == -1) {
> > > +                       if (errno == EINTR)     /* Interrupted by a signal */
> > > +                               continue;           /* Restart poll() */
> > > +
> > > +                       perror("poll");         /* Unexpected error */
> > > +                       exit(EXIT_FAILURE);
> > > +               }
> > > +
> > > +               if (poll_num > 0) {
> > > +
> > > +                       if (fds[0].revents & POLLIN) {
> > > +
> > > +                               /* Fanotify events are available */
> > > +                               handle_events(fd);
> > > +                       }
> > > +               }
> > > +       }
> > > +
> > > +       fclose(f);
> > > +       printf("Listening for events stopped.\n");
> > > +       exit(EXIT_SUCCESS);
> > > +}
> > > diff --git a/testcases/kernel/fs/fs-notify/freadfile.c b/testcases/kernel/fs/fs-notify/freadfile.c
> > > new file mode 100644
> > > index 000000000..24bf76bcd
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/freadfile.c
> > > @@ -0,0 +1,27 @@
> > > +#include <stdio.h>
> > > +#include <stdlib.h>
> > > +#include <unistd.h>
> > > +#include <string.h>
> > > +#include <sys/types.h>
> > > +#include <sys/stat.h>
> > > +#include <fcntl.h>
> > > +
> > > +int main(int argc, char **argv)
> > > +{
> > > +       int fd;
> > > +       char buf[BUFSIZ];
> > > +       FILE *f;
> > > +
> > > +       memset(buf, 1, BUFSIZ);
> > > +       while(1) {
> > > +               f = fopen(argv[1], "r+");
> > > +               if (f == NULL) {
> > > +                       perror("freadfile fopen");
> > > +                       exit(EXIT_FAILURE);
> > > +               }
> > > +               fread(buf, sizeof(char), BUFSIZ, f);
> > > +               usleep(1);
> > > +       }
> > > +       fclose(f);
> > > +       return 0;
> > > +}
> > > diff --git a/testcases/kernel/fs/fs-notify/fsnotify-stress.sh b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> > > new file mode 100755
> > > index 000000000..d6fd5482b
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> > > @@ -0,0 +1,64 @@
> > > +#!/bin/bash
> > > +
> > > +export TIMEOUT=10
> > > +
> > > +STRESSES="fanotify_flush_stress fanotify_init_stress \
> > > +fanotify_mark_stress fanotify_watch inotify_watch \
> > > +inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress"
> > > +IO_OPES="writefile freadfile fwritefile readfile"
> > > +
> > > +NR_CPUS=$(grep -c processor /proc/cpuinfo)
> > > +[ $NR_CPUS -lt 4 ] && NR_CPUS=4
> > > +
> > > +function cleanup_processes()
> > > +{
> > > +       while ps -eo pid,comm | \
> > > +               grep -q -E "fanotify|inotify|rw_files|readfile|writefile" ; do
> > > +               killall rw_files.sh $STRESSES $IO_OPES > /dev/null 2>&1
> > > +               sleep 1
> > > +       done
> > > +}
> > > +
> > > +function cleanup()
> > > +{
> > > +       sleep 3 # waiting possible unfinished processes
> > > +       cleanup_processes
> > > +       rm -f $STRESSES $IO_OPES fanotify.log inotify.log tmp
> > > +       cd /
> > > +       sync
> > > +}
> > > +
> > > +function run_stress()
> > > +{
> > > +       local i j rcnt=0
> > > +       echo -e "* CPU count: $NR_CPUS"
> > > +       echo -e "* TIMEOUT for each subcase: $TIMEOUT"
> > > +
> > > +       echo -e "* Starting fsnotify stress on directory and regular file"
> > > +       touch $TMPDIR/testfile
> > > +       >tmp
> > > +       for i in $STRESSES $IO_OPES rw_files.sh; do
> > > +               for j in $STRESSES ; do
> > > +                       [ "$i" == "$j" ] && continue
> > > +                       # skip duplicate combinations
> > > +                       grep -w $j tmp | grep -qw $i && continue
> > > +                       echo -e "* Starting $i and $j, rcnt $rcnt"
> > > +                       ./$i $TMPDIR $TIMEOUT > /dev/null 2>&1 &
> > > +                       ./$i $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
> > > +                       ./$j $TMPDIR $TIMEOUT > /dev/null 2>&1 &
> > > +                       ./$j $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
> > > +                       sleep $TIMEOUT
> > > +                       cleanup_processes
> > > +                       echo -e "$i $j" >> tmp
> > > +                       ((rcnt++))
> > > +               done
> > > +       done
> > > +}
> > > +
> > > +trap "cleanup; exit;" 2
> > > +
> > > +echo "***** Starting tests *****"
> > > +run_stress
> > > +
> > > +echo -e "\n***** Cleanup fanotify inotify device *****"
> > > +cleanup
> > > diff --git a/testcases/kernel/fs/fs-notify/fwritefile.c b/testcases/kernel/fs/fs-notify/fwritefile.c
> > > new file mode 100644
> > > index 000000000..a2956d60b
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/fwritefile.c
> > > @@ -0,0 +1,27 @@
> > > +#include <stdio.h>
> > > +#include <stdlib.h>
> > > +#include <unistd.h>
> > > +#include <string.h>
> > > +#include <sys/types.h>
> > > +#include <sys/stat.h>
> > > +#include <fcntl.h>
> > > +
> > > +int main(int argc, char **argv)
> > > +{
> > > +       int fd;
> > > +       char buf[BUFSIZ];
> > > +       FILE *f;
> > > +
> > > +       memset(buf, 1, BUFSIZ);
> > > +       while(1) {
> > > +               f = fopen(argv[1], "w+");
> > > +               if (f == NULL) {
> > > +                       perror("fwritefile fopen");
> > > +                       exit(EXIT_FAILURE);
> > > +               }
> > > +               fwrite(buf, sizeof(char), BUFSIZ, f);
> > > +               usleep(1);
> > > +       }
> > > +       fclose(f);
> > > +       return 0;
> > > +}
> > > diff --git a/testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c b/testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c
> > > new file mode 100644
> > > index 000000000..e88fc088e
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c
> > > @@ -0,0 +1,36 @@
> > > +#include <sys/types.h>
> > > +#include <sys/stat.h>
> > > +#include <fcntl.h>
> > > +#include <unistd.h>
> > > +#include <stdlib.h>
> > > +#include <dirent.h>
> > > +#include <stdio.h>
> > > +#include <sys/inotify.h>
> > > +
> > > +int main(int argc, char *argv[])
> > > +{
> > > +       int notify_fd;
> > > +       int wd, ret;
> > > +
> > > +       notify_fd = inotify_init1(IN_CLOEXEC);
> > > +       if (notify_fd == -1) {
> > > +               perror("inotify_init1");
> > > +               return -1;
> > > +       }
> > > +
> > > +       while (1) {
> > > +               wd = inotify_add_watch(notify_fd, argv[1],
> > > +                       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);
> > > +               if (wd < 0)
> > > +                       perror("inotify_add_watch");
> > > +
> > > +               ret = inotify_rm_watch(notify_fd, wd);
> > > +               if (ret < 0)
> > > +                       perror("inotify_rm_watch");
> > > +       }
> > > +       close(notify_fd);
> > > +       return 0;
> > > +}
> > > diff --git a/testcases/kernel/fs/fs-notify/inotify_init_stress.c b/testcases/kernel/fs/fs-notify/inotify_init_stress.c
> > > new file mode 100644
> > > index 000000000..62cb7c2e6
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/inotify_init_stress.c
> > > @@ -0,0 +1,22 @@
> > > +#include <sys/types.h>
> > > +#include <sys/stat.h>
> > > +#include <fcntl.h>
> > > +#include <unistd.h>
> > > +#include <stdlib.h>
> > > +#include <dirent.h>
> > > +#include <stdio.h>
> > > +#include <sys/inotify.h>
> > > +
> > > +int main(int argc, char *argv[])
> > > +{
> > > +       int notify_fd;
> > > +       int wd;
> > > +
> > > +       while (1) {
> > > +               notify_fd = inotify_init1(IN_CLOEXEC);
> > > +               if (notify_fd == -1)
> > > +                       perror("inotify_init1");
> > > +               close(notify_fd);
> > > +       }
> > > +       return 0;
> > > +}
> > > diff --git a/testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c b/testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c
> > > new file mode 100644
> > > index 000000000..546ccb76f
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c
> > > @@ -0,0 +1,17 @@
> > > +#include <sys/inotify.h>
> > > +#include <stdio.h>
> > > +#include <unistd.h>
> > > +
> > > +/*
> > > + * Calls inotify_rm_watch in a loop.
> > > + */
> > > +int main(int argc, char **argv)
> > > +{
> > > +       int fd = inotify_init();
> > > +       while (1) {
> > > +               int wd = inotify_add_watch(fd, argv[1], IN_MODIFY);
> > > +               inotify_rm_watch(fd, wd);
> > > +       }
> > > +       close(fd);
> > > +       return 0;
> > > +}
> > > diff --git a/testcases/kernel/fs/fs-notify/inotify_watch.c b/testcases/kernel/fs/fs-notify/inotify_watch.c
> > > new file mode 100644
> > > index 000000000..b4b908b6b
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/inotify_watch.c
> > > @@ -0,0 +1,98 @@
> > > +#include <sys/types.h>
> > > +#include <sys/stat.h>
> > > +#include <fcntl.h>
> > > +#include <unistd.h>
> > > +#include <stdlib.h>
> > > +#include <dirent.h>
> > > +#include <stdio.h>
> > > +#include <sys/inotify.h>
> > > +
> > > +int main(int argc, char *argv[])
> > > +{
> > > +       int notify_fd;
> > > +       int wd, ret;
> > > +       char *buf;
> > > +       FILE *f;
> > > +
> > > +       f = freopen("inotify.log", "w+", stdout);
> > > +       if (f == NULL) {
> > > +               perror("freopen");
> > > +               exit(EXIT_FAILURE);
> > > +       }
> > > +
> > > +       buf = malloc(sizeof(struct inotify_event) + NAME_MAX + 1);
> > > +       if (buf == NULL) {
> > > +               perror("malloc");
> > > +               return -1;
> > > +       }
> > > +
> > > +       notify_fd = inotify_init1(IN_CLOEXEC);
> > > +       if (notify_fd == -1) {
> > > +               perror("inotify_init1");
> > > +               return -1;
> > > +       }
> > > +
> > > +       wd = inotify_add_watch(notify_fd, argv[1],
> > > +               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);
> > > +
> > > +       if (wd < 0) {
> > > +               perror("inotify_add_watch");
> > > +               return -1;
> > > +       }
> > > +
> > > +       while (ret = read(notify_fd, buf, NAME_MAX) != -1) {
> > > +               struct inotify_event *ip = (struct inotify_event *)buf;
> > > +               printf("name %s event ", ip->name);
> > > +               switch (ip->mask) {
> > > +               case IN_ACCESS:
> > > +                       printf("access\n");
> > > +                       break;
> > > +               case IN_ATTRIB:
> > > +                       printf("attrib\n");
> > > +                       break;
> > > +               case IN_CLOSE_WRITE:
> > > +                       printf("close write\n");
> > > +                       break;
> > > +               case IN_CLOSE_NOWRITE:
> > > +                       printf("close nowrite\n");
> > > +                       break;
> > > +               case IN_CREATE:
> > > +                       printf("create\n");
> > > +                       break;
> > > +               case IN_DELETE:
> > > +                       printf("delete\n");
> > > +                       break;
> > > +               case IN_DELETE_SELF:
> > > +                       printf("deleteself\n");
> > > +                       break;
> > > +               case IN_MODIFY:
> > > +                       printf("modify\n");
> > > +                       break;
> > > +               case IN_MOVE_SELF:
> > > +                       printf("move self\n");
> > > +                       break;
> > > +               case IN_MOVED_FROM:
> > > +                       printf("move from\n");
> > > +                       break;
> > > +               case IN_MOVED_TO:
> > > +                       printf("move to\n");
> > > +                       break;
> > > +               case IN_OPEN:
> > > +                       printf("open\n");
> > > +                       break;
> > > +               default:
> > > +                       printf("\n");
> > > +                       break;
> > > +               };
> > > +       }
> > > +
> > > +       ret = inotify_rm_watch(notify_fd, wd);
> > > +       if (ret < 0)
> > > +               perror("inotify_rm_watch");
> > > +
> > > +       fclose(f);
> > > +       close(notify_fd);
> > > +       return 0;
> > > +}
> > > diff --git a/testcases/kernel/fs/fs-notify/readfile.c b/testcases/kernel/fs/fs-notify/readfile.c
> > > new file mode 100644
> > > index 000000000..2ab1a3694
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/readfile.c
> > > @@ -0,0 +1,28 @@
> > > +#include <stdio.h>
> > > +#include <stdlib.h>
> > > +#include <unistd.h>
> > > +#include <string.h>
> > > +#include <sys/types.h>
> > > +#include <sys/stat.h>
> > > +#include <fcntl.h>
> > > +
> > > +int main(int argc, char **argv)
> > > +{
> > > +       int fd, ret;
> > > +       char buf[BUFSIZ];
> > > +
> > > +       memset(buf, 1, BUFSIZ);
> > > +       while (1) {
> > > +               fd = open(argv[1], O_RDWR);
> > > +               if (fd == -1) {
> > > +                       perror("readfile open");
> > > +                       exit(EXIT_FAILURE);
> > > +               }
> > > +               ret = read(fd, buf, BUFSIZ);
> > > +               if (ret == -1)
> > > +                       perror("readfile read");
> > > +               usleep(1);
> > > +       }
> > > +       close(fd);
> > > +       return 0;
> > > +}
> > > diff --git a/testcases/kernel/fs/fs-notify/rw_files.sh b/testcases/kernel/fs/fs-notify/rw_files.sh
> > > new file mode 100755
> > > index 000000000..bb3387160
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/rw_files.sh
> > > @@ -0,0 +1,90 @@
> > > +#!/bin/bash
> > > +
> > > +TDIR=$1
> > > +TIMEO=$2
> > > +
> > > +[ -z "$TDIR" ] && TDIR=/tmp/
> > > +[ -d $TDIR ] || TDIR=/tmp/
> > > +[ -z "$TIMEO" ] && TIMEO=1m
> > > +
> > > +[ ! -d $TDIR ] && exit
> > > +
> > > +function add_files()
> > > +{
> > > +       local i=0
> > > +
> > > +       while true ; do
> > > +
> > > +               touch f-$i
> > > +               ln -s f-$i f-$i-sym
> > > +               ln f-$i f-$i-hdl
> > > +
> > > +               mkdir d-$i
> > > +
> > > +               mknod c-$i c 1 2
> > > +               mknod b-$i b 1 2
> > > +               mknod p-$i p
> > > +
> > > +               ((i++))
> > > +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> > > +       done
> > > +}
> > > +
> > > +function mv_files()
> > > +{
> > > +       local i=0
> > > +
> > > +       while true ; do
> > > +
> > > +               mv -f f-$i f-$i-rename
> > > +               mv -f f-$i-rename f-$i
> > > +               ((i++))
> > > +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> > > +       done
> > > +}
> > > +
> > > +function read_files()
> > > +{
> > > +       while true ; do
> > > +
> > > +               find .
> > > +               cat f-*
> > > +               ls d-*
> > > +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> > > +       done
> > > +}
> > > +
> > > +function write_files()
> > > +{
> > > +       while true ; do
> > > +
> > > +               for j in f-* d-* c-* b-* p-* ; do
> > > +                       echo 1 > $j
> > > +                       echo 2 >> $j
> > > +                       [ -e stoptest ] && { echo $FUNCNAME; exit; }
> > > +               done
> > > +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> > > +       done
> > > +}
> > > +
> > > +function rm_files()
> > > +{
> > > +       while true ; do
> > > +
> > > +               rm -rf d-* f-* c-* b-* p-*
> > > +               sleep 3
> > > +               [ -e stoptest ] && { echo $FUNCNAME; exit; }
> > > +       done
> > > +}
> > > +
> > > +pushd $TDIR > /dev/null 2>&1
> > > +rm -f stoptest
> > > +add_files > /dev/null 2>&1 &
> > > +mv_files > /dev/null 2>&1 &
> > > +read_files > /dev/null 2>&1 &
> > > +write_files > /dev/null 2>&1 &
> > > +rm_files > /dev/null 2>&1 &
> > > +popd > /dev/null 2>&1
> > > +
> > > +sleep $TIMEO
> > > +touch $TDIR/stoptest
> > > diff --git a/testcases/kernel/fs/fs-notify/writefile.c b/testcases/kernel/fs/fs-notify/writefile.c
> > > new file mode 100644
> > > index 000000000..9025b5d95
> > > --- /dev/null
> > > +++ b/testcases/kernel/fs/fs-notify/writefile.c
> > > @@ -0,0 +1,28 @@
> > > +#include <stdio.h>
> > > +#include <stdlib.h>
> > > +#include <unistd.h>
> > > +#include <string.h>
> > > +#include <sys/types.h>
> > > +#include <sys/stat.h>
> > > +#include <fcntl.h>
> > > +
> > > +int main(int argc, char **argv)
> > > +{
> > > +       int fd, ret;
> > > +       char buf[BUFSIZ];
> > > +
> > > +       memset(buf, 1, BUFSIZ);
> > > +       while (1) {
> > > +               fd = open(argv[1], O_RDWR);
> > > +               if (fd == -1) {
> > > +                       perror("writefile open");
> > > +                       exit(EXIT_FAILURE);
> > > +               }
> > > +               ret = write(fd, buf, BUFSIZ);
> > > +               if (ret == -1)
> > > +                       perror("writefile write");
> > > +               usleep(1);
> > > +       }
> > > +       close(fd);
> > > +       return 0;
> > > +}
> > > --
> > > 2.31.1
> > >
> > >
> > > --
> > > Mailing list info: https://lists.linux.it/listinfo/ltp
> 
> -- 
> Murphy
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp
>
Cyril Hrubis Jan. 25, 2022, 11:04 a.m. UTC | #5
Hi!
> diff --git a/testcases/kernel/fs/fs-notify/Makefile b/testcases/kernel/fs/fs-notify/Makefile
> new file mode 100644
> index 000000000..328783942
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/Makefile
> @@ -0,0 +1,18 @@
> +#
> +#    kernel/fs/fs-notify testcases Makefile.
> +#
> +
> +top_srcdir			?= ../../../..
> +
> +include $(top_srcdir)/include/mk/testcases.mk
> +
> +BINARIES:=fanotify_flush_stress fanotify_init_stress \
> +fanotify_mark_stress fanotify_watch inotify_watch \
> +inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress\
> +writefile freadfile fwritefile readfile
> +
> +INSTALL_TARGETS			:= fsnotify-stress.sh $(BINARIES) rw_files.sh
> +
> +MAKE_TARGETS			:= $(BINARIES)
> +
> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> new file mode 100644
> index 000000000..493acfb56
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> @@ -0,0 +1,52 @@
> +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <limits.h>
> +#include <poll.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/fanotify.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +int main(int argc, char *argv[])
> +{
> +	char buf;
> +	int fd;
> +
> +	/* Create the file descriptor for accessing the fanotify API */
> +	fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> +					   O_RDONLY | O_LARGEFILE);
> +	if (fd == -1) {
> +		perror("fanotify_init");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	/* Loop marking all kinds of events and flush */
> +	while (1) {
> +
> +		if (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, argv[1]) == -1)
> +
> +			perror("fanotify_mark add");
> +
> +		if (fanotify_mark(fd, FAN_MARK_FLUSH | FAN_MARK_MOUNT,
> +						0, -1, argv[1]) == -1)
> +			perror("fanotify_mark flush mount");
> +
> +		if (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, argv[1]) == -1)
> +
> +			perror("fanotify_mark add");
> +
> +		if (fanotify_mark(fd, FAN_MARK_FLUSH, 0, -1, argv[1]) == -1)
> +			perror("fanotify_mark flush");
> +	}
> +
> +	close(fd);
> +	exit(EXIT_SUCCESS);
> +}
> diff --git a/testcases/kernel/fs/fs-notify/fanotify_init_stress.c b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> new file mode 100644
> index 000000000..d11924b57
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> @@ -0,0 +1,32 @@
> +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> +#include <errno.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <sys/fanotify.h>
> +
> +int main(int argc, char *argv[])
> +{
> +	char buf;
> +	int fd;
> +	while (1) {
> +
> +		/* Create the file descriptor for accessing the fanotify API */
> +		fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT |
> +				FAN_NONBLOCK, O_RDONLY | O_LARGEFILE);
> +		if (fd == -1)
> +			perror("fanotify_init");
> +
> +		if (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,
> +				argv[1]) == -1)
> +			perror("fanotify_mark");
> +
> +		close(fd);
> +	}
> +
> +	exit(EXIT_SUCCESS);
> +}
> diff --git a/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> new file mode 100644
> index 000000000..7f648e103
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> @@ -0,0 +1,58 @@
> +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <limits.h>
> +#include <poll.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/fanotify.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +void add_mark(int fd, uint64_t mask, char *path)
> +{
> +	if (fanotify_mark(fd, FAN_MARK_ADD, mask, -1, path) == -1)
> +		perror("fanotify_mark add");
> +}
> +
> +void remove_mark(int fd, uint64_t mask, char *path)
> +{
> +	if (fanotify_mark(fd, FAN_MARK_REMOVE, mask, -1, path) == -1)
> +		perror("fanotify_mark remove");
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	char buf;
> +	int fd;
> +	/* Create the file descriptor for accessing the fanotify API */
> +	fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> +					   O_RDONLY | O_LARGEFILE);
> +	if (fd == -1) {
> +		perror("fanotify_init");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	/* Loop marking all kinds of events */
> +	while (1) {
> +		add_mark(fd, FAN_ACCESS, argv[1]);
> +		remove_mark(fd, FAN_ACCESS, argv[1]);
> +		add_mark(fd, FAN_MODIFY, argv[1]);
> +		remove_mark(fd, FAN_MODIFY, argv[1]);
> +		add_mark(fd, FAN_OPEN_PERM, argv[1]);
> +		remove_mark(fd, FAN_OPEN_PERM, argv[1]);
> +		add_mark(fd, FAN_CLOSE, argv[1]);
> +		remove_mark(fd, FAN_CLOSE, argv[1]);
> +		add_mark(fd, FAN_OPEN, argv[1]);
> +		remove_mark(fd, FAN_OPEN, argv[1]);
> +		add_mark(fd, FAN_ACCESS_PERM, argv[1]);
> +		remove_mark(fd, FAN_ACCESS_PERM, argv[1]);
> +		add_mark(fd, FAN_ONDIR, argv[1]);
> +		remove_mark(fd, FAN_ONDIR, argv[1]);
> +		add_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
> +		remove_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
> +	}
> +
> +	close(fd);
> +	exit(EXIT_SUCCESS);
> +}
> diff --git a/testcases/kernel/fs/fs-notify/fanotify_watch.c b/testcases/kernel/fs/fs-notify/fanotify_watch.c
> new file mode 100644
> index 000000000..1028e0e30
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/fanotify_watch.c
> @@ -0,0 +1,244 @@
> +/* Example in man 7 fanotify */
> +
> +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <limits.h>
> +#include <poll.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/fanotify.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +/* get comm for pid from /proc/pid/comm */
> +static char * get_comm_pid(unsigned int pid)
> +{
> +	char * proc_name;
> +	char * comm;
> +	int comm_fd, cnt;
> +
> +	proc_name = (char *)malloc(50);
> +	if (proc_name != NULL)
> +		sprintf(proc_name, "/proc/%u/comm\0", pid);
> +	else
> +		return NULL;
> +
> +	comm = (char *)malloc(50);
> +	if (comm != NULL)
> +		memset(comm, 0, 50);
> +	else
> +		return NULL;
> +
> +	comm_fd = open(proc_name, O_RDONLY);
> +	if (comm_fd != -1) {
> +		cnt = read(comm_fd, comm, 50);
> +		if (cnt != -1) {
> +			comm[cnt] = '\0';
> +			close(comm_fd);
> +			return comm;
> +		}
> +		close(comm_fd);
> +	}
> +
> +	return NULL;
> +}
> +
> +/* Read all available fanotify events from the file descriptor 'fd' */
> +
> +static void handle_events(int fd)
> +{
> +	const struct fanotify_event_metadata *metadata;
> +	struct fanotify_event_metadata buf[200];
> +	ssize_t len;
> +	char path[PATH_MAX];
> +	ssize_t path_len;
> +	char procfd_path[PATH_MAX];
> +	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) {
> +			perror("read");
> +			exit(EXIT_FAILURE);
> +		}
> +
> +		/* 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)) {
> +
> +			/* Check that run-time and compile-time structures match */
> +
> +			if (metadata->vers != FANOTIFY_METADATA_VERSION) {
> +				fprintf(stderr,
> +				    "Mismatch of fanotify metadata version.\n");
> +				exit(EXIT_FAILURE);
> +			}
> +
> +			/* 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) {
> +					printf("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) {
> +					printf("FAN_ACCESS_PERM: ");
> +
> +					/* Allow file to be accessed */
> +					response.fd = metadata->fd;
> +					response.response = FAN_ALLOW;
> +					write(fd, &response,
> +					    sizeof(struct fanotify_response));
> +				}
> +
> +				/* Handle closing of writable file event */
> +				if (metadata->mask & FAN_CLOSE_WRITE)
> +					printf("FAN_CLOSE_WRITE: ");
> +
> +				/* Handle closing of not writable file event */
> +				if (metadata->mask & FAN_CLOSE_NOWRITE)
> +					printf("FAN_CLOSE_NOWRITE: ");
> +
> +				/* Handle modify file event */
> +				if (metadata->mask & FAN_MODIFY)
> +					printf("FAN_MODIFY: ");
> +
> +				/* Handle open event */
> +				if (metadata->mask & FAN_OPEN)
> +					printf("FAN_OPEN: ");
> +
> +				/* Handle access event */
> +				if (metadata->mask & FAN_ACCESS)
> +					printf("FAN_ACCESS: ");
> +
> +				/* Handle access event */
> +				if (metadata->mask & FAN_ONDIR)
> +					printf("FAN_ONDIR: ");
> +
> +				/* Handle access event */
> +				if (metadata->mask & FAN_EVENT_ON_CHILD)
> +					printf("FAN_EVENT_ON_CHILD: ");
> +
> +				/* Retrieve/print the accessed file path*/
> +				snprintf(procfd_path, sizeof(procfd_path),
> +					    "/proc/self/fd/%d", metadata->fd);
> +				path_len = readlink(procfd_path, path,
> +					    sizeof(path) - 1);
> +				if (path_len == -1) {
> +					perror("readlink");
> +					exit(EXIT_FAILURE);
> +				}
> +
> +				path[path_len] = '\0';
> +				printf("File %s.\t\t Comm %s", path,
> +					get_comm_pid(metadata->pid));
> +
> +				/* Close the file descriptor of the event */
> +
> +				close(metadata->fd);
> +			}
> +
> +			/* Advance to next event */
> +			metadata = FAN_EVENT_NEXT(metadata, len);
> +		}
> +	}
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	char buf;
> +	int fd, poll_num;
> +	nfds_t nfds;
> +	struct pollfd fds[2];
> +	FILE *f;
> +#if 0
> +	/* Check mount point is supplied */
> +	if (argc != 2) {
> +		fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
> +		exit(EXIT_FAILURE);
> +	}
> +#endif
> +	printf("%s on %s\n", argv[0], argv[1]);
> +	fflush(stdout);
> +	f = freopen("fanotify.log", "w+", stdout);
> +	if (f == NULL) {
> +		perror("freopen");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	/* Create the file descriptor for accessing the fanotify API */
> +	fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> +					   O_RDONLY | O_LARGEFILE);
> +	if (fd == -1) {
> +		perror("fanotify_init");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	/* Mark the mount for:
> +	   - permission events before opening files
> +	   - notification events after closing a write-enabled
> +		 file descriptor */
> +	if (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, argv[1]) == -1) {
> +
> +		perror("fanotify_mark");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	/* Prepare for polling */
> +	nfds = 1;
> +
> +	/* Fanotify input */
> +	fds[0].fd = fd;
> +	fds[0].events = POLLIN;
> +
> +	/* This is the loop to wait for incoming events */
> +	printf("Listening for events.\n");
> +	while (1) {
> +		poll_num = poll(fds, nfds, -1);
> +		if (poll_num == -1) {
> +			if (errno == EINTR)     /* Interrupted by a signal */
> +				continue;           /* Restart poll() */
> +
> +			perror("poll");         /* Unexpected error */
> +			exit(EXIT_FAILURE);
> +		}
> +
> +		if (poll_num > 0) {
> +
> +			if (fds[0].revents & POLLIN) {
> +
> +				/* Fanotify events are available */
> +				handle_events(fd);
> +			}
> +		}
> +	}
> +
> +	fclose(f);
> +	printf("Listening for events stopped.\n");
> +	exit(EXIT_SUCCESS);
> +}
> diff --git a/testcases/kernel/fs/fs-notify/freadfile.c b/testcases/kernel/fs/fs-notify/freadfile.c
> new file mode 100644
> index 000000000..24bf76bcd
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/freadfile.c
> @@ -0,0 +1,27 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +
> +int main(int argc, char **argv)
> +{
> +	int fd;
> +	char buf[BUFSIZ];
> +	FILE *f;
> +
> +	memset(buf, 1, BUFSIZ);
> +	while(1) {
> +		f = fopen(argv[1], "r+");
> +		if (f == NULL) {
> +			perror("freadfile fopen");
> +			exit(EXIT_FAILURE);
> +		}
> +		fread(buf, sizeof(char), BUFSIZ, f);
> +		usleep(1);
> +	}
> +	fclose(f);
> +	return 0;
> +}

There is no real reason to keep these as several separate files. We can
actually put the whole test into one single C source that forks severa
times and each child runs one of loops from these helpers.

> diff --git a/testcases/kernel/fs/fs-notify/fsnotify-stress.sh b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> new file mode 100755
> index 000000000..d6fd5482b
> --- /dev/null
> +++ b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> @@ -0,0 +1,64 @@
> +#!/bin/bash
> +
> +export TIMEOUT=10
> +
> +STRESSES="fanotify_flush_stress fanotify_init_stress \
> +fanotify_mark_stress fanotify_watch inotify_watch \
> +inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress"
> +IO_OPES="writefile freadfile fwritefile readfile"
> +
> +NR_CPUS=$(grep -c processor /proc/cpuinfo)
> +[ $NR_CPUS -lt 4 ] && NR_CPUS=4
> +
> +function cleanup_processes()
> +{
> +	while ps -eo pid,comm | \
> +		grep -q -E "fanotify|inotify|rw_files|readfile|writefile" ; do
> +		killall rw_files.sh $STRESSES $IO_OPES > /dev/null 2>&1
> +		sleep 1
> +	done
> +}
> +
> +function cleanup()
> +{
> +	sleep 3 # waiting possible unfinished processes
> +	cleanup_processes
> +	rm -f $STRESSES $IO_OPES fanotify.log inotify.log tmp
> +	cd /
> +	sync
> +}
> +
> +function run_stress()
> +{
> +	local i j rcnt=0
> +	echo -e "* CPU count: $NR_CPUS"
> +	echo -e "* TIMEOUT for each subcase: $TIMEOUT"
> +
> +	echo -e "* Starting fsnotify stress on directory and regular file"
> +	touch $TMPDIR/testfile
> +	>tmp
> +	for i in $STRESSES $IO_OPES rw_files.sh; do
> +		for j in $STRESSES ; do
> +			[ "$i" == "$j" ] && continue
> +			# skip duplicate combinations
> +			grep -w $j tmp | grep -qw $i && continue
> +			echo -e "* Starting $i and $j, rcnt $rcnt"
> +			./$i $TMPDIR $TIMEOUT > /dev/null 2>&1 &
> +			./$i $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
> +			./$j $TMPDIR $TIMEOUT > /dev/null 2>&1 &
> +			./$j $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
> +			sleep $TIMEOUT
> +			cleanup_processes
> +			echo -e "$i $j" >> tmp
> +			((rcnt++))
> +		done
> +	done
> +}
> +
> +trap "cleanup; exit;" 2
> +
> +echo "***** Starting tests *****"
> +run_stress
> +
> +echo -e "\n***** Cleanup fanotify inotify device *****"
> +cleanup

This could be easily rewritten in the LTP C API. We do have helper sofr
most of the functionality that is reimplemented poorly in shell here.

So the whole test should really be a single C source where the testrun
forks children that runs the stress and I/O rutines that are currently
in the $BINARIES and the main pid would watch over the execution.
Murphy Zhou Jan. 27, 2022, 4:42 a.m. UTC | #6
Thanks all for reviewing! Very good points.

I'll try my best.

On Tue, Jan 25, 2022 at 7:02 PM Cyril Hrubis <chrubis@suse.cz> wrote:
>
> Hi!
> > diff --git a/testcases/kernel/fs/fs-notify/Makefile b/testcases/kernel/fs/fs-notify/Makefile
> > new file mode 100644
> > index 000000000..328783942
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/Makefile
> > @@ -0,0 +1,18 @@
> > +#
> > +#    kernel/fs/fs-notify testcases Makefile.
> > +#
> > +
> > +top_srcdir                   ?= ../../../..
> > +
> > +include $(top_srcdir)/include/mk/testcases.mk
> > +
> > +BINARIES:=fanotify_flush_stress fanotify_init_stress \
> > +fanotify_mark_stress fanotify_watch inotify_watch \
> > +inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress\
> > +writefile freadfile fwritefile readfile
> > +
> > +INSTALL_TARGETS                      := fsnotify-stress.sh $(BINARIES) rw_files.sh
> > +
> > +MAKE_TARGETS                 := $(BINARIES)
> > +
> > +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> > diff --git a/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> > new file mode 100644
> > index 000000000..493acfb56
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> > @@ -0,0 +1,52 @@
> > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <limits.h>
> > +#include <poll.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <sys/fanotify.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +     char buf;
> > +     int fd;
> > +
> > +     /* Create the file descriptor for accessing the fanotify API */
> > +     fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> > +                                        O_RDONLY | O_LARGEFILE);
> > +     if (fd == -1) {
> > +             perror("fanotify_init");
> > +             exit(EXIT_FAILURE);
> > +     }
> > +
> > +     /* Loop marking all kinds of events and flush */
> > +     while (1) {
> > +
> > +             if (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, argv[1]) == -1)
> > +
> > +                     perror("fanotify_mark add");
> > +
> > +             if (fanotify_mark(fd, FAN_MARK_FLUSH | FAN_MARK_MOUNT,
> > +                                             0, -1, argv[1]) == -1)
> > +                     perror("fanotify_mark flush mount");
> > +
> > +             if (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, argv[1]) == -1)
> > +
> > +                     perror("fanotify_mark add");
> > +
> > +             if (fanotify_mark(fd, FAN_MARK_FLUSH, 0, -1, argv[1]) == -1)
> > +                     perror("fanotify_mark flush");
> > +     }
> > +
> > +     close(fd);
> > +     exit(EXIT_SUCCESS);
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/fanotify_init_stress.c b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> > new file mode 100644
> > index 000000000..d11924b57
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> > @@ -0,0 +1,32 @@
> > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > +#include <errno.h>
> > +#include <stdio.h>
> > +#include <unistd.h>
> > +#include <fcntl.h>
> > +#include <stdlib.h>
> > +#include <sys/fanotify.h>
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +     char buf;
> > +     int fd;
> > +     while (1) {
> > +
> > +             /* Create the file descriptor for accessing the fanotify API */
> > +             fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT |
> > +                             FAN_NONBLOCK, O_RDONLY | O_LARGEFILE);
> > +             if (fd == -1)
> > +                     perror("fanotify_init");
> > +
> > +             if (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,
> > +                             argv[1]) == -1)
> > +                     perror("fanotify_mark");
> > +
> > +             close(fd);
> > +     }
> > +
> > +     exit(EXIT_SUCCESS);
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> > new file mode 100644
> > index 000000000..7f648e103
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> > @@ -0,0 +1,58 @@
> > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <limits.h>
> > +#include <poll.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <sys/fanotify.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +
> > +void add_mark(int fd, uint64_t mask, char *path)
> > +{
> > +     if (fanotify_mark(fd, FAN_MARK_ADD, mask, -1, path) == -1)
> > +             perror("fanotify_mark add");
> > +}
> > +
> > +void remove_mark(int fd, uint64_t mask, char *path)
> > +{
> > +     if (fanotify_mark(fd, FAN_MARK_REMOVE, mask, -1, path) == -1)
> > +             perror("fanotify_mark remove");
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +     char buf;
> > +     int fd;
> > +     /* Create the file descriptor for accessing the fanotify API */
> > +     fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> > +                                        O_RDONLY | O_LARGEFILE);
> > +     if (fd == -1) {
> > +             perror("fanotify_init");
> > +             exit(EXIT_FAILURE);
> > +     }
> > +
> > +     /* Loop marking all kinds of events */
> > +     while (1) {
> > +             add_mark(fd, FAN_ACCESS, argv[1]);
> > +             remove_mark(fd, FAN_ACCESS, argv[1]);
> > +             add_mark(fd, FAN_MODIFY, argv[1]);
> > +             remove_mark(fd, FAN_MODIFY, argv[1]);
> > +             add_mark(fd, FAN_OPEN_PERM, argv[1]);
> > +             remove_mark(fd, FAN_OPEN_PERM, argv[1]);
> > +             add_mark(fd, FAN_CLOSE, argv[1]);
> > +             remove_mark(fd, FAN_CLOSE, argv[1]);
> > +             add_mark(fd, FAN_OPEN, argv[1]);
> > +             remove_mark(fd, FAN_OPEN, argv[1]);
> > +             add_mark(fd, FAN_ACCESS_PERM, argv[1]);
> > +             remove_mark(fd, FAN_ACCESS_PERM, argv[1]);
> > +             add_mark(fd, FAN_ONDIR, argv[1]);
> > +             remove_mark(fd, FAN_ONDIR, argv[1]);
> > +             add_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
> > +             remove_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
> > +     }
> > +
> > +     close(fd);
> > +     exit(EXIT_SUCCESS);
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/fanotify_watch.c b/testcases/kernel/fs/fs-notify/fanotify_watch.c
> > new file mode 100644
> > index 000000000..1028e0e30
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fanotify_watch.c
> > @@ -0,0 +1,244 @@
> > +/* Example in man 7 fanotify */
> > +
> > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <limits.h>
> > +#include <poll.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <sys/fanotify.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +
> > +/* get comm for pid from /proc/pid/comm */
> > +static char * get_comm_pid(unsigned int pid)
> > +{
> > +     char * proc_name;
> > +     char * comm;
> > +     int comm_fd, cnt;
> > +
> > +     proc_name = (char *)malloc(50);
> > +     if (proc_name != NULL)
> > +             sprintf(proc_name, "/proc/%u/comm\0", pid);
> > +     else
> > +             return NULL;
> > +
> > +     comm = (char *)malloc(50);
> > +     if (comm != NULL)
> > +             memset(comm, 0, 50);
> > +     else
> > +             return NULL;
> > +
> > +     comm_fd = open(proc_name, O_RDONLY);
> > +     if (comm_fd != -1) {
> > +             cnt = read(comm_fd, comm, 50);
> > +             if (cnt != -1) {
> > +                     comm[cnt] = '\0';
> > +                     close(comm_fd);
> > +                     return comm;
> > +             }
> > +             close(comm_fd);
> > +     }
> > +
> > +     return NULL;
> > +}
> > +
> > +/* Read all available fanotify events from the file descriptor 'fd' */
> > +
> > +static void handle_events(int fd)
> > +{
> > +     const struct fanotify_event_metadata *metadata;
> > +     struct fanotify_event_metadata buf[200];
> > +     ssize_t len;
> > +     char path[PATH_MAX];
> > +     ssize_t path_len;
> > +     char procfd_path[PATH_MAX];
> > +     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) {
> > +                     perror("read");
> > +                     exit(EXIT_FAILURE);
> > +             }
> > +
> > +             /* 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)) {
> > +
> > +                     /* Check that run-time and compile-time structures match */
> > +
> > +                     if (metadata->vers != FANOTIFY_METADATA_VERSION) {
> > +                             fprintf(stderr,
> > +                                 "Mismatch of fanotify metadata version.\n");
> > +                             exit(EXIT_FAILURE);
> > +                     }
> > +
> > +                     /* 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) {
> > +                                     printf("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) {
> > +                                     printf("FAN_ACCESS_PERM: ");
> > +
> > +                                     /* Allow file to be accessed */
> > +                                     response.fd = metadata->fd;
> > +                                     response.response = FAN_ALLOW;
> > +                                     write(fd, &response,
> > +                                         sizeof(struct fanotify_response));
> > +                             }
> > +
> > +                             /* Handle closing of writable file event */
> > +                             if (metadata->mask & FAN_CLOSE_WRITE)
> > +                                     printf("FAN_CLOSE_WRITE: ");
> > +
> > +                             /* Handle closing of not writable file event */
> > +                             if (metadata->mask & FAN_CLOSE_NOWRITE)
> > +                                     printf("FAN_CLOSE_NOWRITE: ");
> > +
> > +                             /* Handle modify file event */
> > +                             if (metadata->mask & FAN_MODIFY)
> > +                                     printf("FAN_MODIFY: ");
> > +
> > +                             /* Handle open event */
> > +                             if (metadata->mask & FAN_OPEN)
> > +                                     printf("FAN_OPEN: ");
> > +
> > +                             /* Handle access event */
> > +                             if (metadata->mask & FAN_ACCESS)
> > +                                     printf("FAN_ACCESS: ");
> > +
> > +                             /* Handle access event */
> > +                             if (metadata->mask & FAN_ONDIR)
> > +                                     printf("FAN_ONDIR: ");
> > +
> > +                             /* Handle access event */
> > +                             if (metadata->mask & FAN_EVENT_ON_CHILD)
> > +                                     printf("FAN_EVENT_ON_CHILD: ");
> > +
> > +                             /* Retrieve/print the accessed file path*/
> > +                             snprintf(procfd_path, sizeof(procfd_path),
> > +                                         "/proc/self/fd/%d", metadata->fd);
> > +                             path_len = readlink(procfd_path, path,
> > +                                         sizeof(path) - 1);
> > +                             if (path_len == -1) {
> > +                                     perror("readlink");
> > +                                     exit(EXIT_FAILURE);
> > +                             }
> > +
> > +                             path[path_len] = '\0';
> > +                             printf("File %s.\t\t Comm %s", path,
> > +                                     get_comm_pid(metadata->pid));
> > +
> > +                             /* Close the file descriptor of the event */
> > +
> > +                             close(metadata->fd);
> > +                     }
> > +
> > +                     /* Advance to next event */
> > +                     metadata = FAN_EVENT_NEXT(metadata, len);
> > +             }
> > +     }
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +     char buf;
> > +     int fd, poll_num;
> > +     nfds_t nfds;
> > +     struct pollfd fds[2];
> > +     FILE *f;
> > +#if 0
> > +     /* Check mount point is supplied */
> > +     if (argc != 2) {
> > +             fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
> > +             exit(EXIT_FAILURE);
> > +     }
> > +#endif
> > +     printf("%s on %s\n", argv[0], argv[1]);
> > +     fflush(stdout);
> > +     f = freopen("fanotify.log", "w+", stdout);
> > +     if (f == NULL) {
> > +             perror("freopen");
> > +             exit(EXIT_FAILURE);
> > +     }
> > +
> > +     /* Create the file descriptor for accessing the fanotify API */
> > +     fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> > +                                        O_RDONLY | O_LARGEFILE);
> > +     if (fd == -1) {
> > +             perror("fanotify_init");
> > +             exit(EXIT_FAILURE);
> > +     }
> > +
> > +     /* Mark the mount for:
> > +        - permission events before opening files
> > +        - notification events after closing a write-enabled
> > +              file descriptor */
> > +     if (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, argv[1]) == -1) {
> > +
> > +             perror("fanotify_mark");
> > +             exit(EXIT_FAILURE);
> > +     }
> > +
> > +     /* Prepare for polling */
> > +     nfds = 1;
> > +
> > +     /* Fanotify input */
> > +     fds[0].fd = fd;
> > +     fds[0].events = POLLIN;
> > +
> > +     /* This is the loop to wait for incoming events */
> > +     printf("Listening for events.\n");
> > +     while (1) {
> > +             poll_num = poll(fds, nfds, -1);
> > +             if (poll_num == -1) {
> > +                     if (errno == EINTR)     /* Interrupted by a signal */
> > +                             continue;           /* Restart poll() */
> > +
> > +                     perror("poll");         /* Unexpected error */
> > +                     exit(EXIT_FAILURE);
> > +             }
> > +
> > +             if (poll_num > 0) {
> > +
> > +                     if (fds[0].revents & POLLIN) {
> > +
> > +                             /* Fanotify events are available */
> > +                             handle_events(fd);
> > +                     }
> > +             }
> > +     }
> > +
> > +     fclose(f);
> > +     printf("Listening for events stopped.\n");
> > +     exit(EXIT_SUCCESS);
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/freadfile.c b/testcases/kernel/fs/fs-notify/freadfile.c
> > new file mode 100644
> > index 000000000..24bf76bcd
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/freadfile.c
> > @@ -0,0 +1,27 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +
> > +int main(int argc, char **argv)
> > +{
> > +     int fd;
> > +     char buf[BUFSIZ];
> > +     FILE *f;
> > +
> > +     memset(buf, 1, BUFSIZ);
> > +     while(1) {
> > +             f = fopen(argv[1], "r+");
> > +             if (f == NULL) {
> > +                     perror("freadfile fopen");
> > +                     exit(EXIT_FAILURE);
> > +             }
> > +             fread(buf, sizeof(char), BUFSIZ, f);
> > +             usleep(1);
> > +     }
> > +     fclose(f);
> > +     return 0;
> > +}
>
> There is no real reason to keep these as several separate files. We can
> actually put the whole test into one single C source that forks severa
> times and each child runs one of loops from these helpers.
>
> > diff --git a/testcases/kernel/fs/fs-notify/fsnotify-stress.sh b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> > new file mode 100755
> > index 000000000..d6fd5482b
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> > @@ -0,0 +1,64 @@
> > +#!/bin/bash
> > +
> > +export TIMEOUT=10
> > +
> > +STRESSES="fanotify_flush_stress fanotify_init_stress \
> > +fanotify_mark_stress fanotify_watch inotify_watch \
> > +inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress"
> > +IO_OPES="writefile freadfile fwritefile readfile"
> > +
> > +NR_CPUS=$(grep -c processor /proc/cpuinfo)
> > +[ $NR_CPUS -lt 4 ] && NR_CPUS=4
> > +
> > +function cleanup_processes()
> > +{
> > +     while ps -eo pid,comm | \
> > +             grep -q -E "fanotify|inotify|rw_files|readfile|writefile" ; do
> > +             killall rw_files.sh $STRESSES $IO_OPES > /dev/null 2>&1
> > +             sleep 1
> > +     done
> > +}
> > +
> > +function cleanup()
> > +{
> > +     sleep 3 # waiting possible unfinished processes
> > +     cleanup_processes
> > +     rm -f $STRESSES $IO_OPES fanotify.log inotify.log tmp
> > +     cd /
> > +     sync
> > +}
> > +
> > +function run_stress()
> > +{
> > +     local i j rcnt=0
> > +     echo -e "* CPU count: $NR_CPUS"
> > +     echo -e "* TIMEOUT for each subcase: $TIMEOUT"
> > +
> > +     echo -e "* Starting fsnotify stress on directory and regular file"
> > +     touch $TMPDIR/testfile
> > +     >tmp
> > +     for i in $STRESSES $IO_OPES rw_files.sh; do
> > +             for j in $STRESSES ; do
> > +                     [ "$i" == "$j" ] && continue
> > +                     # skip duplicate combinations
> > +                     grep -w $j tmp | grep -qw $i && continue
> > +                     echo -e "* Starting $i and $j, rcnt $rcnt"
> > +                     ./$i $TMPDIR $TIMEOUT > /dev/null 2>&1 &
> > +                     ./$i $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
> > +                     ./$j $TMPDIR $TIMEOUT > /dev/null 2>&1 &
> > +                     ./$j $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
> > +                     sleep $TIMEOUT
> > +                     cleanup_processes
> > +                     echo -e "$i $j" >> tmp
> > +                     ((rcnt++))
> > +             done
> > +     done
> > +}
> > +
> > +trap "cleanup; exit;" 2
> > +
> > +echo "***** Starting tests *****"
> > +run_stress
> > +
> > +echo -e "\n***** Cleanup fanotify inotify device *****"
> > +cleanup
>
> This could be easily rewritten in the LTP C API. We do have helper sofr
> most of the functionality that is reimplemented poorly in shell here.
>
> So the whole test should really be a single C source where the testrun
> forks children that runs the stress and I/O rutines that are currently
> in the $BINARIES and the main pid would watch over the execution.
>
> --
> Cyril Hrubis
> chrubis@suse.cz
Murphy Zhou Feb. 28, 2022, 6:29 a.m. UTC | #7
Hi all,

How to run another LTP test case fs_racer.sh or read_all in a new C
programme testcase?

I tried but hit some issues with the PATH configuration.

Is this recommended by you guys?

Thanks,
Murphy

On Tue, Jan 25, 2022 at 7:02 PM Cyril Hrubis <chrubis@suse.cz> wrote:
>
> Hi!
> > diff --git a/testcases/kernel/fs/fs-notify/Makefile b/testcases/kernel/fs/fs-notify/Makefile
> > new file mode 100644
> > index 000000000..328783942
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/Makefile
> > @@ -0,0 +1,18 @@
> > +#
> > +#    kernel/fs/fs-notify testcases Makefile.
> > +#
> > +
> > +top_srcdir                   ?= ../../../..
> > +
> > +include $(top_srcdir)/include/mk/testcases.mk
> > +
> > +BINARIES:=fanotify_flush_stress fanotify_init_stress \
> > +fanotify_mark_stress fanotify_watch inotify_watch \
> > +inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress\
> > +writefile freadfile fwritefile readfile
> > +
> > +INSTALL_TARGETS                      := fsnotify-stress.sh $(BINARIES) rw_files.sh
> > +
> > +MAKE_TARGETS                 := $(BINARIES)
> > +
> > +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> > diff --git a/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> > new file mode 100644
> > index 000000000..493acfb56
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
> > @@ -0,0 +1,52 @@
> > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <limits.h>
> > +#include <poll.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <sys/fanotify.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +     char buf;
> > +     int fd;
> > +
> > +     /* Create the file descriptor for accessing the fanotify API */
> > +     fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> > +                                        O_RDONLY | O_LARGEFILE);
> > +     if (fd == -1) {
> > +             perror("fanotify_init");
> > +             exit(EXIT_FAILURE);
> > +     }
> > +
> > +     /* Loop marking all kinds of events and flush */
> > +     while (1) {
> > +
> > +             if (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, argv[1]) == -1)
> > +
> > +                     perror("fanotify_mark add");
> > +
> > +             if (fanotify_mark(fd, FAN_MARK_FLUSH | FAN_MARK_MOUNT,
> > +                                             0, -1, argv[1]) == -1)
> > +                     perror("fanotify_mark flush mount");
> > +
> > +             if (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, argv[1]) == -1)
> > +
> > +                     perror("fanotify_mark add");
> > +
> > +             if (fanotify_mark(fd, FAN_MARK_FLUSH, 0, -1, argv[1]) == -1)
> > +                     perror("fanotify_mark flush");
> > +     }
> > +
> > +     close(fd);
> > +     exit(EXIT_SUCCESS);
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/fanotify_init_stress.c b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> > new file mode 100644
> > index 000000000..d11924b57
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
> > @@ -0,0 +1,32 @@
> > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > +#include <errno.h>
> > +#include <stdio.h>
> > +#include <unistd.h>
> > +#include <fcntl.h>
> > +#include <stdlib.h>
> > +#include <sys/fanotify.h>
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +     char buf;
> > +     int fd;
> > +     while (1) {
> > +
> > +             /* Create the file descriptor for accessing the fanotify API */
> > +             fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT |
> > +                             FAN_NONBLOCK, O_RDONLY | O_LARGEFILE);
> > +             if (fd == -1)
> > +                     perror("fanotify_init");
> > +
> > +             if (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,
> > +                             argv[1]) == -1)
> > +                     perror("fanotify_mark");
> > +
> > +             close(fd);
> > +     }
> > +
> > +     exit(EXIT_SUCCESS);
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> > new file mode 100644
> > index 000000000..7f648e103
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
> > @@ -0,0 +1,58 @@
> > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <limits.h>
> > +#include <poll.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <sys/fanotify.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +
> > +void add_mark(int fd, uint64_t mask, char *path)
> > +{
> > +     if (fanotify_mark(fd, FAN_MARK_ADD, mask, -1, path) == -1)
> > +             perror("fanotify_mark add");
> > +}
> > +
> > +void remove_mark(int fd, uint64_t mask, char *path)
> > +{
> > +     if (fanotify_mark(fd, FAN_MARK_REMOVE, mask, -1, path) == -1)
> > +             perror("fanotify_mark remove");
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +     char buf;
> > +     int fd;
> > +     /* Create the file descriptor for accessing the fanotify API */
> > +     fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> > +                                        O_RDONLY | O_LARGEFILE);
> > +     if (fd == -1) {
> > +             perror("fanotify_init");
> > +             exit(EXIT_FAILURE);
> > +     }
> > +
> > +     /* Loop marking all kinds of events */
> > +     while (1) {
> > +             add_mark(fd, FAN_ACCESS, argv[1]);
> > +             remove_mark(fd, FAN_ACCESS, argv[1]);
> > +             add_mark(fd, FAN_MODIFY, argv[1]);
> > +             remove_mark(fd, FAN_MODIFY, argv[1]);
> > +             add_mark(fd, FAN_OPEN_PERM, argv[1]);
> > +             remove_mark(fd, FAN_OPEN_PERM, argv[1]);
> > +             add_mark(fd, FAN_CLOSE, argv[1]);
> > +             remove_mark(fd, FAN_CLOSE, argv[1]);
> > +             add_mark(fd, FAN_OPEN, argv[1]);
> > +             remove_mark(fd, FAN_OPEN, argv[1]);
> > +             add_mark(fd, FAN_ACCESS_PERM, argv[1]);
> > +             remove_mark(fd, FAN_ACCESS_PERM, argv[1]);
> > +             add_mark(fd, FAN_ONDIR, argv[1]);
> > +             remove_mark(fd, FAN_ONDIR, argv[1]);
> > +             add_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
> > +             remove_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
> > +     }
> > +
> > +     close(fd);
> > +     exit(EXIT_SUCCESS);
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/fanotify_watch.c b/testcases/kernel/fs/fs-notify/fanotify_watch.c
> > new file mode 100644
> > index 000000000..1028e0e30
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fanotify_watch.c
> > @@ -0,0 +1,244 @@
> > +/* Example in man 7 fanotify */
> > +
> > +#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <limits.h>
> > +#include <poll.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <sys/fanotify.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +
> > +/* get comm for pid from /proc/pid/comm */
> > +static char * get_comm_pid(unsigned int pid)
> > +{
> > +     char * proc_name;
> > +     char * comm;
> > +     int comm_fd, cnt;
> > +
> > +     proc_name = (char *)malloc(50);
> > +     if (proc_name != NULL)
> > +             sprintf(proc_name, "/proc/%u/comm\0", pid);
> > +     else
> > +             return NULL;
> > +
> > +     comm = (char *)malloc(50);
> > +     if (comm != NULL)
> > +             memset(comm, 0, 50);
> > +     else
> > +             return NULL;
> > +
> > +     comm_fd = open(proc_name, O_RDONLY);
> > +     if (comm_fd != -1) {
> > +             cnt = read(comm_fd, comm, 50);
> > +             if (cnt != -1) {
> > +                     comm[cnt] = '\0';
> > +                     close(comm_fd);
> > +                     return comm;
> > +             }
> > +             close(comm_fd);
> > +     }
> > +
> > +     return NULL;
> > +}
> > +
> > +/* Read all available fanotify events from the file descriptor 'fd' */
> > +
> > +static void handle_events(int fd)
> > +{
> > +     const struct fanotify_event_metadata *metadata;
> > +     struct fanotify_event_metadata buf[200];
> > +     ssize_t len;
> > +     char path[PATH_MAX];
> > +     ssize_t path_len;
> > +     char procfd_path[PATH_MAX];
> > +     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) {
> > +                     perror("read");
> > +                     exit(EXIT_FAILURE);
> > +             }
> > +
> > +             /* 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)) {
> > +
> > +                     /* Check that run-time and compile-time structures match */
> > +
> > +                     if (metadata->vers != FANOTIFY_METADATA_VERSION) {
> > +                             fprintf(stderr,
> > +                                 "Mismatch of fanotify metadata version.\n");
> > +                             exit(EXIT_FAILURE);
> > +                     }
> > +
> > +                     /* 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) {
> > +                                     printf("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) {
> > +                                     printf("FAN_ACCESS_PERM: ");
> > +
> > +                                     /* Allow file to be accessed */
> > +                                     response.fd = metadata->fd;
> > +                                     response.response = FAN_ALLOW;
> > +                                     write(fd, &response,
> > +                                         sizeof(struct fanotify_response));
> > +                             }
> > +
> > +                             /* Handle closing of writable file event */
> > +                             if (metadata->mask & FAN_CLOSE_WRITE)
> > +                                     printf("FAN_CLOSE_WRITE: ");
> > +
> > +                             /* Handle closing of not writable file event */
> > +                             if (metadata->mask & FAN_CLOSE_NOWRITE)
> > +                                     printf("FAN_CLOSE_NOWRITE: ");
> > +
> > +                             /* Handle modify file event */
> > +                             if (metadata->mask & FAN_MODIFY)
> > +                                     printf("FAN_MODIFY: ");
> > +
> > +                             /* Handle open event */
> > +                             if (metadata->mask & FAN_OPEN)
> > +                                     printf("FAN_OPEN: ");
> > +
> > +                             /* Handle access event */
> > +                             if (metadata->mask & FAN_ACCESS)
> > +                                     printf("FAN_ACCESS: ");
> > +
> > +                             /* Handle access event */
> > +                             if (metadata->mask & FAN_ONDIR)
> > +                                     printf("FAN_ONDIR: ");
> > +
> > +                             /* Handle access event */
> > +                             if (metadata->mask & FAN_EVENT_ON_CHILD)
> > +                                     printf("FAN_EVENT_ON_CHILD: ");
> > +
> > +                             /* Retrieve/print the accessed file path*/
> > +                             snprintf(procfd_path, sizeof(procfd_path),
> > +                                         "/proc/self/fd/%d", metadata->fd);
> > +                             path_len = readlink(procfd_path, path,
> > +                                         sizeof(path) - 1);
> > +                             if (path_len == -1) {
> > +                                     perror("readlink");
> > +                                     exit(EXIT_FAILURE);
> > +                             }
> > +
> > +                             path[path_len] = '\0';
> > +                             printf("File %s.\t\t Comm %s", path,
> > +                                     get_comm_pid(metadata->pid));
> > +
> > +                             /* Close the file descriptor of the event */
> > +
> > +                             close(metadata->fd);
> > +                     }
> > +
> > +                     /* Advance to next event */
> > +                     metadata = FAN_EVENT_NEXT(metadata, len);
> > +             }
> > +     }
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +     char buf;
> > +     int fd, poll_num;
> > +     nfds_t nfds;
> > +     struct pollfd fds[2];
> > +     FILE *f;
> > +#if 0
> > +     /* Check mount point is supplied */
> > +     if (argc != 2) {
> > +             fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
> > +             exit(EXIT_FAILURE);
> > +     }
> > +#endif
> > +     printf("%s on %s\n", argv[0], argv[1]);
> > +     fflush(stdout);
> > +     f = freopen("fanotify.log", "w+", stdout);
> > +     if (f == NULL) {
> > +             perror("freopen");
> > +             exit(EXIT_FAILURE);
> > +     }
> > +
> > +     /* Create the file descriptor for accessing the fanotify API */
> > +     fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
> > +                                        O_RDONLY | O_LARGEFILE);
> > +     if (fd == -1) {
> > +             perror("fanotify_init");
> > +             exit(EXIT_FAILURE);
> > +     }
> > +
> > +     /* Mark the mount for:
> > +        - permission events before opening files
> > +        - notification events after closing a write-enabled
> > +              file descriptor */
> > +     if (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, argv[1]) == -1) {
> > +
> > +             perror("fanotify_mark");
> > +             exit(EXIT_FAILURE);
> > +     }
> > +
> > +     /* Prepare for polling */
> > +     nfds = 1;
> > +
> > +     /* Fanotify input */
> > +     fds[0].fd = fd;
> > +     fds[0].events = POLLIN;
> > +
> > +     /* This is the loop to wait for incoming events */
> > +     printf("Listening for events.\n");
> > +     while (1) {
> > +             poll_num = poll(fds, nfds, -1);
> > +             if (poll_num == -1) {
> > +                     if (errno == EINTR)     /* Interrupted by a signal */
> > +                             continue;           /* Restart poll() */
> > +
> > +                     perror("poll");         /* Unexpected error */
> > +                     exit(EXIT_FAILURE);
> > +             }
> > +
> > +             if (poll_num > 0) {
> > +
> > +                     if (fds[0].revents & POLLIN) {
> > +
> > +                             /* Fanotify events are available */
> > +                             handle_events(fd);
> > +                     }
> > +             }
> > +     }
> > +
> > +     fclose(f);
> > +     printf("Listening for events stopped.\n");
> > +     exit(EXIT_SUCCESS);
> > +}
> > diff --git a/testcases/kernel/fs/fs-notify/freadfile.c b/testcases/kernel/fs/fs-notify/freadfile.c
> > new file mode 100644
> > index 000000000..24bf76bcd
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/freadfile.c
> > @@ -0,0 +1,27 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +
> > +int main(int argc, char **argv)
> > +{
> > +     int fd;
> > +     char buf[BUFSIZ];
> > +     FILE *f;
> > +
> > +     memset(buf, 1, BUFSIZ);
> > +     while(1) {
> > +             f = fopen(argv[1], "r+");
> > +             if (f == NULL) {
> > +                     perror("freadfile fopen");
> > +                     exit(EXIT_FAILURE);
> > +             }
> > +             fread(buf, sizeof(char), BUFSIZ, f);
> > +             usleep(1);
> > +     }
> > +     fclose(f);
> > +     return 0;
> > +}
>
> There is no real reason to keep these as several separate files. We can
> actually put the whole test into one single C source that forks severa
> times and each child runs one of loops from these helpers.
>
> > diff --git a/testcases/kernel/fs/fs-notify/fsnotify-stress.sh b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> > new file mode 100755
> > index 000000000..d6fd5482b
> > --- /dev/null
> > +++ b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
> > @@ -0,0 +1,64 @@
> > +#!/bin/bash
> > +
> > +export TIMEOUT=10
> > +
> > +STRESSES="fanotify_flush_stress fanotify_init_stress \
> > +fanotify_mark_stress fanotify_watch inotify_watch \
> > +inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress"
> > +IO_OPES="writefile freadfile fwritefile readfile"
> > +
> > +NR_CPUS=$(grep -c processor /proc/cpuinfo)
> > +[ $NR_CPUS -lt 4 ] && NR_CPUS=4
> > +
> > +function cleanup_processes()
> > +{
> > +     while ps -eo pid,comm | \
> > +             grep -q -E "fanotify|inotify|rw_files|readfile|writefile" ; do
> > +             killall rw_files.sh $STRESSES $IO_OPES > /dev/null 2>&1
> > +             sleep 1
> > +     done
> > +}
> > +
> > +function cleanup()
> > +{
> > +     sleep 3 # waiting possible unfinished processes
> > +     cleanup_processes
> > +     rm -f $STRESSES $IO_OPES fanotify.log inotify.log tmp
> > +     cd /
> > +     sync
> > +}
> > +
> > +function run_stress()
> > +{
> > +     local i j rcnt=0
> > +     echo -e "* CPU count: $NR_CPUS"
> > +     echo -e "* TIMEOUT for each subcase: $TIMEOUT"
> > +
> > +     echo -e "* Starting fsnotify stress on directory and regular file"
> > +     touch $TMPDIR/testfile
> > +     >tmp
> > +     for i in $STRESSES $IO_OPES rw_files.sh; do
> > +             for j in $STRESSES ; do
> > +                     [ "$i" == "$j" ] && continue
> > +                     # skip duplicate combinations
> > +                     grep -w $j tmp | grep -qw $i && continue
> > +                     echo -e "* Starting $i and $j, rcnt $rcnt"
> > +                     ./$i $TMPDIR $TIMEOUT > /dev/null 2>&1 &
> > +                     ./$i $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
> > +                     ./$j $TMPDIR $TIMEOUT > /dev/null 2>&1 &
> > +                     ./$j $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
> > +                     sleep $TIMEOUT
> > +                     cleanup_processes
> > +                     echo -e "$i $j" >> tmp
> > +                     ((rcnt++))
> > +             done
> > +     done
> > +}
> > +
> > +trap "cleanup; exit;" 2
> > +
> > +echo "***** Starting tests *****"
> > +run_stress
> > +
> > +echo -e "\n***** Cleanup fanotify inotify device *****"
> > +cleanup
>
> This could be easily rewritten in the LTP C API. We do have helper sofr
> most of the functionality that is reimplemented poorly in shell here.
>
> So the whole test should really be a single C source where the testrun
> forks children that runs the stress and I/O rutines that are currently
> in the $BINARIES and the main pid would watch over the execution.
>
> --
> Cyril Hrubis
> chrubis@suse.cz
Petr Vorel Feb. 28, 2022, 6:42 a.m. UTC | #8
Hi Murphy,

> Hi all,

> How to run another LTP test case fs_racer.sh or read_all in a new C
> programme testcase?
Both read_all and fs_racer.sh are in runtest/fs.

You can run them manually with corrctly set PATH [1] (best is to fully install
LTP and add $LTPROOT/testcases/bin:$LTPROOT/bin (where LTPROOT is prefix for
installed LTP, i.e. /opt/ltp [2]).

Or you just run whole runtest/fs with the old runltp.

Note, we're working hard on new runner, but not finished yet.

Kind regards,
Petr

> I tried but hit some issues with the PATH configuration.

> Is this recommended by you guys?

> Thanks,
> Murphy

[1] https://github.com/linux-test-project/ltp#shortcut-to-running-a-single-test
[2] https://github.com/linux-test-project/ltp/wiki/User-Guidelines
diff mbox series

Patch

diff --git a/testcases/kernel/fs/fs-notify/Makefile b/testcases/kernel/fs/fs-notify/Makefile
new file mode 100644
index 000000000..328783942
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/Makefile
@@ -0,0 +1,18 @@ 
+#
+#    kernel/fs/fs-notify testcases Makefile.
+#
+
+top_srcdir			?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+BINARIES:=fanotify_flush_stress fanotify_init_stress \
+fanotify_mark_stress fanotify_watch inotify_watch \
+inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress\
+writefile freadfile fwritefile readfile
+
+INSTALL_TARGETS			:= fsnotify-stress.sh $(BINARIES) rw_files.sh
+
+MAKE_TARGETS			:= $(BINARIES)
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
new file mode 100644
index 000000000..493acfb56
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/fanotify_flush_stress.c
@@ -0,0 +1,52 @@ 
+#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/fanotify.h>
+#include <unistd.h>
+#include <string.h>
+
+int main(int argc, char *argv[])
+{
+	char buf;
+	int fd;
+
+	/* Create the file descriptor for accessing the fanotify API */
+	fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
+					   O_RDONLY | O_LARGEFILE);
+	if (fd == -1) {
+		perror("fanotify_init");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Loop marking all kinds of events and flush */
+	while (1) {
+
+		if (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, argv[1]) == -1)
+
+			perror("fanotify_mark add");
+
+		if (fanotify_mark(fd, FAN_MARK_FLUSH | FAN_MARK_MOUNT,
+						0, -1, argv[1]) == -1)
+			perror("fanotify_mark flush mount");
+
+		if (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, argv[1]) == -1)
+
+			perror("fanotify_mark add");
+
+		if (fanotify_mark(fd, FAN_MARK_FLUSH, 0, -1, argv[1]) == -1)
+			perror("fanotify_mark flush");
+	}
+
+	close(fd);
+	exit(EXIT_SUCCESS);
+}
diff --git a/testcases/kernel/fs/fs-notify/fanotify_init_stress.c b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
new file mode 100644
index 000000000..d11924b57
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/fanotify_init_stress.c
@@ -0,0 +1,32 @@ 
+#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/fanotify.h>
+
+int main(int argc, char *argv[])
+{
+	char buf;
+	int fd;
+	while (1) {
+
+		/* Create the file descriptor for accessing the fanotify API */
+		fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT |
+				FAN_NONBLOCK, O_RDONLY | O_LARGEFILE);
+		if (fd == -1)
+			perror("fanotify_init");
+
+		if (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,
+				argv[1]) == -1)
+			perror("fanotify_mark");
+
+		close(fd);
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
new file mode 100644
index 000000000..7f648e103
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/fanotify_mark_stress.c
@@ -0,0 +1,58 @@ 
+#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/fanotify.h>
+#include <unistd.h>
+#include <string.h>
+
+void add_mark(int fd, uint64_t mask, char *path)
+{
+	if (fanotify_mark(fd, FAN_MARK_ADD, mask, -1, path) == -1)
+		perror("fanotify_mark add");
+}
+
+void remove_mark(int fd, uint64_t mask, char *path)
+{
+	if (fanotify_mark(fd, FAN_MARK_REMOVE, mask, -1, path) == -1)
+		perror("fanotify_mark remove");
+}
+
+int main(int argc, char *argv[])
+{
+	char buf;
+	int fd;
+	/* Create the file descriptor for accessing the fanotify API */
+	fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
+					   O_RDONLY | O_LARGEFILE);
+	if (fd == -1) {
+		perror("fanotify_init");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Loop marking all kinds of events */
+	while (1) {
+		add_mark(fd, FAN_ACCESS, argv[1]);
+		remove_mark(fd, FAN_ACCESS, argv[1]);
+		add_mark(fd, FAN_MODIFY, argv[1]);
+		remove_mark(fd, FAN_MODIFY, argv[1]);
+		add_mark(fd, FAN_OPEN_PERM, argv[1]);
+		remove_mark(fd, FAN_OPEN_PERM, argv[1]);
+		add_mark(fd, FAN_CLOSE, argv[1]);
+		remove_mark(fd, FAN_CLOSE, argv[1]);
+		add_mark(fd, FAN_OPEN, argv[1]);
+		remove_mark(fd, FAN_OPEN, argv[1]);
+		add_mark(fd, FAN_ACCESS_PERM, argv[1]);
+		remove_mark(fd, FAN_ACCESS_PERM, argv[1]);
+		add_mark(fd, FAN_ONDIR, argv[1]);
+		remove_mark(fd, FAN_ONDIR, argv[1]);
+		add_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
+		remove_mark(fd, FAN_EVENT_ON_CHILD, argv[1]);
+	}
+
+	close(fd);
+	exit(EXIT_SUCCESS);
+}
diff --git a/testcases/kernel/fs/fs-notify/fanotify_watch.c b/testcases/kernel/fs/fs-notify/fanotify_watch.c
new file mode 100644
index 000000000..1028e0e30
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/fanotify_watch.c
@@ -0,0 +1,244 @@ 
+/* Example in man 7 fanotify */
+
+#define _GNU_SOURCE     /* Needed to get O_LARGEFILE definition */
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/fanotify.h>
+#include <unistd.h>
+#include <string.h>
+
+/* get comm for pid from /proc/pid/comm */
+static char * get_comm_pid(unsigned int pid)
+{
+	char * proc_name;
+	char * comm;
+	int comm_fd, cnt;
+
+	proc_name = (char *)malloc(50);
+	if (proc_name != NULL)
+		sprintf(proc_name, "/proc/%u/comm\0", pid);
+	else
+		return NULL;
+
+	comm = (char *)malloc(50);
+	if (comm != NULL)
+		memset(comm, 0, 50);
+	else
+		return NULL;
+
+	comm_fd = open(proc_name, O_RDONLY);
+	if (comm_fd != -1) {
+		cnt = read(comm_fd, comm, 50);
+		if (cnt != -1) {
+			comm[cnt] = '\0';
+			close(comm_fd);
+			return comm;
+		}
+		close(comm_fd);
+	}
+
+	return NULL;
+}
+
+/* Read all available fanotify events from the file descriptor 'fd' */
+
+static void handle_events(int fd)
+{
+	const struct fanotify_event_metadata *metadata;
+	struct fanotify_event_metadata buf[200];
+	ssize_t len;
+	char path[PATH_MAX];
+	ssize_t path_len;
+	char procfd_path[PATH_MAX];
+	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) {
+			perror("read");
+			exit(EXIT_FAILURE);
+		}
+
+		/* 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)) {
+
+			/* Check that run-time and compile-time structures match */
+
+			if (metadata->vers != FANOTIFY_METADATA_VERSION) {
+				fprintf(stderr,
+				    "Mismatch of fanotify metadata version.\n");
+				exit(EXIT_FAILURE);
+			}
+
+			/* 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) {
+					printf("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) {
+					printf("FAN_ACCESS_PERM: ");
+
+					/* Allow file to be accessed */
+					response.fd = metadata->fd;
+					response.response = FAN_ALLOW;
+					write(fd, &response,
+					    sizeof(struct fanotify_response));
+				}
+
+				/* Handle closing of writable file event */
+				if (metadata->mask & FAN_CLOSE_WRITE)
+					printf("FAN_CLOSE_WRITE: ");
+
+				/* Handle closing of not writable file event */
+				if (metadata->mask & FAN_CLOSE_NOWRITE)
+					printf("FAN_CLOSE_NOWRITE: ");
+
+				/* Handle modify file event */
+				if (metadata->mask & FAN_MODIFY)
+					printf("FAN_MODIFY: ");
+
+				/* Handle open event */
+				if (metadata->mask & FAN_OPEN)
+					printf("FAN_OPEN: ");
+
+				/* Handle access event */
+				if (metadata->mask & FAN_ACCESS)
+					printf("FAN_ACCESS: ");
+
+				/* Handle access event */
+				if (metadata->mask & FAN_ONDIR)
+					printf("FAN_ONDIR: ");
+
+				/* Handle access event */
+				if (metadata->mask & FAN_EVENT_ON_CHILD)
+					printf("FAN_EVENT_ON_CHILD: ");
+
+				/* Retrieve/print the accessed file path*/
+				snprintf(procfd_path, sizeof(procfd_path),
+					    "/proc/self/fd/%d", metadata->fd);
+				path_len = readlink(procfd_path, path,
+					    sizeof(path) - 1);
+				if (path_len == -1) {
+					perror("readlink");
+					exit(EXIT_FAILURE);
+				}
+
+				path[path_len] = '\0';
+				printf("File %s.\t\t Comm %s", path,
+					get_comm_pid(metadata->pid));
+
+				/* Close the file descriptor of the event */
+
+				close(metadata->fd);
+			}
+
+			/* Advance to next event */
+			metadata = FAN_EVENT_NEXT(metadata, len);
+		}
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	char buf;
+	int fd, poll_num;
+	nfds_t nfds;
+	struct pollfd fds[2];
+	FILE *f;
+#if 0
+	/* Check mount point is supplied */
+	if (argc != 2) {
+		fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+#endif
+	printf("%s on %s\n", argv[0], argv[1]);
+	fflush(stdout);
+	f = freopen("fanotify.log", "w+", stdout);
+	if (f == NULL) {
+		perror("freopen");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Create the file descriptor for accessing the fanotify API */
+	fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
+					   O_RDONLY | O_LARGEFILE);
+	if (fd == -1) {
+		perror("fanotify_init");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Mark the mount for:
+	   - permission events before opening files
+	   - notification events after closing a write-enabled
+		 file descriptor */
+	if (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, argv[1]) == -1) {
+
+		perror("fanotify_mark");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Prepare for polling */
+	nfds = 1;
+
+	/* Fanotify input */
+	fds[0].fd = fd;
+	fds[0].events = POLLIN;
+
+	/* This is the loop to wait for incoming events */
+	printf("Listening for events.\n");
+	while (1) {
+		poll_num = poll(fds, nfds, -1);
+		if (poll_num == -1) {
+			if (errno == EINTR)     /* Interrupted by a signal */
+				continue;           /* Restart poll() */
+
+			perror("poll");         /* Unexpected error */
+			exit(EXIT_FAILURE);
+		}
+
+		if (poll_num > 0) {
+
+			if (fds[0].revents & POLLIN) {
+
+				/* Fanotify events are available */
+				handle_events(fd);
+			}
+		}
+	}
+
+	fclose(f);
+	printf("Listening for events stopped.\n");
+	exit(EXIT_SUCCESS);
+}
diff --git a/testcases/kernel/fs/fs-notify/freadfile.c b/testcases/kernel/fs/fs-notify/freadfile.c
new file mode 100644
index 000000000..24bf76bcd
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/freadfile.c
@@ -0,0 +1,27 @@ 
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int main(int argc, char **argv)
+{
+	int fd;
+	char buf[BUFSIZ];
+	FILE *f;
+
+	memset(buf, 1, BUFSIZ);
+	while(1) {
+		f = fopen(argv[1], "r+");
+		if (f == NULL) {
+			perror("freadfile fopen");
+			exit(EXIT_FAILURE);
+		}
+		fread(buf, sizeof(char), BUFSIZ, f);
+		usleep(1);
+	}
+	fclose(f);
+	return 0;
+}
diff --git a/testcases/kernel/fs/fs-notify/fsnotify-stress.sh b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
new file mode 100755
index 000000000..d6fd5482b
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/fsnotify-stress.sh
@@ -0,0 +1,64 @@ 
+#!/bin/bash
+
+export TIMEOUT=10
+
+STRESSES="fanotify_flush_stress fanotify_init_stress \
+fanotify_mark_stress fanotify_watch inotify_watch \
+inotify_add_rm_stress inotify_init_stress inotify_inmodify_stress"
+IO_OPES="writefile freadfile fwritefile readfile"
+
+NR_CPUS=$(grep -c processor /proc/cpuinfo)
+[ $NR_CPUS -lt 4 ] && NR_CPUS=4
+
+function cleanup_processes()
+{
+	while ps -eo pid,comm | \
+		grep -q -E "fanotify|inotify|rw_files|readfile|writefile" ; do
+		killall rw_files.sh $STRESSES $IO_OPES > /dev/null 2>&1
+		sleep 1
+	done
+}
+
+function cleanup()
+{
+	sleep 3 # waiting possible unfinished processes
+	cleanup_processes
+	rm -f $STRESSES $IO_OPES fanotify.log inotify.log tmp
+	cd /
+	sync
+}
+
+function run_stress()
+{
+	local i j rcnt=0
+	echo -e "* CPU count: $NR_CPUS"
+	echo -e "* TIMEOUT for each subcase: $TIMEOUT"
+
+	echo -e "* Starting fsnotify stress on directory and regular file"
+	touch $TMPDIR/testfile
+	>tmp
+	for i in $STRESSES $IO_OPES rw_files.sh; do
+		for j in $STRESSES ; do
+			[ "$i" == "$j" ] && continue
+			# skip duplicate combinations
+			grep -w $j tmp | grep -qw $i && continue
+			echo -e "* Starting $i and $j, rcnt $rcnt"
+			./$i $TMPDIR $TIMEOUT > /dev/null 2>&1 &
+			./$i $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
+			./$j $TMPDIR $TIMEOUT > /dev/null 2>&1 &
+			./$j $TMPDIR/testfile $TIMEOUT > /dev/null 2>&1 &
+			sleep $TIMEOUT
+			cleanup_processes
+			echo -e "$i $j" >> tmp
+			((rcnt++))
+		done
+	done
+}
+
+trap "cleanup; exit;" 2
+
+echo "***** Starting tests *****"
+run_stress
+
+echo -e "\n***** Cleanup fanotify inotify device *****"
+cleanup
diff --git a/testcases/kernel/fs/fs-notify/fwritefile.c b/testcases/kernel/fs/fs-notify/fwritefile.c
new file mode 100644
index 000000000..a2956d60b
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/fwritefile.c
@@ -0,0 +1,27 @@ 
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int main(int argc, char **argv)
+{
+	int fd;
+	char buf[BUFSIZ];
+	FILE *f;
+
+	memset(buf, 1, BUFSIZ);
+	while(1) {
+		f = fopen(argv[1], "w+");
+		if (f == NULL) {
+			perror("fwritefile fopen");
+			exit(EXIT_FAILURE);
+		}
+		fwrite(buf, sizeof(char), BUFSIZ, f);
+		usleep(1);
+	}
+	fclose(f);
+	return 0;
+}
diff --git a/testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c b/testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c
new file mode 100644
index 000000000..e88fc088e
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/inotify_add_rm_stress.c
@@ -0,0 +1,36 @@ 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <sys/inotify.h>
+
+int main(int argc, char *argv[])
+{
+	int notify_fd;
+	int wd, ret;
+
+	notify_fd = inotify_init1(IN_CLOEXEC);
+	if (notify_fd == -1) {
+		perror("inotify_init1");
+		return -1;
+	}
+
+	while (1) {
+		wd = inotify_add_watch(notify_fd, argv[1],
+			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);
+		if (wd < 0)
+			perror("inotify_add_watch");
+
+		ret = inotify_rm_watch(notify_fd, wd);
+		if (ret < 0)
+			perror("inotify_rm_watch");
+	}
+	close(notify_fd);
+	return 0;
+}
diff --git a/testcases/kernel/fs/fs-notify/inotify_init_stress.c b/testcases/kernel/fs/fs-notify/inotify_init_stress.c
new file mode 100644
index 000000000..62cb7c2e6
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/inotify_init_stress.c
@@ -0,0 +1,22 @@ 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <sys/inotify.h>
+
+int main(int argc, char *argv[])
+{
+	int notify_fd;
+	int wd;
+
+	while (1) {
+		notify_fd = inotify_init1(IN_CLOEXEC);
+		if (notify_fd == -1)
+			perror("inotify_init1");
+		close(notify_fd);
+	}
+	return 0;
+}
diff --git a/testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c b/testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c
new file mode 100644
index 000000000..546ccb76f
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/inotify_inmodify_stress.c
@@ -0,0 +1,17 @@ 
+#include <sys/inotify.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/*
+ * Calls inotify_rm_watch in a loop.
+ */
+int main(int argc, char **argv)
+{
+	int fd = inotify_init();
+	while (1) {
+		int wd = inotify_add_watch(fd, argv[1], IN_MODIFY);
+		inotify_rm_watch(fd, wd);
+	}
+	close(fd);
+	return 0;
+}
diff --git a/testcases/kernel/fs/fs-notify/inotify_watch.c b/testcases/kernel/fs/fs-notify/inotify_watch.c
new file mode 100644
index 000000000..b4b908b6b
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/inotify_watch.c
@@ -0,0 +1,98 @@ 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <sys/inotify.h>
+
+int main(int argc, char *argv[])
+{
+	int notify_fd;
+	int wd, ret;
+	char *buf;
+	FILE *f;
+
+	f = freopen("inotify.log", "w+", stdout);
+	if (f == NULL) {
+		perror("freopen");
+		exit(EXIT_FAILURE);
+	}
+
+	buf = malloc(sizeof(struct inotify_event) + NAME_MAX + 1);
+	if (buf == NULL) {
+		perror("malloc");
+		return -1;
+	}
+
+	notify_fd = inotify_init1(IN_CLOEXEC);
+	if (notify_fd == -1) {
+		perror("inotify_init1");
+		return -1;
+	}
+
+	wd = inotify_add_watch(notify_fd, argv[1],
+		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);
+
+	if (wd < 0) {
+		perror("inotify_add_watch");
+		return -1;
+	}
+
+	while (ret = read(notify_fd, buf, NAME_MAX) != -1) {
+		struct inotify_event *ip = (struct inotify_event *)buf;
+		printf("name %s event ", ip->name);
+		switch (ip->mask) {
+		case IN_ACCESS:
+			printf("access\n");
+			break;
+		case IN_ATTRIB:
+			printf("attrib\n");
+			break;
+		case IN_CLOSE_WRITE:
+			printf("close write\n");
+			break;
+		case IN_CLOSE_NOWRITE:
+			printf("close nowrite\n");
+			break;
+		case IN_CREATE:
+			printf("create\n");
+			break;
+		case IN_DELETE:
+			printf("delete\n");
+			break;
+		case IN_DELETE_SELF:
+			printf("deleteself\n");
+			break;
+		case IN_MODIFY:
+			printf("modify\n");
+			break;
+		case IN_MOVE_SELF:
+			printf("move self\n");
+			break;
+		case IN_MOVED_FROM:
+			printf("move from\n");
+			break;
+		case IN_MOVED_TO:
+			printf("move to\n");
+			break;
+		case IN_OPEN:
+			printf("open\n");
+			break;
+		default:
+			printf("\n");
+			break;
+		};
+	}
+
+	ret = inotify_rm_watch(notify_fd, wd);
+	if (ret < 0)
+		perror("inotify_rm_watch");
+
+	fclose(f);
+	close(notify_fd);
+	return 0;
+}
diff --git a/testcases/kernel/fs/fs-notify/readfile.c b/testcases/kernel/fs/fs-notify/readfile.c
new file mode 100644
index 000000000..2ab1a3694
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/readfile.c
@@ -0,0 +1,28 @@ 
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int main(int argc, char **argv)
+{
+	int fd, ret;
+	char buf[BUFSIZ];
+
+	memset(buf, 1, BUFSIZ);
+	while (1) {
+		fd = open(argv[1], O_RDWR);
+		if (fd == -1) {
+			perror("readfile open");
+			exit(EXIT_FAILURE);
+		}
+		ret = read(fd, buf, BUFSIZ);
+		if (ret == -1)
+			perror("readfile read");
+		usleep(1);
+	}
+	close(fd);
+	return 0;
+}
diff --git a/testcases/kernel/fs/fs-notify/rw_files.sh b/testcases/kernel/fs/fs-notify/rw_files.sh
new file mode 100755
index 000000000..bb3387160
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/rw_files.sh
@@ -0,0 +1,90 @@ 
+#!/bin/bash
+
+TDIR=$1
+TIMEO=$2
+
+[ -z "$TDIR" ] && TDIR=/tmp/
+[ -d $TDIR ] || TDIR=/tmp/
+[ -z "$TIMEO" ] && TIMEO=1m
+
+[ ! -d $TDIR ] && exit
+
+function add_files()
+{
+	local i=0
+
+	while true ; do
+
+		touch f-$i
+		ln -s f-$i f-$i-sym
+		ln f-$i f-$i-hdl
+
+		mkdir d-$i
+
+		mknod c-$i c 1 2
+		mknod b-$i b 1 2
+		mknod p-$i p
+
+		((i++))
+		[ -e stoptest ] && { echo $FUNCNAME; exit; }
+	done
+}
+
+function mv_files()
+{
+	local i=0
+
+	while true ; do
+
+		mv -f f-$i f-$i-rename
+		mv -f f-$i-rename f-$i
+		((i++))
+		[ -e stoptest ] && { echo $FUNCNAME; exit; }
+	done
+}
+
+function read_files()
+{
+	while true ; do
+
+		find .
+		cat f-*
+		ls d-*
+		[ -e stoptest ] && { echo $FUNCNAME; exit; }
+	done
+}
+
+function write_files()
+{
+	while true ; do
+
+		for j in f-* d-* c-* b-* p-* ; do
+			echo 1 > $j
+			echo 2 >> $j
+			[ -e stoptest ] && { echo $FUNCNAME; exit; }
+		done
+		[ -e stoptest ] && { echo $FUNCNAME; exit; }
+	done
+}
+
+function rm_files()
+{
+	while true ; do
+
+		rm -rf d-* f-* c-* b-* p-*
+		sleep 3
+		[ -e stoptest ] && { echo $FUNCNAME; exit; }
+	done
+}
+
+pushd $TDIR > /dev/null 2>&1
+rm -f stoptest
+add_files > /dev/null 2>&1 &
+mv_files > /dev/null 2>&1 &
+read_files > /dev/null 2>&1 &
+write_files > /dev/null 2>&1 &
+rm_files > /dev/null 2>&1 &
+popd > /dev/null 2>&1
+
+sleep $TIMEO
+touch $TDIR/stoptest
diff --git a/testcases/kernel/fs/fs-notify/writefile.c b/testcases/kernel/fs/fs-notify/writefile.c
new file mode 100644
index 000000000..9025b5d95
--- /dev/null
+++ b/testcases/kernel/fs/fs-notify/writefile.c
@@ -0,0 +1,28 @@ 
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int main(int argc, char **argv)
+{
+	int fd, ret;
+	char buf[BUFSIZ];
+
+	memset(buf, 1, BUFSIZ);
+	while (1) {
+		fd = open(argv[1], O_RDWR);
+		if (fd == -1) {
+			perror("writefile open");
+			exit(EXIT_FAILURE);
+		}
+		ret = write(fd, buf, BUFSIZ);
+		if (ret == -1)
+			perror("writefile write");
+		usleep(1);
+	}
+	close(fd);
+	return 0;
+}