[CRIU] [PATCH 2/2] zdtm: Add OFD file locks test

Pavel Begunkov asml.silence at gmail.com
Tue Dec 20 02:24:39 PST 2016


From: Begunkov Pavel <asml.silence at gmail.com>

There are 3 tests that cover the following cases:

1. single OFD lock
2. overlapped OFD locks
3. inhertited OFD locks

Tests logic is similar to logic of tests for other lock types.

OFD lock specific header-only library was added to avoid code
duplication in the tests.

Signed-off-by: Begunkov Pavel <asml.silence at gmail.com>
Signed-off-by: Eugene Batalov <eabatalov89 at gmail.com>
---
 test/zdtm/static/Makefile          |   3 +
 test/zdtm/static/file_locks06.c    |  67 ++++++++++++++++
 test/zdtm/static/file_locks06.desc |   1 +
 test/zdtm/static/file_locks07.c    | 101 ++++++++++++++++++++++++
 test/zdtm/static/file_locks07.desc |   1 +
 test/zdtm/static/file_locks08.c    |  86 +++++++++++++++++++++
 test/zdtm/static/file_locks08.desc |   1 +
 test/zdtm/static/ofd_file_locks.h  | 153 +++++++++++++++++++++++++++++++++++++
 8 files changed, 413 insertions(+)
 create mode 100644 test/zdtm/static/file_locks06.c
 create mode 100644 test/zdtm/static/file_locks06.desc
 create mode 100644 test/zdtm/static/file_locks07.c
 create mode 100644 test/zdtm/static/file_locks07.desc
 create mode 100644 test/zdtm/static/file_locks08.c
 create mode 100644 test/zdtm/static/file_locks08.desc
 create mode 100644 test/zdtm/static/ofd_file_locks.h

diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
index c932093..f270f9f 100644
--- a/test/zdtm/static/Makefile
+++ b/test/zdtm/static/Makefile
@@ -221,6 +221,9 @@ TST_FILE	=				\
 		file_locks03			\
 		file_locks04			\
 		file_locks05			\
+		file_locks06			\
+		file_locks07			\
+		file_locks08			\
 		netns-nf			\
 		maps_file_prot			\
 		socket_close_data01		\
diff --git a/test/zdtm/static/file_locks06.c b/test/zdtm/static/file_locks06.c
new file mode 100644
index 0000000..2e1ba43
--- /dev/null
+++ b/test/zdtm/static/file_locks06.c
@@ -0,0 +1,67 @@
+#define _GNU_SOURCE
+
+#include <sys/file.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "ofd_file_locks.h"
+#include "zdtmtst.h"
+
+const char *test_doc    = "Check that OFD lock for the whole file is restored";
+const char *test_author = "Begunkov Pavel <asml.silence at gmail.com>";
+
+char *filename;
+TEST_OPTION(filename, string, "file name", 1);
+
+
+int init_lock(int *fd, struct flock *lck)
+{
+	*fd = open(filename, O_RDWR | O_CREAT, 0666);
+	if (*fd < 0) {
+		pr_perror("Can't open file");
+		return -1;
+	}
+
+	lck->l_type = F_WRLCK;
+	lck->l_whence = SEEK_SET;
+	lck->l_start = 0;
+	lck->l_len = 0;
+	lck->l_pid = 0;
+
+	if (fcntl(*fd, F_OFD_SETLK, lck) < 0) {
+		pr_perror("Can't set ofd lock");
+		return -1;
+	}
+	return 0;
+}
+
+void cleanup(int *fd)
+{
+	if (close(*fd))
+		pr_perror("Can't close fd\n");
+
+	if (unlink(filename))
+		pr_perror("Can't unlink file\n");
+}
+
+int main(int argc, char **argv)
+{
+	int fd;
+	struct flock lck;
+
+	test_init(argc, argv);
+	if (init_lock(&fd, &lck))
+		return 1;
+
+	test_daemon();
+	test_waitsig();
+
+	if (check_file_lock_restored(getpid(), fd, &lck) ||
+		check_lock_exists(filename, &lck) < 0)
+		fail("OFD file locks check failed\n");
+	else
+		pass();
+
+	cleanup(&fd);
+	return 0;
+}
diff --git a/test/zdtm/static/file_locks06.desc b/test/zdtm/static/file_locks06.desc
new file mode 100644
index 0000000..80cd04e
--- /dev/null
+++ b/test/zdtm/static/file_locks06.desc
@@ -0,0 +1 @@
+{'flags': 'excl', 'opts': '--file-locks'}
diff --git a/test/zdtm/static/file_locks07.c b/test/zdtm/static/file_locks07.c
new file mode 100644
index 0000000..1f94625
--- /dev/null
+++ b/test/zdtm/static/file_locks07.c
@@ -0,0 +1,101 @@
+#define _GNU_SOURCE
+
+#include <sys/file.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "ofd_file_locks.h"
+#include "zdtmtst.h"
+
+const char *test_doc    = "Check that 'overlapping' OFD read locks work";
+const char *test_author = "Begunkov Pavel <asml.silence at gmail.com>";
+
+char *filename;
+TEST_OPTION(filename, string, "file name", 1);
+
+
+#define FILE_NUM 4
+static int fds[FILE_NUM];
+static struct flock lcks[FILE_NUM];
+static short types[] = {F_RDLCK, F_RDLCK, F_RDLCK, F_RDLCK};
+static off_t starts[] = {0, 10, 0, 70};
+static off_t lens[]  = {20, 30, 100, 200};
+
+void fill_lock(struct flock *lock, off_t start, off_t len, short int type)
+{
+	lock->l_start = start;
+	lock->l_len = len;
+	lock->l_type = type;
+	lock->l_whence = SEEK_SET;
+	lock->l_pid = 0;
+}
+
+int init_file_locks(void)
+{
+	size_t i;
+
+	for (i = 0; i < FILE_NUM; ++i)
+		fill_lock(&lcks[i], starts[i], lens[i], types[i]);
+
+	for (i = 0; i < FILE_NUM; ++i) {
+		fds[i] = open(filename, O_RDWR | O_CREAT, 0666);
+
+		if (fds[i] < 0) {
+			pr_perror("Can't open file");
+			return -1;
+		}
+	}
+
+	for (i = 0; i < FILE_NUM; ++i)
+		if (fcntl(fds[i], F_OFD_SETLKW, &lcks[i]) < 0) {
+			pr_perror("Can't set ofd lock");
+			return -1;
+		}
+
+	return 0;
+}
+
+void cleanup(void)
+{
+	size_t i;
+
+	for (i = 0; i < FILE_NUM; ++i)
+		if (close(fds[i]))
+			pr_perror("Can't close fd\n");
+
+	if (unlink(filename))
+		pr_perror("Can't unlink file failed\n");
+}
+
+int check_file_locks_restored(void)
+{
+	size_t i;
+	int pid = getpid();
+
+	for (i = 0; i < FILE_NUM; ++i) {
+		if (check_file_lock_restored(pid, fds[i], &lcks[i]))
+			return -1;
+		if (check_lock_exists(filename, &lcks[i]) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	test_init(argc, argv);
+	if (init_file_locks())
+		return -1;
+
+	test_daemon();
+	test_waitsig();
+
+	if (check_file_locks_restored())
+		fail("OFD file locks check failed\n");
+	else
+		pass();
+
+	cleanup();
+	return 0;
+}
diff --git a/test/zdtm/static/file_locks07.desc b/test/zdtm/static/file_locks07.desc
new file mode 100644
index 0000000..80cd04e
--- /dev/null
+++ b/test/zdtm/static/file_locks07.desc
@@ -0,0 +1 @@
+{'flags': 'excl', 'opts': '--file-locks'}
diff --git a/test/zdtm/static/file_locks08.c b/test/zdtm/static/file_locks08.c
new file mode 100644
index 0000000..a0d93dd
--- /dev/null
+++ b/test/zdtm/static/file_locks08.c
@@ -0,0 +1,86 @@
+#define _GNU_SOURCE
+
+#include <sys/wait.h>
+#include <sys/file.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include "ofd_file_locks.h"
+#include "zdtmtst.h"
+
+const char *test_doc    = "Check that inherited OFD locks work";
+const char *test_author = "Begunkov Pavel <asml.silence at gmail.com>";
+
+char *filename;
+TEST_OPTION(filename, string, "file name", 1);
+
+
+int init_file_lock(int *fd, struct flock *lck)
+{
+	*fd = open(filename, O_RDWR | O_CREAT, 0666);
+	if (*fd < 0) {
+		pr_perror("Can't open file");
+		return -1;
+	}
+
+	lck->l_type = F_WRLCK;
+	lck->l_whence = SEEK_SET;
+	lck->l_start = 0;
+	lck->l_len = 0; /* lock whole file */
+	lck->l_pid = 0; /* should be 0 for ofd lock */
+
+	if (fcntl(*fd, F_OFD_SETLKW, lck) < 0) {
+		pr_perror("Can't set ofd lock");
+		return -1;
+	}
+	return 0;
+}
+
+void cleanup(int *fd)
+{
+	if (close(*fd))
+		pr_perror("Can't close fd\n");
+
+	if (unlink(filename))
+		pr_perror("Can't unlink file\n");
+}
+
+int main(int argc, char **argv)
+{
+	int fd;
+	int pid;
+	int status;
+	int ret = 0;
+	struct flock lck;
+
+	test_init(argc, argv);
+	if (init_file_lock(&fd, &lck))
+		return -1;
+
+	pid = fork();
+	if (pid == 0) {
+		if (check_file_lock_restored(getpid(), fd, &lck) ||
+			check_lock_exists(filename, &lck) < 0)
+			ret = -1;
+		exit(ret);
+	}
+
+	test_daemon();
+	test_waitsig();
+
+	if (check_file_lock_restored(getpid(), fd, &lck) ||
+		check_lock_exists(filename, &lck) < 0)
+		fail("OFD file locks check failed\n");
+
+	kill(pid, SIGTERM);
+	ret = waitpid(pid, &status, 0);
+
+	if (ret < 0 || !WIFEXITED(status) || WEXITSTATUS(status))
+		fail("OFD file locks check failed\n");
+	else
+		pass();
+
+	cleanup(&fd);
+	return 0;
+}
diff --git a/test/zdtm/static/file_locks08.desc b/test/zdtm/static/file_locks08.desc
new file mode 100644
index 0000000..80cd04e
--- /dev/null
+++ b/test/zdtm/static/file_locks08.desc
@@ -0,0 +1 @@
+{'flags': 'excl', 'opts': '--file-locks'}
diff --git a/test/zdtm/static/ofd_file_locks.h b/test/zdtm/static/ofd_file_locks.h
new file mode 100644
index 0000000..049401a
--- /dev/null
+++ b/test/zdtm/static/ofd_file_locks.h
@@ -0,0 +1,153 @@
+#ifndef ZDTM_OFD_FILE_LOCKS_H_
+#define ZDTM_OFD_FILE_LOCKS_H_
+
+#include <sys/file.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "zdtmtst.h"
+#include "fs.h"
+
+#ifndef F_OFD_GETLK
+#define F_OFD_GETLK	36
+#define F_OFD_SETLK	37
+#define F_OFD_SETLKW	38
+#endif
+
+/*
+ * Header library for parsing of OFD locks
+ * from procfs and checking them after restoring.
+ */
+
+static int parse_ofd_lock(char *buf, struct flock *lck)
+{
+	char fl_flag[10], fl_type[15], fl_option[10], fl_end[32];
+	long long start;
+	int num;
+
+	if (strncmp(buf, "lock:\t", 6) != 0)
+		return 1; /* isn't lock, skip record */
+
+	num = sscanf(buf,
+		"%*s %*d: %s %s %s %*d %*x:%*x:%*d %lld %s",
+		fl_flag, fl_type, fl_option, &start, fl_end);
+
+	if (num < 4) {
+		pr_err("Invalid lock info %s\n", buf);
+		return -1;
+	}
+	if (strcmp(fl_flag, "OFDLCK"))
+		return 1;
+
+	lck->l_start = start;
+
+	if (strcmp(fl_end, "EOF")) {
+		unsigned long end;
+
+		if (sscanf(fl_end, "%lu", &end) <= 0) {
+			pr_err("Invalid lock entry\n");
+			return -1;
+		}
+		lck->l_len = end - lck->l_start + 1;
+	} else {
+		lck->l_len = 0;
+	}
+	if (strcmp(fl_option, "WRITE") == 0)
+		lck->l_type = F_WRLCK;
+	else
+		lck->l_type = F_RDLCK;
+
+	return 0;
+}
+
+static int read_fd_ofd_lock(int pid, int fd, struct flock *lck)
+{
+	char path[PATH_MAX];
+	char buf[100];
+	int num;
+	FILE *proc_file = NULL;
+
+	sprintf(path, "/proc/%i/fdinfo/%i", pid, fd);
+	proc_file = fopen(path, "r");
+
+	if (!proc_file) {
+		pr_err("Can't open %s\n", path);
+		return -1;
+	}
+
+	num = -1;
+	while (fgets(buf, sizeof(buf), proc_file)) {
+		num = parse_ofd_lock(buf, lck);
+		if (num <= 0)
+			break;
+	}
+
+	if (fclose(proc_file)) {
+		pr_err("Can't close %s\n", path);
+		return -1;
+	}
+	return num;
+}
+
+static int check_lock_exists(const char *filename, struct flock *lck)
+{
+	int ret = -1;
+	int fd;
+
+	fd = open(filename, O_RDWR, 0666);
+
+	if (lck->l_type == F_RDLCK) {
+		/* check, that there is no write lock */
+		ret = fcntl(fd, F_OFD_GETLK, lck);
+		if (ret) {
+			pr_err("fcntl failed (%i)\n", ret);
+			goto out;
+		}
+		if (lck->l_type != F_UNLCK) {
+			pr_err("OFD lock type do not match\n");
+			goto out;
+		}
+	}
+
+	/* check, that lock is set */
+	lck->l_type = F_WRLCK;
+	ret = fcntl(fd, F_OFD_GETLK, lck);
+	if (ret) {
+		pr_err("fcntl failed (%i)\n", ret);
+		goto out;
+	}
+	if (lck->l_type == F_UNLCK) {
+		pr_err("Lock not found\n");
+		goto out;
+	}
+
+	ret = 0;
+out:
+	if (close(fd))
+		return -1;
+	return ret;
+}
+
+static int check_file_locks_match(struct flock *orig_lck, struct flock *lck)
+{
+	return orig_lck->l_start == lck->l_start &&
+		orig_lck->l_len == lck->l_len &&
+		orig_lck->l_type == lck->l_type;
+}
+
+static int check_file_lock_restored(int pid, int fd, struct flock *lck)
+{
+	struct flock lck_restored;
+
+	if (read_fd_ofd_lock(pid, fd, &lck_restored))
+		return -1;
+
+	if (!check_file_locks_match(lck, &lck_restored)) {
+		pr_err("Can't restore file lock (fd: %i)\n", fd);
+		return -1;
+	}
+	return 0;
+}
+
+#endif /* ZDTM_OFD_FILE_LOCKS_H_ */
-- 
2.10.0



More information about the CRIU mailing list