| diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c |
| index d3362777a425..d8119de2a342 100644 |
| --- a/tools/testing/selftests/vm/userfaultfd.c |
| +++ b/tools/testing/selftests/vm/userfaultfd.c |
| @@ -85,6 +85,7 @@ static int uffd, uffd_flags, finished, *pipefd; |
| static char *area_src, *area_src_alias, *area_dst, *area_dst_alias; |
| static char *zeropage; |
| pthread_attr_t attr; |
| +pthread_key_t long_jmp_key; |
| |
| /* pthread_mutex_t starts at page offset 0 */ |
| #define area_mutex(___area, ___nr) \ |
| @@ -284,23 +285,11 @@ static int my_bcmp(char *str1, char *str2, size_t n) |
| static void *locking_thread(void *arg) |
| { |
| unsigned long cpu = (unsigned long) arg; |
| - struct random_data rand; |
| unsigned long page_nr = *(&(page_nr)); /* uninitialized warning */ |
| - int32_t rand_nr; |
| unsigned long long count; |
| - char randstate[64]; |
| - unsigned int seed; |
| time_t start; |
| |
| - if (bounces & BOUNCE_RANDOM) { |
| - seed = (unsigned int) time(NULL) - bounces; |
| - if (!(bounces & BOUNCE_RACINGFAULTS)) |
| - seed += cpu; |
| - bzero(&rand, sizeof(rand)); |
| - bzero(&randstate, sizeof(randstate)); |
| - if (initstate_r(seed, randstate, sizeof(randstate), &rand)) |
| - fprintf(stderr, "srandom_r error\n"), exit(1); |
| - } else { |
| + if (!(bounces & BOUNCE_RANDOM)) { |
| page_nr = -bounces; |
| if (!(bounces & BOUNCE_RACINGFAULTS)) |
| page_nr += cpu * nr_pages_per_cpu; |
| @@ -308,13 +297,9 @@ static void *locking_thread(void *arg) |
| |
| while (!finished) { |
| if (bounces & BOUNCE_RANDOM) { |
| - if (random_r(&rand, &rand_nr)) |
| - fprintf(stderr, "random_r 1 error\n"), exit(1); |
| - page_nr = rand_nr; |
| - if (sizeof(page_nr) > sizeof(rand_nr)) { |
| - if (random_r(&rand, &rand_nr)) |
| - fprintf(stderr, "random_r 2 error\n"), exit(1); |
| - page_nr |= (((unsigned long) rand_nr) << 16) << |
| + page_nr = random(); |
| + if (sizeof(page_nr) > sizeof(uint32_t)) { |
| + page_nr |= (((unsigned long) random()) << 16) << |
| 16; |
| } |
| } else |
| @@ -548,18 +533,31 @@ static void *uffd_poll_thread(void *arg) |
| |
| pthread_mutex_t uffd_read_mutex = PTHREAD_MUTEX_INITIALIZER; |
| |
| +static void sigusr1_handler(int signum, siginfo_t *siginfo, void *ptr) |
| +{ |
| + jmp_buf *env; |
| + env = pthread_getspecific(long_jmp_key); |
| + longjmp(*env, 1); |
| +} |
| + |
| static void *uffd_read_thread(void *arg) |
| { |
| unsigned long *this_cpu_userfaults; |
| struct uffd_msg msg; |
| + jmp_buf env; |
| + int setjmp_ret; |
| + |
| + pthread_setspecific(long_jmp_key, &env); |
| |
| this_cpu_userfaults = (unsigned long *) arg; |
| *this_cpu_userfaults = 0; |
| |
| pthread_mutex_unlock(&uffd_read_mutex); |
| - /* from here cancellation is ok */ |
| |
| - for (;;) { |
| + // One first return setjmp return 0. On second (fake) return from |
| + // longjmp() it returns the provided value, which will be 1 in our case. |
| + setjmp_ret = setjmp(env); |
| + while (!setjmp_ret) { |
| if (uffd_read_msg(uffd, &msg)) |
| continue; |
| (*this_cpu_userfaults) += uffd_handle_page_fault(&msg); |
| @@ -608,6 +606,7 @@ static int stress(unsigned long *userfaults) |
| background_thread, (void *)cpu)) |
| return 1; |
| } |
| + |
| for (cpu = 0; cpu < nr_cpus; cpu++) |
| if (pthread_join(background_threads[cpu], NULL)) |
| return 1; |
| @@ -640,7 +639,7 @@ static int stress(unsigned long *userfaults) |
| if (pthread_join(uffd_threads[cpu], &_userfaults[cpu])) |
| return 1; |
| } else { |
| - if (pthread_cancel(uffd_threads[cpu])) |
| + if (pthread_kill(uffd_threads[cpu], SIGUSR1)) |
| return 1; |
| if (pthread_join(uffd_threads[cpu], NULL)) |
| return 1; |
| @@ -654,7 +653,7 @@ static int userfaultfd_open(int features) |
| { |
| struct uffdio_api uffdio_api; |
| |
| - uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); |
| + uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY); |
| if (uffd < 0) { |
| fprintf(stderr, |
| "userfaultfd syscall not available in this kernel\n"); |
| @@ -1036,6 +1035,7 @@ static int userfaultfd_stress(void) |
| char *tmp_area; |
| unsigned long nr; |
| struct uffdio_register uffdio_register; |
| + struct sigaction act; |
| unsigned long cpu; |
| int err; |
| unsigned long userfaults[nr_cpus]; |
| @@ -1094,6 +1094,17 @@ static int userfaultfd_stress(void) |
| pthread_attr_init(&attr); |
| pthread_attr_setstacksize(&attr, 16*1024*1024); |
| |
| + // For handling thread termination of read thread in the absense of |
| + // pthread_cancel(). |
| + pthread_key_create(&long_jmp_key, NULL); |
| + memset(&act, 0, sizeof(act)); |
| + act.sa_sigaction = sigusr1_handler; |
| + act.sa_flags = SA_SIGINFO; |
| + if (sigaction(SIGUSR1, &act, 0)) { |
| + perror("sigaction"); |
| + return 1; |
| + } |
| + |
| err = 0; |
| while (bounces--) { |
| unsigned long expected_ioctls; |
| @@ -1215,6 +1226,8 @@ static int userfaultfd_stress(void) |
| printf("\n"); |
| } |
| |
| + pthread_key_delete(long_jmp_key); |
| + |
| if (err) |
| return err; |
| |
| @@ -1291,6 +1304,9 @@ static void sigalrm(int sig) |
| |
| int main(int argc, char **argv) |
| { |
| + char randstate[64]; |
| + unsigned int seed; |
| + |
| if (argc < 4) |
| usage(); |
| |
| @@ -1332,6 +1348,12 @@ int main(int argc, char **argv) |
| } |
| printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n", |
| nr_pages, nr_pages_per_cpu); |
| + |
| + seed = (unsigned int) time(NULL); |
| + bzero(&randstate, sizeof(randstate)); |
| + if (!initstate(seed, randstate, sizeof(randstate))) |
| + fprintf(stderr, "srandom_r error\n"), exit(1); |
| + |
| return userfaultfd_stress(); |
| } |
| |