diff options
author | Lokesh Gidra <lokeshgidra@google.com> | 2021-06-17 17:22:07 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-06-17 17:22:07 +0000 |
commit | 7df967e36f4fc86b8feec28ce37bd2c28d38c79f (patch) | |
tree | 097b765ce718eb915f22809be893413ab2eb9965 | |
parent | 34dab569465f0528f8f8f2756fec2badc0233d0e (diff) | |
parent | 599ed29be16f2612c1ca1bc2cab1b95e1ae0e6f7 (diff) | |
download | linux-kselftest-7df967e36f4fc86b8feec28ce37bd2c28d38c79f.tar.gz |
Enable userfaultfd selftest am: 599ed29be1android-s-beta-4android-s-beta-3android-s-beta-4
Original change: https://android-review.googlesource.com/c/platform/external/linux-kselftest/+/1723330
Change-Id: I0e98cddb403eea353d6400d7544f29d9c727c1df
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | android/README.md | 3 | ||||
-rw-r--r-- | android/kselftest_test_list.mk | 1 | ||||
-rw-r--r-- | android/patches/0019-userfaultfd.patch | 172 | ||||
-rw-r--r-- | tools/testing/selftests/vm/userfaultfd.c | 70 |
5 files changed, 220 insertions, 27 deletions
diff --git a/Android.bp b/Android.bp index e56904c3722e..43ec24a18293 100644 --- a/Android.bp +++ b/Android.bp @@ -575,6 +575,7 @@ cc_test { "tools/testing/selftests/vm/mlock-random-test.c", "tools/testing/selftests/vm/mlock2-tests.c", "tools/testing/selftests/vm/on-fault-limit.c", + "tools/testing/selftests/vm/userfaultfd.c", "tools/testing/selftests/vm/thuge-gen.c", "tools/testing/selftests/vm/transhuge-stress.c", ], diff --git a/android/README.md b/android/README.md index 2c94e05b4cdf..7a12a1d3aa21 100644 --- a/android/README.md +++ b/android/README.md @@ -334,9 +334,6 @@ kernel module is not required by Android. The hugepage-mmap, hugepage-shm, compaction, and map_hugetlb tests rely on hugetlbfs/hugetlb page support which is not required by Android. -The userfaultfd test relies on the userfaultfd syscall which is not required by -Android. - ### watchdog/ The watchdog test depends on CONFIG_WATCHDOG which is not required by Android. diff --git a/android/kselftest_test_list.mk b/android/kselftest_test_list.mk index 5445bd12d26f..dc65a47250c3 100644 --- a/android/kselftest_test_list.mk +++ b/android/kselftest_test_list.mk @@ -52,6 +52,7 @@ kselftest_modules += \ kselftest_vdso_test \ kselftest_vm_tests_mlock2-tests \ kselftest_vm_tests_on-fault-limit \ + kselftest_vm_tests_userfaultfd \ kselftest_vm64_tests_virtual_address_range \ kselftest_x86_ptrace_syscall \ kselftest_x86_check_initial_reg_state \ diff --git a/android/patches/0019-userfaultfd.patch b/android/patches/0019-userfaultfd.patch new file mode 100644 index 000000000000..b0cc72bb01e6 --- /dev/null +++ b/android/patches/0019-userfaultfd.patch @@ -0,0 +1,172 @@ +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(); + } + 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(); } |