• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1From 6387912710bf3762635e5bd6ddb4be59f50d9b78 Mon Sep 17 00:00:00 2001
2From: Edward Liaw <edliaw@google.com>
3Date: Wed, 20 Apr 2022 00:29:06 +0000
4Subject: [PATCH 16/24] userfaultfd
5
6Fix ARM related issues in userfaultfd selftest
7
8Following issues were observed while running userfaultfd selftest on ARM
9devices. On x86_64 no issues were detected:
10
111) posix_memalign returned tagged pointer, which isn't handled well by
12the kernel. So replace its use with mmap
132) pthread_create followed by fork caused deadlock in certain cases
14wherein fork required some work to be completed by the created thread.
15Used synchronization to ensure that created thread's start funtion has
16started before invoking fork.
17
18(cherry picked from commit 9b11d1b6ab483cb451b102a30d996dc180330161)
19Bug: 160737021
20Bug: 169683130
21Test: atest vts_linux_kselftest_arm_64
22
23Enable userfaultfd selftest
24
25Now that the userfaultfd feature is enabled in the Android kernel, it
26makes sense to have its selftest enabled in the test infra.
27
28The test source code required the following changes:
291) Use UFFD_USER_MODE_ONLY as unprivileged processes are not allowed
30userfaults from kernel space on Android
312) Use random/initstate instead of random_r/initstate_r as bionic
32doesn't support the latter.
333) Since bionic doesn't have pthread_cancel() implemented, we
34implemented the same functionality using pthread_kill() and longjmp().
35
36(cherry picked from commit 599ed29be16f2612c1ca1bc2cab1b95e1ae0e6f7)
37Bug: 160737021
38Bug: 169683130
39Test: treehugger
40---
41 tools/testing/selftests/vm/userfaultfd.c | 74 ++++++++++++++++++++++--
42 1 file changed, 69 insertions(+), 5 deletions(-)
43
44diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c
45index 3fc1d2ee29485..e7a79f120cbde 100644
46--- a/tools/testing/selftests/vm/userfaultfd.c
47+++ b/tools/testing/selftests/vm/userfaultfd.c
48@@ -93,9 +93,11 @@ static char *huge_fd_off0;
49 static unsigned long long *count_verify;
50 static int uffd = -1;
51 static int uffd_flags, finished, *pipefd;
52+static volatile bool ready_for_fork;
53 static char *area_src, *area_src_alias, *area_dst, *area_dst_alias;
54 static char *zeropage;
55 pthread_attr_t attr;
56+pthread_key_t long_jmp_key;
57
58 /* Userfaultfd test statistics */
59 struct uffd_stats {
60@@ -377,8 +379,13 @@ static void userfaultfd_open(uint64_t *features)
61 	struct uffdio_api uffdio_api;
62
63 	uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY);
64-	if (uffd < 0)
65-		err("userfaultfd syscall not available in this kernel");
66+	if (uffd < 0) {
67+		if (errno == ENOSYS) {
68+			printf("userfaultfd syscall not available in this kernel\n");
69+			exit(KSFT_SKIP);
70+		}
71+		err("userfaultfd syscall failed with errno: %d\n", errno);
72+	}
73 	uffd_flags = fcntl(uffd, F_GETFD, NULL);
74
75 	uffdio_api.api = UFFD_API;
76@@ -720,6 +727,9 @@ static void *uffd_poll_thread(void *arg)
77 	pollfd[1].fd = pipefd[cpu*2];
78 	pollfd[1].events = POLLIN;
79
80+	// Notify the main thread that it can now fork.
81+	ready_for_fork = true;
82+
83 	for (;;) {
84 		ret = poll(pollfd, 2, -1);
85 		if (ret <= 0) {
86@@ -766,15 +776,28 @@ static void *uffd_poll_thread(void *arg)
87
88 pthread_mutex_t uffd_read_mutex = PTHREAD_MUTEX_INITIALIZER;
89
90+static void sigusr1_handler(int signum, siginfo_t *siginfo, void *ptr)
91+{
92+	jmp_buf *env;
93+	env = pthread_getspecific(long_jmp_key);
94+	longjmp(*env, 1);
95+}
96+
97 static void *uffd_read_thread(void *arg)
98 {
99 	struct uffd_stats *stats = (struct uffd_stats *)arg;
100 	struct uffd_msg msg;
101+	jmp_buf env;
102+	int setjmp_ret;
103+
104+	pthread_setspecific(long_jmp_key, &env);
105
106 	pthread_mutex_unlock(&uffd_read_mutex);
107-	/* from here cancellation is ok */
108
109-	for (;;) {
110+	// One first return setjmp return 0. On second (fake) return from
111+	// longjmp() it returns the provided value, which will be 1 in our case.
112+	setjmp_ret = setjmp(env);
113+	while (!setjmp_ret) {
114 		if (uffd_read_msg(uffd, &msg))
115 			continue;
116 		uffd_handle_page_fault(&msg, stats);
117@@ -872,7 +895,7 @@ static int stress(struct uffd_stats *uffd_stats)
118 					 (void *)&uffd_stats[cpu]))
119 				return 1;
120 		} else {
121-			if (pthread_cancel(uffd_threads[cpu]))
122+			if (pthread_kill(uffd_threads[cpu], SIGUSR1))
123 				return 1;
124 			if (pthread_join(uffd_threads[cpu], NULL))
125 				return 1;
126@@ -1112,6 +1135,10 @@ static int userfaultfd_events_test(void)
127 	char c;
128 	struct uffd_stats stats = { 0 };
129
130+	// All the syscalls below up to pthread_create will ensure that this
131+	// write is completed before, the uffd_thread sets it to true.
132+	ready_for_fork = false;
133+
134 	printf("testing events (fork, remap, remove): ");
135 	fflush(stdout);
136
137@@ -1135,6 +1162,11 @@ static int userfaultfd_events_test(void)
138 	if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, &stats))
139 		err("uffd_poll_thread create");
140
141+	// Wait for the poll_thread to start executing before forking. This is
142+	// required to avoid a deadlock, which can happen if poll_thread doesn't
143+	// start getting executed by the time fork is invoked.
144+	while (!ready_for_fork);
145+
146 	pid = fork();
147 	if (pid < 0)
148 		err("fork");
149@@ -1165,6 +1197,10 @@ static int userfaultfd_sig_test(void)
150 	char c;
151 	struct uffd_stats stats = { 0 };
152
153+	// All the syscalls below up to pthread_create will ensure that this
154+	// write is completed before, the uffd_thread sets it to true.
155+	ready_for_fork = false;
156+
157 	printf("testing signal delivery: ");
158 	fflush(stdout);
159
160@@ -1192,6 +1228,11 @@ static int userfaultfd_sig_test(void)
161 	if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, &stats))
162 		err("uffd_poll_thread create");
163
164+	// Wait for the poll_thread to start executing before forking. This is
165+	// required to avoid a deadlock, which can happen if poll_thread doesn't
166+	// start getting executed by the time fork is invoked.
167+	while (!ready_for_fork);
168+
169 	pid = fork();
170 	if (pid < 0)
171 		err("fork");
172@@ -1421,6 +1462,7 @@ static int userfaultfd_stress(void)
173 	char *tmp_area;
174 	unsigned long nr;
175 	struct uffdio_register uffdio_register;
176+	struct sigaction act;
177 	struct uffd_stats uffd_stats[nr_cpus];
178
179 	uffd_test_ctx_init(0);
180@@ -1435,6 +1477,17 @@ static int userfaultfd_stress(void)
181 	pthread_attr_init(&attr);
182 	pthread_attr_setstacksize(&attr, 16*1024*1024);
183
184+	// For handling thread termination of read thread in the absense of
185+	// pthread_cancel().
186+	pthread_key_create(&long_jmp_key, NULL);
187+	memset(&act, 0, sizeof(act));
188+	act.sa_sigaction = sigusr1_handler;
189+	act.sa_flags = SA_SIGINFO;
190+	if (sigaction(SIGUSR1, &act, 0)) {
191+		perror("sigaction");
192+		return 1;
193+	}
194+
195 	while (bounces--) {
196 		printf("bounces: %d, mode:", bounces);
197 		if (bounces & BOUNCE_RANDOM)
198@@ -1555,6 +1608,8 @@ static int userfaultfd_stress(void)
199 		userfaultfd_pagemap_test(page_size * 512);
200 	}
201
202+	pthread_key_delete(long_jmp_key);
203+
204 	return userfaultfd_zeropage_test() || userfaultfd_sig_test()
205 		|| userfaultfd_events_test() || userfaultfd_minor_test();
206 }
207@@ -1649,6 +1704,9 @@ static void sigalrm(int sig)
208
209 int main(int argc, char **argv)
210 {
211+	char randstate[64];
212+	unsigned int seed;
213+
214 	if (argc < 4)
215 		usage();
216
217@@ -1692,6 +1750,12 @@ int main(int argc, char **argv)
218 			      nr_pages * page_size * 2))
219 			err("fallocate");
220 	}
221+
222+	seed = (unsigned int) time(NULL);
223+	bzero(&randstate, sizeof(randstate));
224+	if (!initstate(seed, randstate, sizeof(randstate)))
225+		fprintf(stderr, "srandom_r error\n"), exit(1);
226+
227 	printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n",
228 	       nr_pages, nr_pages_per_cpu);
229 	return userfaultfd_stress();
230--
2312.36.0.550.gb090851708-goog
232
233