Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

binder: encapsulate individual alloc test cases

Each case tested by the binder allocator test is defined by 3 parameters:
the end alignment type of each requested buffer allocation, whether those
buffers share the front or back pages of the allotted address space, and
the order in which those buffers should be released. The alignment type
represents how a binder buffer may be laid out within or across page
boundaries and relative to other buffers, and it's used along with
whether the buffers cover part (sharing the front pages) of or all
(sharing the back pages) of the vma to calculate the sizes passed into
each test.

binder_alloc_test_alloc recursively generates each possible arrangement
of alignment types and then tests that the binder_alloc code tracks pages
correctly when those buffers are allocated and then freed in every
possible order at both ends of the address space. While they provide
comprehensive coverage, they are poor candidates to be represented as
KUnit test cases, which must be statically enumerated. For 5 buffers and
5 end alignment types, the test case array would have 750,000 entries.
This change structures the recursive calls into meaningful test cases so
that failures are easier to interpret.

Signed-off-by: Tiffany Yang <ynaffit@google.com>
Acked-by: Carlos Llamas <cmllamas@google.com>
Link: https://lore.kernel.org/r/20250714185321.2417234-7-ynaffit@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Tiffany Yang and committed by
Greg Kroah-Hartman
d1934ed9 f6544dcd

+179 -51
+179 -51
drivers/android/tests/binder_alloc_kunit.c
··· 24 24 #define BUFFER_NUM 5 25 25 #define BUFFER_MIN_SIZE (PAGE_SIZE / 8) 26 26 27 - static int binder_alloc_test_failures; 27 + #define FREESEQ_BUFLEN ((3 * BUFFER_NUM) + 1) 28 + 29 + #define ALIGN_TYPE_STRLEN (12) 30 + 31 + #define ALIGNMENTS_BUFLEN (((ALIGN_TYPE_STRLEN + 6) * BUFFER_NUM) + 1) 32 + 33 + #define PRINT_ALL_CASES (0) 34 + 35 + /* 5^5 alignment combinations * 2 places to share pages * 5! free sequences */ 36 + #define TOTAL_EXHAUSTIVE_CASES (3125 * 2 * 120) 28 37 29 38 /** 30 39 * enum buf_end_align_type - Page alignment of a buffer ··· 95 86 LOOP_END, 96 87 }; 97 88 98 - static void pr_err_size_seq(struct kunit *test, size_t *sizes, int *seq) 89 + static const char *const buf_end_align_type_strs[LOOP_END] = { 90 + [SAME_PAGE_UNALIGNED] = "SP_UNALIGNED", 91 + [SAME_PAGE_ALIGNED] = " SP_ALIGNED ", 92 + [NEXT_PAGE_UNALIGNED] = "NP_UNALIGNED", 93 + [NEXT_PAGE_ALIGNED] = " NP_ALIGNED ", 94 + [NEXT_NEXT_UNALIGNED] = "NN_UNALIGNED", 95 + }; 96 + 97 + struct binder_alloc_test_case_info { 98 + size_t *buffer_sizes; 99 + int *free_sequence; 100 + char alignments[ALIGNMENTS_BUFLEN]; 101 + bool front_pages; 102 + }; 103 + 104 + static void stringify_free_seq(struct kunit *test, int *seq, char *buf, 105 + size_t buf_len) 99 106 { 107 + size_t bytes = 0; 100 108 int i; 101 109 102 - kunit_err(test, "alloc sizes: "); 103 - for (i = 0; i < BUFFER_NUM; i++) 104 - pr_cont("[%zu]", sizes[i]); 105 - pr_cont("\n"); 106 - kunit_err(test, "free seq: "); 107 - for (i = 0; i < BUFFER_NUM; i++) 108 - pr_cont("[%d]", seq[i]); 109 - pr_cont("\n"); 110 + for (i = 0; i < BUFFER_NUM; i++) { 111 + bytes += snprintf(buf + bytes, buf_len - bytes, "[%d]", seq[i]); 112 + if (bytes >= buf_len) 113 + break; 114 + } 115 + KUNIT_EXPECT_LT(test, bytes, buf_len); 116 + } 117 + 118 + static void stringify_alignments(struct kunit *test, int *alignments, 119 + char *buf, size_t buf_len) 120 + { 121 + size_t bytes = 0; 122 + int i; 123 + 124 + for (i = 0; i < BUFFER_NUM; i++) { 125 + bytes += snprintf(buf + bytes, buf_len - bytes, "[ %d:%s ]", i, 126 + buf_end_align_type_strs[alignments[i]]); 127 + if (bytes >= buf_len) 128 + break; 129 + } 130 + 131 + KUNIT_EXPECT_LT(test, bytes, buf_len); 110 132 } 111 133 112 134 static bool check_buffer_pages_allocated(struct kunit *test, ··· 164 124 return true; 165 125 } 166 126 167 - static void binder_alloc_test_alloc_buf(struct kunit *test, 168 - struct binder_alloc *alloc, 169 - struct binder_buffer *buffers[], 170 - size_t *sizes, int *seq) 127 + static unsigned long binder_alloc_test_alloc_buf(struct kunit *test, 128 + struct binder_alloc *alloc, 129 + struct binder_buffer *buffers[], 130 + size_t *sizes, int *seq) 171 131 { 132 + unsigned long failures = 0; 172 133 int i; 173 134 174 135 for (i = 0; i < BUFFER_NUM; i++) { 175 136 buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0); 176 137 if (IS_ERR(buffers[i]) || 177 - !check_buffer_pages_allocated(test, alloc, buffers[i], sizes[i])) { 178 - pr_err_size_seq(test, sizes, seq); 179 - binder_alloc_test_failures++; 180 - } 138 + !check_buffer_pages_allocated(test, alloc, buffers[i], sizes[i])) 139 + failures++; 181 140 } 141 + 142 + return failures; 182 143 } 183 144 184 - static void binder_alloc_test_free_buf(struct kunit *test, 185 - struct binder_alloc *alloc, 186 - struct binder_buffer *buffers[], 187 - size_t *sizes, int *seq, size_t end) 145 + static unsigned long binder_alloc_test_free_buf(struct kunit *test, 146 + struct binder_alloc *alloc, 147 + struct binder_buffer *buffers[], 148 + size_t *sizes, int *seq, size_t end) 188 149 { 150 + unsigned long failures = 0; 189 151 int i; 190 152 191 153 for (i = 0; i < BUFFER_NUM; i++) ··· 195 153 196 154 for (i = 0; i <= (end - 1) / PAGE_SIZE; i++) { 197 155 if (list_empty(page_to_lru(alloc->pages[i]))) { 198 - pr_err_size_seq(test, sizes, seq); 199 156 kunit_err(test, "expect lru but is %s at page index %d\n", 200 157 alloc->pages[i] ? "alloc" : "free", i); 201 - binder_alloc_test_failures++; 158 + failures++; 202 159 } 203 160 } 161 + 162 + return failures; 204 163 } 205 164 206 - static void binder_alloc_test_free_page(struct kunit *test, 207 - struct binder_alloc *alloc) 165 + static unsigned long binder_alloc_test_free_page(struct kunit *test, 166 + struct binder_alloc *alloc) 208 167 { 168 + unsigned long failures = 0; 209 169 unsigned long count; 210 170 int i; 211 171 ··· 221 177 kunit_err(test, "expect free but is %s at page index %d\n", 222 178 list_empty(page_to_lru(alloc->pages[i])) ? 223 179 "alloc" : "lru", i); 224 - binder_alloc_test_failures++; 180 + failures++; 225 181 } 226 182 } 183 + 184 + return failures; 227 185 } 228 186 229 - static void binder_alloc_test_alloc_free(struct kunit *test, 187 + /* Executes one full test run for the given test case. */ 188 + static bool binder_alloc_test_alloc_free(struct kunit *test, 230 189 struct binder_alloc *alloc, 231 - size_t *sizes, int *seq, size_t end) 190 + struct binder_alloc_test_case_info *tc, 191 + size_t end) 232 192 { 193 + unsigned long pages = PAGE_ALIGN(end) / PAGE_SIZE; 233 194 struct binder_buffer *buffers[BUFFER_NUM]; 195 + unsigned long failures; 196 + bool failed = false; 234 197 235 - binder_alloc_test_alloc_buf(test, alloc, buffers, sizes, seq); 236 - binder_alloc_test_free_buf(test, alloc, buffers, sizes, seq, end); 198 + failures = binder_alloc_test_alloc_buf(test, alloc, buffers, 199 + tc->buffer_sizes, 200 + tc->free_sequence); 201 + failed = failed || failures; 202 + KUNIT_EXPECT_EQ_MSG(test, failures, 0, 203 + "Initial allocation failed: %lu/%u buffers with errors", 204 + failures, BUFFER_NUM); 205 + 206 + failures = binder_alloc_test_free_buf(test, alloc, buffers, 207 + tc->buffer_sizes, 208 + tc->free_sequence, end); 209 + failed = failed || failures; 210 + KUNIT_EXPECT_EQ_MSG(test, failures, 0, 211 + "Initial buffers not freed correctly: %lu/%lu pages not on lru list", 212 + failures, pages); 237 213 238 214 /* Allocate from lru. */ 239 - binder_alloc_test_alloc_buf(test, alloc, buffers, sizes, seq); 240 - if (list_lru_count(alloc->freelist)) 241 - kunit_err(test, "lru list should be empty but is not\n"); 215 + failures = binder_alloc_test_alloc_buf(test, alloc, buffers, 216 + tc->buffer_sizes, 217 + tc->free_sequence); 218 + failed = failed || failures; 219 + KUNIT_EXPECT_EQ_MSG(test, failures, 0, 220 + "Reallocation failed: %lu/%u buffers with errors", 221 + failures, BUFFER_NUM); 242 222 243 - binder_alloc_test_free_buf(test, alloc, buffers, sizes, seq, end); 244 - binder_alloc_test_free_page(test, alloc); 223 + failures = list_lru_count(alloc->freelist); 224 + failed = failed || failures; 225 + KUNIT_EXPECT_EQ_MSG(test, failures, 0, 226 + "lru list should be empty after reallocation but still has %lu pages", 227 + failures); 228 + 229 + failures = binder_alloc_test_free_buf(test, alloc, buffers, 230 + tc->buffer_sizes, 231 + tc->free_sequence, end); 232 + failed = failed || failures; 233 + KUNIT_EXPECT_EQ_MSG(test, failures, 0, 234 + "Reallocated buffers not freed correctly: %lu/%lu pages not on lru list", 235 + failures, pages); 236 + 237 + failures = binder_alloc_test_free_page(test, alloc); 238 + failed = failed || failures; 239 + KUNIT_EXPECT_EQ_MSG(test, failures, 0, 240 + "Failed to clean up allocated pages: %lu/%lu pages still installed", 241 + failures, (alloc->buffer_size / PAGE_SIZE)); 242 + 243 + return failed; 245 244 } 246 245 247 246 static bool is_dup(int *seq, int index, int val) ··· 300 213 301 214 /* Generate BUFFER_NUM factorial free orders. */ 302 215 static void permute_frees(struct kunit *test, struct binder_alloc *alloc, 303 - size_t *sizes, int *seq, int index, size_t end) 216 + struct binder_alloc_test_case_info *tc, 217 + unsigned long *runs, unsigned long *failures, 218 + int index, size_t end) 304 219 { 220 + bool case_failed; 305 221 int i; 306 222 307 223 if (index == BUFFER_NUM) { 308 - binder_alloc_test_alloc_free(test, alloc, sizes, seq, end); 224 + char freeseq_buf[FREESEQ_BUFLEN]; 225 + 226 + case_failed = binder_alloc_test_alloc_free(test, alloc, tc, end); 227 + *runs += 1; 228 + *failures += case_failed; 229 + 230 + if (case_failed || PRINT_ALL_CASES) { 231 + stringify_free_seq(test, tc->free_sequence, freeseq_buf, 232 + FREESEQ_BUFLEN); 233 + kunit_err(test, "case %lu: [%s] | %s - %s - %s", *runs, 234 + case_failed ? "FAILED" : "PASSED", 235 + tc->front_pages ? "front" : "back ", 236 + tc->alignments, freeseq_buf); 237 + } 238 + 309 239 return; 310 240 } 311 241 for (i = 0; i < BUFFER_NUM; i++) { 312 - if (is_dup(seq, index, i)) 242 + if (is_dup(tc->free_sequence, index, i)) 313 243 continue; 314 - seq[index] = i; 315 - permute_frees(test, alloc, sizes, seq, index + 1, end); 244 + tc->free_sequence[index] = i; 245 + permute_frees(test, alloc, tc, runs, failures, index + 1, end); 316 246 } 317 247 } 318 248 319 - static void gen_buf_sizes(struct kunit *test, struct binder_alloc *alloc, 320 - size_t *end_offset) 249 + static void gen_buf_sizes(struct kunit *test, 250 + struct binder_alloc *alloc, 251 + struct binder_alloc_test_case_info *tc, 252 + size_t *end_offset, unsigned long *runs, 253 + unsigned long *failures) 321 254 { 322 255 size_t last_offset, offset = 0; 323 256 size_t front_sizes[BUFFER_NUM]; ··· 345 238 int seq[BUFFER_NUM] = {0}; 346 239 int i; 347 240 241 + tc->free_sequence = seq; 348 242 for (i = 0; i < BUFFER_NUM; i++) { 349 243 last_offset = offset; 350 244 offset = end_offset[i]; 351 245 front_sizes[i] = offset - last_offset; 352 246 back_sizes[BUFFER_NUM - i - 1] = front_sizes[i]; 353 247 } 248 + back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1]; 249 + 354 250 /* 355 251 * Buffers share the first or last few pages. 356 252 * Only BUFFER_NUM - 1 buffer sizes are adjustable since 357 253 * we need one giant buffer before getting to the last page. 358 254 */ 359 - back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1]; 360 - permute_frees(test, alloc, front_sizes, seq, 0, 255 + tc->front_pages = true; 256 + tc->buffer_sizes = front_sizes; 257 + permute_frees(test, alloc, tc, runs, failures, 0, 361 258 end_offset[BUFFER_NUM - 1]); 362 - permute_frees(test, alloc, back_sizes, seq, 0, alloc->buffer_size); 259 + 260 + tc->front_pages = false; 261 + tc->buffer_sizes = back_sizes; 262 + permute_frees(test, alloc, tc, runs, failures, 0, alloc->buffer_size); 363 263 } 364 264 365 265 static void gen_buf_offsets(struct kunit *test, struct binder_alloc *alloc, 366 - size_t *end_offset, int index) 266 + size_t *end_offset, int *alignments, 267 + unsigned long *runs, unsigned long *failures, 268 + int index) 367 269 { 368 270 size_t end, prev; 369 271 int align; 370 272 371 273 if (index == BUFFER_NUM) { 372 - gen_buf_sizes(test, alloc, end_offset); 274 + struct binder_alloc_test_case_info tc = {0}; 275 + 276 + stringify_alignments(test, alignments, tc.alignments, 277 + ALIGNMENTS_BUFLEN); 278 + 279 + gen_buf_sizes(test, alloc, &tc, end_offset, runs, failures); 373 280 return; 374 281 } 375 282 prev = index == 0 ? 0 : end_offset[index - 1]; ··· 397 276 else 398 277 end += BUFFER_MIN_SIZE; 399 278 end_offset[index] = end; 400 - gen_buf_offsets(test, alloc, end_offset, index + 1); 279 + alignments[index] = align; 280 + gen_buf_offsets(test, alloc, end_offset, alignments, runs, 281 + failures, index + 1); 401 282 } 402 283 } 403 284 ··· 451 328 { 452 329 struct binder_alloc_test *priv = test->priv; 453 330 size_t end_offset[BUFFER_NUM]; 331 + int alignments[BUFFER_NUM]; 332 + unsigned long failures = 0; 333 + unsigned long runs = 0; 454 334 455 - gen_buf_offsets(test, &priv->alloc, end_offset, 0); 335 + gen_buf_offsets(test, &priv->alloc, end_offset, alignments, &runs, 336 + &failures, 0); 456 337 457 - KUNIT_EXPECT_EQ(test, binder_alloc_test_failures, 0); 338 + KUNIT_EXPECT_EQ(test, runs, TOTAL_EXHAUSTIVE_CASES); 339 + KUNIT_EXPECT_EQ(test, failures, 0); 458 340 } 459 341 460 342 /* ===== End test cases ===== */