[Devel] [PATCH 06/11] filelease1: Test restore of file leases
Sukadev Bhattiprolu
sukadev at linux.vnet.ibm.com
Fri Jan 29 12:42:45 PST 2010
From: Sukadev Bhattiprolu <sukadev at linux.vnet.ibm.com>
Date: Thu, 21 Jan 2010 12:36:24 -0800
Subject: [PATCH 06/11] filelease1: Test restore of file leases
Checkpoint an application that has F_RDLCK and F_WRLCK leases on files.
Restart the application and ensure that the leases are restored.
Signed-off-by: Sukadev Bhattiprolu <sukadev at linux.vnet.ibm.com>
---
fileio/Makefile | 4 +-
fileio/filelease1.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++
fileio/run-filelease1.sh | 3 +
fileio/runtests.sh | 5 +
4 files changed, 272 insertions(+), 2 deletions(-)
create mode 100644 fileio/filelease1.c
create mode 100755 fileio/run-filelease1.sh
diff --git a/fileio/Makefile b/fileio/Makefile
index eb3887b..acc2df9 100644
--- a/fileio/Makefile
+++ b/fileio/Makefile
@@ -1,4 +1,4 @@
-targets = fileio1 filelock1
+targets = fileio1 filelock1 filelease1
INCLUDE = ../libcrtest
LIBCRTEST = ../libcrtest/common.o
@@ -9,4 +9,4 @@ all: $(LIBCRTEST) $(targets)
clean:
rm -f $(targets)
- rm -rf cr_fileio* cr_filelock1*
+ rm -rf cr_fileio* cr_filelock1* cr_filelease1*
diff --git a/fileio/filelease1.c b/fileio/filelease1.c
new file mode 100644
index 0000000..21494e9
--- /dev/null
+++ b/fileio/filelease1.c
@@ -0,0 +1,262 @@
+#include <stdio.h>
+#include <unistd.h>
+#define __USE_GNU
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include "libcrtest.h"
+
+#define TEST_FILE1 "data.d/data.filelease1"
+#define TEST_FILE2 "data.d/data.filelease2"
+#define LOG_FILE "logs.d/log.filelease1"
+
+extern FILE *logfp;
+int test_fd;
+int event_fd1;
+int event_fd2;
+
+/*
+ * Description:
+ * Ensure that F_RDLCK and F_WRLCK file leases held by a process at
+ * the time of checkpoint are properly restored when the process is
+ * restarted from the checkpoint.
+ *
+ * Implementation:
+ * Two processes, P0 and P1 acquire a F_RDLCK lease on file F1.
+ * Process P2 acquires a F_WRLCK lease on file F2. After acquiring
+ * leases the processes notify parent they are ready for checkpoint
+ * and wait for checkpoint to be done. When they are restarted
+ * (i.e when test_done() is TRUE), each process verifies that it has the
+ * lease it had at the time of checkpoint.
+ */
+
+void set_lease(int fd, int type)
+{
+ int rc;
+
+ fprintf(logfp, "%d: set_lease() called for fd %d, type %d\n",
+ getpid(), fd, type);
+
+ rc = fcntl(fd, F_SETLEASE, type);
+ if (rc < 0) {
+ fprintf(logfp, "%d: set_lease(type %d):, ERROR %s\n",
+ getpid(), type, strerror(errno));
+ if (errno == EINVAL)
+ fprintf(logfp, "%d: Maybe the fs does not support "
+ "F_SETLEASE (eg: NFS)\n", getpid());
+ fflush(logfp);
+ kill(getppid(), SIGUSR1);
+ do_exit(1);
+ }
+
+ fprintf(logfp, "%d: set_lease(%d): %s\n", getpid(), type,
+ rc < 0 ? strerror(errno) : "done");
+}
+
+char *get_lease_desc(int type)
+{
+ switch(type) {
+ case F_RDLCK: return "F_RDLCK";
+ case F_WRLCK: return "F_WRLCK";
+ case F_UNLCK: return "F_UNLCK";
+ default: return "Unknown !";
+ }
+}
+
+void test_lease(int fd, int exp_type)
+{
+ int rc;
+
+ rc = fcntl(fd, F_GETLEASE, 0);
+ if (rc < 0 || rc > 2) {
+ fprintf(logfp, "ERROR: fcntl(F_GETLEASE): expected %s, rc %d, "
+ "error %s\n", get_lease_desc(exp_type), rc,
+ strerror(errno));
+ do_exit(1);
+ }
+
+ if (rc != exp_type) {
+ fprintf(logfp, "%d: FAIL: Expected %s, actual %s\n", getpid(),
+ get_lease_desc(exp_type), get_lease_desc(rc));
+ do_exit(1);
+ }
+
+ fprintf(logfp, "%d: PASS: Expected %s, actual %s\n", getpid(),
+ get_lease_desc(exp_type), get_lease_desc(rc));
+ return;
+}
+
+struct test_arg {
+ int fd;
+ int type;
+ int pid;
+};
+
+struct test_arg test_data[3];
+
+int do_child(int idx)
+{
+ int type = test_data[idx].type;
+ int fd = test_data[idx].fd;
+
+ fprintf(logfp, "%d: Setting lease to type %s\n", getpid(),
+ get_lease_desc(type));
+
+ set_lease(fd, type);
+
+ /*
+ * Tell parent we are ready for checkpoint...
+ */
+ notify_one_event(event_fd1);
+
+ /*
+ * Wait for checkpoint/restart
+ */
+ fprintf(logfp, "%d: waiting for test-done\n", getpid());
+ while(!test_done()) {
+ sleep(1);
+ }
+ fprintf(logfp, "%d: Found test-done\n", getpid());
+
+ test_lease(fd, type);
+
+ do_exit(0);
+}
+
+/*
+ * Create two test files and populate test_data[] so that:
+ * - first two childrent get a F_RDLCK lease on file TEST_FILE1.
+ * - third child gets a F_WRLCK lease on file TEST_FILE2.
+ */
+void setup_test_data()
+{
+ int fd;
+ char buf[256];
+
+ /* Create TEST_FILE1 */
+ fd = open(TEST_FILE1, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (fd < 0) {
+ fprintf(logfp, "ERROR: open(%s): %s\n", TEST_FILE1,
+ strerror(errno));
+ do_exit(1);
+ }
+
+ memset(buf, 0, sizeof(buf));
+ write(fd, buf, sizeof(buf));
+
+ /* Close TEST_FILE1 and open for read-only */
+ close(fd);
+
+ fd = open(TEST_FILE1, O_RDONLY);
+ if (fd < 0) {
+ fprintf(logfp, "ERROR: open(%s): %s\n", TEST_FILE1,
+ strerror(errno));
+ do_exit(1);
+ }
+
+ /*
+ * First two childrent get a F_RDLCK lease on file TEST_FILE1.
+ * Third child gets a F_WRLCK lease on file TEST_FILE2.
+ */
+ test_data[0].fd = test_data[1].fd = fd;
+ test_data[0].type = test_data[1].type = F_RDLCK;
+ fprintf(logfp, "fd0: %d, type %d\n",
+ test_data[0].fd, test_data[0].type);
+
+ /* Create TEST_FILE2 */
+ fd = open(TEST_FILE2, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (fd < 0) {
+ fprintf(logfp, "ERROR: open(%s): %s\n", TEST_FILE2,
+ strerror(errno));
+ do_exit(1);
+ }
+ write(fd, buf, sizeof(buf));
+
+ test_data[2].fd = fd;
+ test_data[2].type = F_WRLCK;
+
+ return;
+}
+
+void child_handler(int sig)
+{
+ int i;
+ int num_children = 3;
+ /*
+ * Test failed or a child encountered an error.
+ * Kill (remaining) children, reap children and exit.
+ */
+ fprintf(logfp, "%d: Got signal %d\n", getpid(), sig);
+ for (i = 0; i < num_children; i++)
+ if (test_data[i].pid)
+ kill(test_data[i].pid, SIGKILL);
+
+ fprintf(logfp, "%d: Test case FAILED\n", getpid());
+ fflush(logfp);
+
+ do_wait(num_children);
+
+ do_exit(-1);
+}
+
+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 and/or exits prematurely.
+ */
+ signal(SIGUSR1, child_handler);
+ signal(SIGCHLD, child_handler);
+
+ /*
+ * Create the test processes and wait for them to be ready for
+ * checkpoint.
+ */
+ for (i = 0; i < 3; i ++) {
+ pid = fork();
+ if (pid == 0)
+ do_child(i);
+ test_data[i].pid = pid;
+ }
+
+ wait_for_events(event_fd1, 1);
+
+ /*
+ * Now that the test processes are ready, tell any wrapper scripts,
+ * we are ready for checkpoint
+ */
+ set_checkpoint_ready();
+
+ fprintf(logfp, "***** %d: Ready for checkpoint\n", getpid());
+ fflush(logfp);
+
+ do_wait(3);
+
+ do_exit(0);
+}
diff --git a/fileio/run-filelease1.sh b/fileio/run-filelease1.sh
new file mode 100755
index 0000000..41249a8
--- /dev/null
+++ b/fileio/run-filelease1.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+./run-fcntltests.sh filelease1
diff --git a/fileio/runtests.sh b/fileio/runtests.sh
index d674311..e83f9cc 100755
--- a/fileio/runtests.sh
+++ b/fileio/runtests.sh
@@ -9,3 +9,8 @@ echo
echo "****** $0: Running test: filelock1"
echo
./run-fcntltests.sh filelock1
+
+echo
+echo "****** $0: Running test: filelease1"
+echo
+./run-fcntltests.sh filelease1
--
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