Test for select, poll and epoll syscall overrides
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 256 lines · Julien Desfossez
This test for
root_regressionchecks if the syscall overrides for select, pselect6, poll, ppoll,epoll_ctl,epoll_waitandepoll_pwaitwork as expected on arm and x86 (32 and 64-bit).There are 11 test cases that check for normal and abnormal behaviour. If the test system has the Babeltrace python bindings, the test validates the content of the events, otherwise only the presence of the generated events is checked.
We also check if kernel OOPS, WARNING or BUG were generated during the test.
Signed-off-by Julien Desfossez <[email protected]>--- tests/regression/kernel/Makefile.am | 7 +- tests/regression/kernel/select_poll_epoll.c | 904 +++++++++++++++++++++ tests/regression/kernel/test_select_poll_epoll | 398 +++++++++ .../kernel/validate_select_poll_epoll.py | 783 ++++++++++++++++++ tests/root_regression | 1 + 5 files changed, 2092 insertions(+), 1 deletion(-) create mode 100644 tests/regression/kernel/select_poll_epoll.c create mode 100755 tests/regression/kernel/test_select_poll_epoll create mode 100755 tests/regression/kernel/validate_select_poll_epoll.pytests/regression/kernel/Makefile.am +6
-1@@ -1,4 +1,9 @@ -EXTRA_DIST = test_event_basic test_all_events test_syscall +noinst_PROGRAMS = select_poll_epoll +select_poll_epoll_SOURCES = select_poll_epoll.c +select_poll_epoll_LDADD = -lpthread -lpopt +select_poll_epoll_CFLAGS = -fno-stack-protector -D_FORTIFY_SOURCE=0 + +EXTRA_DIST = test_event_basic test_all_events test_syscall test_select_poll_epoll all-local: @if [ x"$(srcdir)" != x"$(builddir)" ]; then \tests/regression/kernel/select_poll_epoll.c new file +211
-0@@ -0,0 +1,904 @@ +#include <stdio.h> +#include <poll.h> +#include <signal.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <stddef.h> +#include <sys/select.h> +#include <sys/epoll.h> +#include <popt.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <limits.h> +#include <pthread.h> +#include <sys/mman.h> +#include <time.h> + +#define BUF_SIZE 256 +#define NB_FD 1 +#define MAX_FDS 2047 +#define NR_ITER 1000/* for stress-tests */ + +#define MIN_NR_FDS 5/* the minimum number of open FDs required for the test to run */ +#define BIG_SELECT_FD 1022 + +#define MSEC_PER_USEC 1000 +#define MSEC_PER_NSEC (MSEC_PER_USEC * 1000) + +static int timeout;/* seconds, -1 to disable */ +static int stop_thread; +static int wait_fd; + +struct ppoll_thread_data { +struct pollfd *ufds; +int value; +}; + +void test_select_big (void ) +{ +fd_set rfds, wfds, exfds; +struct timeval tv; +int ret; +int fd2; +char buf[BUF_SIZE ]; + +FD_ZERO (&rfds); +FD_ZERO (&wfds); +FD_ZERO (&exfds); + + fd2 =dup2 (wait_fd,BIG_SELECT_FD ); +if (fd2 <0 ) { +perror ("dup2" ); + goto end; + } +FD_SET (fd2, &rfds); + + tv.tv_sec =0 ; + tv.tv_usec = timeout *MSEC_PER_USEC ; + +if (timeout >0 ) { + ret =select (fd2 +1 , &rfds, &wfds, &exfds, &tv); + }else { + ret =select (fd2 +1 , &rfds, &wfds, &exfds,NULL ); + } + +if (ret ==-1 ) { +perror ("select()" ); + }else if (ret) { +printf ("# [select] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[select] read" ); + } + }else { +printf ("# [select] timeout\n" ); + } + + ret =close (BIG_SELECT_FD ); +if (ret) +perror ("close" ); + +end: +return ; +} + +void test_pselect (void ) +{ +fd_set rfds; +struct timespec tv; +int ret; +char buf[BUF_SIZE ]; + +FD_ZERO (&rfds); +FD_SET (wait_fd, &rfds); + + tv.tv_sec =0 ; + tv.tv_nsec = timeout *MSEC_PER_NSEC ; + +if (timeout >0 ) { + ret =pselect (1 , &rfds,NULL ,NULL , &tv,NULL ); + }else { + ret =pselect (1 , &rfds,NULL ,NULL ,NULL ,NULL ); + } + +if (ret ==-1 ) { +perror ("pselect()" ); + }else if (ret) { +printf ("# [pselect] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[pselect] read" ); + } + }else { +printf ("# [pselect] timeout\n" ); + } + +} + +void test_select (void ) +{ +fd_set rfds; +struct timeval tv; +int ret; +char buf[BUF_SIZE ]; + +FD_ZERO (&rfds); +FD_SET (wait_fd, &rfds); + + tv.tv_sec =0 ; + tv.tv_usec = timeout *MSEC_PER_USEC ; + +if (timeout >0 ) { + ret =select (1 , &rfds,NULL ,NULL , &tv); + }else { + ret =select (1 , &rfds,NULL ,NULL ,NULL ); + } + +if (ret ==-1 ) { +perror ("select()" ); + }else if (ret) { +printf ("# [select] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[select] read" ); + } + }else { +printf ("# [select] timeout\n" ); + } + +} + +void test_poll (void ) +{ +struct pollfd ufds[NB_FD ]; +char buf[BUF_SIZE ]; +int ret; + + ufds[0 ].fd = wait_fd; + ufds[0 ].events =POLLIN |POLLPRI ; + + ret =poll (ufds,1 , timeout); + +if (ret <0 ) { +perror ("poll" ); + }else if (ret >0 ) { +printf ("# [poll] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[poll] read" ); + } + }else { +printf ("# [poll] timeout\n" ); + } +} + +void test_ppoll (void ) +{ +struct pollfd ufds[NB_FD ]; +char buf[BUF_SIZE ]; +int ret; +struct timespec ts; + + ufds[0 ].fd = wait_fd; + ufds[0 ].events =POLLIN |POLLPRI ; + +if (timeout >0 ) { + ts.tv_sec =0 ; + ts.tv_nsec = timeout *MSEC_PER_NSEC ; + ret =ppoll (ufds,1 , &ts,NULL ); + }else { + ret =ppoll (ufds,1 ,NULL ,NULL ); + } + + +if (ret <0 ) { +perror ("ppoll" ); + }else if (ret >0 ) { +printf ("# [ppoll] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[ppoll] read" ); + } + }else { +printf ("# [ppoll] timeout\n" ); + } +} +
tests/regression/kernel/select_poll_epoll.c line 221
Quoted 10 lines
tests/regression/kernel/select_poll_epoll.c new file +10
-0+void test_ppoll_big (void ) +{ +struct pollfd ufds[MAX_FDS ]; +char buf[BUF_SIZE ]; +int ret, i, fds[MAX_FDS ]; + +for (i =0 ; i <MAX_FDS ; i++) { + fds[i] =dup (wait_fd); +if (fds[i] <0 ) +perror ("dup" );
Use braces on single-line conditions.
Quoted 12 lines
tests/regression/kernel/select_poll_epoll.c new file +12
-0+ ufds[i].fd = fds[i]; + ufds[i].events =POLLIN |POLLPRI ; + } + + ret =ppoll (ufds,MAX_FDS ,NULL ,NULL ); + +if (ret <0 ) { +perror ("ppoll" ); + }else if (ret >0 ) { +printf ("# [ppoll] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) {
tests/regression/kernel/select_poll_epoll.c line 243
Quoted 10 lines
tests/regression/kernel/select_poll_epoll.c new file +10
-0+perror ("[ppoll] read" ); + } + }else { +printf ("# [ppoll] timeout\n" ); + } + +for (i =0 ; i <MAX_FDS ; i++) { + ret =close (fds[i]); +if (ret !=0 ) +perror ("close" );
Use braces on single-line conditions.
tests/regression/kernel/select_poll_epoll.c line 245
Quoted 2 lines
tests/regression/kernel/select_poll_epoll.c new file +2
-0+ } +
Remove trailing tab.
Quoted 78 lines
tests/regression/kernel/select_poll_epoll.c new file +78
-0+return ; +} + +void test_epoll (void ) +{ +int ret, epollfd; +char buf[BUF_SIZE ]; +struct epoll_event epoll_event; + + epollfd =epoll_create (NB_FD ); +if (epollfd <0 ) { +perror ("[epoll] create" ); + goto end; + } + + epoll_event.events =EPOLLIN |EPOLLPRI |EPOLLET ; + epoll_event.data.fd = wait_fd; + ret =epoll_ctl (epollfd,EPOLL_CTL_ADD , wait_fd, &epoll_event); +if (ret <0 ) { +perror ("[epoll] add" ); + goto end; + } + +if (timeout >0 ) { + ret =epoll_wait (epollfd, &epoll_event,1 , timeout); + }else { + ret =epoll_wait (epollfd, &epoll_event,1 ,-1 ); + } + +if (ret ==1 ) { +printf ("# [epoll] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[epoll] read" ); + } + }else if (ret ==0 ) { +printf ("# [epoll] timeout\n" ); + }else { +perror ("epoll_wait" ); + } + +end: +return ; +} + +void test_pepoll (void ) +{ +int ret, epollfd; +char buf[BUF_SIZE ]; +struct epoll_event epoll_event; + + epollfd =epoll_create (NB_FD ); +if (epollfd <0 ) { +perror ("[eppoll] create" ); + goto end; + } + + epoll_event.events =EPOLLIN |EPOLLPRI |EPOLLET ; + epoll_event.data.fd = wait_fd; + ret =epoll_ctl (epollfd,EPOLL_CTL_ADD , wait_fd, &epoll_event); +if (ret <0 ) { +perror ("[eppoll] add" ); + goto end; + } + +if (timeout >0 ) { + ret =epoll_pwait (epollfd, &epoll_event,1 , timeout,NULL ); + }else { + ret =epoll_pwait (epollfd, &epoll_event,1 ,-1 ,NULL ); + } + +if (ret ==1 ) { +printf ("# [eppoll] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[eppoll] read" ); + } + }else if (ret ==0 ) {
tests/regression/kernel/select_poll_epoll.c line 333
Quoted 10 lines
tests/regression/kernel/select_poll_epoll.c new file +10
-0+printf ("# [eppoll] timeout\n" ); + }else { +perror ("epoll_pwait" ); + } + +end: +return ; +} + +void should_work (void )
Something like "run_working_cases()" seems clearer here? Better names are welcome :-)
tests/regression/kernel/select_poll_epoll.c line 342
Quoted 9 lines
tests/regression/kernel/select_poll_epoll.c new file +9
-0+{ +int ret; +int pipe_fds[2 ]; + +if (timeout >0 ) { +/* +* When launched with the run.sh script, stdin randomly +* receives some garbage that make the timeout cases +* fail, use a dummy pipe for this test.
I'm not sure what you mean here.
Quoted 10 lines
tests/regression/kernel/select_poll_epoll.c new file +10
-0+*/ + ret =pipe (pipe_fds); +if (ret !=0 ) { +perror ("pipe" ); + goto end; + } + wait_fd = pipe_fds[0 ]; + } +test_select (); +test_pselect ();
tests/regression/kernel/select_poll_epoll.c line 362
Quoted 10 lines
tests/regression/kernel/select_poll_epoll.c new file +10
-0+test_select_big (); +test_poll (); +test_ppoll (); +test_epoll (); +test_pepoll (); + +if (timeout >0 ) { + ret =close (pipe_fds[0 ]); +if (ret) +perror ("close" );
Use braces on single-line conditions.
tests/regression/kernel/select_poll_epoll.c line 365
Quoted 3 lines
tests/regression/kernel/select_poll_epoll.c new file +3
-0+ ret =close (pipe_fds[1 ]); +if (ret) +perror ("close" );
Use braces on single-line conditions.
Quoted 220 lines
tests/regression/kernel/select_poll_epoll.c new file +220
-0+ } + +end: +return ; +} + +/* +* Ask for 100 FDs in a buffer for allocated for only 1 FD, should +* segfault (eventually with a "*** stack smashing detected ***" message). +* The event should contain an array of 100 FDs filled with garbage. +*/ +void ppoll_fds_buffer_overflow (void ) +{ +struct pollfd ufds[NB_FD ]; +char buf[BUF_SIZE ]; +int ret; + + ufds[0 ].fd = wait_fd; + ufds[0 ].events =POLLIN |POLLPRI ; + + ret =syscall (SYS_ppoll, ufds,100 ,NULL ,NULL ); + +if (ret <0 ) { +perror ("ppoll" ); + }else if (ret >0 ) { +printf ("# [ppoll] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[ppoll] read" ); + } + }else { +printf ("# [ppoll] timeout\n" ); + } + +return ; +} + +/* +* Ask for ULONG_MAX FDs in a buffer for allocated for only 1 FD, should +* cleanly fail with a "Invalid argument". +* The event should contain an empty array of FDs and overflow = 1. +*/ +void ppoll_fds_ulong_max (void ) +{ +struct pollfd ufds[NB_FD ]; +char buf[BUF_SIZE ]; +int ret; + + ufds[0 ].fd = wait_fd; + ufds[0 ].events =POLLIN |POLLPRI ; + + ret =syscall (SYS_ppoll, ufds,ULONG_MAX ,NULL ,NULL ); + +if (ret <0 ) { +perror ("# ppoll" ); + }else if (ret >0 ) { +printf ("# [ppoll] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[ppoll] read" ); + } + }else { +printf ("# [ppoll] timeout\n" ); + } + +return ; +} + +/* +* Select is limited to 1024 FDs, should output a pselect event +* with 0 FDs. +*/ +void pselect_fd_too_big (void ) +{ +fd_set rfds; +int ret; +int fd2; +char buf[BUF_SIZE ]; + +/* +* Test if nfds > 1024. +* Make sure ulimit is set correctly (ulimit -n 2048). +*/ + fd2 =dup2 (wait_fd,2047 ); +if (fd2 !=2047 ) { +perror ("dup2" ); +return ; + } +FD_ZERO (&rfds); +FD_SET (fd2, &rfds); + + ret =syscall (SYS_pselect6, fd2 +1 , &rfds,NULL ,NULL ,NULL ,NULL ); + +if (ret ==-1 ) { +perror ("# pselect()" ); + }else if (ret) { +printf ("# [pselect] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[pselect] read" ); + } + }else { +printf ("# [pselect] timeout\n" ); + } + +} + +/* +* Invalid pointer as writefds, should output a ppoll event +* with 0 FDs. +*/ +void pselect_invalid_pointer (void ) +{ +fd_set rfds; +int ret; +char buf[BUF_SIZE ]; +void *invalid = (void *)0x42 ; + +FD_ZERO (&rfds); +FD_SET (wait_fd, &rfds); + + ret =syscall (SYS_pselect6,1 , &rfds, (fd_set *) invalid,NULL ,NULL , +NULL ); + +if (ret ==-1 ) { +perror ("# pselect()" ); + }else if (ret) { +printf ("# [pselect] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[pselect] read" ); + } + }else { +printf ("# [pselect] timeout\n" ); + } + +} + +/* +* Pass an invalid pointer to epoll_pwait, should fail with +* "Bad address", the event returns 0 FDs. +*/ +void epoll_pwait_invalid_pointer (void ) +{ +int ret, epollfd; +char buf[BUF_SIZE ]; +struct epoll_event epoll_event; +void *invalid = (void *)0x42 ; + + epollfd =epoll_create (NB_FD ); +if (epollfd <0 ) { +perror ("[eppoll] create" ); + goto end; + } + + epoll_event.events =EPOLLIN |EPOLLPRI |EPOLLET ; + epoll_event.data.fd = wait_fd; + ret =epoll_ctl (epollfd,EPOLL_CTL_ADD , wait_fd, &epoll_event); +if (ret <0 ) { +perror ("[eppoll] add" ); + goto end; + } + + ret =syscall (SYS_epoll_pwait, epollfd, + (struct epoll_event *) invalid,1 ,-1 ,NULL ); + +if (ret ==1 ) { +printf ("# [eppoll] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[eppoll] read" ); + } + }else if (ret ==0 ) { +printf ("# [eppoll] timeout\n" ); + }else { +perror ("# epoll_pwait" ); + } + +end: +return ; +} + +/* +* Set maxevents to INT_MAX, should output "Invalid argument" +* The event should return an empty array. +*/ +void epoll_pwait_int_max (void ) +{ +int ret, epollfd; +char buf[BUF_SIZE ]; +struct epoll_event epoll_event; + + epollfd =epoll_create (NB_FD ); +if (epollfd <0 ) { +perror ("[eppoll] create" ); + goto end; + } + + epoll_event.events =EPOLLIN |EPOLLPRI |EPOLLET ; + epoll_event.data.fd = wait_fd; + ret =epoll_ctl (epollfd,EPOLL_CTL_ADD , wait_fd, &epoll_event); +if (ret <0 ) { +perror ("[eppoll] add" ); + goto end; + } + + ret =syscall (SYS_epoll_pwait, epollfd, &epoll_event,INT_MAX ,-1 , +NULL ); + +if (ret ==1 ) { +printf ("# [eppoll] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[eppoll] read" ); + } + }else if (ret ==0 ) { +printf ("# [eppoll] timeout\n" ); + }else { +perror ("# epoll_pwait" ); + }
tests/regression/kernel/select_poll_epoll.c line 595
Quoted 10 lines
tests/regression/kernel/select_poll_epoll.c new file +10
-0+ +end: +return ; +} + +void *ppoll_writer (void *arg) +{ +struct ppoll_thread_data *data = (struct ppoll_thread_data *) arg; + +while (!stop_thread) {
stop_thread should be declared "volatile" to ensure compiler optimizations don't cache its value.
Quoted 39 lines
tests/regression/kernel/select_poll_epoll.c new file +39
-0+memset (data->ufds, data->value, +MAX_FDS *sizeof (struct pollfd )); +usleep (100 ); + } + +return NULL ; +} + +void do_ppoll (int *fds,struct pollfd *ufds) +{ +int i, ret; +struct timespec ts; +char buf[BUF_SIZE ]; + + ts.tv_sec =0 ; + ts.tv_nsec =1 *MSEC_PER_NSEC ; + +for (i =0 ; i <MAX_FDS ; i++) { + ufds[i].fd = fds[i]; + ufds[i].events =POLLIN |POLLPRI ; + } + + ret =ppoll (ufds,MAX_FDS , &ts,NULL ); + +if (ret <0 ) { +perror ("ppoll" ); + }else if (ret >0 ) { +printf ("# [ppoll] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[ppoll] read" ); + } + }else { +printf ("# [ppoll] timeout\n" ); + } +} + +void stress_ppoll (int *fds,int value) +{
tests/regression/kernel/select_poll_epoll.c line 644
Quoted 10 lines
tests/regression/kernel/select_poll_epoll.c new file +10
-0+pthread_t writer; +int iter; +struct ppoll_thread_data thread_data; +struct pollfd ufds[MAX_FDS ]; + + thread_data.ufds = ufds; + thread_data.value = value; + + stop_thread =0 ; +pthread_create (&writer,NULL , &ppoll_writer, (void *) &thread_data);
Check return value of pthread_create.
Quoted 76 lines
tests/regression/kernel/select_poll_epoll.c new file +76
-0+for (iter =0 ; iter <NR_ITER ; iter++) { +do_ppoll (fds, ufds); + } + stop_thread =1 ; +pthread_join (writer,NULL ); +} + +/* +* 3 rounds of NR_ITER iterations with concurrent updates of the pollfd +* structure: +* - memset to 0 +* - memset to 1 +* - memset to INT_MAX +* Waits for input, but also set a timeout in case the input FD is overwritten +* before entering in the syscall. We use MAX_FDS FDs (dup of stdin), so the +* resulting trace is big (20MB). +* +* ppoll should work as expected and the trace should be readable at the end. +*/ +void ppoll_concurrent_write (void ) +{ +int i, ret, fds[MAX_FDS ]; + +for (i =0 ; i <MAX_FDS ; i++) { + fds[i] =dup (wait_fd); +if (fds[i] <0 ) +perror ("dup" ); + } + +stress_ppoll (fds,0 ); +stress_ppoll (fds,1 ); +stress_ppoll (fds,INT_MAX ); + +for (i =0 ; i <MAX_FDS ; i++) { + ret =close (fds[i]); +if (ret !=0 ) +perror ("close" ); + } + +return ; +} + +void *epoll_pwait_writer (void *addr) +{ +srand (time (NULL )); + +while (!stop_thread) { +usleep (rand () %30 ); +munmap (addr,MAX_FDS *sizeof (struct epoll_event )); + } + +return NULL ; +} + +/* +* epoll_pwait on MAX_FDS fds while a concurrent thread munmaps the +* buffer allocated for the returned data. This should randomly segfault. +* The trace should be readable and no kernel OOPS should occur. +*/ +void epoll_pwait_concurrent_munmap (void ) +{ +int ret, epollfd, i, fds[MAX_FDS ]; +char buf[BUF_SIZE ]; +struct epoll_event *epoll_event; +void *addr =NULL ; +pthread_t writer; + + + epollfd =epoll_create (MAX_FDS ); +if (epollfd <0 ) { +perror ("[eppoll] create" ); + goto end; + } + + epoll_event = mmap(addr, MAX_FDS * sizeof(struct epoll_event), + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
tests/regression/kernel/select_poll_epoll.c line 730
Quoted 10 lines
tests/regression/kernel/select_poll_epoll.c new file +10
-0+ -1, 0); +if (epoll_event ==MAP_FAILED ) { +perror ("mmap" ); + goto end; + } + +for (i =0 ; i <MAX_FDS ; i++) { + fds[i] =dup (wait_fd); +if (fds[i] <0 ) +perror ("dup" );
Use braces on single-line conditions.
Quoted 23 lines
tests/regression/kernel/select_poll_epoll.c new file +23
-0+ epoll_event[i].events =EPOLLIN |EPOLLPRI |EPOLLET ; + epoll_event[i].data.fd = fds[i]; + ret =epoll_ctl (epollfd,EPOLL_CTL_ADD , fds[i], epoll_event); +if (ret <0 ) { +perror ("[eppoll] add" ); + goto end_unmap; + } + } + stop_thread =0 ; +pthread_create (&writer,NULL , &epoll_pwait_writer, (void *) epoll_event); + + ret =epoll_pwait (epollfd, epoll_event,1 ,1 ,NULL ); + +if (ret ==1 ) { +printf ("# [eppoll] data available\n" ); + ret =read (wait_fd, buf,BUF_SIZE ); +if (ret <0 ) { +perror ("[eppoll] read" ); + } + }else if (ret ==0 ) { +printf ("# [eppoll] timeout\n" ); + }else { +perror ("# epoll_pwait" );
tests/regression/kernel/select_poll_epoll.c line 763
Quoted 10 lines
tests/regression/kernel/select_poll_epoll.c new file +10
-0+ } + + stop_thread =1 ; +pthread_join (writer,NULL ); + +end_unmap: +for (i =0 ; i <MAX_FDS ; i++) { + ret =close (fds[i]); +if (ret !=0 ) +perror ("close" );
Use braces on single-line conditions.
Quoted 5 lines
tests/regression/kernel/select_poll_epoll.c new file +5
-0+ } + + ret =munmap (addr,MAX_FDS *sizeof (struct epoll_event )); +if (ret !=0 ) +perror ("munmap" );
tests/regression/kernel/select_poll_epoll.c line 778
Quoted 10 lines
tests/regression/kernel/select_poll_epoll.c new file +10
-0+ +end: +return ; +} + +void usage (poptContext optCon,int exitcode,char *error,char *addl) +{ +poptPrintUsage (optCon, stderr,0 ); +if (error) +fprintf (stderr,"%s: %s\n" , error, addl);
Use braces on single-line conditions.
Quoted 575 lines
tests/regression/kernel/select_poll_epoll.c new file +126
-0+exit (exitcode); +} + +void print_list (void ) +{ +fprintf (stderr,"Test list (-t X):\n" ); +fprintf (stderr,"\t1: Working cases for select, pselect6, poll, ppoll " +"and epoll, waiting for input\n" ); +fprintf (stderr,"\t2: Timeout cases (1ms) for select, pselect6, poll, " +"ppoll and epoll\n" ); +fprintf (stderr,"\t3: pselect with a FD > 1023\n" ); +fprintf (stderr,"\t4: ppoll with %d FDs\n" ,MAX_FDS ); +fprintf (stderr,"\t5: ppoll buffer overflow, should segfault, waits " +"for input\n" ); +fprintf (stderr,"\t6: pselect with invalid pointer, waits for " +"input\n" ); +fprintf (stderr,"\t7: ppoll with ulong_max fds, waits for input\n" ); +fprintf (stderr,"\t8: epoll_pwait with invalid pointer, waits for " +"input\n" ); +fprintf (stderr,"\t9: epoll_pwait with maxevents set to INT_MAX, " +"waits for input\n" ); +fprintf (stderr,"\t10: ppoll with concurrent updates of the structure " +"from user-space, stress test (3000 iterations), " +"waits for input + timeout 1ms\n" ); +fprintf (stderr,"\t11: epoll_pwait with concurrent munmap of the buffer " +"from user-space, should randomly segfault, run " +"multiple times, waits for input + timeout 1ms\n" ); +} + +int main (int argc,const char **argv) +{ +int c, ret, test =-1 ; +poptContext optCon; +struct rlimit open_lim; + +struct poptOption optionsTable[] = { + {"test" ,'t' ,POPT_ARG_INT , &test,0 , +"Test to run" ,NULL }, + {"list" ,'l' ,0 ,0 ,'l' , +"List of tests (-t X)" ,NULL }, + POPT_AUTOHELP + {NULL ,0 ,0 ,NULL ,0 } + }; + + optCon =poptGetContext (NULL , argc, argv, optionsTable,0 ); + +if (argc <2 ) { +poptPrintUsage (optCon, stderr,0 ); + ret =-1 ; + goto end; + } + + ret =0 ; + +while ((c =poptGetNextOpt (optCon)) >=0 ) { +switch (c) { +case 'l' : +print_list (); + goto end; + } + } + + open_lim.rlim_cur =MAX_FDS +MIN_NR_FDS ; + open_lim.rlim_max =MAX_FDS +MIN_NR_FDS ; + + ret =setrlimit (RLIMIT_NOFILE , &open_lim); +if (ret <0 ) { +perror ("setrlimit" ); + goto end; + } + +/* +* Some tests might segfault, but we need the getpid() to be output +* for the validation, disabling the buffering on stdout works. +*/ +setbuf (stdout,NULL ); +printf ("%d\n" ,getpid ()); + + wait_fd =STDIN_FILENO ; + +switch (test) { +case 1 : + timeout =-1 ; +should_work (); +break ; +case 2 : + timeout =1 ; +should_work (); +break ; +case 3 : +pselect_fd_too_big (); +break ; +case 4 : +test_ppoll_big (); +break ; +case 5 : +ppoll_fds_buffer_overflow (); +break ; +case 6 : +pselect_invalid_pointer (); +break ; +case 7 : +ppoll_fds_ulong_max (); +break ; +case 8 : +epoll_pwait_invalid_pointer (); +break ; +case 9 : +epoll_pwait_int_max (); +break ; +case 10 : +ppoll_concurrent_write (); +break ; +case 11 : +epoll_pwait_concurrent_munmap (); +break ; +default : +poptPrintUsage (optCon, stderr,0 ); + ret =-1 ; +break ; + } + +end: +poptFreeContext (optCon); +return ret; +}tests/regression/kernel/test_select_poll_epoll new file +398
-0@@ -0,0 +1,398 @@ +#!/bin/bash +# +# Copyright (C) - 2016 Julien Desfossez <[email protected]> +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License, version 2 only, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., 51 +# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +TEST_DESC="Kernel tracer - select, poll and epoll payload extraction" + +CURDIR=$(dirname $0)/ +TESTDIR=$CURDIR/../.. +VALIDATE_SCRIPT="$CURDIR/validate_select_poll_epoll.py" +NUM_TESTS=102 + +# Only run this test on x86 and arm +uname -m | grep -E "x86|arm" >/dev/null 2>&1 +if test $? != 0; then + exit 0 +fi + +DISABLE_VALIDATE=0 +# Babeltrace python bindings are required for the validation, but +# it is not a mandatory dependancy of the project, so fail run the +# without the content validation, at least we test that we are not +# crashing the kernel. +$VALIDATE_SCRIPT --help >/dev/null +if test $? != 0; then + echo "# Failed to run the validation script, Babeltrace Python bindings might be missing" + DISABLE_VALIDATE=1 +fi + +LAST_WARNING=$(dmesg | grep " WARNING:" | cut -d' ' -f1 | tail -1) +LAST_OOPS=$(dmesg | grep " OOPS:" | cut -d' ' -f1 | tail -1) +LAST_BUG=$(dmesg | grep " BUG:" | cut -d' ' -f1 | tail -1) + +source $TESTDIR/utils/utils.sh + +function check_trace_content() +{ + if test $DISABLE_VALIDATE == 1; then + ok 0 "Validation skipped" + return + fi + + $VALIDATE_SCRIPT $@ + if test $? = 0; then + ok 0 "Validation success" + else + fail "Validation" + fi +} + +function test_working_cases() +{ + TRACE_PATH=$(mktemp -d) + SESSION_NAME="syscall_payload" + SYSCALL_LIST="select,pselect6,poll,ppoll,epoll_ctl,epoll_wait,epoll_pwait" + + diag "Working cases for select, pselect6, poll, ppoll and epoll, waiting for input" + + create_lttng_session_ok $SESSION_NAME $TRACE_PATH + + lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST + add_context_kernel_ok $SESSION_NAME channel0 pid + + start_lttng_tracing_ok + { out=$(yes | $CURDIR/select_poll_epoll -t 1); } 2>/dev/null + stop_lttng_tracing_ok + pid=$(echo $out | cut -d' ' -f1) + + validate_trace "$SYSCALL_LIST" $TRACE_PATH + check_trace_content -t 1 -p $pid $TRACE_PATH + + destroy_lttng_session_ok $SESSION_NAME + + rm -rf $TRACE_PATH +} + +function test_timeout_cases() +{ + TRACE_PATH=$(mktemp -d) + SESSION_NAME="syscall_payload" + SYSCALL_LIST="select,pselect6,poll,ppoll,epoll_ctl,epoll_wait,epoll_pwait" + + diag "Timeout cases (1ms) for select, pselect6, poll, ppoll and epoll" + + create_lttng_session_ok $SESSION_NAME $TRACE_PATH + + lttng_enable_kernel_syscall_ok $SESSION_NAME "$SYSCALL_LIST" + add_context_kernel_ok $SESSION_NAME channel0 pid + + start_lttng_tracing_ok + { out=$($CURDIR/select_poll_epoll -t 2); } 2>/dev/null + stop_lttng_tracing_ok + pid=$(echo $out | cut -d' ' -f1) + + validate_trace "$SYSCALL_LIST" $TRACE_PATH + check_trace_content -t 2 -p $pid $TRACE_PATH 2>/dev/null + + destroy_lttng_session_ok $SESSION_NAME + + rm -rf $TRACE_PATH +} + +function test_big_pselect() +{ + TRACE_PATH=$(mktemp -d) + SESSION_NAME="syscall_payload" + SYSCALL_LIST="pselect6" + + diag "pselect with a FD > 1023" + + create_lttng_session_ok $SESSION_NAME $TRACE_PATH + + lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST + add_context_kernel_ok $SESSION_NAME channel0 pid + + start_lttng_tracing_ok + { out=$($CURDIR/select_poll_epoll -t 3); } 2>/dev/null + stop_lttng_tracing_ok + pid=$(echo $out | cut -d' ' -f1) + + validate_trace "$SYSCALL_LIST" $TRACE_PATH + check_trace_content -t 3 -p $pid $TRACE_PATH 2>/dev/null + + destroy_lttng_session_ok $SESSION_NAME + + rm -rf $TRACE_PATH +} + +function test_big_ppoll() +{ + TRACE_PATH=$(mktemp -d) + SESSION_NAME="syscall_payload" + SYSCALL_LIST="ppoll" + + diag "ppoll with 2047 FDs" + + create_lttng_session_ok $SESSION_NAME $TRACE_PATH + + lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST + add_context_kernel_ok $SESSION_NAME channel0 pid + + start_lttng_tracing_ok + { out=$(yes | $CURDIR/select_poll_epoll -t 4); } 2>/dev/null + stop_lttng_tracing_ok + pid=$(echo $out | cut -d' ' -f1) + + validate_trace "$SYSCALL_LIST" $TRACE_PATH + check_trace_content -t 4 -p $pid $TRACE_PATH 2>/dev/null + + destroy_lttng_session_ok $SESSION_NAME + + rm -rf $TRACE_PATH +} + +function test_ppoll_overflow() +{ + TRACE_PATH=$(mktemp -d) + SESSION_NAME="syscall_payload" + SYSCALL_LIST="ppoll" + + diag "ppoll buffer overflow, should segfault, waits for input" + + create_lttng_session_ok $SESSION_NAME $TRACE_PATH + + lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST + add_context_kernel_ok $SESSION_NAME channel0 pid + + start_lttng_tracing_ok + diag "Expect segfaults" + { out=$(yes | $CURDIR/select_poll_epoll -t 5); } 2>/dev/null + stop_lttng_tracing_ok + echo $out + pid=$(echo $out | cut -d' ' -f1) + + validate_trace "$SYSCALL_LIST" $TRACE_PATH + + check_trace_content -t 5 -p $pid $TRACE_PATH 2>/dev/null + + destroy_lttng_session_ok $SESSION_NAME + + rm -rf $TRACE_PATH +} + +function test_pselect_invalid_ptr() +{ + TRACE_PATH=$(mktemp -d) + SESSION_NAME="syscall_payload" + SYSCALL_LIST="pselect6" + + diag "pselect with invalid pointer, waits for input" + + create_lttng_session_ok $SESSION_NAME $TRACE_PATH + + lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST + add_context_kernel_ok $SESSION_NAME channel0 pid + + start_lttng_tracing_ok + { out=$(yes | $CURDIR/select_poll_epoll -t 6); } 2>/dev/null + stop_lttng_tracing_ok + pid=$(echo $out | cut -d' ' -f1) + + validate_trace "$SYSCALL_LIST" $TRACE_PATH + check_trace_content -t 6 -p $pid $TRACE_PATH 2>/dev/null + + destroy_lttng_session_ok $SESSION_NAME + + rm -rf $TRACE_PATH +} + +function test_ppoll_ulong_max() +{ + TRACE_PATH=$(mktemp -d) + SESSION_NAME="syscall_payload" + SYSCALL_LIST="ppoll" + + diag "ppoll with ulong_max fds, waits for input" + + create_lttng_session_ok $SESSION_NAME $TRACE_PATH + + lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST + add_context_kernel_ok $SESSION_NAME channel0 pid + + start_lttng_tracing_ok + { out=$(yes | $CURDIR/select_poll_epoll -t 7); } 2>/dev/null + stop_lttng_tracing_ok + pid=$(echo $out | cut -d' ' -f1) + + validate_trace "$SYSCALL_LIST" $TRACE_PATH + check_trace_content -t 7 -p $pid $TRACE_PATH 2>/dev/null + + destroy_lttng_session_ok $SESSION_NAME + + rm -rf $TRACE_PATH +} + +function test_epoll_pwait_invalid_ptr() +{ + TRACE_PATH=$(mktemp -d) + SESSION_NAME="syscall_payload" + SYSCALL_LIST="epoll_pwait" + + diag "epoll_pwait with invalid pointer, waits for input" + + create_lttng_session_ok $SESSION_NAME $TRACE_PATH + + lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST + add_context_kernel_ok $SESSION_NAME channel0 pid + + start_lttng_tracing_ok + { out=$(yes | $CURDIR/select_poll_epoll -t 8); } 2>/dev/null + stop_lttng_tracing_ok + pid=$(echo $out | cut -d' ' -f1) + + validate_trace "$SYSCALL_LIST" $TRACE_PATH + check_trace_content -t 8 -p $pid $TRACE_PATH 2>/dev/null + + destroy_lttng_session_ok $SESSION_NAME + + rm -rf $TRACE_PATH +} + +function test_epoll_pwait_int_max() +{ + TRACE_PATH=$(mktemp -d) + SESSION_NAME="syscall_payload" + SYSCALL_LIST="epoll_pwait" + + diag "epoll_pwait with maxevents set to INT_MAX, waits for input" + + create_lttng_session_ok $SESSION_NAME $TRACE_PATH + + lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST + add_context_kernel_ok $SESSION_NAME channel0 pid + + start_lttng_tracing_ok + { out=$(yes | $CURDIR/select_poll_epoll -t 9); } 2>/dev/null + stop_lttng_tracing_ok + pid=$(echo $out | cut -d' ' -f1) + + validate_trace "$SYSCALL_LIST" $TRACE_PATH + check_trace_content -t 9 -p $pid $TRACE_PATH 2>/dev/null + + destroy_lttng_session_ok $SESSION_NAME + + rm -rf $TRACE_PATH +} + +function test_ppoll_concurrent() +{ + TRACE_PATH=$(mktemp -d) + SESSION_NAME="syscall_payload" + SYSCALL_LIST="ppoll" + + diag "ppoll with concurrent updates of the structure from user-space, stress test (3000 iterations), waits for input + timeout 1ms" + + create_lttng_session_ok $SESSION_NAME $TRACE_PATH + + lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST + add_context_kernel_ok $SESSION_NAME channel0 pid + + start_lttng_tracing_ok + { out=$(yes | $CURDIR/select_poll_epoll -t 10); } 2>/dev/null + stop_lttng_tracing_ok + pid=$(echo $out | cut -d' ' -f1) + + validate_trace "$SYSCALL_LIST" $TRACE_PATH + check_trace_content -t 10 -p $pid $TRACE_PATH 2>/dev/null + + destroy_lttng_session_ok $SESSION_NAME + + rm -rf $TRACE_PATH +} + +function test_epoll_pwait_concurrent() +{ + TRACE_PATH=$(mktemp -d) + SESSION_NAME="syscall_payload" + SYSCALL_LIST="epoll_ctl,epoll_pwait" + + diag "epoll_pwait with concurrent munmap of the buffer from user-space, should randomly segfault, run multiple times, waits for input + timeout 1ms" + + create_lttng_session_ok $SESSION_NAME $TRACE_PATH + + lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST + add_context_kernel_ok $SESSION_NAME channel0 pid + + start_lttng_tracing_ok + diag "Expect segfaults" + for i in $(seq 1 100); do + { out=$($CURDIR/select_poll_epoll -t 11); } 2>/dev/null + done + pid=$(echo $out | cut -d' ' -f1) + stop_lttng_tracing_ok + + # epoll_wait is not always generated in the trace (stress test) + validate_trace "epoll_ctl" $TRACE_PATH + check_trace_content -t 11 -p $pid $TRACE_PATH 2>/dev/null + + destroy_lttng_session_ok $SESSION_NAME + + rm -rf $TRACE_PATH +} + +# MUST set TESTDIR before calling those functions +plan_tests $NUM_TESTS + +print_test_banner "$TEST_DESC" + +if [ "$(id -u)" == "0" ]; then + isroot=1 +else + isroot=0 +fi + +skip $isroot "Root access is needed. Skipping all tests." $NUM_TESTS || +{ + start_lttng_sessiond + + test_working_cases + test_timeout_cases + test_big_pselect + test_big_ppoll + test_ppoll_overflow + test_pselect_invalid_ptr + test_ppoll_ulong_max + test_epoll_pwait_invalid_ptr + test_epoll_pwait_int_max + test_ppoll_concurrent + test_epoll_pwait_concurrent + + stop_lttng_sessiond + + NEW_WARNING=$(dmesg | grep " WARNING:" | cut -d' ' -f1 | tail -1) + NEW_OOPS=$(dmesg | grep " OOPS:" | cut -d' ' -f1 | tail -1) + NEW_BUG=$(dmesg | grep " BUG:" | cut -d' ' -f1 | tail -1) + + if test "$LAST_WARNING" != "$NEW_WARNING"; then + fail "New WARNING generated" + fi + if test "$LAST_OOPS" != "$NEW_OOPS"; then + fail "New OOPS generated" + fi + if test "$LAST_BUG" != "$NEW_BUG"; then + fail "New BUG generated" + fi +}tests/regression/kernel/validate_select_poll_epoll.py new file +39
-0@@ -0,0 +1,783 @@ +#!/usr/bin/env python3 + +import sys +import time +import argparse + +NSEC_PER_SEC = 1000000000 + +try: + from babeltrace import TraceCollection +except ImportError: + # quick fix for debian-based distros + sys.path.append("/usr/local/lib/python%d.%d/site-packages" % + (sys.version_info.major, sys.version_info.minor)) + from babeltrace import TraceCollection + + +class TraceParser: + def __init__(self, trace, pid): + self.trace = trace + self.pid = pid + self.expect = {} + + def ns_to_hour_nsec(self, ns): + d = time.localtime(ns/NSEC_PER_SEC) + return "%02d:%02d:%02d.%09d" % (d.tm_hour, d.tm_min, d.tm_sec, + ns % NSEC_PER_SEC) + + def parse(self): + # iterate over all the events + for event in self.trace.events: + if self.pid is not None and event["pid"] != self.pid: + continue + + method_name = "handle_%s" % event.name.replace(":", "_").replace("+", "_") + # call the function to handle each event individually + if hasattr(TraceParser, method_name): + func = getattr(TraceParser, method_name) + func(self, event)
tests/regression/kernel/validate_select_poll_epoll.py line 49
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ + ret = 0 + for i in self.expect.keys(): + if self.expect[i] == 0: + print("%s not validated" % i) + ret = 1 + + return ret + + ### epoll_ctl
Use a single '#' for comments.
Quoted 9 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +9
-0+ def handle_compat_syscall_entry_epoll_ctl(self, event): + self.epoll_ctl_entry(event) + + def handle_compat_syscall_exit_epoll_ctl(self, event): + self.epoll_ctl_exit(event) + + def handle_syscall_entry_epoll_ctl(self, event): + self.epoll_ctl_entry(event) +
tests/regression/kernel/validate_select_poll_epoll.py line 68
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ def handle_syscall_exit_epoll_ctl(self, event): + self.epoll_ctl_exit(event) + + def epoll_ctl_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + epfd = event["epfd"] + op_enum = event["op_enum"] + fd = event["fd"] + _event = event["event"]
This method seems to have no side effect. Am I missing something?
If this is done to provide a default implementation of the method, replace by "pass".
tests/regression/kernel/validate_select_poll_epoll.py line 73
Quoted 5 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +5
-0+ + def epoll_ctl_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"]
Same here.
tests/regression/kernel/validate_select_poll_epoll.py line 75
Quoted 2 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +2
-0+ + ### epoll_wait + epoll_pwait
Use a single '#' for comments.
Quoted 20 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +20
-0+ def handle_compat_syscall_entry_epoll_wait(self, event): + self.epoll_wait_entry(event) + + def handle_compat_syscall_exit_epoll_wait(self, event): + self.epoll_wait_exit(event) + + def handle_syscall_entry_epoll_wait(self, event): + self.epoll_wait_entry(event) + + def handle_syscall_exit_epoll_wait(self, event): + self.epoll_wait_exit(event) + + def handle_compat_syscall_entry_epoll_pwait(self, event): + self.epoll_wait_entry(event) + + def handle_compat_syscall_exit_epoll_pwait(self, event): + self.epoll_wait_exit(event) + + def handle_syscall_entry_epoll_pwait(self, event): + self.epoll_wait_entry(event)
tests/regression/kernel/validate_select_poll_epoll.py line 105
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ + def handle_syscall_exit_epoll_pwait(self, event): + self.epoll_wait_exit(event) + + def epoll_wait_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + epfd = event["epfd"] + maxevents = event["maxevents"] + timeout = event["timeout"]
No side effect?
tests/regression/kernel/validate_select_poll_epoll.py line 113
Quoted 8 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +8
-0+ + def epoll_wait_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"]
Same.
tests/regression/kernel/validate_select_poll_epoll.py line 115
Quoted 2 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +2
-0+ + #### poll + ppoll
Use a single '#' for comments.
Quoted 21 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +21
-0+ def handle_compat_syscall_entry_poll(self, event): + self.poll_entry(event) + + def handle_compat_syscall_exit_poll(self, event): + self.poll_exit(event) + + def handle_syscall_entry_poll(self, event): + self.poll_entry(event) + + def handle_syscall_exit_poll(self, event): + self.poll_exit(event) + + def handle_compat_syscall_entry_ppoll(self, event): + self.poll_entry(event) + + def handle_compat_syscall_exit_ppoll(self, event): + self.poll_exit(event) + + def handle_syscall_entry_ppoll(self, event): + self.poll_entry(event) +
tests/regression/kernel/validate_select_poll_epoll.py line 146
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ def handle_syscall_exit_ppoll(self, event): + self.poll_exit(event) + + def poll_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + nfds = event["nfds"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"]
No side effect?
tests/regression/kernel/validate_select_poll_epoll.py line 154
Quoted 8 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +8
-0+ + def poll_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + nfds = event["nfds"] + fds_length = event["fds_length"] + fds = event["fds"]
No side effect?
tests/regression/kernel/validate_select_poll_epoll.py line 156
Quoted 2 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +2
-0+ + ### epoll_create
Use a single '#' for comments.
Quoted 31 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +31
-0+ def handle_compat_syscall_entry_epoll_create1(self, event): + self.epoll_create_entry(event) + + def handle_compat_syscall_exit_epoll_create1(self, event): + self.epoll_create_exit(event) + + def handle_compat_syscall_entry_epoll_create(self, event): + self.epoll_create_entry(event) + + def handle_compat_syscall_exit_epoll_create(self, event): + self.epoll_create_exit(event) + + def handle_syscall_entry_epoll_create1(self, event): + self.epoll_create_entry(event) + + def handle_syscall_exit_epoll_create1(self, event): + self.epoll_create_exit(event) + + def handle_syscall_entry_epoll_create(self, event): + self.epoll_create_entry(event) + + def handle_syscall_exit_epoll_create(self, event): + self.epoll_create_exit(event) + + def handle_compat_syscall_entry_epoll_create1(self, event): + self.epoll_create_entry(event) + + def handle_compat_syscall_exit_epoll_create(self, event): + self.epoll_create_exit(event) + + def epoll_create_entry(self, event):
tests/regression/kernel/validate_select_poll_epoll.py line 197
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ timestamp = event.timestamp + cpu_id = event["cpu_id"] + flags = event["flags"] + + def epoll_create_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + + ### select + pselect6
Use a single '#' for comments.
Quoted 26 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +26
-0+ def handle_syscall_entry_pselect6(self, event): + self.select_entry(event) + + def handle_syscall_exit_pselect6(self, event): + self.select_exit(event) + + def handle_compat_syscall_entry_pselect6(self, event): + self.select_entry(event) + + def handle_compat_syscall_exit_pselect6(self, event): + self.select_exit(event) + + def handle_syscall_entry_select(self, event): + self.select_entry(event) + + def handle_syscall_exit_select(self, event): + self.select_exit(event) + + def handle_compat_syscall_entry_select(self, event): + self.select_entry(event) + + def handle_compat_syscall_exit_select(self, event): + self.select_exit(event) + + def select_entry(self, event): + timestamp = event.timestamp
tests/regression/kernel/validate_select_poll_epoll.py line 233
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ cpu_id = event["cpu_id"] + n = event["n"] + overflow = event["overflow"] + tvp = event["tvp"] + _readfds_length = event["_readfds_length"] + readfds = event["readfds"] + _writefds_length = event["_writefds_length"] + writefds = event["writefds"] + _exceptfds_length = event["_exceptfds_length"] + exceptfds = event["exceptfds"]
No side effect?
tests/regression/kernel/validate_select_poll_epoll.py line 246
Quoted 13 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +13
-0+ + def select_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + overflow = event["overflow"] + tvp = event["tvp"] + _readfds_length = event["_readfds_length"] + readfds = event["readfds"] + _writefds_length = event["_writefds_length"] + writefds = event["writefds"] + _exceptfds_length = event["_exceptfds_length"] + exceptfds = event["exceptfds"]
No side effect?
Quoted 45 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +45
-0+ + +class Test1(TraceParser): + def __init__(self, trace, pid): + super().__init__(trace, pid) + self.expect["select_in_fd0"] = 0 + self.expect["select_in_fd1023"] = 0 + self.expect["select_out_fd0"] = 0 + self.expect["select_out_fd1023"] = 0 + self.expect["poll_in_nfds1"] = 0 + self.expect["poll_out_nfds1"] = 0 + self.expect["epoll_ctl_in_add"] = 0 + self.expect["epoll_ctl_out_ok"] = 0 + self.expect["epoll_wait_in_ok"] = 0 + self.expect["epoll_wait_out_fd0"] = 0 + + def select_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + n = event["n"] + overflow = event["overflow"] + tvp = event["tvp"] + _readfds_length = event["_readfds_length"] + readfds = event["readfds"] + _writefds_length = event["_writefds_length"] + writefds = event["writefds"] + _exceptfds_length = event["_exceptfds_length"] + exceptfds = event["exceptfds"] + + if n == 1 and readfds[0] == 1: + self.expect["select_in_fd0"] = 1 + if n == 1023: + if readfds[127] == 0x40 and writefds[127] == 0 and \ + exceptfds[127] == 0 and overflow == 0: + self.expect["select_in_fd1023"] = 1 + + def select_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + overflow = event["overflow"] + tvp = event["tvp"] + _readfds_length = event["_readfds_length"] + readfds = event["readfds"] + _writefds_length = event["_writefds_length"]
tests/regression/kernel/validate_select_poll_epoll.py line 301
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ writefds = event["writefds"] + _exceptfds_length = event["_exceptfds_length"] + exceptfds = event["exceptfds"] + + if ret == 1: + if readfds[0] == 1: + self.expect["select_out_fd0"] = 1 + if _readfds_length == 128 and readfds[127] == 0x40 and \ + writefds[127] == 0 and exceptfds[127] == 0 and tvp == 0: + self.expect["select_out_fd1023"] = 1
Please add comments to explain what is being checked in the various test methods.
Quoted 50 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +50
-0+ + def poll_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + nfds = event["nfds"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"] + + if nfds == 1 and fds_length == 1 and fds[0]["raw_events"] == 0x3 \ + and fds[0]["events"]["POLLIN"] == 1 and \ + fds[0]["events"]["padding"] == 0: + self.expect["poll_in_nfds1"] = 1 + + def poll_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + nfds = event["nfds"] + fds_length = event["fds_length"] + fds = event["fds"] + + if ret == 1 and fds_length == 1 and fds[0]["raw_events"] == 0x1 \ + and fds[0]["events"]["POLLIN"] == 1 and \ + fds[0]["events"]["padding"] == 0: + self.expect["poll_out_nfds1"] = 1 + + def epoll_ctl_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + epfd = event["epfd"] + op_enum = event["op_enum"] + fd = event["fd"] + _event = event["event"] + + if epfd == 3 and op_enum == "EPOLL_CTL_ADD" and fd == 0 and \ + _event["data_union"]["fd"] == 0 and \ + _event["events"]["EPOLLIN"] == 1 and \ + _event["events"]["EPOLLPRI"] == 1: + self.expect["epoll_ctl_in_add"] = 1 + + def epoll_ctl_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + + if ret == 0: + self.expect["epoll_ctl_out_ok"] = 1 + + def epoll_wait_entry(self, event):
tests/regression/kernel/validate_select_poll_epoll.py line 361
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ timestamp = event.timestamp + cpu_id = event["cpu_id"] + epfd = event["epfd"] + maxevents = event["maxevents"] + timeout = event["timeout"] + + if epfd == 3 and maxevents == 1 and timeout == -1: + self.expect["epoll_wait_in_ok"] = 1 + +
Remove extra blank line.
Quoted 35 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +35
-0+ def epoll_wait_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"] + + if ret == 1 and fds_length == 1 and overflow == 0 and \ + fds[0]["data_union"]["fd"] == 0 and \ + fds[0]["events"]["EPOLLIN"] == 1: + self.expect["epoll_wait_out_fd0"] = 1 + + +class Test2(TraceParser): + def __init__(self, trace, pid): + super().__init__(trace, pid) + self.expect["select_timeout_in_fd0"] = 0 + self.expect["select_timeout_in_fd1023"] = 0 + self.expect["select_timeout_out"] = 0 + self.expect["poll_timeout_in"] = 0 + self.expect["poll_timeout_out"] = 0 + self.expect["epoll_ctl_timeout_in_add"] = 0 + self.expect["epoll_ctl_timeout_out_ok"] = 0 + self.expect["epoll_wait_timeout_in"] = 0 + self.expect["epoll_wait_timeout_out"] = 0 + + def select_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + n = event["n"] + overflow = event["overflow"] + tvp = event["tvp"] + _readfds_length = event["_readfds_length"] + readfds = event["readfds"]
tests/regression/kernel/validate_select_poll_epoll.py line 406
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ _writefds_length = event["_writefds_length"] + writefds = event["writefds"] + _exceptfds_length = event["_exceptfds_length"] + exceptfds = event["exceptfds"] + + if n == 1 and tvp != 0: + self.expect["select_timeout_in_fd0"] = 1 + if n == 1023: + if readfds[127] == 0x40 and writefds[127] == 0 and \ + exceptfds[127] == 0 and tvp != 0:
Indent ^ by one more level.
Quoted 64 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +64
-0+ self.expect["select_timeout_in_fd1023"] = 1 + + def select_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + overflow = event["overflow"] + tvp = event["tvp"] + _readfds_length = event["_readfds_length"] + readfds = event["readfds"] + _writefds_length = event["_writefds_length"] + writefds = event["writefds"] + _exceptfds_length = event["_exceptfds_length"] + exceptfds = event["exceptfds"] + + if ret == 0 and tvp != 0: + self.expect["select_timeout_out"] = 1 + + def poll_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + nfds = event["nfds"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"] + + if nfds == 1 and fds_length == 1 and fds[0]["raw_events"] == 0x3 \ + and fds[0]["events"]["POLLIN"] == 1 and \ + fds[0]["events"]["padding"] == 0: + self.expect["poll_timeout_in"] = 1 + + def poll_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + nfds = event["nfds"] + fds_length = event["fds_length"] + fds = event["fds"] + + if ret == 0 and nfds == 1 and fds_length == 0: + self.expect["poll_timeout_out"] = 1 + + def epoll_ctl_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + epfd = event["epfd"] + op_enum = event["op_enum"] + fd = event["fd"] + _event = event["event"] + + if op_enum == "EPOLL_CTL_ADD" and \ + _event["events"]["EPOLLIN"] == 1 and \ + _event["events"]["EPOLLPRI"] == 1: + self.expect["epoll_ctl_timeout_in_add"] = 1 + + def epoll_ctl_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + + if ret == 0: + self.expect["epoll_ctl_timeout_out_ok"] = 1 + + def epoll_wait_entry(self, event):
tests/regression/kernel/validate_select_poll_epoll.py line 480
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ timestamp = event.timestamp + cpu_id = event["cpu_id"] + epfd = event["epfd"] + maxevents = event["maxevents"] + timeout = event["timeout"] + + if maxevents == 1 and timeout == 1: + self.expect["epoll_wait_timeout_in"] = 1 + +
Remove extra blank line.
Quoted 75 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +75
-0+ def epoll_wait_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"] + + if ret == 0 and fds_length == 0 and overflow == 0: + self.expect["epoll_wait_timeout_out"] = 1 + + +class Test3(TraceParser): + def __init__(self, trace, pid): + super().__init__(trace, pid) + self.expect["select_too_big_in"] = 0 + self.expect["select_too_big_out"] = 0 + + def select_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + n = event["n"] + overflow = event["overflow"] + tvp = event["tvp"] + _readfds_length = event["_readfds_length"] + readfds = event["readfds"] + _writefds_length = event["_writefds_length"] + writefds = event["writefds"] + _exceptfds_length = event["_exceptfds_length"] + exceptfds = event["exceptfds"] + + if n == 2048 and overflow == 0 and _readfds_length == 0: + self.expect["select_too_big_in"] = 1 + + def select_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + overflow = event["overflow"] + tvp = event["tvp"] + _readfds_length = event["_readfds_length"] + readfds = event["readfds"] + _writefds_length = event["_writefds_length"] + writefds = event["writefds"] + _exceptfds_length = event["_exceptfds_length"] + exceptfds = event["exceptfds"] + + if ret == -9 and overflow == 0 and _readfds_length == 0: + self.expect["select_too_big_out"] = 1 + + +class Test4(TraceParser): + def __init__(self, trace, pid): + super().__init__(trace, pid) + self.expect["big_poll_in"] = 0 + self.expect["big_poll_out"] = 0 + + def poll_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + nfds = event["nfds"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"] + + if nfds == 2047 and fds_length == 512 and overflow == 1 and \ + fds[0]["raw_events"] == 0x3 \ + and fds[0]["events"]["POLLIN"] == 1 and \ + fds[0]["events"]["padding"] == 0 and \ + fds[511]["events"]["POLLIN"] == 1 and \ + fds[511]["events"]["POLLPRI"] == 1: + self.expect["big_poll_in"] = 1 + + def poll_exit(self, event): + timestamp = event.timestamp
tests/regression/kernel/validate_select_poll_epoll.py line 565
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ cpu_id = event["cpu_id"] + ret = event["ret"] + nfds = event["nfds"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"] + + if ret == 2047 and nfds == 2047 and fds_length == 512 and \ + overflow == 1 and fds[0]["events"]["POLLIN"] == 1 and \ + fds[511]["events"]["POLLIN"] == 1:
^ Indent by one more level.
Quoted 110 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +110
-0+ self.expect["big_poll_out"] = 1 + + +class Test5(TraceParser): + def __init__(self, trace, pid): + super().__init__(trace, pid) + self.expect["poll_overflow_in"] = 0 + self.expect["poll_overflow_out"] = 0 + + def poll_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + nfds = event["nfds"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"] + + if nfds == 100 and fds_length == 100 and overflow == 0 and \ + fds[0]["events"]["POLLIN"] == 1: + self.expect["poll_overflow_in"] = 1 + + def poll_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + nfds = event["nfds"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"] + + if nfds == 100 and overflow == 0: + self.expect["poll_overflow_out"] = 1 + + +class Test6(TraceParser): + def __init__(self, trace, pid): + super().__init__(trace, pid) + self.expect["pselect_invalid_in"] = 0 + self.expect["pselect_invalid_out"] = 0 + + def select_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + n = event["n"] + overflow = event["overflow"] + tvp = event["tvp"] + _readfds_length = event["_readfds_length"] + readfds = event["readfds"] + _writefds_length = event["_writefds_length"] + writefds = event["writefds"] + _exceptfds_length = event["_exceptfds_length"] + exceptfds = event["exceptfds"] + + if n == 1 and overflow == 0 and _readfds_length == 0: + self.expect["pselect_invalid_in"] = 1 + + def select_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + overflow = event["overflow"] + tvp = event["tvp"] + _readfds_length = event["_readfds_length"] + readfds = event["readfds"] + _writefds_length = event["_writefds_length"] + writefds = event["writefds"] + _exceptfds_length = event["_exceptfds_length"] + exceptfds = event["exceptfds"] + + if ret == -14 and overflow == 0 and _readfds_length == 0: + self.expect["pselect_invalid_out"] = 1 + + +class Test7(TraceParser): + def __init__(self, trace, pid): + super().__init__(trace, pid) + self.expect["poll_max_in"] = 0 + self.expect["poll_max_out"] = 0 + + def poll_entry(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + nfds = event["nfds"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"] + + if nfds == 4294967295 and overflow == 1: + self.expect["poll_max_in"] = 1 + + def poll_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + nfds = event["nfds"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"] + + if ret == -22 and nfds == 4294967295 and overflow == 0: + self.expect["poll_max_out"] = 1 + + +class Test8(TraceParser): + def __init__(self, trace, pid): + super().__init__(trace, pid) + self.expect["epoll_wait_invalid_in"] = 0 + self.expect["epoll_wait_invalid_out"] = 0 + + def epoll_wait_entry(self, event):
tests/regression/kernel/validate_select_poll_epoll.py line 685
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ timestamp = event.timestamp + cpu_id = event["cpu_id"] + epfd = event["epfd"] + maxevents = event["maxevents"] + timeout = event["timeout"] + + if epfd == 3 and maxevents == 1 and timeout == -1: + self.expect["epoll_wait_invalid_in"] = 1 + +
Remove extra blank line.
Quoted 19 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +19
-0+ def epoll_wait_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"] + + if ret == -14 and fds_length == 0 and overflow == 0: + self.expect["epoll_wait_invalid_out"] = 1 + + +class Test9(TraceParser): + def __init__(self, trace, pid): + super().__init__(trace, pid) + self.expect["epoll_wait_max_in"] = 0 + self.expect["epoll_wait_max_out"] = 0 + + def epoll_wait_entry(self, event):
tests/regression/kernel/validate_select_poll_epoll.py line 714
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ timestamp = event.timestamp + cpu_id = event["cpu_id"] + epfd = event["epfd"] + maxevents = event["maxevents"] + timeout = event["timeout"] + + if epfd == 3 and maxevents == 2147483647 and timeout == -1: + self.expect["epoll_wait_max_in"] = 1 + +
Remove extra blank line.
Quoted 22 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +22
-0+ def epoll_wait_exit(self, event): + timestamp = event.timestamp + cpu_id = event["cpu_id"] + ret = event["ret"] + fds_length = event["fds_length"] + overflow = event["overflow"] + fds = event["fds"] + + if ret == -22 and fds_length == 0 and overflow == 0: + self.expect["epoll_wait_max_out"] = 1 + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Trace parser') + parser.add_argument('path', metavar="<path/to/trace>", help='Trace path') + parser.add_argument('-t', '--test', type=int, help='Test to validate') + parser.add_argument('-p', '--pid', type=int, help='PID of the app') + args = parser.parse_args() + + if not args.test: + print("Need to pass a test to validate (-t)") + sys.exit(1)
tests/regression/kernel/validate_select_poll_epoll.py line 746
Quoted 10 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +10
-0+ + if not args.pid: + print("Need to pass the PID to check (-p)") + sys.exit(1) + + traces = TraceCollection() + handle = traces.add_traces_recursive(args.path, "ctf") + if handle is None: + sys.exit(1) +
Remove tab here ^
Quoted 56 lines
tests/regression/kernel/validate_select_poll_epoll.py new file +37
-0+ t = None + + if args.test == 1: + t = Test1(traces, args.pid) + elif args.test == 2: + t = Test2(traces, args.pid) + elif args.test == 3: + t = Test3(traces, args.pid) + elif args.test == 4: + t = Test4(traces, args.pid) + elif args.test == 5: + t = Test5(traces, args.pid) + elif args.test == 6: + t = Test6(traces, args.pid) + elif args.test == 7: + t = Test7(traces, args.pid) + elif args.test == 8: + t = Test8(traces, args.pid) + elif args.test == 9: + t = Test9(traces, args.pid) + elif args.test == 10: + # stress test, nothing reliable to check + ret = 0 + elif args.test == 11: + # stress test, nothing reliable to check + ret = 0 + else: + print("Invalid test case") + sys.exit(1) + + if t is not None: + ret = t.parse() + + for h in handle.values(): + traces.remove_trace(h) + + sys.exit(ret)tests/root_regression +1
-1@@ -1,6 +1,7 @@ regression/kernel/test_all_events regression/kernel/test_event_basic regression/kernel/test_syscall +regression/kernel/test_select_poll_epoll regression/tools/live/test_kernel regression/tools/live/test_lttng_kernel regression/tools/streaming/test_high_throughput_limits --1.9.1
_______________________________________________
lttng-dev mailing list
[email protected]
https://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
Signature · 7 lines
Jérémie Galarneau EfficiOS Inc. http://www.efficios.com _______________________________________________ lttng-dev mailing list [email protected] https://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev