xref: /linux/drivers/android/tests/binder_alloc_kunit.c (revision 260f6f4fda93c8485c8037865c941b42b9cba5d2)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Test cases for binder allocator code.
4  *
5  * Copyright 2025 Google LLC.
6  * Author: Tiffany Yang <ynaffit@google.com>
7  */
8 
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 
11 #include <kunit/test.h>
12 #include <linux/anon_inodes.h>
13 #include <linux/err.h>
14 #include <linux/file.h>
15 #include <linux/fs.h>
16 #include <linux/mm.h>
17 #include <linux/mman.h>
18 #include <linux/seq_buf.h>
19 #include <linux/sizes.h>
20 
21 #include "../binder_alloc.h"
22 #include "../binder_internal.h"
23 
24 MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
25 
26 #define BINDER_MMAP_SIZE SZ_128K
27 
28 #define BUFFER_NUM 5
29 #define BUFFER_MIN_SIZE (PAGE_SIZE / 8)
30 
31 #define FREESEQ_BUFLEN ((3 * BUFFER_NUM) + 1)
32 
33 #define ALIGN_TYPE_STRLEN (12)
34 
35 #define ALIGNMENTS_BUFLEN (((ALIGN_TYPE_STRLEN + 6) * BUFFER_NUM) + 1)
36 
37 #define PRINT_ALL_CASES (0)
38 
39 /* 5^5 alignment combinations * 2 places to share pages * 5! free sequences */
40 #define TOTAL_EXHAUSTIVE_CASES (3125 * 2 * 120)
41 
42 /**
43  * enum buf_end_align_type - Page alignment of a buffer
44  * end with regard to the end of the previous buffer.
45  *
46  * In the pictures below, buf2 refers to the buffer we
47  * are aligning. buf1 refers to previous buffer by addr.
48  * Symbol [ means the start of a buffer, ] means the end
49  * of a buffer, and | means page boundaries.
50  */
51 enum buf_end_align_type {
52 	/**
53 	 * @SAME_PAGE_UNALIGNED: The end of this buffer is on
54 	 * the same page as the end of the previous buffer and
55 	 * is not page aligned. Examples:
56 	 * buf1 ][ buf2 ][ ...
57 	 * buf1 ]|[ buf2 ][ ...
58 	 */
59 	SAME_PAGE_UNALIGNED = 0,
60 	/**
61 	 * @SAME_PAGE_ALIGNED: When the end of the previous buffer
62 	 * is not page aligned, the end of this buffer is on the
63 	 * same page as the end of the previous buffer and is page
64 	 * aligned. When the previous buffer is page aligned, the
65 	 * end of this buffer is aligned to the next page boundary.
66 	 * Examples:
67 	 * buf1 ][ buf2 ]| ...
68 	 * buf1 ]|[ buf2 ]| ...
69 	 */
70 	SAME_PAGE_ALIGNED,
71 	/**
72 	 * @NEXT_PAGE_UNALIGNED: The end of this buffer is on
73 	 * the page next to the end of the previous buffer and
74 	 * is not page aligned. Examples:
75 	 * buf1 ][ buf2 | buf2 ][ ...
76 	 * buf1 ]|[ buf2 | buf2 ][ ...
77 	 */
78 	NEXT_PAGE_UNALIGNED,
79 	/**
80 	 * @NEXT_PAGE_ALIGNED: The end of this buffer is on
81 	 * the page next to the end of the previous buffer and
82 	 * is page aligned. Examples:
83 	 * buf1 ][ buf2 | buf2 ]| ...
84 	 * buf1 ]|[ buf2 | buf2 ]| ...
85 	 */
86 	NEXT_PAGE_ALIGNED,
87 	/**
88 	 * @NEXT_NEXT_UNALIGNED: The end of this buffer is on
89 	 * the page that follows the page after the end of the
90 	 * previous buffer and is not page aligned. Examples:
91 	 * buf1 ][ buf2 | buf2 | buf2 ][ ...
92 	 * buf1 ]|[ buf2 | buf2 | buf2 ][ ...
93 	 */
94 	NEXT_NEXT_UNALIGNED,
95 	/**
96 	 * @LOOP_END: The number of enum values in &buf_end_align_type.
97 	 * It is used for controlling loop termination.
98 	 */
99 	LOOP_END,
100 };
101 
102 static const char *const buf_end_align_type_strs[LOOP_END] = {
103 	[SAME_PAGE_UNALIGNED] = "SP_UNALIGNED",
104 	[SAME_PAGE_ALIGNED]   = " SP_ALIGNED ",
105 	[NEXT_PAGE_UNALIGNED] = "NP_UNALIGNED",
106 	[NEXT_PAGE_ALIGNED]   = " NP_ALIGNED ",
107 	[NEXT_NEXT_UNALIGNED] = "NN_UNALIGNED",
108 };
109 
110 struct binder_alloc_test_case_info {
111 	char alignments[ALIGNMENTS_BUFLEN];
112 	struct seq_buf alignments_sb;
113 	size_t *buffer_sizes;
114 	int *free_sequence;
115 	bool front_pages;
116 };
117 
118 static void stringify_free_seq(struct kunit *test, int *seq, struct seq_buf *sb)
119 {
120 	int i;
121 
122 	for (i = 0; i < BUFFER_NUM; i++)
123 		seq_buf_printf(sb, "[%d]", seq[i]);
124 
125 	KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(sb));
126 }
127 
128 static void stringify_alignments(struct kunit *test, int *alignments,
129 				 struct seq_buf *sb)
130 {
131 	int i;
132 
133 	for (i = 0; i < BUFFER_NUM; i++)
134 		seq_buf_printf(sb, "[ %d:%s ]", i,
135 			       buf_end_align_type_strs[alignments[i]]);
136 
137 	KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(sb));
138 }
139 
140 static bool check_buffer_pages_allocated(struct kunit *test,
141 					 struct binder_alloc *alloc,
142 					 struct binder_buffer *buffer,
143 					 size_t size)
144 {
145 	unsigned long page_addr;
146 	unsigned long end;
147 	int page_index;
148 
149 	end = PAGE_ALIGN(buffer->user_data + size);
150 	page_addr = buffer->user_data;
151 	for (; page_addr < end; page_addr += PAGE_SIZE) {
152 		page_index = (page_addr - alloc->vm_start) / PAGE_SIZE;
153 		if (!alloc->pages[page_index] ||
154 		    !list_empty(page_to_lru(alloc->pages[page_index]))) {
155 			kunit_err(test, "expect alloc but is %s at page index %d\n",
156 				  alloc->pages[page_index] ?
157 				  "lru" : "free", page_index);
158 			return false;
159 		}
160 	}
161 	return true;
162 }
163 
164 static unsigned long binder_alloc_test_alloc_buf(struct kunit *test,
165 						 struct binder_alloc *alloc,
166 						 struct binder_buffer *buffers[],
167 						 size_t *sizes, int *seq)
168 {
169 	unsigned long failures = 0;
170 	int i;
171 
172 	for (i = 0; i < BUFFER_NUM; i++) {
173 		buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);
174 		if (IS_ERR(buffers[i]) ||
175 		    !check_buffer_pages_allocated(test, alloc, buffers[i], sizes[i]))
176 			failures++;
177 	}
178 
179 	return failures;
180 }
181 
182 static unsigned long binder_alloc_test_free_buf(struct kunit *test,
183 						struct binder_alloc *alloc,
184 						struct binder_buffer *buffers[],
185 						size_t *sizes, int *seq, size_t end)
186 {
187 	unsigned long failures = 0;
188 	int i;
189 
190 	for (i = 0; i < BUFFER_NUM; i++)
191 		binder_alloc_free_buf(alloc, buffers[seq[i]]);
192 
193 	for (i = 0; i <= (end - 1) / PAGE_SIZE; i++) {
194 		if (list_empty(page_to_lru(alloc->pages[i]))) {
195 			kunit_err(test, "expect lru but is %s at page index %d\n",
196 				  alloc->pages[i] ? "alloc" : "free", i);
197 			failures++;
198 		}
199 	}
200 
201 	return failures;
202 }
203 
204 static unsigned long binder_alloc_test_free_page(struct kunit *test,
205 						 struct binder_alloc *alloc)
206 {
207 	unsigned long failures = 0;
208 	unsigned long count;
209 	int i;
210 
211 	while ((count = list_lru_count(alloc->freelist))) {
212 		list_lru_walk(alloc->freelist, binder_alloc_free_page,
213 			      NULL, count);
214 	}
215 
216 	for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) {
217 		if (alloc->pages[i]) {
218 			kunit_err(test, "expect free but is %s at page index %d\n",
219 				  list_empty(page_to_lru(alloc->pages[i])) ?
220 				  "alloc" : "lru", i);
221 			failures++;
222 		}
223 	}
224 
225 	return failures;
226 }
227 
228 /* Executes one full test run for the given test case. */
229 static bool binder_alloc_test_alloc_free(struct kunit *test,
230 					 struct binder_alloc *alloc,
231 					 struct binder_alloc_test_case_info *tc,
232 					 size_t end)
233 {
234 	unsigned long pages = PAGE_ALIGN(end) / PAGE_SIZE;
235 	struct binder_buffer *buffers[BUFFER_NUM];
236 	unsigned long failures;
237 	bool failed = false;
238 
239 	failures = binder_alloc_test_alloc_buf(test, alloc, buffers,
240 					       tc->buffer_sizes,
241 					       tc->free_sequence);
242 	failed = failed || failures;
243 	KUNIT_EXPECT_EQ_MSG(test, failures, 0,
244 			    "Initial allocation failed: %lu/%u buffers with errors",
245 			    failures, BUFFER_NUM);
246 
247 	failures = binder_alloc_test_free_buf(test, alloc, buffers,
248 					      tc->buffer_sizes,
249 					      tc->free_sequence, end);
250 	failed = failed || failures;
251 	KUNIT_EXPECT_EQ_MSG(test, failures, 0,
252 			    "Initial buffers not freed correctly: %lu/%lu pages not on lru list",
253 			    failures, pages);
254 
255 	/* Allocate from lru. */
256 	failures = binder_alloc_test_alloc_buf(test, alloc, buffers,
257 					       tc->buffer_sizes,
258 					       tc->free_sequence);
259 	failed = failed || failures;
260 	KUNIT_EXPECT_EQ_MSG(test, failures, 0,
261 			    "Reallocation failed: %lu/%u buffers with errors",
262 			    failures, BUFFER_NUM);
263 
264 	failures = list_lru_count(alloc->freelist);
265 	failed = failed || failures;
266 	KUNIT_EXPECT_EQ_MSG(test, failures, 0,
267 			    "lru list should be empty after reallocation but still has %lu pages",
268 			    failures);
269 
270 	failures = binder_alloc_test_free_buf(test, alloc, buffers,
271 					      tc->buffer_sizes,
272 					      tc->free_sequence, end);
273 	failed = failed || failures;
274 	KUNIT_EXPECT_EQ_MSG(test, failures, 0,
275 			    "Reallocated buffers not freed correctly: %lu/%lu pages not on lru list",
276 			    failures, pages);
277 
278 	failures = binder_alloc_test_free_page(test, alloc);
279 	failed = failed || failures;
280 	KUNIT_EXPECT_EQ_MSG(test, failures, 0,
281 			    "Failed to clean up allocated pages: %lu/%lu pages still installed",
282 			    failures, (alloc->buffer_size / PAGE_SIZE));
283 
284 	return failed;
285 }
286 
287 static bool is_dup(int *seq, int index, int val)
288 {
289 	int i;
290 
291 	for (i = 0; i < index; i++) {
292 		if (seq[i] == val)
293 			return true;
294 	}
295 	return false;
296 }
297 
298 /* Generate BUFFER_NUM factorial free orders. */
299 static void permute_frees(struct kunit *test, struct binder_alloc *alloc,
300 			  struct binder_alloc_test_case_info *tc,
301 			  unsigned long *runs, unsigned long *failures,
302 			  int index, size_t end)
303 {
304 	bool case_failed;
305 	int i;
306 
307 	if (index == BUFFER_NUM) {
308 		DECLARE_SEQ_BUF(freeseq_sb, FREESEQ_BUFLEN);
309 
310 		case_failed = binder_alloc_test_alloc_free(test, alloc, tc, end);
311 		*runs += 1;
312 		*failures += case_failed;
313 
314 		if (case_failed || PRINT_ALL_CASES) {
315 			stringify_free_seq(test, tc->free_sequence,
316 					   &freeseq_sb);
317 			kunit_err(test, "case %lu: [%s] | %s - %s - %s", *runs,
318 				  case_failed ? "FAILED" : "PASSED",
319 				  tc->front_pages ? "front" : "back ",
320 				  seq_buf_str(&tc->alignments_sb),
321 				  seq_buf_str(&freeseq_sb));
322 		}
323 
324 		return;
325 	}
326 	for (i = 0; i < BUFFER_NUM; i++) {
327 		if (is_dup(tc->free_sequence, index, i))
328 			continue;
329 		tc->free_sequence[index] = i;
330 		permute_frees(test, alloc, tc, runs, failures, index + 1, end);
331 	}
332 }
333 
334 static void gen_buf_sizes(struct kunit *test,
335 			  struct binder_alloc *alloc,
336 			  struct binder_alloc_test_case_info *tc,
337 			  size_t *end_offset, unsigned long *runs,
338 			  unsigned long *failures)
339 {
340 	size_t last_offset, offset = 0;
341 	size_t front_sizes[BUFFER_NUM];
342 	size_t back_sizes[BUFFER_NUM];
343 	int seq[BUFFER_NUM] = {0};
344 	int i;
345 
346 	tc->free_sequence = seq;
347 	for (i = 0; i < BUFFER_NUM; i++) {
348 		last_offset = offset;
349 		offset = end_offset[i];
350 		front_sizes[i] = offset - last_offset;
351 		back_sizes[BUFFER_NUM - i - 1] = front_sizes[i];
352 	}
353 	back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1];
354 
355 	/*
356 	 * Buffers share the first or last few pages.
357 	 * Only BUFFER_NUM - 1 buffer sizes are adjustable since
358 	 * we need one giant buffer before getting to the last page.
359 	 */
360 	tc->front_pages = true;
361 	tc->buffer_sizes = front_sizes;
362 	permute_frees(test, alloc, tc, runs, failures, 0,
363 		      end_offset[BUFFER_NUM - 1]);
364 
365 	tc->front_pages = false;
366 	tc->buffer_sizes = back_sizes;
367 	permute_frees(test, alloc, tc, runs, failures, 0, alloc->buffer_size);
368 }
369 
370 static void gen_buf_offsets(struct kunit *test, struct binder_alloc *alloc,
371 			    size_t *end_offset, int *alignments,
372 			    unsigned long *runs, unsigned long *failures,
373 			    int index)
374 {
375 	size_t end, prev;
376 	int align;
377 
378 	if (index == BUFFER_NUM) {
379 		struct binder_alloc_test_case_info tc = {0};
380 
381 		seq_buf_init(&tc.alignments_sb, tc.alignments,
382 			     ALIGNMENTS_BUFLEN);
383 		stringify_alignments(test, alignments, &tc.alignments_sb);
384 
385 		gen_buf_sizes(test, alloc, &tc, end_offset, runs, failures);
386 		return;
387 	}
388 	prev = index == 0 ? 0 : end_offset[index - 1];
389 	end = prev;
390 
391 	BUILD_BUG_ON(BUFFER_MIN_SIZE * BUFFER_NUM >= PAGE_SIZE);
392 
393 	for (align = SAME_PAGE_UNALIGNED; align < LOOP_END; align++) {
394 		if (align % 2)
395 			end = ALIGN(end, PAGE_SIZE);
396 		else
397 			end += BUFFER_MIN_SIZE;
398 		end_offset[index] = end;
399 		alignments[index] = align;
400 		gen_buf_offsets(test, alloc, end_offset, alignments, runs,
401 				failures, index + 1);
402 	}
403 }
404 
405 struct binder_alloc_test {
406 	struct binder_alloc alloc;
407 	struct list_lru binder_test_freelist;
408 	struct file *filp;
409 	unsigned long mmap_uaddr;
410 };
411 
412 static void binder_alloc_test_init_freelist(struct kunit *test)
413 {
414 	struct binder_alloc_test *priv = test->priv;
415 
416 	KUNIT_EXPECT_PTR_EQ(test, priv->alloc.freelist,
417 			    &priv->binder_test_freelist);
418 }
419 
420 static void binder_alloc_test_mmap(struct kunit *test)
421 {
422 	struct binder_alloc_test *priv = test->priv;
423 	struct binder_alloc *alloc = &priv->alloc;
424 	struct binder_buffer *buf;
425 	struct rb_node *n;
426 
427 	KUNIT_EXPECT_EQ(test, alloc->mapped, true);
428 	KUNIT_EXPECT_EQ(test, alloc->buffer_size, BINDER_MMAP_SIZE);
429 
430 	n = rb_first(&alloc->allocated_buffers);
431 	KUNIT_EXPECT_PTR_EQ(test, n, NULL);
432 
433 	n = rb_first(&alloc->free_buffers);
434 	buf = rb_entry(n, struct binder_buffer, rb_node);
435 	KUNIT_EXPECT_EQ(test, binder_alloc_buffer_size(alloc, buf),
436 			BINDER_MMAP_SIZE);
437 	KUNIT_EXPECT_TRUE(test, list_is_last(&buf->entry, &alloc->buffers));
438 }
439 
440 /**
441  * binder_alloc_exhaustive_test() - Exhaustively test alloc and free of buffer pages.
442  * @test: The test context object.
443  *
444  * Allocate BUFFER_NUM buffers to cover all page alignment cases,
445  * then free them in all orders possible. Check that pages are
446  * correctly allocated, put onto lru when buffers are freed, and
447  * are freed when binder_alloc_free_page() is called.
448  */
449 static void binder_alloc_exhaustive_test(struct kunit *test)
450 {
451 	struct binder_alloc_test *priv = test->priv;
452 	size_t end_offset[BUFFER_NUM];
453 	int alignments[BUFFER_NUM];
454 	unsigned long failures = 0;
455 	unsigned long runs = 0;
456 
457 	gen_buf_offsets(test, &priv->alloc, end_offset, alignments, &runs,
458 			&failures, 0);
459 
460 	KUNIT_EXPECT_EQ(test, runs, TOTAL_EXHAUSTIVE_CASES);
461 	KUNIT_EXPECT_EQ(test, failures, 0);
462 }
463 
464 /* ===== End test cases ===== */
465 
466 static void binder_alloc_test_vma_close(struct vm_area_struct *vma)
467 {
468 	struct binder_alloc *alloc = vma->vm_private_data;
469 
470 	binder_alloc_vma_close(alloc);
471 }
472 
473 static const struct vm_operations_struct binder_alloc_test_vm_ops = {
474 	.close = binder_alloc_test_vma_close,
475 	.fault = binder_vm_fault,
476 };
477 
478 static int binder_alloc_test_mmap_handler(struct file *filp,
479 					  struct vm_area_struct *vma)
480 {
481 	struct binder_alloc *alloc = filp->private_data;
482 
483 	vm_flags_mod(vma, VM_DONTCOPY | VM_MIXEDMAP, VM_MAYWRITE);
484 
485 	vma->vm_ops = &binder_alloc_test_vm_ops;
486 	vma->vm_private_data = alloc;
487 
488 	return binder_alloc_mmap_handler(alloc, vma);
489 }
490 
491 static const struct file_operations binder_alloc_test_fops = {
492 	.mmap = binder_alloc_test_mmap_handler,
493 };
494 
495 static int binder_alloc_test_init(struct kunit *test)
496 {
497 	struct binder_alloc_test *priv;
498 	int ret;
499 
500 	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
501 	if (!priv)
502 		return -ENOMEM;
503 	test->priv = priv;
504 
505 	ret = list_lru_init(&priv->binder_test_freelist);
506 	if (ret) {
507 		kunit_err(test, "Failed to initialize test freelist\n");
508 		return ret;
509 	}
510 
511 	/* __binder_alloc_init requires mm to be attached */
512 	ret = kunit_attach_mm();
513 	if (ret) {
514 		kunit_err(test, "Failed to attach mm\n");
515 		return ret;
516 	}
517 	__binder_alloc_init(&priv->alloc, &priv->binder_test_freelist);
518 
519 	priv->filp = anon_inode_getfile("binder_alloc_kunit",
520 					&binder_alloc_test_fops, &priv->alloc,
521 					O_RDWR | O_CLOEXEC);
522 	if (IS_ERR_OR_NULL(priv->filp)) {
523 		kunit_err(test, "Failed to open binder alloc test driver file\n");
524 		return priv->filp ? PTR_ERR(priv->filp) : -ENOMEM;
525 	}
526 
527 	priv->mmap_uaddr = kunit_vm_mmap(test, priv->filp, 0, BINDER_MMAP_SIZE,
528 					 PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
529 					 0);
530 	if (!priv->mmap_uaddr) {
531 		kunit_err(test, "Could not map the test's transaction memory\n");
532 		return -ENOMEM;
533 	}
534 
535 	return 0;
536 }
537 
538 static void binder_alloc_test_exit(struct kunit *test)
539 {
540 	struct binder_alloc_test *priv = test->priv;
541 
542 	/* Close the backing file to make sure binder_alloc_vma_close runs */
543 	if (!IS_ERR_OR_NULL(priv->filp))
544 		fput(priv->filp);
545 
546 	if (priv->alloc.mm)
547 		binder_alloc_deferred_release(&priv->alloc);
548 
549 	/* Make sure freelist is empty */
550 	KUNIT_EXPECT_EQ(test, list_lru_count(&priv->binder_test_freelist), 0);
551 	list_lru_destroy(&priv->binder_test_freelist);
552 }
553 
554 static struct kunit_case binder_alloc_test_cases[] = {
555 	KUNIT_CASE(binder_alloc_test_init_freelist),
556 	KUNIT_CASE(binder_alloc_test_mmap),
557 	KUNIT_CASE(binder_alloc_exhaustive_test),
558 	{}
559 };
560 
561 static struct kunit_suite binder_alloc_test_suite = {
562 	.name = "binder_alloc",
563 	.test_cases = binder_alloc_test_cases,
564 	.init = binder_alloc_test_init,
565 	.exit = binder_alloc_test_exit,
566 };
567 
568 kunit_test_suite(binder_alloc_test_suite);
569 
570 MODULE_AUTHOR("Tiffany Yang <ynaffit@google.com>");
571 MODULE_DESCRIPTION("Binder Alloc KUnit tests");
572 MODULE_LICENSE("GPL");
573