blob: b0cc72bb01e64ce35f4e0365f8d6bead7a34916f [file] [log] [blame]
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();
}