/** * enum buf_end_align_type - Page alignment of a buffer * end with regard to the end of the previous buffer. * * In the pictures below, buf2 refers to the buffer we * are aligning. buf1 refers to previous buffer by addr. * Symbol [ means the start of a buffer, ] means the end * of a buffer, and | means page boundaries.
*/ enum buf_end_align_type { /** * @SAME_PAGE_UNALIGNED: The end of this buffer is on * the same page as the end of the previous buffer and * is not page aligned. Examples: * buf1 ][ buf2 ][ ... * buf1 ]|[ buf2 ][ ...
*/
SAME_PAGE_UNALIGNED = 0, /** * @SAME_PAGE_ALIGNED: When the end of the previous buffer * is not page aligned, the end of this buffer is on the * same page as the end of the previous buffer and is page * aligned. When the previous buffer is page aligned, the * end of this buffer is aligned to the next page boundary. * Examples: * buf1 ][ buf2 ]| ... * buf1 ]|[ buf2 ]| ...
*/
SAME_PAGE_ALIGNED, /** * @NEXT_PAGE_UNALIGNED: The end of this buffer is on * the page next to the end of the previous buffer and * is not page aligned. Examples: * buf1 ][ buf2 | buf2 ][ ... * buf1 ]|[ buf2 | buf2 ][ ...
*/
NEXT_PAGE_UNALIGNED, /** * @NEXT_PAGE_ALIGNED: The end of this buffer is on * the page next to the end of the previous buffer and * is page aligned. Examples: * buf1 ][ buf2 | buf2 ]| ... * buf1 ]|[ buf2 | buf2 ]| ...
*/
NEXT_PAGE_ALIGNED, /** * @NEXT_NEXT_UNALIGNED: The end of this buffer is on * the page that follows the page after the end of the * previous buffer and is not page aligned. Examples: * buf1 ][ buf2 | buf2 | buf2 ][ ... * buf1 ]|[ buf2 | buf2 | buf2 ][ ...
*/
NEXT_NEXT_UNALIGNED, /** * @LOOP_END: The number of enum values in &buf_end_align_type. * It is used for controlling loop termination.
*/
LOOP_END,
};
for (i = 0; i < BUFFER_NUM; i++)
binder_alloc_free_buf(alloc, buffers[seq[i]]);
for (i = 0; i <= (end - 1) / PAGE_SIZE; i++) { if (list_empty(page_to_lru(alloc->pages[i]))) {
kunit_err(test, "expect lru but is %s at page index %d\n",
alloc->pages[i] ? "alloc" : "free", i);
failures++;
}
}
while ((count = list_lru_count(alloc->freelist))) {
list_lru_walk(alloc->freelist, binder_alloc_free_page,
NULL, count);
}
for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) { if (alloc->pages[i]) {
kunit_err(test, "expect free but is %s at page index %d\n",
list_empty(page_to_lru(alloc->pages[i])) ? "alloc" : "lru", i);
failures++;
}
}
return failures;
}
/* Executes one full test run for the given test case. */ staticbool binder_alloc_test_alloc_free(struct kunit *test, struct binder_alloc *alloc, struct binder_alloc_test_case_info *tc,
size_t end)
{ unsignedlong pages = PAGE_ALIGN(end) / PAGE_SIZE; struct binder_buffer *buffers[BUFFER_NUM]; unsignedlong failures; bool failed = false;
failures = list_lru_count(alloc->freelist);
failed = failed || failures;
KUNIT_EXPECT_EQ_MSG(test, failures, 0, "lru list should be empty after reallocation but still has %lu pages",
failures);
failures = binder_alloc_test_free_buf(test, alloc, buffers,
tc->buffer_sizes,
tc->free_sequence, end);
failed = failed || failures;
KUNIT_EXPECT_EQ_MSG(test, failures, 0, "Reallocated buffers not freed correctly: %lu/%lu pages not on lru list",
failures, pages);
failures = binder_alloc_test_free_page(test, alloc);
failed = failed || failures;
KUNIT_EXPECT_EQ_MSG(test, failures, 0, "Failed to clean up allocated pages: %lu/%lu pages still installed",
failures, (alloc->buffer_size / PAGE_SIZE));
return failed;
}
staticbool is_dup(int *seq, int index, int val)
{ int i;
for (i = 0; i < index; i++) { if (seq[i] == val) returntrue;
} returnfalse;
}
tc->free_sequence = seq; for (i = 0; i < BUFFER_NUM; i++) {
last_offset = offset;
offset = end_offset[i];
front_sizes[i] = offset - last_offset;
back_sizes[BUFFER_NUM - i - 1] = front_sizes[i];
}
back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1];
/* * Buffers share the first or last few pages. * Only BUFFER_NUM - 1 buffer sizes are adjustable since * we need one giant buffer before getting to the last page.
*/
tc->front_pages = true;
tc->buffer_sizes = front_sizes;
permute_frees(test, alloc, tc, runs, failures, 0,
end_offset[BUFFER_NUM - 1]);
/** * binder_alloc_exhaustive_test() - Exhaustively test alloc and free of buffer pages. * @test: The test context object. * * Allocate BUFFER_NUM buffers to cover all page alignment cases, * then free them in all orders possible. Check that pages are * correctly allocated, put onto lru when buffers are freed, and * are freed when binder_alloc_free_page() is called.
*/ staticvoid binder_alloc_exhaustive_test(struct kunit *test)
{ struct binder_alloc_test *priv = test->priv;
size_t end_offset[BUFFER_NUM]; int alignments[BUFFER_NUM]; unsignedlong failures = 0; unsignedlong runs = 0;
ret = list_lru_init(&priv->binder_test_freelist); if (ret) {
kunit_err(test, "Failed to initialize test freelist\n"); return ret;
}
/* __binder_alloc_init requires mm to be attached */
ret = kunit_attach_mm(); if (ret) {
kunit_err(test, "Failed to attach mm\n"); return ret;
}
__binder_alloc_init(&priv->alloc, &priv->binder_test_freelist);
priv->filp = anon_inode_getfile("binder_alloc_kunit",
&binder_alloc_test_fops, &priv->alloc,
O_RDWR | O_CLOEXEC); if (IS_ERR_OR_NULL(priv->filp)) {
kunit_err(test, "Failed to open binder alloc test driver file\n"); return priv->filp ? PTR_ERR(priv->filp) : -ENOMEM;
}
priv->mmap_uaddr = kunit_vm_mmap(test, priv->filp, 0, BINDER_MMAP_SIZE,
PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
0); if (!priv->mmap_uaddr) {
kunit_err(test, "Could not map the test's transaction memory\n"); return -ENOMEM;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.