static char *zeropage;
 pthread_attr_t attr;
 
+/* Userfaultfd test statistics */
+struct uffd_stats {
+       int cpu;
+       unsigned long missing_faults;
+};
+
 /* pthread_mutex_t starts at page offset 0 */
 #define area_mutex(___area, ___nr)                                     \
        ((pthread_mutex_t *) ((___area) + (___nr)*page_size))
        exit(1);
 }
 
+static void uffd_stats_reset(struct uffd_stats *uffd_stats,
+                            unsigned long n_cpus)
+{
+       int i;
+
+       for (i = 0; i < n_cpus; i++) {
+               uffd_stats[i].cpu = i;
+               uffd_stats[i].missing_faults = 0;
+       }
+}
+
 static int anon_release_pages(char *rel_area)
 {
        int ret = 0;
        return 0;
 }
 
-/* Return 1 if page fault handled by us; otherwise 0 */
-static int uffd_handle_page_fault(struct uffd_msg *msg)
+static void uffd_handle_page_fault(struct uffd_msg *msg,
+                                  struct uffd_stats *stats)
 {
        unsigned long offset;
 
        offset = (char *)(unsigned long)msg->arg.pagefault.address - area_dst;
        offset &= ~(page_size-1);
 
-       return copy_page(uffd, offset);
+       if (copy_page(uffd, offset))
+               stats->missing_faults++;
 }
 
 static void *uffd_poll_thread(void *arg)
 {
-       unsigned long cpu = (unsigned long) arg;
+       struct uffd_stats *stats = (struct uffd_stats *)arg;
+       unsigned long cpu = stats->cpu;
        struct pollfd pollfd[2];
        struct uffd_msg msg;
        struct uffdio_register uffd_reg;
        int ret;
        char tmp_chr;
-       unsigned long userfaults = 0;
 
        pollfd[0].fd = uffd;
        pollfd[0].events = POLLIN;
                                msg.event), exit(1);
                        break;
                case UFFD_EVENT_PAGEFAULT:
-                       userfaults += uffd_handle_page_fault(&msg);
+                       uffd_handle_page_fault(&msg, stats);
                        break;
                case UFFD_EVENT_FORK:
                        close(uffd);
                        break;
                }
        }
-       return (void *)userfaults;
+
+       return NULL;
 }
 
 pthread_mutex_t uffd_read_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 static void *uffd_read_thread(void *arg)
 {
-       unsigned long *this_cpu_userfaults;
+       struct uffd_stats *stats = (struct uffd_stats *)arg;
        struct uffd_msg msg;
 
-       this_cpu_userfaults = (unsigned long *) arg;
-       *this_cpu_userfaults = 0;
-
        pthread_mutex_unlock(&uffd_read_mutex);
        /* from here cancellation is ok */
 
        for (;;) {
                if (uffd_read_msg(uffd, &msg))
                        continue;
-               (*this_cpu_userfaults) += uffd_handle_page_fault(&msg);
+               uffd_handle_page_fault(&msg, stats);
        }
-       return (void *)NULL;
+
+       return NULL;
 }
 
 static void *background_thread(void *arg)
        return NULL;
 }
 
-static int stress(unsigned long *userfaults)
+static int stress(struct uffd_stats *uffd_stats)
 {
        unsigned long cpu;
        pthread_t locking_threads[nr_cpus];
        pthread_t uffd_threads[nr_cpus];
        pthread_t background_threads[nr_cpus];
-       void **_userfaults = (void **) userfaults;
 
        finished = 0;
        for (cpu = 0; cpu < nr_cpus; cpu++) {
                        return 1;
                if (bounces & BOUNCE_POLL) {
                        if (pthread_create(&uffd_threads[cpu], &attr,
-                                          uffd_poll_thread, (void *)cpu))
+                                          uffd_poll_thread,
+                                          (void *)&uffd_stats[cpu]))
                                return 1;
                } else {
                        if (pthread_create(&uffd_threads[cpu], &attr,
                                           uffd_read_thread,
-                                          &_userfaults[cpu]))
+                                          (void *)&uffd_stats[cpu]))
                                return 1;
                        pthread_mutex_lock(&uffd_read_mutex);
                }
                                fprintf(stderr, "pipefd write error\n");
                                return 1;
                        }
-                       if (pthread_join(uffd_threads[cpu], &_userfaults[cpu]))
+                       if (pthread_join(uffd_threads[cpu],
+                                        (void *)&uffd_stats[cpu]))
                                return 1;
                } else {
                        if (pthread_cancel(uffd_threads[cpu]))
 {
        struct uffdio_register uffdio_register;
        unsigned long expected_ioctls;
-       unsigned long userfaults;
        pthread_t uffd_mon;
        int err, features;
        pid_t pid;
        char c;
+       struct uffd_stats stats = { 0 };
 
        printf("testing events (fork, remap, remove): ");
        fflush(stdout);
                        "unexpected missing ioctl for anon memory\n"),
                        exit(1);
 
-       if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, NULL))
+       if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, &stats))
                perror("uffd_poll_thread create"), exit(1);
 
        pid = fork();
 
        if (write(pipefd[1], &c, sizeof(c)) != sizeof(c))
                perror("pipe write"), exit(1);
-       if (pthread_join(uffd_mon, (void **)&userfaults))
+       if (pthread_join(uffd_mon, NULL))
                return 1;
 
        close(uffd);
-       printf("userfaults: %ld\n", userfaults);
+       printf("userfaults: %ld\n", stats.missing_faults);
 
-       return userfaults != nr_pages;
+       return stats.missing_faults != nr_pages;
 }
 
 static int userfaultfd_sig_test(void)
        int err, features;
        pid_t pid;
        char c;
+       struct uffd_stats stats = { 0 };
 
        printf("testing signal delivery: ");
        fflush(stdout);
        if (uffd_test_ops->release_pages(area_dst))
                return 1;
 
-       if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, NULL))
+       if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, &stats))
                perror("uffd_poll_thread create"), exit(1);
 
        pid = fork();
        close(uffd);
        return userfaults != 0;
 }
+
 static int userfaultfd_stress(void)
 {
        void *area;
        struct uffdio_register uffdio_register;
        unsigned long cpu;
        int err;
-       unsigned long userfaults[nr_cpus];
+       struct uffd_stats uffd_stats[nr_cpus];
 
        uffd_test_ops->allocate_area((void **)&area_src);
        if (!area_src)
                if (uffd_test_ops->release_pages(area_dst))
                        return 1;
 
+               uffd_stats_reset(uffd_stats, nr_cpus);
+
                /* bounce pass */
-               if (stress(userfaults))
+               if (stress(uffd_stats))
                        return 1;
 
                /* unregister */
 
                printf("userfaults:");
                for (cpu = 0; cpu < nr_cpus; cpu++)
-                       printf(" %lu", userfaults[cpu]);
+                       printf(" %lu", uffd_stats[cpu].missing_faults);
                printf("\n");
        }