mirror of
https://github.com/checkpoint-restore/criu
synced 2025-09-01 14:55:39 +00:00
zdtm: add posix file lock's test case
We check read lock and write lock for posix file locks. After restore, we use fcntl(fd, F_GETLK, &lock), to see if the file is hold the same lock as it was dumped. Signed-off-by: Qiang Huang <h.huangqiang@huawei.com> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
committed by
Pavel Emelyanov
parent
882005a0ed
commit
a52a66f652
11
test/zdtm.sh
11
test/zdtm.sh
@@ -119,6 +119,10 @@ static/sem
|
|||||||
transition/ipc
|
transition/ipc
|
||||||
"
|
"
|
||||||
|
|
||||||
|
FILE_LOCK_TEST_LIST="
|
||||||
|
static/file_locks00
|
||||||
|
"
|
||||||
|
|
||||||
TEST_CR_KERNEL="
|
TEST_CR_KERNEL="
|
||||||
static/sock_opts01
|
static/sock_opts01
|
||||||
static/sockets01
|
static/sockets01
|
||||||
@@ -442,8 +446,11 @@ if [ $# -eq 0 ]; then
|
|||||||
for t in $IPC_TEST_LIST; do
|
for t in $IPC_TEST_LIST; do
|
||||||
run_test $t -n ipc || case_error $t
|
run_test $t -n ipc || case_error $t
|
||||||
done
|
done
|
||||||
|
for t in $FILE_LOCK_TEST_LIST; do
|
||||||
|
run_test $t -l || case_error $t
|
||||||
|
done
|
||||||
elif [ "$1" = "-l" ]; then
|
elif [ "$1" = "-l" ]; then
|
||||||
echo $TEST_LIST $UTS_TEST_LIST $MNT_TEST_LIST $IPC_TEST_LIST | tr ' ' '\n'
|
echo $TEST_LIST $UTS_TEST_LIST $MNT_TEST_LIST $IPC_TEST_LIST $FILE_LOCK_TEST_LIST | tr ' ' '\n'
|
||||||
elif [ "$1" = "-h" ]; then
|
elif [ "$1" = "-h" ]; then
|
||||||
cat >&2 <<EOF
|
cat >&2 <<EOF
|
||||||
This script is used for executing unit tests.
|
This script is used for executing unit tests.
|
||||||
@@ -465,6 +472,8 @@ else
|
|||||||
run_test $1 -n mnt || case_error $1
|
run_test $1 -n mnt || case_error $1
|
||||||
elif echo $IPC_TEST_LIST | fgrep -qw $1; then
|
elif echo $IPC_TEST_LIST | fgrep -qw $1; then
|
||||||
run_test $1 -n ipc || case_error $1
|
run_test $1 -n ipc || case_error $1
|
||||||
|
elif echo $FILE_LOCK_TEST_LIST | fgrep -qw $1; then
|
||||||
|
run_test $1 -l || case_error $1
|
||||||
else
|
else
|
||||||
run_test $1 || case_error $1
|
run_test $1 || case_error $1
|
||||||
fi
|
fi
|
||||||
|
@@ -85,6 +85,7 @@ TST_NOFILE = \
|
|||||||
cow00 \
|
cow00 \
|
||||||
child_opened_proc \
|
child_opened_proc \
|
||||||
posix_timers \
|
posix_timers \
|
||||||
|
file_locks00 \
|
||||||
# jobctl00 \
|
# jobctl00 \
|
||||||
|
|
||||||
TST_FILE = \
|
TST_FILE = \
|
||||||
|
179
test/zdtm/live/static/file_locks00.c
Normal file
179
test/zdtm/live/static/file_locks00.c
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "zdtmtst.h"
|
||||||
|
|
||||||
|
const char *test_doc = "Check that posix flocks are restored";
|
||||||
|
const char *test_author = "Qiang Huang <h.huangqiang@huawei.com>";
|
||||||
|
|
||||||
|
char file0[] = "/tmp/zdtm_file_locks_XXXXXX";
|
||||||
|
char file1[] = "/tmp/zdtm_file_locks_XXXXXX";
|
||||||
|
|
||||||
|
static int lock_reg(int fd, int cmd, int type, int whence,
|
||||||
|
off_t offset, off_t len)
|
||||||
|
{
|
||||||
|
struct flock lock;
|
||||||
|
|
||||||
|
lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */
|
||||||
|
lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
|
||||||
|
lock.l_start = offset; /* byte offset, relative to l_whence */
|
||||||
|
lock.l_len = len; /* #bytes (0 means to EOF) */
|
||||||
|
|
||||||
|
return fcntl(fd, cmd, &lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define set_read_lock(fd, whence, offset, len) \
|
||||||
|
lock_reg(fd, F_SETLK, F_RDLCK, whence, offset, len)
|
||||||
|
#define set_write_lock(fd, whence, offset, len) \
|
||||||
|
lock_reg(fd, F_SETLK, F_WRLCK, whence, offset, len)
|
||||||
|
|
||||||
|
static int check_read_lock(int fd, int whence, off_t offset, off_t len)
|
||||||
|
{
|
||||||
|
struct flock lock;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
lock.l_type = F_RDLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */
|
||||||
|
lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
|
||||||
|
lock.l_start = offset; /* byte offset, relative to l_whence */
|
||||||
|
lock.l_len = len; /* #bytes (0 means to EOF) */
|
||||||
|
lock.l_pid = -1;
|
||||||
|
|
||||||
|
ret = fcntl(fd, F_GETLK, &lock);
|
||||||
|
if (ret == -1) {
|
||||||
|
err("F_GETLK failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lock.l_pid == -1) {
|
||||||
|
/* Share lock should succeed. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail("Read lock check failed.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_write_lock(int fd, int whence, off_t offset, off_t len)
|
||||||
|
{
|
||||||
|
struct flock lock;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
pid_t ppid = getppid();
|
||||||
|
|
||||||
|
lock.l_type = F_WRLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */
|
||||||
|
lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
|
||||||
|
lock.l_start = offset; /* byte offset, relative to l_whence */
|
||||||
|
lock.l_len = len; /* #bytes (0 means to EOF) */
|
||||||
|
lock.l_pid = -1;
|
||||||
|
|
||||||
|
ret = fcntl(fd, F_GETLK, &lock);
|
||||||
|
if (ret == -1) {
|
||||||
|
err("F_GETLK failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lock.l_pid == -1) {
|
||||||
|
fail("Write lock check failed.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It only succeed when the file lock's owner is exactly
|
||||||
|
* the same as the file lock was dumped.
|
||||||
|
*/
|
||||||
|
if (lock.l_pid == ppid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail("Write lock check failed.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_file_locks()
|
||||||
|
{
|
||||||
|
int fd_0, fd_1;
|
||||||
|
int ret0, ret1;
|
||||||
|
|
||||||
|
fd_0 = open(file0, O_RDWR | O_CREAT, 0644);
|
||||||
|
if (fd_0 < 0) {
|
||||||
|
err("Unable to open file %s", file0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret0 = check_read_lock(fd_0, SEEK_SET, 0, 0);
|
||||||
|
|
||||||
|
fd_1 = open(file1, O_RDWR | O_CREAT, 0644);
|
||||||
|
if (fd_1 < 0) {
|
||||||
|
close(fd_0);
|
||||||
|
unlink(file0);
|
||||||
|
err("Unable to open file %s", file1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret1 = check_write_lock(fd_1, SEEK_SET, 0, 0);
|
||||||
|
|
||||||
|
close(fd_0);
|
||||||
|
close(fd_1);
|
||||||
|
|
||||||
|
return ret0 | ret1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int fd_0, fd_1;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
test_init(argc, argv);
|
||||||
|
|
||||||
|
fd_0 = mkstemp(file0);
|
||||||
|
if (fd_0 < 0) {
|
||||||
|
err("Unable to open file %s", file0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_1 = mkstemp(file1);
|
||||||
|
if (fd_1 < 0) {
|
||||||
|
close(fd_0);
|
||||||
|
unlink(file0);
|
||||||
|
err("Unable to open file %s", file1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
err("Can't fork: %m\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid == 0) { /* child will check father's file locks */
|
||||||
|
test_waitsig();
|
||||||
|
|
||||||
|
if (check_file_locks()) {
|
||||||
|
fail("Posix file lock check failed");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pass();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_read_lock(fd_0, SEEK_SET, 0, 0);
|
||||||
|
set_write_lock(fd_1, SEEK_SET, 0, 0);
|
||||||
|
|
||||||
|
test_daemon();
|
||||||
|
test_waitsig();
|
||||||
|
|
||||||
|
kill(pid, SIGTERM);
|
||||||
|
waitpid(pid, NULL, 0);
|
||||||
|
close(fd_0);
|
||||||
|
close(fd_1);
|
||||||
|
unlink(file0);
|
||||||
|
unlink(file1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Reference in New Issue
Block a user