xref: /linux/mm/gup_test.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/kernel.h>
3 #include <linux/mm.h>
4 #include <linux/slab.h>
5 #include <linux/uaccess.h>
6 #include <linux/ktime.h>
7 #include <linux/debugfs.h>
8 #include <linux/highmem.h>
9 #include "gup_test.h"
10 
11 struct gup_test_data {
12 	struct mutex longterm_mutex;
13 	struct page **longterm_pages;
14 	unsigned long longterm_nr_pages;
15 };
16 
17 static void put_back_pages(unsigned int cmd, struct page **pages,
18 			   unsigned long nr_pages, unsigned int gup_test_flags)
19 {
20 	unsigned long i;
21 
22 	switch (cmd) {
23 	case GUP_FAST_BENCHMARK:
24 	case GUP_BASIC_TEST:
25 		for (i = 0; i < nr_pages; i++)
26 			put_page(pages[i]);
27 		break;
28 
29 	case PIN_FAST_BENCHMARK:
30 	case PIN_BASIC_TEST:
31 	case PIN_LONGTERM_BENCHMARK:
32 		unpin_user_pages(pages, nr_pages);
33 		break;
34 	case DUMP_USER_PAGES_TEST:
35 		if (gup_test_flags & GUP_TEST_FLAG_DUMP_PAGES_USE_PIN) {
36 			unpin_user_pages(pages, nr_pages);
37 		} else {
38 			for (i = 0; i < nr_pages; i++)
39 				put_page(pages[i]);
40 
41 		}
42 		break;
43 	}
44 }
45 
46 static void verify_dma_pinned(unsigned int cmd, struct page **pages,
47 			      unsigned long nr_pages)
48 {
49 	unsigned long i;
50 	struct folio *folio;
51 
52 	switch (cmd) {
53 	case PIN_FAST_BENCHMARK:
54 	case PIN_BASIC_TEST:
55 	case PIN_LONGTERM_BENCHMARK:
56 		for (i = 0; i < nr_pages; i++) {
57 			folio = page_folio(pages[i]);
58 
59 			if (WARN(!folio_maybe_dma_pinned(folio),
60 				 "pages[%lu] is NOT dma-pinned\n", i)) {
61 
62 				dump_page(&folio->page, "gup_test failure");
63 				break;
64 			} else if (cmd == PIN_LONGTERM_BENCHMARK &&
65 				WARN(!folio_is_longterm_pinnable(folio),
66 				     "pages[%lu] is NOT pinnable but pinned\n",
67 				     i)) {
68 				dump_page(&folio->page, "gup_test failure");
69 				break;
70 			}
71 		}
72 		break;
73 	}
74 }
75 
76 static void dump_pages_test(struct gup_test *gup, struct page **pages,
77 			    unsigned long nr_pages)
78 {
79 	unsigned int index_to_dump;
80 	unsigned int i;
81 
82 	/*
83 	 * Zero out any user-supplied page index that is out of range. Remember:
84 	 * .which_pages[] contains a 1-based set of page indices.
85 	 */
86 	for (i = 0; i < GUP_TEST_MAX_PAGES_TO_DUMP; i++) {
87 		if (gup->which_pages[i] > nr_pages) {
88 			pr_warn("ZEROING due to out of range: .which_pages[%u]: %u\n",
89 				i, gup->which_pages[i]);
90 			gup->which_pages[i] = 0;
91 		}
92 	}
93 
94 	for (i = 0; i < GUP_TEST_MAX_PAGES_TO_DUMP; i++) {
95 		index_to_dump = gup->which_pages[i];
96 
97 		if (index_to_dump) {
98 			index_to_dump--; // Decode from 1-based, to 0-based
99 			pr_info("---- page #%u, starting from user virt addr: 0x%llx\n",
100 				index_to_dump, gup->addr);
101 			dump_page(pages[index_to_dump],
102 				  "gup_test: dump_pages() test");
103 		}
104 	}
105 }
106 
107 static int __gup_test_ioctl(unsigned int cmd,
108 		struct gup_test *gup)
109 {
110 	ktime_t start_time, end_time;
111 	unsigned long i, nr_pages, addr, next;
112 	long nr;
113 	struct page **pages;
114 	unsigned long end;
115 	int ret = 0;
116 	bool needs_mmap_lock =
117 		cmd != GUP_FAST_BENCHMARK && cmd != PIN_FAST_BENCHMARK;
118 
119 	if (gup->addr > ULONG_MAX || gup->size > ULONG_MAX)
120 		return -EINVAL;
121 	if (check_add_overflow((unsigned long)gup->addr,
122 			       (unsigned long)gup->size, &end))
123 		return -EINVAL;
124 
125 	nr_pages = gup->size / PAGE_SIZE;
126 	pages = kvcalloc(nr_pages, sizeof(void *), GFP_KERNEL);
127 	if (!pages)
128 		return -ENOMEM;
129 
130 	if (needs_mmap_lock && mmap_read_lock_killable(current->mm)) {
131 		ret = -EINTR;
132 		goto free_pages;
133 	}
134 
135 	i = 0;
136 	nr = gup->nr_pages_per_call;
137 	start_time = ktime_get();
138 	for (addr = gup->addr; addr < end; addr = next) {
139 		if (nr != gup->nr_pages_per_call)
140 			break;
141 
142 		next = addr + nr * PAGE_SIZE;
143 		if (next > end) {
144 			next = end;
145 			nr = (next - addr) / PAGE_SIZE;
146 		}
147 
148 		switch (cmd) {
149 		case GUP_FAST_BENCHMARK:
150 			nr = get_user_pages_fast(addr, nr, gup->gup_flags,
151 						 pages + i);
152 			break;
153 		case GUP_BASIC_TEST:
154 			nr = get_user_pages(addr, nr, gup->gup_flags, pages + i);
155 			break;
156 		case PIN_FAST_BENCHMARK:
157 			nr = pin_user_pages_fast(addr, nr, gup->gup_flags,
158 						 pages + i);
159 			break;
160 		case PIN_BASIC_TEST:
161 			nr = pin_user_pages(addr, nr, gup->gup_flags, pages + i);
162 			break;
163 		case PIN_LONGTERM_BENCHMARK:
164 			nr = pin_user_pages(addr, nr,
165 					    gup->gup_flags | FOLL_LONGTERM,
166 					    pages + i);
167 			break;
168 		case DUMP_USER_PAGES_TEST:
169 			if (gup->test_flags & GUP_TEST_FLAG_DUMP_PAGES_USE_PIN)
170 				nr = pin_user_pages(addr, nr, gup->gup_flags,
171 						    pages + i);
172 			else
173 				nr = get_user_pages(addr, nr, gup->gup_flags,
174 						    pages + i);
175 			break;
176 		default:
177 			ret = -EINVAL;
178 			goto unlock;
179 		}
180 
181 		if (nr <= 0)
182 			break;
183 		i += nr;
184 	}
185 	end_time = ktime_get();
186 
187 	/* Shifting the meaning of nr_pages: now it is actual number pinned: */
188 	nr_pages = i;
189 
190 	gup->get_delta_usec = ktime_us_delta(end_time, start_time);
191 	gup->size = addr - gup->addr;
192 
193 	/*
194 	 * Take an un-benchmark-timed moment to verify DMA pinned
195 	 * state: print a warning if any non-dma-pinned pages are found:
196 	 */
197 	verify_dma_pinned(cmd, pages, nr_pages);
198 
199 	if (cmd == DUMP_USER_PAGES_TEST)
200 		dump_pages_test(gup, pages, nr_pages);
201 
202 	start_time = ktime_get();
203 
204 	put_back_pages(cmd, pages, nr_pages, gup->test_flags);
205 
206 	end_time = ktime_get();
207 	gup->put_delta_usec = ktime_us_delta(end_time, start_time);
208 
209 unlock:
210 	if (needs_mmap_lock)
211 		mmap_read_unlock(current->mm);
212 free_pages:
213 	kvfree(pages);
214 	return ret;
215 }
216 
217 static inline void pin_longterm_test_stop(struct gup_test_data *data)
218 {
219 	if (data->longterm_pages) {
220 		if (data->longterm_nr_pages)
221 			unpin_user_pages(data->longterm_pages,
222 					 data->longterm_nr_pages);
223 		kvfree(data->longterm_pages);
224 		data->longterm_pages = NULL;
225 		data->longterm_nr_pages = 0;
226 	}
227 }
228 
229 static inline int pin_longterm_test_start(struct gup_test_data *data,
230 		unsigned long arg)
231 {
232 	long nr_pages, cur_pages, addr, remaining_pages;
233 	int gup_flags = FOLL_LONGTERM;
234 	struct pin_longterm_test args;
235 	struct page **pages;
236 	int ret = 0;
237 	bool fast;
238 
239 	if (data->longterm_pages)
240 		return -EINVAL;
241 
242 	if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
243 		return -EFAULT;
244 
245 	if (args.flags &
246 	    ~(PIN_LONGTERM_TEST_FLAG_USE_WRITE|PIN_LONGTERM_TEST_FLAG_USE_FAST))
247 		return -EINVAL;
248 	if (!IS_ALIGNED(args.addr | args.size, PAGE_SIZE))
249 		return -EINVAL;
250 	if (args.size > LONG_MAX)
251 		return -EINVAL;
252 	nr_pages = args.size / PAGE_SIZE;
253 	if (!nr_pages)
254 		return -EINVAL;
255 
256 	pages = kvcalloc(nr_pages, sizeof(void *), GFP_KERNEL);
257 	if (!pages)
258 		return -ENOMEM;
259 
260 	if (args.flags & PIN_LONGTERM_TEST_FLAG_USE_WRITE)
261 		gup_flags |= FOLL_WRITE;
262 	fast = !!(args.flags & PIN_LONGTERM_TEST_FLAG_USE_FAST);
263 
264 	if (!fast && mmap_read_lock_killable(current->mm)) {
265 		kvfree(pages);
266 		return -EINTR;
267 	}
268 
269 	data->longterm_pages = pages;
270 	data->longterm_nr_pages = 0;
271 
272 	while (nr_pages - data->longterm_nr_pages) {
273 		remaining_pages = nr_pages - data->longterm_nr_pages;
274 		addr = args.addr + data->longterm_nr_pages * PAGE_SIZE;
275 
276 		if (fast)
277 			cur_pages = pin_user_pages_fast(addr, remaining_pages,
278 							gup_flags, pages);
279 		else
280 			cur_pages = pin_user_pages(addr, remaining_pages,
281 						   gup_flags, pages);
282 		if (cur_pages < 0) {
283 			pin_longterm_test_stop(data);
284 			ret = cur_pages;
285 			break;
286 		}
287 		data->longterm_nr_pages += cur_pages;
288 		pages += cur_pages;
289 	}
290 
291 	if (!fast)
292 		mmap_read_unlock(current->mm);
293 	return ret;
294 }
295 
296 static inline int pin_longterm_test_read(struct gup_test_data *data,
297 		unsigned long arg)
298 {
299 	__u64 user_addr;
300 	unsigned long i;
301 
302 	if (!data->longterm_pages)
303 		return -EINVAL;
304 
305 	if (copy_from_user(&user_addr, (void __user *)arg, sizeof(user_addr)))
306 		return -EFAULT;
307 
308 	for (i = 0; i < data->longterm_nr_pages; i++) {
309 		void *addr = kmap_local_page(data->longterm_pages[i]);
310 		unsigned long ret;
311 
312 		ret = copy_to_user((void __user *)(unsigned long)user_addr, addr,
313 				   PAGE_SIZE);
314 		kunmap_local(addr);
315 		if (ret)
316 			return -EFAULT;
317 		user_addr += PAGE_SIZE;
318 	}
319 	return 0;
320 }
321 
322 static long pin_longterm_test_ioctl(struct file *filep, unsigned int cmd,
323 				    unsigned long arg)
324 {
325 	struct gup_test_data *data = filep->private_data;
326 	int ret = -EINVAL;
327 
328 	if (mutex_lock_killable(&data->longterm_mutex))
329 		return -EINTR;
330 
331 	switch (cmd) {
332 	case PIN_LONGTERM_TEST_START:
333 		ret = pin_longterm_test_start(data, arg);
334 		break;
335 	case PIN_LONGTERM_TEST_STOP:
336 		pin_longterm_test_stop(data);
337 		ret = 0;
338 		break;
339 	case PIN_LONGTERM_TEST_READ:
340 		ret = pin_longterm_test_read(data, arg);
341 		break;
342 	}
343 
344 	mutex_unlock(&data->longterm_mutex);
345 	return ret;
346 }
347 
348 static long gup_test_ioctl(struct file *filep, unsigned int cmd,
349 		unsigned long arg)
350 {
351 	struct gup_test gup;
352 	int ret;
353 
354 	switch (cmd) {
355 	case GUP_FAST_BENCHMARK:
356 	case PIN_FAST_BENCHMARK:
357 	case PIN_LONGTERM_BENCHMARK:
358 	case GUP_BASIC_TEST:
359 	case PIN_BASIC_TEST:
360 	case DUMP_USER_PAGES_TEST:
361 		break;
362 	case PIN_LONGTERM_TEST_START:
363 	case PIN_LONGTERM_TEST_STOP:
364 	case PIN_LONGTERM_TEST_READ:
365 		return pin_longterm_test_ioctl(filep, cmd, arg);
366 	default:
367 		return -EINVAL;
368 	}
369 
370 	if (copy_from_user(&gup, (void __user *)arg, sizeof(gup)))
371 		return -EFAULT;
372 
373 	ret = __gup_test_ioctl(cmd, &gup);
374 	if (ret)
375 		return ret;
376 
377 	if (copy_to_user((void __user *)arg, &gup, sizeof(gup)))
378 		return -EFAULT;
379 
380 	return 0;
381 }
382 
383 static int gup_test_open(struct inode *inode, struct file *file)
384 {
385 	struct gup_test_data *data;
386 	int ret;
387 
388 	data = kzalloc_obj(*data);
389 	if (!data)
390 		return -ENOMEM;
391 
392 	ret = nonseekable_open(inode, file);
393 	if (ret) {
394 		kfree(data);
395 		return ret;
396 	}
397 
398 	mutex_init(&data->longterm_mutex);
399 	file->private_data = data;
400 	return 0;
401 }
402 
403 static int gup_test_release(struct inode *inode, struct file *file)
404 {
405 	struct gup_test_data *data = file->private_data;
406 
407 	pin_longterm_test_stop(data);
408 	mutex_destroy(&data->longterm_mutex);
409 	kfree(data);
410 	file->private_data = NULL;
411 
412 	return 0;
413 }
414 
415 static const struct file_operations gup_test_fops = {
416 	.open = gup_test_open,
417 	.unlocked_ioctl = gup_test_ioctl,
418 	.compat_ioctl = compat_ptr_ioctl,
419 	.release = gup_test_release,
420 };
421 
422 static int __init gup_test_init(void)
423 {
424 	debugfs_create_file_unsafe("gup_test", 0600, NULL, NULL,
425 				   &gup_test_fops);
426 
427 	return 0;
428 }
429 
430 late_initcall(gup_test_init);
431