[Devel] [PATCH 07/11] fsetown1: Test async I/O notification after restart
Sukadev Bhattiprolu
sukadev at linux.vnet.ibm.com
Fri Jan 29 12:43:04 PST 2010
From: Sukadev Bhattiprolu <sukadev at linux.vnet.ibm.com>
Date: Thu, 21 Jan 2010 23:07:51 -0800
Subject: [PATCH 07/11] fsetown1: Test async I/O notification after restart
Checkpoint a process that is waiting for async notification of data
being available on a pipe. When the process is restarted, make data
available on the pipe and ensure that the process is notified.
Signed-off-by: Sukadev Bhattiprolu <sukadev at linux.vnet.ibm.com>
---
fileio/Makefile | 4 +-
fileio/fsetown1.c | 268 ++++++++++++++++++++++++++++++++++++++++++++++++
fileio/run-fsetown1.sh | 3 +
fileio/runtests.sh | 5 +
libcrtest/common.c | 2 +-
5 files changed, 279 insertions(+), 3 deletions(-)
create mode 100644 fileio/fsetown1.c
create mode 100755 fileio/run-fsetown1.sh
diff --git a/fileio/Makefile b/fileio/Makefile
index acc2df9..bd28561 100644
--- a/fileio/Makefile
+++ b/fileio/Makefile
@@ -1,4 +1,4 @@
-targets = fileio1 filelock1 filelease1
+targets = fileio1 filelock1 filelease1 fsetown1
INCLUDE = ../libcrtest
LIBCRTEST = ../libcrtest/common.o
@@ -9,4 +9,4 @@ all: $(LIBCRTEST) $(targets)
clean:
rm -f $(targets)
- rm -rf cr_fileio* cr_filelock1* cr_filelease1*
+ rm -rf cr_fileio* cr_filelock1* cr_filelease1* cr_fsetown1*
diff --git a/fileio/fsetown1.c b/fileio/fsetown1.c
new file mode 100644
index 0000000..c6c5734
--- /dev/null
+++ b/fileio/fsetown1.c
@@ -0,0 +1,268 @@
+#include <stdio.h>
+#include <unistd.h>
+#define __USE_GNU
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <wait.h>
+#include "libcrtest.h"
+
+#define LOG_FILE "logs.d/log.fsetown1"
+
+int pipe_fds[2];
+int event_fd1;
+int got_sigio;
+
+/*
+ * Description:
+ * Checkpoint a process that is waiting for async notification of data
+ * being available on a pipe. When the process is restarted, make data
+ * available on the pipe and ensure that the process is notified.
+ *
+ * Implementation:
+ */
+void iohandler(int sig)
+{
+ int rc;
+ char buf[16];
+
+ fprintf(logfp, "%d: Got signal %d\n", getpid(), sig);
+ fflush(logfp);
+ got_sigio = 1;
+}
+
+static void wait_for_child()
+{
+ int rc;
+ int status;
+
+ rc = waitpid(-1, &status, 0);
+ if (rc < 0) {
+ fprintf(logfp, "%d: waitpid(): rc %d, error %s\n",
+ getpid(), rc, strerror(errno));
+ do_exit(1);
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ fprintf(logfp, "%d: Test case PASSED\n", getpid());
+ rc = 0;
+ } else {
+ fprintf(logfp, "%d: Test case FAILED\n", getpid());
+ print_exit_status(rc, status);
+ rc = 1;
+ }
+ do_exit(rc);
+}
+
+void set_owner(int fd)
+{
+ int rc;
+ long flags;
+
+ fprintf(logfp, "%d: Setting owner to myself\n", getpid());
+
+ signal(SIGIO, iohandler);
+
+ flags = O_ASYNC;
+ rc = fcntl(fd, F_SETFL, flags);
+ if (rc < 0) {
+ fprintf(logfp, "%d: set_owner(): F_SETFL ERROR %s\n", getpid(),
+ strerror(errno));
+ goto error;
+ }
+
+ rc = fcntl(fd, F_SETOWN, getpid());
+ if (rc < 0) {
+ fprintf(logfp, "%d: set_owner():, ERROR %s\n", getpid(),
+ strerror(errno));
+ if (errno == EINVAL)
+ fprintf(logfp, "%d: Maybe the fs does not support "
+ "F_SETLEASE (eg: NFS)\n", getpid());
+ goto error;
+ }
+
+ fprintf(logfp, "%d: Set owner() done\n", getpid());
+ return;
+
+error:
+ /*
+ * Parent will be waiting for notification. Signal that we failed
+ * and are exiting
+ */
+ kill(getppid(), SIGUSR1);
+ do_exit(1);
+}
+
+/*
+ * Called by parent to see if child is still the owner
+ */
+void test_owner(int fd, int exp_owner)
+{
+ int rc;
+
+ rc = fcntl(fd, F_GETOWN, 0);
+ if (rc < 0) {
+ fprintf(logfp, "%d: ERROR: fcntl(F_GETOWN) error %s\n",
+ getpid(), strerror(errno));
+ do_exit(1);
+ }
+
+ if (rc != exp_owner) {
+ fprintf(logfp, "%d: FAILED: Expected owner %d, actual %d\n",
+ getpid(), exp_owner, rc);
+ /*
+ * Terminate the child since it will not be notified of I/O.
+ */
+ kill(exp_owner, SIGKILL);
+ wait_for_child();
+ do_exit(1);
+ }
+
+ fprintf(logfp, "%d: PASS: Owner is %d\n", getpid(), exp_owner);
+ return;
+}
+
+int do_child()
+{
+ int rc;
+ char buf[16];
+ int fd = pipe_fds[0];
+
+ set_owner(fd);
+
+ /*
+ * Tell parent we are ready for checkpoint...
+ */
+ notify_one_event(event_fd1);
+
+ /*
+ * Read data from the pipe. If this synchronous read finds data
+ * without a SIGIO signal, then we were not notified and the
+ * test fails.
+ */
+ fprintf(logfp, "%d: Waiting for data to be available\n", getpid());
+ fflush(logfp);
+
+ rc = read(fd, buf, 4);
+ if (rc <= 0) {
+ fprintf(logfp, "%d: ERROR: read(): rc %d, error %s\n",
+ getpid(), rc, strerror(errno));
+ do_exit(1);
+ } else if (!got_sigio) {
+ fprintf(logfp, "%d: FAILED: read() found data but did not"
+ "get SIGIO, rc %d buf %.4s\n", getpid(),
+ rc, buf);
+ do_exit(1);
+ } else {
+ fprintf(logfp, "%d: PASS: Got SIGIO, read data, rc %d, "
+ "buf '%.4s'\n", getpid(), rc, buf);
+ do_exit(0);
+ }
+}
+
+/*
+ * Create a pipe that the child will try to read from and parent will
+ * write to.
+ */
+void setup_test_data()
+{
+ int rc;
+
+ rc = pipe(pipe_fds);
+ if (rc < 0) {
+ fprintf(logfp, "%d: pipe() failed, rc %d, error %s\n",
+ getpid(), rc, strerror(errno));
+ do_exit(1);
+ }
+
+ return;
+}
+
+void usr1_handler(int sig)
+{
+ /*
+ * Test failed or a child encountered an error.
+ * Reap the child, report error and exit.
+ */
+ fprintf(logfp, "%d: Signal %d, Test case FAILED\n", getpid(), sig);
+ fflush(logfp);
+
+ wait_for_child();
+}
+
+main(int argc, char *argv[])
+{
+ int i, status, rc;
+ int pid;
+
+ if (test_done()) {
+ printf("Remove %s before running test\n", TEST_DONE);
+ do_exit(1);
+ }
+
+ logfp = fopen(LOG_FILE, "w");
+ if (!logfp) {
+ perror("open() logfile");
+ do_exit(1);
+ }
+
+ printf("%s: Closing stdio fds and writing messages to %s\n",
+ argv[0], LOG_FILE);
+
+ for (i=0; i<100; i++) {
+ if (fileno(logfp) != i)
+ close(i);
+ }
+
+ setup_test_data();
+ event_fd1 = setup_notification();
+
+ /*
+ * Before waiting for events below, ensure we will be notified
+ * if a child encounters an error.
+ */
+ signal(SIGUSR1, usr1_handler);
+
+ /*
+ * Create the child process and wait for it to be ready for checkpoint.
+ */
+ pid = fork();
+ if (pid == 0)
+ do_child(i);
+
+ if (pid < 0) {
+ fprintf(logfp, "%d: fork() failed, rc %d, error %s\n", getpid(),
+ rc, strerror(errno));
+ do_exit(1);
+ }
+
+ wait_for_events(event_fd1, 1);
+
+ /*
+ * Tell any wrapper scripts, we are ready for checkpoint
+ */
+ set_checkpoint_ready();
+
+ fprintf(logfp, "%d: ***** Ready for checkpoint\n", getpid());
+ fflush(logfp);
+
+ /* Wait for wrappers to complete checkpoint/restart */
+ while(!test_done())
+ sleep(1);
+
+ /* Ensure that child is still owner for the read side of pipe */
+ test_owner(pipe_fds[0], pid);
+
+ /* Make data available on the pipe for the child */
+ rc = write(pipe_fds[1], "done", 4);
+ if (rc < 0) {
+ fprintf(logfp, "%d: write() failed, rc %d, error %s\n",
+ getpid(), rc, strerror(errno));
+ kill(pid, SIGKILL);
+ do_exit(1);
+ }
+
+ fflush(logfp);
+ wait_for_child();
+}
diff --git a/fileio/run-fsetown1.sh b/fileio/run-fsetown1.sh
new file mode 100755
index 0000000..535c544
--- /dev/null
+++ b/fileio/run-fsetown1.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+./run-fcntltests.sh fsetown1
diff --git a/fileio/runtests.sh b/fileio/runtests.sh
index e83f9cc..b808927 100755
--- a/fileio/runtests.sh
+++ b/fileio/runtests.sh
@@ -14,3 +14,8 @@ echo
echo "****** $0: Running test: filelease1"
echo
./run-fcntltests.sh filelease1
+
+echo
+echo "****** $0: Running test: fsetown1"
+echo
+./run-fcntltests.sh fsetown1
diff --git a/libcrtest/common.c b/libcrtest/common.c
index b29042a..c20da5e 100644
--- a/libcrtest/common.c
+++ b/libcrtest/common.c
@@ -58,7 +58,7 @@ void set_checkpoint_ready()
close(fd);
}
-static void print_exit_status(int pid, int status)
+void print_exit_status(int pid, int status)
{
fprintf(logfp, "Pid %d unexpected exit - ", pid);
if (WIFEXITED(status)) {
--
1.6.0.4
_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
More information about the Devel
mailing list