Received: by 2002:a25:4158:0:0:0:0:0 with SMTP id o85csp5300489yba; Tue, 30 Apr 2019 12:23:55 -0700 (PDT) X-Google-Smtp-Source: APXvYqySapfX9awkJ1naoRr2UrX9jSL99WFfvdeQ3uPcVNfxaAmvZHyi3VrpVIWqCKI48bLcgfI1 X-Received: by 2002:a17:902:e408:: with SMTP id ci8mr38066530plb.100.1556652235344; Tue, 30 Apr 2019 12:23:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1556652235; cv=none; d=google.com; s=arc-20160816; b=GngFfOXfM7eVyexSyuxiVJxWXCjNJf91q9C0hJAwzeAAYYjRBZrhm/IA+GjW0zoYAj JohGcoQV0GkuaAr6Uw004yauGpxT7xiEhb5LdotjUJAWAnZSIfhoz7wUDlFOxxRBnQ83 bn99EGybC0zqns/Yt9obItRqxtHQ7dICMecmKQMfT5nzk481Vv0VnFewxD7X9ejQbjvI qYQaxJ9bTZ/3RKHdRT9zj5odTBELjJSIYh8HLbuoCimqyX0BoMR+sTnwrK36Fuye2tsv fREuLGKlMJn2zutStPtPb2B3ooIiwQeJkZWONssEYD7nCRBKBLn1tdwHt86Req7Xbgd7 w8aQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:from:date:dkim-signature; bh=LCKlak7FYJZjHkPSI2bbY7nJMWKoi5EZ2NHkq7EYp70=; b=yE8wdSPJwx7k17uu93w1M9HgolY1YZYTWWv0kAInUK2FVAvPDMzBz+uA5XV+9GiEpn vgvhUL07XBiwsQfpmvBoNcbW3HwHYJjdsVy5n1FrJP5nMiKkVNAiQWv4XbyBl8iQbwoT ih3r7OvCzWGM6HKqSopqA9qCQlCE9VNr2cFsy/iiCWu4tXX8jPlZoCiVEmXwnCfrFQjS cI73XFZBNrGU0qNdPmFY5T5m8MaQPqHZBz9a9MIHzcvPgVqiPQQbungOQ+ldq2ChtWK/ hfZiluvPR6dkTUM3V9vtTnq77ucR8f81fIIl0KqVeSgncvsZlJl6aQxjYNJ9qmX6PjoK a6/g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@brauner.io header.s=google header.b=dXZuiMii; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a20si4689734pfl.228.2019.04.30.12.23.39; Tue, 30 Apr 2019 12:23:55 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@brauner.io header.s=google header.b=dXZuiMii; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726263AbfD3TVD (ORCPT + 99 others); Tue, 30 Apr 2019 15:21:03 -0400 Received: from mail-ed1-f68.google.com ([209.85.208.68]:42086 "EHLO mail-ed1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725996AbfD3TVD (ORCPT ); Tue, 30 Apr 2019 15:21:03 -0400 Received: by mail-ed1-f68.google.com with SMTP id l25so13274106eda.9 for ; Tue, 30 Apr 2019 12:21:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=brauner.io; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=LCKlak7FYJZjHkPSI2bbY7nJMWKoi5EZ2NHkq7EYp70=; b=dXZuiMiiQ1YMov/LL6PvqoHhbYAEkbFRRTdKzHCifnKtNK49fwX4yNeXShQCtXqBOq yEQRlwiAeEJw7VuTA8jnSMvlQl2Xoc3cvXkBaOlZhRyoq28JoPA1jywWiFdjdtxmfFAR RM0uhHa/Gyftu5bXDoR0R36KiYhF9Kb5ap+b9IHYd2BWafL05z3dhBw/T34+TPxV/Jr+ wRYvCOWsuko9wIIKhUvRCDj6p6AqrBLtb879xe5QfxEoMWA0oOP2AwXEqBkl56B94VY7 RVkJRfzKUJgTd8eOv00cyyC84J2r7ru7ucAdfhi147L2rrXQJkb66WRlfrHwubi2WwoX IvWA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=LCKlak7FYJZjHkPSI2bbY7nJMWKoi5EZ2NHkq7EYp70=; b=eN4XQXlHul7oHjJ0/HWgqe8exPpKgx19VnV8myIl9+JRF9RSOPKcOAAlujDdOlzHle CDn6O2JGaP9Ap2UQSZJ6u/xWXEVEdFOPo7pPrwDEhQo7l0bObLRSz7gHhjx3gHcQn8sO n/RsBy8iFOy+1p4yrzBuJDbnbeCKoJgBjP9ERG2bdnQJa2aB4iEtGH4AiuXf0A5epvBu wDenYHq1/M7Ih+ajAo0OaOIeXVrX03dKbejq4nKnuDzve69bCiqYgx1O+0HryboBThYx fnW5qgNp25BlwLwbMXFC0RvcFj0UGX3uGr0dLpBr3iL6EonYQ5V0hEyVd27oIuc2Cy1g dDrg== X-Gm-Message-State: APjAAAXGmRbBhW/cO5KdfCXhn3G6/x8oZVJYKceuE6f/HciX2DWqmOA7 BVtG3klWY4TDDeTdqXU4NqsFsw== X-Received: by 2002:a17:906:69d6:: with SMTP id g22mr2631702ejs.124.1556652061112; Tue, 30 Apr 2019 12:21:01 -0700 (PDT) Received: from brauner.io ([212.91.227.56]) by smtp.gmail.com with ESMTPSA id 44sm1386526eds.90.2019.04.30.12.20.59 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Tue, 30 Apr 2019 12:21:00 -0700 (PDT) Date: Tue, 30 Apr 2019 21:20:59 +0200 From: Christian Brauner To: "Joel Fernandes (Google)" Cc: linux-kernel@vger.kernel.org, Al Viro , Andrew Morton , Andy Lutomirski , Arnd Bergmann , Daniel Colascione , David Howells , "Eric W. Biederman" , Greg Kroah-Hartman , Ingo Molnar , Jann Horn , Jonathan Kowalski , Kees Cook , kernel-team@android.com, KJ Tsanaktsidis , Linus Torvalds , linux-kselftest@vger.kernel.org, Michal Hocko , Nadav Amit , Oleg Nesterov , "Peter Zijlstra (Intel)" , Serge Hallyn , Shuah Khan , Steven Rostedt , Thomas Gleixner , Tim Murray , Tycho Andersen Subject: Re: [PATCH v2 2/2] Add selftests for pidfd polling Message-ID: <20190430192057.ocevexvebfq2we3d@brauner.io> References: <20190430162154.61314-1-joel@joelfernandes.org> <20190430162154.61314-2-joel@joelfernandes.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: <20190430162154.61314-2-joel@joelfernandes.org> User-Agent: NeoMutt/20180716 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, Apr 30, 2019 at 12:21:54PM -0400, Joel Fernandes (Google) wrote: > Other than verifying pidfd based polling, the tests make sure that > wait semantics are preserved with the pidfd poll. Notably the 2 cases: > 1. If a thread group leader exits while threads still there, then no > pidfd poll notifcation should happen. > 2. If a non-thread group leader does an execve, then the thread group > leader is signaled to exit and is replaced with the execing thread > as the new leader, however the parent is not notified in this case. > > Signed-off-by: Joel Fernandes (Google) > --- > tools/testing/selftests/pidfd/Makefile | 2 +- > tools/testing/selftests/pidfd/pidfd_test.c | 210 +++++++++++++++++++++ > 2 files changed, 211 insertions(+), 1 deletion(-) > > diff --git a/tools/testing/selftests/pidfd/Makefile b/tools/testing/selftests/pidfd/Makefile > index deaf8073bc06..4b31c14f273c 100644 > --- a/tools/testing/selftests/pidfd/Makefile > +++ b/tools/testing/selftests/pidfd/Makefile > @@ -1,4 +1,4 @@ > -CFLAGS += -g -I../../../../usr/include/ > +CFLAGS += -g -I../../../../usr/include/ -lpthread > > TEST_GEN_PROGS := pidfd_test > > diff --git a/tools/testing/selftests/pidfd/pidfd_test.c b/tools/testing/selftests/pidfd/pidfd_test.c > index d59378a93782..8b404ccbc4ff 100644 > --- a/tools/testing/selftests/pidfd/pidfd_test.c > +++ b/tools/testing/selftests/pidfd/pidfd_test.c > @@ -4,18 +4,47 @@ > #include > #include > #include > +#include > #include > #include > #include > #include > #include > #include > +#include > +#include > #include > #include > +#include > #include > > #include "../kselftest.h" > > +#define str(s) _str(s) > +#define _str(s) #s > +#define CHILD_THREAD_MIN_WAIT 3 /* seconds */ > + > +#define MAX_EVENTS 5 > +#ifndef __NR_pidfd_send_signal > +#define __NR_pidfd_send_signal 424 > +#endif > + > +#ifndef CLONE_PIDFD > +#define CLONE_PIDFD 0x00001000 > +#endif > + > +static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *)) > +{ > + size_t stack_size = 1024; > + char *stack[1024] = { 0 }; > + > +#ifdef __ia64__ > + return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd); > +#else > + return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd); > +#endif > +} > + > static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, > unsigned int flags) > { > @@ -368,10 +397,191 @@ static int test_pidfd_send_signal_syscall_support(void) > return 0; > } > > +static void *test_pidfd_poll_exec_thread(void *priv) > +{ > + ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n", > + getpid(), syscall(SYS_gettid)); > + ksft_print_msg("Child Thread: doing exec of sleep\n"); > + > + execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL); > + > + ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", > + getpid(), syscall(SYS_gettid)); > + return NULL; > +} > + > +static void poll_pidfd(const char *test_name, int pidfd) > +{ > + int c; > + int epoll_fd = epoll_create1(EPOLL_CLOEXEC); > + struct epoll_event event, events[MAX_EVENTS]; > + > + if (epoll_fd == -1) > + ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor " > + "(errno %d)\n", > + test_name, errno); > + > + event.events = EPOLLIN; > + event.data.fd = pidfd; > + > + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) { > + ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor " > + "(errno %d)\n", > + test_name, errno); > + } > + > + c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000); > + if (c != 1 || !(events[0].events & EPOLLIN)) > + ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) ", > + "(errno %d)\n", > + test_name, c, events[0].events, errno); > + > + close(epoll_fd); > + return; nit: Function with void usually do not do an explicit return at the end. :) > + > +} > + > +static int child_poll_exec_test(void *args) > +{ > + pthread_t t1; > + > + ksft_print_msg("Child (pidfd): starting. pid %d tid %d\n", getpid(), > + syscall(SYS_gettid)); > + pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL); > + /* > + * Exec in the non-leader thread will destroy the leader immediately. > + * If the wait in the parent returns too soon, the test fails. > + */ > + while (1) > + sleep(1); > +} > + > +static int test_pidfd_poll_exec(int use_waitpid) Please make int use_waitpid a proper bool and make the function void as it's return value is never checked in main. (I know the other ones in the test file here do the same thing and I should switch them to void soon at some point.) > +{ > + int pid, pidfd = 0; > + int status, ret; > + pthread_t t1; > + time_t prog_start = time(NULL); > + const char *test_name = "pidfd_poll check for premature notification on child thread exec"; > + > + ksft_print_msg("Parent: pid: %d\n", getpid()); > + pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test); > + if (pid < 0) > + ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", > + test_name, pid, errno); > + > + ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); > + > + if (use_waitpid) { > + ret = waitpid(pid, &status, 0); > + if (ret == -1) > + ksft_print_msg("Parent: error\n"); > + > + if (ret == pid) > + ksft_print_msg("Parent: Child process waited for.\n"); > + } else { > + poll_pidfd(test_name, pidfd); > + } > + > + time_t prog_time = time(NULL) - prog_start; > + > + ksft_print_msg("Time waited for child: %lu\n", prog_time); > + > + close(pidfd); > + > + if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2) I'm sorry, can you please either briefly explain or comment where this +2 comes from? Why is that the cut-off? > + ksft_exit_fail_msg("%s test: Failed\n", test_name); > + else > + ksft_test_result_pass("%s test: Passed\n", test_name); > +} > + > +static void *test_pidfd_poll_leader_exit_thread(void *priv) > +{ > + ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n", > + getpid(), syscall(SYS_gettid)); > + sleep(CHILD_THREAD_MIN_WAIT); > + ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", getpid(), syscall(SYS_gettid)); > + return NULL; > +} > + > +static time_t *child_exit_secs; > +static int child_poll_leader_exit_test(void *args) > +{ > + pthread_t t1, t2; > + > + ksft_print_msg("Child: starting. pid %d tid %d\n", getpid(), syscall(SYS_gettid)); > + pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL); > + pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL); > + > + /* > + * glibc exit calls exit_group syscall, so explicity call exit only > + * so that only the group leader exits, leaving the threads alone. > + */ > + *child_exit_secs = time(NULL); Why is child_exit_secs a pointer? > + syscall(SYS_exit, 0); > +} > + > +static int test_pidfd_poll_leader_exit(int use_waitpid) Should be void as it's return value isn't checked at all. (I know the other ones in the test file here do the same thing and I should switch them to void soon at some point.) > +{ > + int pid, pidfd = 0; > + int status, ret; > + time_t prog_start = time(NULL); > + const char *test_name = "pidfd_poll check for premature notification on non-empty" > + "group leader exit"; > + > + child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE, > + MAP_SHARED | MAP_ANONYMOUS, -1, 0); > + > + if (child_exit_secs == MAP_FAILED) > + ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n", > + test_name, errno); > + > + ksft_print_msg("Parent: pid: %d\n", getpid()); > + pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test); > + if (pid < 0) > + ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", > + test_name, pid, errno); > + > + ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); > + > + if (use_waitpid) { > + ret = waitpid(pid, &status, 0); > + if (ret == -1) > + ksft_print_msg("Parent: error\n"); > + } else { > + /* > + * This sleep tests for the case where if the child exits, and is in > + * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll > + * doesn't prematurely return even though there are active threads > + */ > + sleep(1); > + poll_pidfd(test_name, pidfd); > + } > + > + if (ret == pid) > + ksft_print_msg("Parent: Child process waited for.\n"); > + > + time_t since_child_exit = time(NULL) - *child_exit_secs; > + > + ksft_print_msg("Time since child exit: %lu\n", since_child_exit); > + > + close(pidfd); > + > + if (since_child_exit < CHILD_THREAD_MIN_WAIT || > + since_child_exit > CHILD_THREAD_MIN_WAIT + 2) Same question as above. > + ksft_exit_fail_msg("%s test: Failed\n", test_name); > + else > + ksft_test_result_pass("%s test: Passed\n", test_name); > +} > + > int main(int argc, char **argv) > { > ksft_print_header(); > > + test_pidfd_poll_exec(0); test_pidfd_poll_exec(false); > + test_pidfd_poll_exec(1); test_pidfd_poll_exec(true); > + test_pidfd_poll_leader_exit(0); test_pidfd_poll_leader_exit(false); > + test_pidfd_poll_leader_exit(1); test_pidfd_poll_leader_exit(true); > test_pidfd_send_signal_syscall_support(); > test_pidfd_send_signal_simple_success(); > test_pidfd_send_signal_exited_fail(); > -- > 2.21.0.593.g511ec345e18-goog >