mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-22 01:51:51 +00:00
zdtm: Check many processes with common dead pidfd
We have multiple processes open a pidfd to a common dead process. After C/R we check that the inode numbers for these pidfds are equal or not. Signed-off-by: Bhavik Sachdev <b.sachdev1904@gmail.com>
This commit is contained in:
parent
6f0ec7def6
commit
223a8f1e86
@ -56,6 +56,7 @@ TST_NOFILE := \
|
||||
pidfd_self \
|
||||
pidfd_of_thread \
|
||||
pidfd_dead \
|
||||
pidfd_diffdead \
|
||||
pidfd_child \
|
||||
pidfd_kill \
|
||||
fd_from_pidfd \
|
||||
|
228
test/zdtm/static/pidfd_diffdead.c
Normal file
228
test/zdtm/static/pidfd_diffdead.c
Normal file
@ -0,0 +1,228 @@
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "zdtmtst.h"
|
||||
|
||||
const char *test_doc = "Check C/R of processes that point to a common dead pidfd\n";
|
||||
const char *test_author = "Bhavik Sachdev <b.sachdev1904@gmail.com>";
|
||||
|
||||
#ifndef PID_FS_MAGIC
|
||||
#define PID_FS_MAGIC 0x50494446
|
||||
#endif
|
||||
|
||||
/*
|
||||
* main
|
||||
* `- child
|
||||
* `- grandchild
|
||||
*
|
||||
* main and child open a pidfd for grandchild.
|
||||
* Before C/R we kill grandchild.
|
||||
* We end up with two pidfds in two diff processes that point to the same dead process.
|
||||
*/
|
||||
|
||||
static long get_fs_type(int lfd)
|
||||
{
|
||||
struct statfs fst;
|
||||
|
||||
if (fstatfs(lfd, &fst)) {
|
||||
return -1;
|
||||
}
|
||||
return fst.f_type;
|
||||
}
|
||||
|
||||
static int pidfd_open(pid_t pid, unsigned int flags)
|
||||
{
|
||||
return syscall(__NR_pidfd_open, pid, flags);
|
||||
}
|
||||
|
||||
static int pidfd_send_signal(int pidfd, int sig, siginfo_t *info, unsigned int flags)
|
||||
{
|
||||
return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
|
||||
}
|
||||
|
||||
static int check_for_pidfs(void)
|
||||
{
|
||||
long type;
|
||||
int pidfd = pidfd_open(getpid(), 0);
|
||||
if (pidfd < 0) {
|
||||
pr_perror("pidfd open() failed");
|
||||
return -1;
|
||||
}
|
||||
type = get_fs_type(pidfd);
|
||||
close(pidfd);
|
||||
return type == PID_FS_MAGIC;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#define READ 0
|
||||
#define WRITE 1
|
||||
|
||||
int child, ret, gchild, status;
|
||||
struct statx stat;
|
||||
task_waiter_t t;
|
||||
unsigned long long ino;
|
||||
|
||||
/*
|
||||
* We use the inop pipe to send the inode number of the
|
||||
* pidfd opened in the child to the main process for
|
||||
* comparison.
|
||||
*/
|
||||
int p[2];
|
||||
int pidfd;
|
||||
|
||||
test_init(argc, argv);
|
||||
task_waiter_init(&t);
|
||||
|
||||
ret = check_for_pidfs();
|
||||
if (ret < 0)
|
||||
return 1;
|
||||
|
||||
if (ret == 0) {
|
||||
test_daemon();
|
||||
test_waitsig();
|
||||
skip("Test requires pidfs. skipping...");
|
||||
pass();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pipe(p)) {
|
||||
pr_perror("pipe");
|
||||
return 1;
|
||||
}
|
||||
|
||||
child = test_fork();
|
||||
if (child < 0) {
|
||||
pr_perror("fork");
|
||||
return 1;
|
||||
} else if (child == 0) {
|
||||
int gchild;
|
||||
gchild = test_fork();
|
||||
if (gchild < 0) {
|
||||
pr_perror("fork");
|
||||
return 1;
|
||||
} else if (gchild == 0) {
|
||||
close(p[READ]);
|
||||
close(p[WRITE]);
|
||||
while (1)
|
||||
sleep(1000);
|
||||
} else {
|
||||
if (write(p[WRITE], &gchild, sizeof(int)) != sizeof(int)) {
|
||||
pr_perror("write");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pidfd = pidfd_open(gchild, 0);
|
||||
if (pidfd < 0) {
|
||||
pr_perror("pidfd_open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (waitpid(gchild, &status, 0) != gchild) {
|
||||
pr_perror("waitpid");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!WIFSIGNALED(status)) {
|
||||
fail("Expected grandchild to be terminated by a signal");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (WTERMSIG(status) != SIGKILL) {
|
||||
fail("Expected grandchild to be terminated by SIGKILL");
|
||||
return 1;
|
||||
}
|
||||
task_waiter_complete(&t, 1);
|
||||
|
||||
test_waitsig();
|
||||
|
||||
if (statx(pidfd, "", AT_EMPTY_PATH, STATX_ALL, &stat) < 0) {
|
||||
pr_perror("statx");
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(p[WRITE]);
|
||||
if (read(p[READ], &ino, sizeof(ino)) != sizeof(ino)) {
|
||||
pr_perror("read");
|
||||
return 1;
|
||||
}
|
||||
close(p[READ]);
|
||||
close(pidfd);
|
||||
|
||||
/* ino number should be same because both pidfds were for the same process */
|
||||
if (ino != stat.stx_ino) {
|
||||
exit(1);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (read(p[READ], &gchild, sizeof(int)) != sizeof(int)) {
|
||||
pr_perror("write");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pidfd = pidfd_open(gchild, 0);
|
||||
if (pidfd < 0) {
|
||||
pr_perror("pidfd_open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We kill grandchild process only after opening pidfd.
|
||||
*/
|
||||
if (pidfd_send_signal(pidfd, SIGKILL, NULL, 0)) {
|
||||
pr_perror("pidfd_send_signal");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Wait for child to waitpid on gchild */
|
||||
task_waiter_wait4(&t, 1);
|
||||
|
||||
test_daemon();
|
||||
test_waitsig();
|
||||
|
||||
close(p[READ]);
|
||||
if (statx(pidfd, "", AT_EMPTY_PATH, STATX_ALL, &stat) < 0) {
|
||||
pr_perror("statx");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Send inode number of pidfd to child for comparison */
|
||||
if (write(p[WRITE], &stat.stx_ino, sizeof(stat.stx_ino)) != sizeof(stat.stx_ino)) {
|
||||
pr_perror("write");
|
||||
goto err;
|
||||
}
|
||||
close(p[WRITE]);
|
||||
|
||||
if (kill(child, SIGTERM)) {
|
||||
pr_perror("kill");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (waitpid(child, &status, 0) != child) {
|
||||
pr_perror("waitpid");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!WIFEXITED(status)) {
|
||||
fail("Expected child to terminate normally");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (WEXITSTATUS(status) != 0) {
|
||||
fail("Child failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
pass();
|
||||
close(pidfd);
|
||||
return 0;
|
||||
err:
|
||||
close(pidfd);
|
||||
return 1;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user