diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 5e55c4d2a..d89e3edc2 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -223,6 +223,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 000000000..2e1ba4370 --- /dev/null +++ b/test/zdtm/static/file_locks06.c @@ -0,0 +1,67 @@ +#define _GNU_SOURCE + +#include +#include +#include + +#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 "; + +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 000000000..80cd04e28 --- /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 000000000..1f946254a --- /dev/null +++ b/test/zdtm/static/file_locks07.c @@ -0,0 +1,101 @@ +#define _GNU_SOURCE + +#include +#include +#include + +#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 "; + +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 000000000..80cd04e28 --- /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 000000000..a0d93ddaf --- /dev/null +++ b/test/zdtm/static/file_locks08.c @@ -0,0 +1,86 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include "ofd_file_locks.h" +#include "zdtmtst.h" + +const char *test_doc = "Check that inherited OFD locks work"; +const char *test_author = "Begunkov Pavel "; + +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 000000000..80cd04e28 --- /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 000000000..049401a9c --- /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 +#include +#include +#include + +#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_ */