On Wed, Jul 24, 2019 at 3:38 AM Christian Brauner <christian@xxxxxxxxxx> wrote: > > On Tue, Jul 23, 2019 at 10:39:07AM -0700, Suren Baghdasaryan wrote: > > This adds testing for polling on pidfd of a process being killed. Test runs > > 10000 iterations by default to stress test pidfd polling functionality. > > It accepts an optional command-line parameter to override the number or > > iterations to run. > > Specifically, it tests for: > > - pidfd_open on a child process succeeds > > - pidfd_send_signal on a child process succeeds > > - polling on pidfd succeeds and returns exactly one event > > - returned event is POLLIN > > - event is received within 3 secs of the process being killed > > > > 10000 iterations was chosen because of the race condition being tested > > which is not consistently reproducible but usually is revealed after less > > than 2000 iterations. > > Reveals race fixed by commit b191d6491be6 ("pidfd: fix a poll race when setting exit_state") > > Thanks for upstreaming the stress-tester. A few comments below. > Thanks for the comments. All make sense. I'll send an update later today or tomorrow. > > > > Signed-off-by: Suren Baghdasaryan <surenb@xxxxxxxxxx> > > --- > > tools/testing/selftests/pidfd/.gitignore | 1 + > > tools/testing/selftests/pidfd/Makefile | 2 +- > > .../testing/selftests/pidfd/pidfd_poll_test.c | 137 ++++++++++++++++++ > > 3 files changed, 139 insertions(+), 1 deletion(-) > > create mode 100644 tools/testing/selftests/pidfd/pidfd_poll_test.c > > > > diff --git a/tools/testing/selftests/pidfd/.gitignore b/tools/testing/selftests/pidfd/.gitignore > > index 16d84d117bc0..a67896347d34 100644 > > --- a/tools/testing/selftests/pidfd/.gitignore > > +++ b/tools/testing/selftests/pidfd/.gitignore > > @@ -1,2 +1,3 @@ > > pidfd_open_test > > +pidfd_poll_test > > pidfd_test > > diff --git a/tools/testing/selftests/pidfd/Makefile b/tools/testing/selftests/pidfd/Makefile > > index 720b2d884b3c..ed58b7108d18 100644 > > --- a/tools/testing/selftests/pidfd/Makefile > > +++ b/tools/testing/selftests/pidfd/Makefile > > @@ -1,7 +1,7 @@ > > # SPDX-License-Identifier: GPL-2.0-only > > CFLAGS += -g -I../../../../usr/include/ -lpthread > > > > -TEST_GEN_PROGS := pidfd_test pidfd_open_test > > +TEST_GEN_PROGS := pidfd_test pidfd_open_test pidfd_poll_test > > > > include ../lib.mk > > > > diff --git a/tools/testing/selftests/pidfd/pidfd_poll_test.c b/tools/testing/selftests/pidfd/pidfd_poll_test.c > > new file mode 100644 > > index 000000000000..f2934aa070ae > > --- /dev/null > > +++ b/tools/testing/selftests/pidfd/pidfd_poll_test.c > > @@ -0,0 +1,137 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > + > > +#define _GNU_SOURCE > > +#include <errno.h> > > +#include <linux/types.h> > > +#include <linux/wait.h> > > +#include <poll.h> > > +#include <signal.h> > > +#include <stdbool.h> > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <string.h> > > +#include <syscall.h> > > +#include <sys/wait.h> > > +#include <unistd.h> > > + > > +#include "pidfd.h" > > +#include "../kselftest.h" > > + > > +#define __NR_pidfd_send_signal 424 > > +#define __NR_pidfd_open 434 > > That won't work on Alpha where this number is unfortunately different so > I'm not sure which syscall you'd hit there (/me checks > 424 common tgkill sys_tgkill > ) > > The better option is to just place > > #ifndef __NR_pidfd_send_signal > #define __NR_pidfd_send_signal -1 > #endif > > #ifndef __NR_pidfd_open > #define __NR_pidfd_open -1 > #endif > > into the pidfd.h header. > > > + > > +static inline int sys_pidfd_open(pid_t pid, unsigned int flags) > > +{ > > + return syscall(__NR_pidfd_open, pid, flags); > > +} > > + > > +static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, > > + unsigned int flags) > > +{ > > + return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); > > +} > > Those can go into pidfd.h too. > > > + > > +static bool timeout; > > + > > +static void handle_alarm(int sig) > > +{ > > + timeout = true; > > +} > > + > > +int main(int argc, char **argv) > > +{ > > + int ret = 1; > > + int pidfd = -1; > > + struct pollfd fds; > > + int iter, nevents; > > + int nr_iterations = 10000; > > + > > + fds.events = POLLIN; > > if (argc > 2) > ksft_exit_fail_msg("Unexpected command line argument"); > > > + if (argc > 1) { > > if (argc == 2) > > > + nr_iterations = atoi(argv[1]); > > + if (!nr_iterations) { > > You should probably also check for negative values. > > > + ksft_test_result_fail("invalid input parameter %s\n", > > + argv[1]); > > + return ksft_exit_fail(); > > + } > > + } > > + > > + ksft_print_msg("running pidfd poll test for %d iterations\n", > > + nr_iterations); > > + > > + for (iter = 0; iter < nr_iterations; iter++) { > > + int child_pid = fork(); > > + > > + if (!child_pid) { > > + /* Child process just sleeps for a min */ > > + sleep(60); > > + exit(0); > > Just for kicks, please use exit(EXIT_SUCCESS) > > > + } > > > You should switch the checkes, i.e. > > if (child_pid < 0) > /* do stuff */ > > if (child_pid == 0) > /* do other stuff */ > > > + > > + /* Parent kills the child and waits for its death */ > > + if (child_pid < 0) { > > + if (errno == EAGAIN) { > > + iter--; > > + continue; > > + } > > + ksft_print_msg("%s - failed to fork a child process\n", > > + strerror(errno)); > > Uhm, shouldn't you exit with an error here?, i.e. > > ksft_exit_fail_msg(... > > > + } > > + pidfd = sys_pidfd_open(child_pid, 0); > > + if (pidfd < 0) { > > + ksft_print_msg("%s - pidfd_open failed\n", > > + strerror(errno)); > > + goto on_error; > > I think you honestly can just call ksft_exit_fail_msg() everywhere. The > fds will be cleaned up on process exit anyway and it's pretty > short-lived. > > > + } > > + /* Setup 3 sec alarm - plenty of time */ > > + if (signal(SIGALRM, handle_alarm) == SIG_ERR) { > > + ksft_print_msg("%s - signal failed\n", > > + strerror(errno)); > > + goto on_error; > > + } > > + alarm(3); > > + /* Send SIGKILL to the child */ > > + if (sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0)) { > > + ksft_print_msg("%s - pidfd_send_signal failed\n", > > + strerror(errno)); > > + goto on_error; > > + } > > + /* Wait for the death notification */ > > + fds.fd = pidfd; > > + nevents = poll(&fds, 1, -1); > > + if (nevents < 0) { > > + ksft_print_msg("%s - poll failed\n", > > + strerror(errno)); > > + goto on_error; > > + } > > + if (nevents != 1) { > > + ksft_print_msg("unexpected poll result: %d\n", > > + nevents); > > + goto on_error; > > + } > > + if (!(fds.revents & POLLIN)) { > > + ksft_print_msg( > > + "unexpected event type received: 0x%x\n", > > + fds.revents); > > + goto on_error; > > + } > > + if (timeout) { > > + ksft_print_msg("death notification wait timeout\n"); > > + goto on_error; > > + } > > + close(pidfd); > > + } > > + ret = 0; > > + > > +on_error: > > + if (pidfd) > > + close(pidfd); > > + > > + if (ret) { > > + ksft_test_result_fail("failed after %d retries\n", iter); > > + return ksft_exit_fail(); > > + } > > + > > + ksft_test_result_pass("pidfd poll test: pass\n"); > > + return ksft_exit_pass(); > > +} > > -- > > 2.22.0.657.g960e92d24f-goog > >