Skip to content

Commit

Permalink
zdtm: Check dead pidfd is restored correctly
Browse files Browse the repository at this point in the history
After, C/R of pidfds that point to dead processes their inodes might
change. But if two pidfds point to same dead process they should
continue to do so after C/R.

This test ensures that this happens by calling statx() on pidfds after
C/R and then comparing their inode numbers.

Support for comparing pidfds by using statx() and inode numbers was
introduced in Linux 6.9, so this test is skipped on < 6.9.

signed-off-by: Bhavik Sachdev <[email protected]>
  • Loading branch information
bsach64 committed Aug 12, 2024
1 parent a2e9053 commit e2746eb
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 0 deletions.
1 change: 1 addition & 0 deletions test/zdtm/static/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ TST_NOFILE := \
shm-mp \
ptrace_sig \
pidfd_self \
pidfd_dead \
pidfd_child \
pidfd_kill \
pipe00 \
Expand Down
163 changes: 163 additions & 0 deletions test/zdtm/static/pidfd_dead.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/utsname.h>

#include "zdtmtst.h"

const char *test_doc = "Check C/R of pidfds that point to dead processes\n";
const char *test_author = "Bhavik Sachdev <[email protected]>";

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 19 in test/zdtm/static/pidfd_dead.c

View workflow job for this annotation

GitHub Actions / build

{
return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
}

static int open_pidfd_pair(int pidfd[2], int pid)
{
pidfd[0] = pidfd_open(pid, 0);
if (pidfd[0] < 0)
return 1;
pidfd[1] = pidfd_open(pid, 0);
if (pidfd[1] < 0)
return 1;
return 0;
}
static int compare_pidfds(int pidfd[2])
{
/*
* After linux 6.9 we can compare inode numbers
* to determine if two pidfds point to the same process.
* While the inode number may change before and after C/R
* pidfds pointing to the same pid should have the same inode number.
*/
struct statx stats[2];
statx(pidfd[0], "", AT_EMPTY_PATH, STATX_ALL, &stats[0]);
statx(pidfd[1], "", AT_EMPTY_PATH, STATX_ALL, &stats[1]);
if (stats[0].stx_ino != stats[1].stx_ino)
return 1;
return 0;
}

static struct utsname buf;

int main(int argc, char* argv[])

Check warning on line 52 in test/zdtm/static/pidfd_dead.c

View workflow job for this annotation

GitHub Actions / build

{
#define READ 0
#define WRITE 1

int child, ret, gchild, p[2];
int cpidfd[2], gpidfd[2];
unsigned major, minor;

test_init(argc, argv);

ret = uname(&buf);
if (ret)
return 1;

if (sscanf(buf.release, "%u.%u", &major, &minor) != 2)
return 1;

if ((major < 6) && (minor < 9)) {
test_daemon();
test_waitsig();
skip("statx on pidfd is only supported on 6.9 and above..\n");
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 = 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 95 in test/zdtm/static/pidfd_dead.c

View workflow job for this annotation

GitHub Actions / build

} else {
close(p[READ]);
if (write(p[WRITE], &gchild, sizeof(int)) != sizeof(int)) {
pr_perror("write");
return 1;
}
close(p[WRITE]);
waitpid(gchild, NULL, 0);
while(1);
}
}

ret = open_pidfd_pair(cpidfd, child);
if (ret) {
pr_perror("pidfd_open");
return 1;
}

close(p[WRITE]);
if (read(p[READ], &gchild, sizeof(int)) != sizeof(int)) {
pr_perror("write");
return 1;
}
close(p[READ]);

ret = open_pidfd_pair(gpidfd, gchild);
if (ret) {
pr_perror("pidfd_open");
return 1;
}

if (pidfd_send_signal(gpidfd[0], SIGKILL, NULL, 0)) {
pr_perror("pidfd_send_signal");
return 1;
}

if (pidfd_send_signal(cpidfd[0], SIGKILL, NULL, 0)) {
pr_perror("pidfd_send_signal");
return 1;
}

if (waitpid(child, &ret, 0) != child) {
pr_perror("waitpid");
return 1;
}

test_daemon();
test_waitsig();

ret = compare_pidfds(cpidfd);
if (ret) {
fail();
goto close;
}

ret = compare_pidfds(gpidfd);
if (ret) {
fail();
goto close;
}
pass();
close:
close(cpidfd[0]);
close(cpidfd[1]);
close(gpidfd[0]);
close(gpidfd[1]);
return 0;
}

0 comments on commit e2746eb

Please sign in to comment.