aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLokesh Gidra <lokeshgidra@google.com>2021-06-17 17:22:07 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-06-17 17:22:07 +0000
commit7df967e36f4fc86b8feec28ce37bd2c28d38c79f (patch)
tree097b765ce718eb915f22809be893413ab2eb9965
parent34dab569465f0528f8f8f2756fec2badc0233d0e (diff)
parent599ed29be16f2612c1ca1bc2cab1b95e1ae0e6f7 (diff)
downloadlinux-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.bp1
-rw-r--r--android/README.md3
-rw-r--r--android/kselftest_test_list.mk1
-rw-r--r--android/patches/0019-userfaultfd.patch172
-rw-r--r--tools/testing/selftests/vm/userfaultfd.c70
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();
}