forked from checkpoint-restore/criu
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
zdtm: Check multiple process with common dead pidfd
Check the case where multiple processes have a pidfd open to a single dead process. Each pidfd in each process should have the same inode number. Signed-off-by: Bhavik Sachdev <[email protected]>
- Loading branch information
Showing
2 changed files
with
225 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
#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 <[email protected]>"; | ||
|
||
#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) | ||
Check warning on line 42 in test/zdtm/static/pidfd_diffdead.c GitHub Actions / build
|
||
{ | ||
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[]) | ||
Check warning on line 60 in test/zdtm/static/pidfd_diffdead.c GitHub Actions / build
|
||
{ | ||
#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) | ||
Check warning on line 111 in test/zdtm/static/pidfd_diffdead.c GitHub Actions / build
|
||
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); | ||
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; | ||
} | ||
|
||
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"); | ||
return 1; | ||
} | ||
|
||
if (write(p[WRITE], &stat.stx_ino, sizeof(stat.stx_ino)) != sizeof(stat.stx_ino)) { | ||
pr_perror("write"); | ||
return 1; | ||
} | ||
close(p[WRITE]); | ||
|
||
if (kill(child, SIGTERM)) { | ||
pr_perror("kill"); | ||
goto err; | ||
} | ||
|
||
if (waitpid(child, &status, 0) != child) { | ||
pr_perror("waitpid"); | ||
return 1; | ||
} | ||
|
||
if (!WIFEXITED(status)) { | ||
fail("Expected child to terminate normally"); | ||
|
||
Check warning on line 210 in test/zdtm/static/pidfd_diffdead.c GitHub Actions / build
|
||
} | ||
|
||
if(WEXITSTATUS(status) != 0) { | ||
fail("Child failed"); | ||
return 1; | ||
} | ||
|
||
pass(); | ||
close(pidfd); | ||
return 0; | ||
err: | ||
close(pidfd); | ||
return 1; | ||
} |