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

Murphy Zhou jencce.kernel@gmail.com
Tue Jan 25 03:47:18 CET 2022


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

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



More information about the ltp mailing list