[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